Install
$ agentstack add skill-wang200935-security-agent-skills-network-pentest Open-source listing, not yet scanned by AgentStack. Follow the source repository for install instructions.
Security review
⚠ Flagged1 finding(s); flagged for manual review. · v0.1.0 How review works →
- • Prompt-injection patterns
- • Secret / credential exfiltration
- • Dangerous shell & filesystem operations
- • Untrusted network calls
- • Known-malicious package signatures
- high Dangerous shell/eval execution.
What it can access
- ✓ Network access No
- ● Filesystem access Used
- ● Shell / process execution Used
- ● Environment & secrets Used
- ● Dynamic code execution Used
From automated source analysis of v0.1.0. “Used” means the capability is present in the source — more access means more to trust, not that it’s unsafe.
Reliability & compatibility
Declared compatibility
Compatibility is declared by the source manifest. End-to-end runtime verification is coming, see below.
We're building live execution health for every listing: tool-call success rate, median latency, uptime, and last-checked timestamps, measured, not self-reported. It isn't live yet, so we don't show numbers we can't stand behind.
How agent discovery & health will work →About
Network Penetration Testing
Complete network pentesting workflow from discovery to exploitation.
Methodology
1. HOST DISCOVERY → 2. PORT SCANNING → 3. SERVICE ENUM → 4. VULN ASSESS → 5. EXPLOITATION
Phase 1: Host Discovery
ARP Scan (local network)
# ARP scan — fastest for local subnet
arp -a
# Or use ping sweep
for i in $(seq 1 254); do
(ping -c 1 -W 1 192.168.1.$i | grep "bytes from" &)
done
IPv6 Host Discovery (2025-2026)
# Nmap IPv6 host discovery (requires -6 flag and interface -e for link-local)
nmap -6 -sn -e eth0 fe80::/64 # Link-local multicast (NDP/NS)
nmap -6 -sn 2001:db8::/64 # Global unicast prefix
nmap -6 -sn --script targets-ipv6-map4to6 192.168.1.0/24 # Map IPv4->IPv6 (NSE)
# IPv6 multicast listeners (MLD)
nmap -6 --script targets-ipv6-multicast-mld -sn ff02::1%eth0
# IPv6 DNS service discovery
nmap -6 --script dns-service-discovery -p 5353
# Passive IPv6 neighbor discovery (no packets sent)
ndp -a # macOS/BSD
ip -6 neigh show # Linux
Key NSE Scripts for IPv6 (2025+):
targets-ipv6-map4to6— Map IPv4 addresses to IPv6 (EUI-64, SLAAC, etc.)targets-ipv6-multicast-mld— Discover hosts via MLD multicast listenersdhcpv6-discover— Discover DHCPv6 serversipv6-neighbor-discovery— Passive NDP neighbor cache enumeration
ICMP / TCP Ping Sweep
import subprocess
import concurrent.futures
def ping_sweep(subnet: str, start: int = 1, end: int = 254) -> list:
"""Discover live hosts via ICMP ping."""
live_hosts = []
def ping_host(ip):
try:
result = subprocess.run(
['ping', '-c', '1', '-W', '1', ip],
capture_output=True, text=True, timeout=2
)
if '1 received' in result.stdout or '1 packets received' in result.stdout:
return ip
except:
pass
return None
with concurrent.futures.ThreadPoolExecutor(max_workers=50) as executor:
futures = {executor.submit(ping_host, f'{subnet}.{i}'): i
for i in range(start, end + 1)}
for future in concurrent.futures.as_completed(futures):
result = future.result()
if result:
live_hosts.append(result)
return sorted(live_hosts)
Phase 2: Port Scanning (No nmap Required)
Pure Python Port Scanner (Fast — concurrent.futures)
When nmap is unavailable (containerized environments, minimal VPS), use Python's concurrent.futures for parallel TCP scanning. 1000+ ports scanned in under 30 seconds.
import socket
import concurrent.futures
def scan_ports_fast(host: str, ports: list, timeout: float = 0.3, workers: int = 100) -> dict:
"""Scan TCP ports in parallel. No nmap needed."""
results = {}
def check_port(port):
try:
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.settimeout(timeout)
result = s.connect_ex((host, port))
s.close()
return (port, result == 0)
except:
return (port, False)
with concurrent.futures.ThreadPoolExecutor(max_workers=workers) as ex:
futures = {ex.submit(check_port, p): p for p in ports}
for f in concurrent.futures.as_completed(futures):
port, is_open = f.result()
if is_open:
results[port] = 'open'
return dict(sorted(results.items()))
# Usage:
# ports = list(range(1, 1025)) + [1433, 1521, 2375, 2376, 3000, 3128,
# 3306, 3389, 4000, 4443, 5000, 5432, 5555, 5566, 5900, 5985, 5986,
# 6379, 6443, 8000, 8080, 8081, 8443, 8888, 9000, 9090, 9200,
# 9300, 9443, 10000, 10250, 11211, 15672, 27017, 50000, 55566, 55666]
# open = scan_ports_fast('59.127.221.52', ports)
# → {80: 'open', 99: 'open', 553: 'open', 554: 'open'}
Key ports to always include in pentests:
- 554 — RTSP streaming (IP cameras, NVR)
- 553 — CCTV/NVR web interfaces (Dahua/Hikvision OEM)
- 99 — Common alternative HTTP port (old/staging sites)
- 55566, 55666 — Often used by custom services (check
plugin.jsfor hints)
See references/cctv-nvr-fingerprinting.md for full CCTV system fingerprinting including Dahua/Hikvision challenge-response auth and default credentials.
Modern Fast Scanners: masscan, RustScan (2025-2026 Updates)
# masscan — fastest Internet-scale scanner (async SYN, 10M pps+)
# GitHub: robertdavidgraham/masscan — 2025 releases: improved IPv6, better banner grabbing, PF_RING support
masscan -p1-65535 10.0.0.0/8 --rate=100000 -oJ masscan.json
masscan -p443 --banners 192.168.1.0/24 --rate=50000 --source-ip 192.168.1.100
# RustScan — 65k ports in ~8 seconds, adaptive learning, auto-handoff to nmap
# GitHub: bee-san/RustScan — 2025: v2.3.0+ improved CIDR, better timeout handling
rustscan -a 192.168.1.50 -- -A -sV -sC # Full nmap handoff
rustscan -a 10.0.0.0/24 --ulimit 5000 -- -p- # CIDR scan with ulimit bump
rustscan -a target --range 1-65535 -- --script vuln
# Comparison: masscan for massive scale, RustScan for fast targeted + nmap enrichment
IPv6 Port Scanning
# nmap IPv6 scanning (requires -6 and -e for link-local)
nmap -6 -sS -p 22,80,443,445,3389 -e eth0 fe80::1%eth0 # Link-local target
nmap -6 -sV -p- 2001:db8::1 # Global target, full scan
nmap -6 -sU --top-ports 100 -e eth0 fe80::/64 # UDP top 100 IPv6
# masscan IPv6 (experimental, use with --ipv6 flag)
masscan -p80,443 --ipv6 2001:db8::/32 --rate=10000
# RustScan IPv6
rustscan -a 2001:db8::1 -- -6 -sV
Common Port Quick Scan
COMMON_PORTS = {
21: 'FTP', 22: 'SSH', 23: 'Telnet', 25: 'SMTP',
53: 'DNS', 80: 'HTTP', 88: 'Kerberos', 110: 'POP3',
111: 'RPC', 135: 'MSRPC', 139: 'NetBIOS', 143: 'IMAP',
161: 'SNMP', 389: 'LDAP', 443: 'HTTPS', 445: 'SMB',
465: 'SMTPS', 514: 'Syslog', 587: 'SMTP-submission',
636: 'LDAPS', 993: 'IMAPS', 995: 'POP3S',
1433: 'MSSQL', 1521: 'Oracle', 2049: 'NFS',
3306: 'MySQL', 3389: 'RDP', 5432: 'PostgreSQL',
5900: 'VNC', 5985: 'WinRM-HTTP', 5986: 'WinRM-HTTPS',
6379: 'Redis', 8080: 'HTTP-Proxy', 8443: 'HTTPS-Alt',
9200: 'Elasticsearch', 11211: 'Memcached',
27017: 'MongoDB', 50000: 'SAP',
}
def quick_scan(host: str, timeout: float = 1.0) -> dict:
"""Quick scan of common ports with service identification."""
open_ports = scan_ports(host, list(COMMON_PORTS.keys()), timeout)
results = {}
for port in open_ports:
service = COMMON_PORTS.get(port, 'unknown')
banner = grab_banner(host, port)
results[port] = {'service': service, 'banner': banner}
return results
Banner Grabbing
def grab_banner(host: str, port: int, timeout: float = 2.0) -> str:
"""Grab service banner from an open port."""
banners_to_send = {
21: b'', # FTP — just connect
22: b'', # SSH — banner sent automatically
25: b'', # SMTP
80: b'HEAD / HTTP/1.0\\r\\n\\r\\n',
110: b'', # POP3
143: b'', # IMAP
443: b'', # HTTPS
3306: b'', # MySQL
5432: b'', # PostgreSQL
}
try:
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock.settimeout(timeout)
sock.connect((host, port))
# Send probe if needed
probe = banners_to_send.get(port, b'\\r\\n')
if probe:
sock.send(probe)
banner = sock.recv(1024)
sock.close()
return banner.decode('utf-8', errors='ignore').strip()
except:
return 'timeout/error'
New Nmap NSE Scripts (2025-2026) — Must-Haves
# Vulnerability detection category (--script vuln)
nmap -sV --script vuln # All vuln scripts
nmap -sV --script "vuln and not dos" # Exclude DoS scripts
# Critical new/updated NSE scripts 2025-2026:
# - http-react2shell.nse → CVE-2025-55182 / CVE-2025-66478 (React/Next.js RCE)
# - smb-vuln-cve2025-33073.nse → NTLM Reflection (CVE-2025-33073) — SYSTEM via SMB
# - smb-vuln-cve2025-58726.nse → SMB Server EoP (CVE-2025-58726)
# - rdp-vuln-cve2025-29966.nse → RDP Client Heap Overflow (CVE-2025-29966)
# - ssh-vuln-cve2025-26465.nse → OpenSSH MITM (VerifyHostKeyDNS) (CVE-2025-26465)
# - ssh-vuln-cve2025-26466.nse → OpenSSH Pre-auth DoS (CVE-2025-26466)
# - snmp-vuln-cve2025-20352.nse → Cisco IOS/IOS XE SNMP RCE (CVE-2025-20352)
# - snmp-vuln-cve2025-68615.nse → net-snmp Buffer Overflow (CVE-2025-68615)
# - http-sharepoint-rce.nse → CVE-2025-53770 / CVE-2026-45659 (SharePoint Deserialization RCE)
# - cisco-ike-rce.nse → CVE-2025-20393 (Cisco IOS RCE, CVSS 10.0)
# - beyondtrust-rce.nse → CVE-2026-1731 (BeyondTrust RCE — VShell/SparkRAT)
# - windows-ike-rce.nse → CVE-2026-33824 (Windows IKE Service RCE)
# - vulners.nse → CPE→CVE lookup via vulners.com API (always run)
# Usage examples:
nmap -sV -p 443 --script http-react2shell
nmap -sV -p 445 --script smb-vuln-cve2025-33073,smb-vuln-cve2025-58726
nmap -sV -p 3389 --script rdp-vuln-cve2025-29966
nmap -sV -p 22 --script ssh-vuln-cve2025-26465,ssh-vuln-cve2025-26466
nmap -sV -p 161 --script snmp-vuln-cve2025-20352,snmp-vuln-cve2025-68615
nmap -sV -p 443 --script http-sharepoint-rce
nmap -sV --script vulners --script-args mincvss=7.0
Automated CVE Detection with vulners.nse
# vulners.nse — maps detected service versions to CVEs via vulners.com API
nmap -sV --script vulners
nmap -sV --script vulners --script-args mincvss=7.0,api_key=
# Output example:
# PORT STATE SERVICE VERSION
# 22/tcp open ssh OpenSSH 9.6p1
# | vulners:
# | CVE-2025-26465 7.5 https://vulners.com/cve/CVE-2025-26465
# | CVE-2025-26466 7.5 https://vulners.com/cve/CVE-2025-26466
# |_ CVE-2025-61984 9.8 https://vulners.com/cve/CVE-2025-61984
UDP Scanning
def scan_udp(host: str, ports: list, timeout: float = 2.0) -> dict:
"""Basic UDP port scanner."""
results = {}
for port in ports:
try:
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
sock.settimeout(timeout)
sock.sendto(b'', (host, port))
try:
data, addr = sock.recvfrom(1024)
results[port] = 'open|filtered'
except socket.timeout:
# Try again — ICMP unreachable
try:
sock2 = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
sock2.settimeout(1)
sock2.sendto(b'', (host, port))
sock2.recvfrom(1024)
except ConnectionRefusedError:
results[port] = 'closed'
except socket.timeout:
results[port] = 'open|filtered'
finally:
sock2.close()
sock.close()
except:
pass
return results
Phase 3: Service Enumeration
SMB Enumeration
def enum_smb(host: str) -> dict:
"""Enumerate SMB shares and information."""
info = {}
# Check SMB port
if 445 not in scan_ports(host, [445]):
return {'error': 'SMB not accessible'}
# Try smbclient
try:
import subprocess
# List shares anonymously
result = subprocess.run(
['smbclient', '-L', f'//{host}', '-N'],
capture_output=True, text=True, timeout=10
)
info['shares'] = result.stdout
# Try null session
result2 = subprocess.run(
['smbclient', f'//{host}/IPC$', '-N', '-c', 'ls'],
capture_output=True, text=True, timeout=10
)
info['ipc'] = result2.stdout
except:
pass
# Check for EternalBlue (MS17-010)
info['vulnerable_to_eternalblue'] = True # flag for further testing
return info
SNMP Enumeration
def enum_snmp(host: str, community: str = 'public') -> dict:
"""Enumerate SNMP information."""
from hermes_tools import terminal
results = {}
# Try common community strings
communities = ['public', 'private', 'internal', 'snmp', 'cisco', 'secret']
for comm in communities:
result = terminal(
f"snmpwalk -v2c -c {comm} {host} 2>&1 | head -50",
timeout=15
)
if 'No Such Object' not in result['output'] and 'Timeout' not in result['output']:
results[comm] = result['output'][:1000]
return results
DNS Enumeration
def enum_dns(domain: str) -> dict:
"""Comprehensive DNS enumeration."""
from hermes_tools import terminal
results = {}
record_types = ['A', 'AAAA', 'MX', 'NS', 'TXT', 'CNAME', 'SOA', 'PTR']
for rtype in record_types:
result = terminal(f'dig +short {domain} {rtype}', timeout=10)
results[rtype] = result['output'].strip().split('\\n')
# Zone transfer attempt
ns_servers = results.get('NS', [])
for ns in ns_servers[:5]:
if ns:
axfr = terminal(f'dig AXFR {domain} @{ns}', timeout=10)
if 'XFR size' in axfr['output']:
results['zone_transfer'] = axfr['output']
break
# Subdomain brute force
common_subs = ['www', 'mail', 'ftp', 'admin', 'api', 'dev', 'staging',
'vpn', 'remote', 'portal', 'test', 'demo', 'blog', 'shop']
subs = []
for sub in common_subs:
result = terminal(f'dig +short {sub}.{domain}', timeout=5)
if result['output'].strip():
subs.append(f'{sub}.{domain}')
results['discovered_subdomains'] = subs
return results
Phase 4: Vulnerability Assessment
Service Version → CVE Mapping
# Common vulnerabilities to check for each service
VULN_CHECKS = {
'vsftpd 2.3.4': {'cve': 'CVE-2011-2523', 'desc': 'Backdoor command execution', 'cvss': 10.0},
'OpenSSH 7.2p1': {'cve': 'CVE-2016-6210', 'desc': 'User enumeration via timing', 'cvss': 5.9},
'Apache 2.4.49': {'cve': 'CVE-2021-41773', 'desc': 'Path traversal / RCE', 'cvss': 7.5},
'Apache 2.4.50': {'cve': 'CVE-2021-42013', 'desc': 'Path traversal bypass', 'cvss': 9.8},
'nginx 1.20': {'cve': 'CVE-2021-23017', 'desc': 'DNS resolver vuln', 'cvss': 7.7},
'Tomcat': {'check': 'Is /manager accessible? Default creds? CVE-2025-XXXXX'},
'Jenkins': {'check': 'Unauthenticated script console? CVE-2024-23897'},
'WordPress': {'check': 'wpscan for vulnerable plugins'},
'Redis': {'check': 'Unauthenticated access? Write SSH key?'},
'MongoDB': {'check': 'No auth required? Default admin?'},
'Elasticsearch': {'check': 'CVE-2015-1427 Groovy RCE? CVE-2015-5531 path traversal?'},
'Docker': {'check': 'Exposed API on 2375/2376? Container escape?'},
'Kubernetes': {'check': 'Exposed etcd 2379? kubelet 10250? API server 6443?'},
}
Automated Vuln Scanner (Simplified)
def quick_vuln_scan(host: str) -> list:
"""Quick vulnerability scan based on open ports and service versions."""
findings = []
# Get open ports and banners
open_ports = quick_scan(host)
for port, info in open_ports.items():
banner = info.get('banner', '')
# Check for common vulns based on banner
if 'vsftpd 2.3.4' in banner:
findings.append({
'port': port, 'service': info['service'],
'cve': 'CVE-2011-2523',
'desc': 'vsftpd 2.3.4 backdoor — smiley face exploit',
'cvss': 10.0,
})
if 'OpenSSH' in banner:
# Extract version
impo
…
## Source & license
This open-source skill is cataloged on AgentStack and links to its original source — we do not rehost the code.
- **Author:** [Wang200935](https://github.com/Wang200935)
- **Source:** [Wang200935/security-agent-skills](https://github.com/Wang200935/security-agent-skills)
- **License:** MIT
Install and usage instructions live in the source repository linked above.
Reviews
No reviews yet, be the first.
Write a review
Versions
- v0.1.0 Imported from the upstream source.