Back to Articles

ReverseIP: Mapping Shared Hosting Infrastructure with Ruby

[ View on GitHub ]

ReverseIP: Mapping Shared Hosting Infrastructure with Ruby

Hook

Every shared hosting server tells a story through its neighbors—and in penetration testing, knowing who shares your target's IP address can reveal unexpected attack surfaces, misconfigurations, and trust relationships that wouldn't appear in a standard scan.

Context

In the early days of web infrastructure, most organizations ran dedicated servers with one-to-one IP-to-domain mappings. Today's reality is radically different: shared hosting, cloud platforms, and CDN services routinely host hundreds or thousands of domains on a single IP address. This shift created an information asymmetry problem for security researchers and penetration testers.

When assessing a target's attack surface, you need to know what else lives on their infrastructure. A vulnerable WordPress blog on a shared server can become a pivot point to your actual target. A misconfigured vhost might leak internal information. Understanding the neighborhood matters. ReverseIP emerged as a focused solution to this reconnaissance challenge, providing a command-line tool that answers one critical question: what other domains resolve to this IP address? Unlike sprawling OSINT frameworks or commercial intelligence platforms, it does exactly one thing—enumerate domains sharing an IP and validate their availability.

Technical Insight

HTTP Request

HTML/JSON Response

Extract Domains

Check Each Domain

Status Code

IP Address Input

Mechanize Agent

Reverse IP Service

YouGetSignal/API

Domain Parser

Domain List

HTTP Status Validator

HTTP Request

Per Domain

Colorized Output

Terminal Display

System architecture — auto-generated

ReverseIP's architecture exemplifies the Unix philosophy: do one thing well. At its core, the tool chains together three operations: querying a reverse IP lookup service, parsing the results, and validating discovered domains through HTTP requests. The implementation relies on Ruby's Mechanize gem, which provides a scriptable browser environment perfect for interacting with web-based lookup services.

The workflow begins by accepting an IP address as input and submitting it to a reverse IP lookup service (typically sites like YouGetSignal or similar). Mechanize handles the HTTP negotiation, form submission, and response parsing. Here's a simplified version of what the core lookup mechanism might look like:

require 'mechanize'
require 'colorize'

class ReverseIPLookup
  def initialize(ip_address)
    @ip = ip_address
    @agent = Mechanize.new
    @agent.user_agent_alias = 'Mac Safari'
  end

  def discover_domains
    page = @agent.get('http://www.yougetsignal.com/tools/web-sites-on-web-server/')
    form = page.forms.first
    form['remoteAddress'] = @ip
    
    results_page = form.submit
    parse_domains(results_page.body)
  end

  def parse_domains(html)
    # Extract domain list from JSON-embedded response
    domains = html.scan(/"([\w.-]+\.[a-z]{2,})"/i).flatten.uniq
    domains.reject { |d| d.include?('yougetsignal') }
  end
  
  def validate_domain(domain)
    begin
      response = @agent.get("http://#{domain}")
      { domain: domain, status: response.code, active: true }
    rescue Mechanize::ResponseCodeError => e
      { domain: domain, status: e.response_code, active: false }
    rescue => e
      { domain: domain, status: 'ERROR', active: false }
    end
  end
end

This approach leverages web scraping rather than direct API access, which has both advantages and drawbacks. The benefit is accessibility—no API keys, no rate limit negotiations, just HTTP requests. The downside is fragility; any change to the target site's HTML structure breaks the parser.

The validation phase adds significant value beyond raw domain enumeration. After discovering domains, ReverseIP attempts HTTP requests to each one, checking whether they're actually serving content. This transforms a simple list into actionable intelligence:

def check_all_domains(domains)
  results = domains.map do |domain|
    result = validate_domain(domain)
    display_result(result)
    result
  end
  
  summarize(results)
end

def display_result(result)
  if result[:active]
    puts "[+] #{result[:domain]} (#{result[:status]})".green
  else
    puts "[-] #{result[:domain]} (#{result[:status]})".red
  end
end

The colorized output, courtesy of the colorize gem, provides immediate visual feedback during enumeration. Green indicates live domains, red marks dead or error states. For reconnaissance workflows where you're scanning multiple IPs, this visual distinction helps prioritize follow-up investigation.

One clever aspect of using Mechanize is its built-in handling of redirects, cookies, and session management. Many domains implement HTTP-to-HTTPS redirects or geographic filtering. Mechanize follows these automatically, providing more accurate availability data than simple TCP socket checks would offer. However, this same feature introduces latency—each validation is a full HTTP transaction, making the tool strictly sequential in its default implementation.

The tool's simplicity also means it lacks sophisticated error handling for edge cases. Domains with aggressive rate limiting, WAFs that block automated requests, or exotic vhost configurations might return false negatives. There's no built-in retry logic, no exponential backoff, and no support for authenticated requests to services that might require login.

Gotcha

ReverseIP's reliance on third-party lookup services introduces several practical limitations that become apparent in real-world usage. First, you're dependent on external service availability and accuracy. If YouGetSignal is down, rate-limits your requests, or simply doesn't have complete data for a given IP, you get incomplete results with no fallback mechanism. Unlike tools that query multiple sources or maintain their own databases, ReverseIP puts all eggs in one basket.

Performance degrades significantly with large result sets. Because the tool validates domains sequentially with full HTTP requests, discovering 100 domains means 100 separate HTTP transactions. On a server hosting 500+ domains (common for large shared hosting providers), this can take minutes and may trigger abuse detection systems on either the lookup service or the target domains themselves. There's no parallelization, no batch processing, and no option to skip validation if you only need the domain list. Additionally, the tool lacks output flexibility—results appear only in the terminal with no JSON export, CSV formatting, or integration hooks for feeding data into other tools in a reconnaissance pipeline. For one-off investigations, this is fine. For automated workflows or integration with frameworks like Metasploit or Burp Suite, you'll need to pipe output through custom parsers or abandon ReverseIP for more automation-friendly alternatives.

Verdict

Use ReverseIP if you're conducting ad-hoc reconnaissance in a Ruby environment, need quick command-line results for a few IPs during penetration testing, or want a simple tool that doesn't require API keys, complex configuration, or dependency hell. It excels at its narrow purpose: answering "what else is on this server?" during the early enumeration phase of security assessments. Skip if you need bulk processing of many IPs, require reliable uptime for automated workflows, want multiple data sources for comprehensive results, or need structured output formats for tool integration. For enterprise reconnaissance, continuous monitoring, or professional engagements where reliability matters more than simplicity, invest in commercial platforms like SecurityTrails or Shodan, or adopt full-featured frameworks like Recon-ng that offer better error handling, caching, and extensibility. ReverseIP is a pocket knife, not a Swiss Army chainsaw—useful for quick cuts, inadequate for heavy-duty work.

// ADD TO YOUR README
[![Featured on Starlog](https://starlog.is/api/badge/developer-tools/lolwaleet-reverseip.svg)](https://starlog.is/api/badge-click/developer-tools/lolwaleet-reverseip)