domainlooker
Version:
🕵️ Mission-critical domain intelligence gathering tool with spy-themed interface. Comprehensive WHOIS, DNS, SSL, network analysis, subdomain discovery, and API-ready JSON exports.
202 lines • 9.21 kB
JavaScript
import { promises as dns } from 'dns';
import axios from 'axios';
export class SubdomainService {
constructor() {
this.commonSubdomains = [
'www', 'mail', 'ftp', 'localhost', 'webmail', 'smtp', 'pop', 'ns1', 'webdisk', 'ns2',
'cpanel', 'whm', 'autodiscover', 'autoconfig', 'mobile', 'm', 'dev', 'staging', 'test',
'api', 'admin', 'blog', 'shop', 'cdn', 'assets', 'static', 'img', 'images', 'media',
'secure', 'vpn', 'remote', 'support', 'help', 'docs', 'status', 'monitor', 'demo',
'beta', 'alpha', 'preview', 'sandbox', 'app', 'portal', 'dashboard', 'panel', 'control',
'git', 'repo', 'code', 'build', 'ci', 'jenkins', 'gitlab', 'github', 'bitbucket',
'email', 'imap', 'pop3', 'exchange', 'outlook', 'office', 'calendar', 'contacts',
'intranet', 'extranet', 'internal', 'external', 'public', 'private', 'secure2',
'news', 'press', 'media2', 'content', 'cms', 'editor', 'author', 'writer',
'video', 'stream', 'live', 'broadcast', 'radio', 'podcast', 'audio', 'music',
'files', 'download', 'upload', 'share', 'cloud', 'storage', 'backup', 'archive',
'search', 'find', 'directory', 'index', 'catalog', 'library', 'database', 'db',
'forum', 'community', 'social', 'chat', 'discuss', 'feedback', 'comments', 'reviews'
];
}
async discoverSubdomains(domain) {
const sources = {
dnsEnumeration: [],
certificateTransparency: [],
commonNames: []
};
// Run all discovery methods in parallel
const [dnsResults, ctResults, commonResults] = await Promise.allSettled([
this.dnsEnumeration(domain),
this.certificateTransparencyLookup(domain),
this.commonSubdomainCheck(domain)
]);
if (dnsResults.status === 'fulfilled') {
sources.dnsEnumeration = dnsResults.value;
}
if (ctResults.status === 'fulfilled') {
sources.certificateTransparency = ctResults.value;
}
if (commonResults.status === 'fulfilled') {
sources.commonNames = commonResults.value;
}
// Combine and deduplicate all found subdomains
const allSubdomains = new Set([
...sources.dnsEnumeration,
...sources.certificateTransparency,
...sources.commonNames
]);
const subdomains = Array.from(allSubdomains).sort();
return {
subdomains,
sources,
totalFound: subdomains.length
};
}
async dnsEnumeration(domain) {
const subdomains = [];
try {
// Try to get NS records and enumerate from them
const nsRecords = await dns.resolveNs(domain).catch(() => []);
// Check for wildcard DNS
const wildcardTest = await this.checkWildcardDNS(domain);
if (!wildcardTest) {
// Perform zone transfer attempt (usually blocked but worth trying)
await this.attemptZoneTransfer(domain, nsRecords, subdomains);
}
// Try some advanced DNS techniques
await this.tryDNSBruteforce(domain, subdomains);
}
catch (error) {
// DNS enumeration failed, continue with other methods
}
return subdomains;
}
async certificateTransparencyLookup(domain) {
const subdomains = [];
try {
// Use crt.sh API for certificate transparency logs
const response = await axios.get(`https://crt.sh/?q=${encodeURIComponent(domain)}&output=json`, {
timeout: 10000,
headers: {
'User-Agent': 'DOMAINLOOKER/1.0 Security Research Tool'
}
});
if (response.data && Array.isArray(response.data)) {
const certificates = response.data;
const subdomainSet = new Set();
certificates.forEach((cert) => {
if (cert.name_value) {
const names = cert.name_value.split('\n');
names.forEach((name) => {
name = name.trim().toLowerCase();
// Filter valid subdomains
if (name.endsWith(`.${domain}`) && name !== domain) {
// Remove wildcards and get the subdomain
const cleanName = name.replace(/^\*\./, '');
if (cleanName !== domain && this.isValidSubdomain(cleanName, domain)) {
subdomainSet.add(cleanName);
}
}
});
}
});
subdomains.push(...Array.from(subdomainSet));
}
}
catch (error) {
// Certificate transparency lookup failed
}
return subdomains;
}
async commonSubdomainCheck(domain) {
const foundSubdomains = [];
const batchSize = 10; // Process in batches to avoid overwhelming DNS servers
for (let i = 0; i < this.commonSubdomains.length; i += batchSize) {
const batch = this.commonSubdomains.slice(i, i + batchSize);
const batchPromises = batch.map(subdomain => this.checkSubdomain(subdomain, domain));
const results = await Promise.allSettled(batchPromises);
results.forEach((result, index) => {
if (result.status === 'fulfilled' && result.value) {
foundSubdomains.push(`${batch[index]}.${domain}`);
}
});
// Small delay between batches to be respectful
if (i + batchSize < this.commonSubdomains.length) {
await new Promise(resolve => setTimeout(resolve, 100));
}
}
return foundSubdomains;
}
async checkSubdomain(subdomain, domain) {
const fullDomain = `${subdomain}.${domain}`;
try {
// Try both A and AAAA records
const [aRecords, aaaaRecords] = await Promise.allSettled([
dns.resolve4(fullDomain),
dns.resolve6(fullDomain)
]);
return aRecords.status === 'fulfilled' || aaaaRecords.status === 'fulfilled';
}
catch (error) {
return false;
}
}
async checkWildcardDNS(domain) {
try {
// Check if a random subdomain resolves (indicating wildcard DNS)
const randomSubdomain = `random-${Date.now()}-test.${domain}`;
await dns.resolve4(randomSubdomain);
return true; // Wildcard DNS detected
}
catch (error) {
return false; // No wildcard DNS
}
}
async attemptZoneTransfer(domain, nsRecords, subdomains) {
// Zone transfer attempts (usually blocked but educational)
// This is a placeholder - actual zone transfer would require more complex DNS queries
// Most modern DNS servers block zone transfers for security reasons
}
async tryDNSBruteforce(domain, subdomains) {
// Additional DNS techniques could be added here
// Like trying numerical subdomains, etc.
}
isValidSubdomain(subdomain, baseDomain) {
// Basic validation for subdomain format
if (!subdomain || subdomain === baseDomain)
return false;
// Check if it's actually a subdomain of the base domain
if (!subdomain.endsWith(`.${baseDomain}`))
return false;
// Remove the base domain part
const subPart = subdomain.replace(`.${baseDomain}`, '');
// Check for valid subdomain characters
const validSubdomainRegex = /^[a-zA-Z0-9]([a-zA-Z0-9\-]{0,61}[a-zA-Z0-9])?(\.[a-zA-Z0-9]([a-zA-Z0-9\-]{0,61}[a-zA-Z0-9])?)*$/;
return validSubdomainRegex.test(subPart);
}
// Get subdomain statistics
getSubdomainStats(subdomainData) {
const stats = {
bySource: {
'DNS Enumeration': subdomainData.sources.dnsEnumeration.length,
'Certificate Transparency': subdomainData.sources.certificateTransparency.length,
'Common Names': subdomainData.sources.commonNames.length
},
commonPatterns: {},
depthAnalysis: {}
};
// Analyze common patterns
subdomainData.subdomains.forEach(subdomain => {
const parts = subdomain.split('.');
const depth = parts.length - 2; // Subtract base domain parts
stats.depthAnalysis[depth] = (stats.depthAnalysis[depth] || 0) + 1;
// Extract first level subdomain for pattern analysis
if (parts.length >= 3) {
const firstLevel = parts[parts.length - 3]; // e.g., 'www' from 'www.example.com'
stats.commonPatterns[firstLevel] = (stats.commonPatterns[firstLevel] || 0) + 1;
}
});
return stats;
}
}
//# sourceMappingURL=subdomain.js.map