GetAltName: Direct SSL Certificate Inspection for Subdomain Discovery Beyond Certificate Transparency
Hook
Certificate Transparency logs have indexed over 9 billion certificates, yet they'll never show you the self-signed certificate running on your target's internal staging server. That's where direct certificate inspection comes in.
Context
Subdomain enumeration is a cornerstone of security reconnaissance and asset discovery. For years, security professionals have relied on DNS brute-forcing—hammering nameservers with massive wordlists hoping to find dev.example.com or api.example.com. This approach is noisy, slow, and incomplete. The emergence of Certificate Transparency (CT) logs revolutionized subdomain discovery by making certificate issuance publicly auditable. Tools like crt.sh and Censys allow researchers to query these logs and extract Subject Alternative Names (SANs) from millions of certificates without touching the target infrastructure.
But CT logs have a blind spot: they only index certificates issued by public Certificate Authorities that participate in CT logging. Internal networks with self-signed certificates, enterprises using private CAs, legacy systems, and air-gapped environments remain invisible. GetAltName fills this gap by performing direct TLS connections to HTTPS servers and extracting certificate data in real-time. Instead of querying a third-party database, it connects to port 443 (or any specified port), completes the TLS handshake, retrieves the X.509 certificate, and parses the SAN extension—all without needing the certificate to be publicly logged. This makes it invaluable for penetration testers working on internal networks, bug bounty hunters validating CT log findings, and security teams auditing their own infrastructure.
Technical Insight
GetAltName's architecture is deliberately minimalist, leveraging Python's standard ssl library to establish TLS connections and extract certificate data. At its core, the tool wraps a socket connection with SSL context, retrieves the peer certificate in DER format, converts it to a Python dictionary, and extracts the subjectAltName field. This straightforward approach means zero dependency on external APIs, certificate databases, or complex parsing libraries.
Here's a simplified version of the core extraction logic:
import ssl
import socket
def get_certificate(hostname, port=443):
context = ssl.create_default_context()
conn = context.wrap_socket(
socket.socket(socket.AF_INET),
server_hostname=hostname
)
conn.connect((hostname, port))
cert = conn.getpeercert()
conn.close()
return cert
def extract_san(cert):
san_list = []
if 'subjectAltName' in cert:
for item in cert['subjectAltName']:
if item[0] == 'DNS':
san_list.append(item[1])
return san_list
hostname = "www.github.com"
cert = get_certificate(hostname)
domains = extract_san(cert)
print("\n".join(domains))
This produces output like:
github.com
www.github.com
*.github.com
*.github.io
The beauty of this approach is its transparency—you're seeing exactly what the server presents during the TLS handshake, not what a third-party indexer chose to store. This matters for time-sensitive reconnaissance where newly deployed services won't appear in CT logs for hours or days, and for internal assessments where certificates never leave the organization.
GetAltName embraces the Unix philosophy of doing one thing well. Rather than building in parallelization, DNS resolution, or HTTP validation, it outputs clean line-delimited results designed to pipe into other tools. Want to scan 1,000 hosts? Combine it with xargs:
cat targets.txt | xargs -P 20 -I {} getaltname {}
Need to discover subdomains from Shodan results? Chain the tools:
shodan search "ssl.cert.subject.cn:example.com" --fields ip_str,port \
| awk '{print $1":"$2}' \
| getaltname --stdin \
| sort -u > discovered_subdomains.txt
The tool supports non-standard ports, critical for discovering development servers or applications running on high ports. You can specify example.com:8443 to inspect certificates on alternative HTTPS ports, something that CT log searches don't naturally support since they index by certificate content, not by where certificates are deployed.
Another architectural decision worth noting is GetAltName's handling of SNI (Server Name Indication). Modern servers often host multiple domains on a single IP address, serving different certificates based on the SNI hostname provided during the TLS handshake. GetAltName properly sets the SNI hostname, ensuring you retrieve the correct certificate for the domain you're investigating rather than a default catch-all certificate. This is crucial for shared hosting environments and CDN edge servers where dozens of domains might resolve to the same IP address.
The tool is distributed both as a pip package and a Docker container, making it trivial to integrate into CI/CD pipelines for continuous asset discovery. A security team could run daily scans of their known IP ranges, extract all SANs, and diff the results to detect shadow IT or unauthorized certificate issuance—all without maintaining complex infrastructure.
Gotcha
GetAltName's simplicity is both its strength and its limitation. The tool performs zero validation of discovered domains—it dumps whatever strings appear in the SAN extension, which may include wildcards (*.example.com), expired domains, typos, or domains that no longer resolve. You'll need downstream validation with tools like massdns or httpx to determine which discovered subdomains are actually live and accessible. This adds an extra step to your workflow that integrated tools like Amass handle automatically.
Performance becomes a concern at scale. GetAltName processes hosts sequentially by default, establishing a full TCP connection and TLS handshake for each target. For scanning thousands of hosts, this synchronous approach is painfully slow compared to asynchronous tools like zgrab2 that can maintain thousands of concurrent connections. While you can parallelize with xargs -P, this is crude compared to proper async implementations with connection pooling and intelligent rate limiting. If a target's firewall drops packets instead of sending RST, you'll wait for the socket timeout (often 60+ seconds) before moving to the next host. There's no built-in retry logic, exponential backoff, or smart timeout handling.
Error reporting is minimal. When a connection fails—whether due to network issues, firewall blocks, certificate validation errors, or non-HTTPS services—GetAltName typically outputs nothing and moves on. For troubleshooting or auditing scan coverage, you won't know which targets failed or why. Verbose logging exists but doesn't capture structured data suitable for parsing. In production reconnaissance workflows, you'll want to maintain separate logs of failed connections to revisit with different tools or techniques.
Verdict
Use if: You're conducting penetration tests on internal networks where CT logs provide no value, need to discover domains from IP addresses obtained through port scanning (nmap, masscan) or threat intelligence feeds (Shodan, Censys), want a lightweight tool that chains cleanly into existing Unix pipelines without API keys or cloud dependencies, or need to validate that a specific server is presenting the correct certificate with expected SANs as part of deployment verification. Skip if: You're doing comprehensive external subdomain enumeration where tools like subfinder or Amass provide CT log aggregation plus DNS validation in one package, need to scan tens of thousands of hosts efficiently (use zgrab2 or masscan with certificate extraction), require active validation that discovered domains resolve and respond to HTTP requests, or want automatic recursive discovery where found subdomains spawn new certificate checks. GetAltName excels as a focused component in a larger reconnaissance toolkit, not as a standalone subdomain enumeration solution.