# Pentest Script Generator

> Tự động tạo pentest script và verify script từ báo cáo lỗ hổng Strix (vuln-XXXX.md). Kích hoạt khi người dùng đưa vào file vuln-XXXX.md, mô tả lỗ hổng bằng văn bản, dán raw HTTP request từ Burp Suite, hoặc nói 'viết script test', 'tạo pentest script', 'tạo verify script', 'generate test từ vuln'. Output: pentest_TYPE_vulnXXXX.py (TC-01..TC-N, cleanup, JSON export, dry-run) và verify_vulnXXXX.py (exit 0/1/2). Dùng cho authorized security research và bug bounty.

- Skill: `ptn1411/pentest-script-generator` (Agent Skill)
- Install (CLI): `npx skillmds@latest add ptn1411/pentest-script-generator`
- Raw SKILL.md: https://api.skillmd.com/api/skills/ptn1411/pentest-script-generator/raw
- Safety review: pending
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: Security
- Author: ptn1411 (https://skillmd.com/u/ptn1411)
- Updated: 2026-09-17
- Page: https://skillmd.com/skills/ptn1411/pentest-script-generator

---


# Pentest Script Generator — SOP (Strix-native v2)

Generate two professional Python scripts for each `vuln-XXXX.md` report.
Updated from analysis of 196 real-world vulnerabilities.

> **Language rule**: All skill instructions and generated script code use English.
> **Final summary presented to the user must be in Vietnamese.**

---

## Step 1 — Parse vuln-XXXX.md (Strix schema)

Schema produced by `tracer.py → create_vulnerability_report()`:

```
# <title>
**ID:** vuln-XXXX
**Severity:** CRITICAL | HIGH | MEDIUM | LOW
**Found:** <ISO timestamp UTC>
**Target:** <base URL>
**Endpoint:** <path>          ← optional
**Method:** <HTTP method>     ← optional
**CVE:** CVE-YYYY-NNNNN       ← optional
**CWE:** CWE-NNN              ← optional
**CVSS:** <float>

## Description
## Impact
## Technical Analysis
## Proof of Concept
<poc_description>
```<poc_script_code — ALWAYS PRESENT>```
## Code Analysis    ← optional, whitebox
## Remediation
```

**Key rule:** `poc_script_code` is always present — use it as the primary source for test logic.
If `Endpoint` is missing → extract from Technical Analysis or PoC code.

---

## Step 2 — Identify vulnerability type

### Authorization / Access Control

| Type | Trigger Keywords | TC Pattern |
|------|-----------------|------------|
| **BFLA** | admin endpoint, non-admin users can access, BFLA | Low-priv token → admin route |
| **IDOR/BOLA** | cross-user, order id, user_id param | Swap resource ID to another user |
| **Unauth API** | unauthenticated access, no auth required | Request with no Authorization header |
| **Supabase PostgREST** | anon apikey, PostgREST, RLS bypass | Call REST with public `apikey` |
| **Firestore Rules** | Firestore, RLS misconfiguration | Read/write with anonymous user |
| **Unauth Order Ops** | order cancellation, order status | GET/POST order endpoint without token |

### Business Logic

| Type | Trigger Keywords | TC Pattern |
|------|----------|--------------|
| **Price Tampering** | price tampering, client-side price | POST order with price=1 |
| **Payment Bypass** | payment bypass, free license, paid without | Create order, skip payment step |
| **Negative Total** | negative totals, wallet credit | Send negative amount |
| **Rounding Error** | rounding error, free credit | Try decimal edge-case values |
| **Rate Limit Bypass** | X-Forwarded-For, IP spoofing | Add `X-Forwarded-For: 1.2.3.X` header |
| **OTP Brute Force** | missing OTP brute-force protection | Send many wrong OTPs in sequence |
| **Registration Farming** | unlimited trial, credit farming | Create multiple accounts for trial |

### Injection / XSS

| Type | Trigger Keywords | TC Pattern |
|------|----------|--------------|
| **Stored XSS** | stored xss, innerHTML, marked.parse | Upload payload with unique marker |
| **DOM XSS** | DOM-based, innerHTML, url param | Playwright + javascript: URL |
| **Reflected XSS** | reflected xss, POST body reflection | GET/POST with payload in param |
| **JSONP Injection** | JSONP callback, arbitrary JS | Call callback with random function name |
| **Script Injection** | installer script, key parameter | Send bash command substitution payload |
| **SQLi** | SQL injection, remember_token cookie | SQLi payload via cookie/param |

### SSRF

| Type | Trigger Keywords | TC Pattern |
|------|----------|--------------|
| **Blind SSRF** | blind SSRF, OAST, webhook | Send webhook.site domain |
| **SSRF IMDS** | cloud metadata, IMDS, 169.254 | Send http://169.254.169.254/ |
| **SSRF Internal** | internal network, port scanning | Send 127.0.0.1.nip.io variants |
| **SSRF xmlrpc** | wordpress xmlrpc, pingback | POST xmlrpc.php with internal URL |

### Account Takeover

| Type | Trigger Keywords | TC Pattern |
|------|----------|--------------|
| **Password Reset Leak** | plaintext password, password in response | POST forgot-password → check response for password field |
| **Account Enumeration** | differential error, user enumeration | Try existing vs non-existing email, compare response |
| **Session Fixation** | PHPSESSID not rotated, session fixation | Capture session before login, verify PHPSESSID changes after |
| **Token Not Revoked** | token remains valid after logout | Logout → replay old token on API |
| **OTP Disclosed** | OTP in response, OTP disclosed | POST forgot → check response for OTP field |
| **Default Credentials** | default credentials, admin:admin | Login with default credential pairs |

### CORS / Cookie

| Type | Trigger Keywords | TC Pattern |
|------|----------|--------------|
| **CORS Arbitrary Origin** | arbitrary origin reflection, CORS misconfiguration | Send `Origin: https://evil.com`, check Access-Control-Allow-Origin |
| **Cookie Missing Secure** | missing Secure flag, session cookie HTTP | Send HTTP request, check Set-Cookie flags |
| **CSRF** | CSRF, state-changing GET | Send request without CSRF token |

### Information Disclosure

| Type | Trigger Keywords | TC Pattern |
|------|----------|--------------|
| **Source Map** | sourcemap, sourcesContent | GET .js.map file, check sourcesContent |
| **Hardcoded Key in JS** | hardcoded API key, JS bundle | Fetch JS file, grep for key patterns |
| **Laravel Debug** | Laravel debug, stack trace, Ignition | GET endpoint with Accept: text/html |
| **Vite Dev Server** | Vite dev server, /@fs | GET /@vite/client, /@fs/etc/passwd |
| **Backup Archive** | backup archive, .zip, .sql dump | GET /htdocs.zip, /backup.sql |
| **phpinfo Exposure** | phpinfo, /info.php | GET /info.php |

### Infrastructure

| Type | Trigger Keywords | TC Pattern |
|------|----------|--------------|
| **Cloudflare Origin Bypass** | origin exposure, WAF bypass | Resolve subdomain, call origin IP directly |
| **Exposed DB** | exposed MySQL, MariaDB, Redis public | Check open ports, read banner |
| **Kubernetes Exposed** | Kubernetes API, TCP/6443 | GET /version, /healthz |
| **WordPress User Enum** | WordPress REST API, user enumeration | GET /wp-json/wp/v2/users |

---

## Step 3 — Identify auth mechanism

| PoC Signal | Auth Type | How to obtain |
|------------|-----------|----------------|
| `Authorization: Bearer eyJ...` | JWT | register → login → `access_token` |
| `apikey=` or `x-api-key` | API Key | From config/profile endpoint |
| Supabase `anon` key | Supabase anon | From JS bundle or network tab |
| Cookie `PHPSESSID` / `session` | PHP session | Login form → capture cookie |
| `recaptchaToken: ""` | reCAPTCHA bypass | Send empty string |
| No token in PoC | Unauthenticated | No Authorization header needed |
| `X-Forwarded-For` | Rate limit bypass | Add spoofed IP header |

---

## Step 4 — Standard code template (use for all pentest scripts)

```python
#!/usr/bin/env python3
"""
============================================================================
  Penetration Test Script — vuln-XXXX — <title>
  Target   : <target>
  Severity : <SEVERITY>  |  CVSS: <score>
  CWE      : <CWE-NNN>
============================================================================
  Description: <1-2 sentences>

  Test Cases:
    TC-01: ...
    TC-0N: Cleanup

  Usage:
    pip install requests colorama
    python pentest_TYPE_vulnXXXX.py [--base-url URL] [--dry-run] [--output-dir DIR]

  ⚠️  RUN ONLY ON AUTHORIZED TEST TARGETS  ⚠️
============================================================================
"""
import argparse, json, os, time, sys
from dataclasses import dataclass, field
from datetime import datetime, timezone
from enum import Enum
from typing import Any, Optional

try:
    import requests; from requests.exceptions import RequestException
except ImportError:
    print("[!] pip install requests"); sys.exit(1)

try:
    from colorama import Fore, Style, init as colorama_init; colorama_init(autoreset=True)
except ImportError:
    class _Stub:
        def __getattr__(self, _): return ""
    Fore = Style = _Stub()


class Verdict(Enum):
    VULN="VULNERABLE"; SAFE="SAFE"; ERROR="ERROR"; INFO="INFO"; SKIP="SKIPPED"

@dataclass
class TestResult:
    test_id: str; name: str; verdict: Verdict
    status_code: Optional[int]=None; detail: str=""
    response_preview: str=""; raw_response: Any=None
    timestamp: str=field(default_factory=lambda: datetime.now(timezone.utc).isoformat())


def _print_result(r: TestResult):
    c={Verdict.VULN:Fore.RED,Verdict.SAFE:Fore.GREEN,Verdict.ERROR:Fore.YELLOW,
       Verdict.INFO:Fore.BLUE,Verdict.SKIP:Fore.WHITE}.get(r.verdict,"")
    i={Verdict.VULN:"✗ VULNERABLE",Verdict.SAFE:"✓ SAFE",Verdict.ERROR:"⚠ ERROR",
       Verdict.INFO:"ℹ INFO",Verdict.SKIP:"⊘ SKIPPED"}.get(r.verdict,"?")
    print(f"\n{c}[{r.test_id}] {r.name}\n  Result  : {i}")
    if r.status_code: print(f"  HTTP    : {r.status_code}")
    if r.detail:      print(f"  Detail  : {r.detail}")
    if r.response_preview: print(f"  Response: {r.response_preview[:300]}")

def _summary(results, vuln_id):
    v=sum(1 for r in results if r.verdict==Verdict.VULN)
    s=sum(1 for r in results if r.verdict==Verdict.SAFE)
    e=sum(1 for r in results if r.verdict==Verdict.ERROR)
    print(f"\n{'═'*68}\n  SUMMARY — {vuln_id}")
    for r in results:
        c=Fore.RED if r.verdict==Verdict.VULN else Fore.GREEN if r.verdict==Verdict.SAFE \
          else Fore.YELLOW if r.verdict==Verdict.ERROR else Fore.BLUE
        print(f"  {c}[{r.verdict.value:12s}] {r.test_id}: {r.name}")
    print(f"\n  Vulnerable: {v}  |  Safe: {s}  |  Error: {e}")
    if v: print(f"\n  {Fore.RED}⚠  CONCLUSION: VULNERABILITY CONFIRMED ({v} endpoint(s))")

def _export(results, vuln_id, target, output_dir):
    os.makedirs(output_dir, exist_ok=True)
    p = os.path.join(output_dir, f"pentest_{vuln_id}_report.json")
    with open(p,"w",encoding="utf-8") as f:
        json.dump({"vulnerability_id":vuln_id,"target":target,
            "timestamp":datetime.now(timezone.utc).isoformat(),
            "summary":{"total":len(results),
                "vulnerable":sum(1 for r in results if r.verdict==Verdict.VULN),
                "safe":sum(1 for r in results if r.verdict==Verdict.SAFE)},
            "results":[{"test_id":r.test_id,"name":r.name,"verdict":r.verdict.value,
                "status_code":r.status_code,"detail":r.detail,
                "raw_response":r.raw_response,"timestamp":r.timestamp}
                for r in results]},f,indent=2,ensure_ascii=False,default=str)
    print(f"\n  {Fore.CYAN}📄 Report: {p}")
```

---

## Step 5 — TC patterns by vulnerability type

### BFLA / IDOR

```
TC-01: Register test account (recaptchaToken="" if bypass available)
TC-02: Login → capture JWT access_token
TC-03: Decode JWT → confirm role = "user"
TC-04: Call admin endpoint with user token → expect 403; 200 = VULNERABLE
TC-05: Control: call properly-enforced endpoint → confirm 403
TC-06: (IDOR) Swap resource ID to another user's resource
TC-07: Cleanup
```

### Unauthenticated API / Supabase

```
TC-01: GET endpoint with NO Authorization header → expect 401/403; 200 = VULNERABLE
TC-02: GET with valid token → expect 200 (confirm endpoint functions)
TC-03: GET with invalid token → expect 401
# Supabase variant:
TC-01: GET /rest/v1/{table} with header "apikey: <anon_key>" → inspect returned data
TC-02: No apikey header → expect 401
```

### Business Logic — Price Tampering

```
TC-01: Create order with original price → expect success (baseline)
TC-02: Create order with price=1 (tampered) → if success = VULNERABLE
TC-03: Create order with price=-1 (negative) → observe response
TC-04: Cleanup — cancel created orders
```

### Business Logic — Payment Bypass

```
TC-01: Check if confirm-payment endpoint requires valid payment token
TC-02: POST confirm with arbitrary order_id → expect 403/404; 200 = VULNERABLE
TC-03: Check order status after confirm
TC-04: Cleanup
```

### Account Takeover — Password Reset Leak

```
TC-01: POST /forgot-password with victim email
TC-02: Check response body for "password" field → VULNERABLE if present
TC-03: Attempt login with password from response → confirms full ATO
TC-04: (Optional) Try non-existent email → compare response (enumeration check)
```

### Account Takeover — Token Not Revoked After Logout

```
TC-01: Login → capture access_token
TC-02: Call authenticated API → expect 200 (token valid)
TC-03: POST /logout (or /api/auth/logout)
TC-04: Replay old token on authenticated API → expect 401; 200 = VULNERABLE
```

### Rate Limit Bypass via X-Forwarded-For

```
TC-01: Send N requests with real IP → record when blocked
TC-02: Send N+1 requests with X-Forwarded-For: <random_IP> → if not blocked = VULNERABLE
TC-03: Test X-Real-IP, CF-Connecting-IP header variants
```

### CORS Arbitrary Origin

```
TC-01: GET endpoint with Origin: https://evil.com
        → check Access-Control-Allow-Origin: https://evil.com = VULNERABLE
TC-02: GET with Origin: null → check response
TC-03: GET with no Origin → baseline
TC-04: If credentials: check Access-Control-Allow-Credentials: true (escalates severity)
```

### Stored XSS (Upload)

```
TC-01: Get auth token (if required)
TC-02: Upload SVG/HTML file with payload + unique marker
TC-03: Fetch CDN URL → check Content-Type and payload presence
TC-04: (Playwright) Browser-verify JS execution via dialog event
TC-05: Cleanup — DELETE uploaded file
```

### SSRF (Blind)

```
TC-01: Get auth token
TC-02: Trigger with OAST domain (webhook.site) → print manual check instructions
TC-03: Trigger with 127.0.0.1.nip.io, 10.0.0.1.nip.io
TC-04: (if applicable) Trigger with http://169.254.169.254/latest/meta-data/
TC-05: Print manual checklist
TC-06: Cleanup
```

### Information Disclosure — Source Map

```
TC-01: GET /main-XXXX.js → check for "//# sourceMappingURL=" comment
TC-02: GET /main-XXXX.js.map → check for "sourcesContent" field
TC-03: Analyze sourcesContent for hardcoded secrets (key, password, apikey)
```

### Information Disclosure — Laravel Debug / Vite Dev Server

```
TC-01: GET endpoint with Accept: text/html → check for Ignition/debug page
TC-02: GET /@vite/client → 200 = Vite dev server exposed
TC-03: GET /@fs/etc/passwd → check for file read
TC-04: GET /info.php → check for phpinfo() output
```

### WordPress

```
TC-01: GET /wp-json/wp/v2/users?per_page=100 → user enumeration
TC-02: GET /?author=1 → redirect-based user enumeration
TC-03: POST /xmlrpc.php with system.listMethods payload
TC-04: POST /xmlrpc.php with pingback SSRF payload → OAST domain
```

### Cloudflare Origin Bypass

```
TC-01: Resolve subdomain (e.g., api.example.com) → obtain origin IP
TC-02: GET http://<origin_IP>/ directly → compare with CDN response
TC-03: Check WAF/rate-limit bypass on direct origin access
```

### Session Fixation

```
TC-01: GET login page → capture PHPSESSID from Set-Cookie
TC-02: POST login with credentials + same pre-login session cookie
TC-03: Check PHPSESSID after login → UNCHANGED = VULNERABLE
```

---

## Step 6 — Generate verify_vulnXXXX.py

Minimal script: 1–3 requests, exit 0/1/2:

```python
#!/usr/bin/env python3
"""
Verify Script — vuln-XXXX — <title>
Exit codes: 0=SAFE  1=VULNERABLE  2=ERROR
Usage: python verify_vulnXXXX.py [--base-url URL]
"""
import sys, argparse, requests
requests.packages.urllib3.disable_warnings()

DEFAULT = "<TARGET>"

def verify(base_url: str) -> int:
    try:
        r = requests.get(f"{base_url}/endpoint", timeout=15, verify=False)
        if r.status_code == 200:
            print(f"[VULNERABLE] {r.status_code} — <reason>")
            print(f"  {r.text[:300]}")
            return 1
        elif r.status_code in (401, 403):
            print(f"[SAFE] {r.status_code} — endpoint properly protected")
            return 0
        print(f"[UNKNOWN] {r.status_code}")
        return 2
    except Exception as e:
        print(f"[ERROR] {e}"); return 2

if __name__ == "__main__":
    p = argparse.ArgumentParser()
    p.add_argument("--base-url", default=DEFAULT)
    sys.exit(verify(p.parse_args().base_url))
```

---

## Step 7 — File naming convention

| Vulnerability Type | Type Prefix |
|-------------------|-------------|
| BFLA | `bfla` |
| IDOR / BOLA | `idor` |
| Unauthenticated API | `unauth` |
| Stored XSS | `xss_stored` |
| DOM XSS | `xss_dom` |
| Reflected XSS | `xss_reflected` |
| SSRF | `ssrf` |
| Business Logic (price/payment) | `bizlogic` |
| Account Takeover | `ato` |
| CORS | `cors` |
| SQL Injection | `sqli` |
| Information Disclosure | `infodisclosure` |
| Rate Limit | `ratelimit` |
| Session/Cookie | `session` |
| WordPress-specific | `wordpress` |
| Supabase-specific | `supabase` |
| Infrastructure | `infra` |

Save output to: `<project_dir>/vulnerabilities/`

---

## Step 8 — Workflow

```
1. READ   → Parse vuln-XXXX.md (or description / raw HTTP request)
2. DETECT → Identify vuln type from trigger keywords
3. AUTH   → Identify auth mechanism from PoC signals
4. WRITE  → Generate pentest_TYPE_vulnXXXX.py
            - Header with metadata (ID, Severity, CVSS, CWE, Target)
            - Verdict enum + TestResult dataclass
            - TC-01..TC-N methods (exploit + control + cleanup)
            - _save_evidence() helper
            - _summary() and _export() helpers
            - main() with argparse (--base-url, --dry-run, --output-dir)
5. WRITE  → Generate verify_vulnXXXX.py (minimal, exit 0/1/2)
6. REPORT → Present final summary to user IN VIETNAMESE (see Step 9)
```

---

## Step 9 — Final report to user (ALWAYS in Vietnamese)

After generating both files, present this summary **in Vietnamese**:

```
✅ Đã tạo xong cho vuln-XXXX (<tiêu đề>):

  📄 vulnerabilities/vuln-XXXX.md               (Severity: X, CVSS: Y)
  🐍 vulnerabilities/pentest_TYPE_vulnXXXX.py   (N test cases)
  ⚡ vulnerabilities/verify_vulnXXXX.py          (quick verify, exit 0/1/2)

▶  Cách chạy:
   python vulnerabilities/pentest_TYPE_vulnXXXX.py --base-url https://target.com
   python vulnerabilities/verify_vulnXXXX.py --base-url https://target.com

📋 Tóm tắt:
   - Loại lỗ hổng : <TYPE>
   - Auth mechanism: <auth type>
   - Số test cases : N
   - Cleanup       : ✅ included
```

---

## Anti-Patterns

| ❌ Don't | ✅ Do |
|----------|-------|
| Hardcode credentials in script | Use argparse + env vars |
| Skip cleanup TC | Always add cleanup as last TC |
| Claim vuln without HTTP evidence | Log status_code + response preview |
| Use `requests.get` without timeout | Always `timeout=15` |
| Skip dry-run mode | Always support `--dry-run` flag |
| Generate script without verify script | Always generate both |
| Present results to user in English | Always present final summary in Vietnamese |

