Files
god-eye/internal/dns/resolver.go
T
Vyntral 6f3bc2f952 🚀 God's Eye v0.1 - Initial Release
God's Eye is an ultra-fast subdomain enumeration and reconnaissance tool with AI-powered security analysis.

##  Key Features

### 🔍 Comprehensive Enumeration
- 20+ passive sources (crt.sh, Censys, URLScan, etc.)
- DNS brute-force with smart wordlists
- Wildcard detection and filtering
- 1000 concurrent workers for maximum speed

### 🌐 Deep Reconnaissance
- HTTP probing with 13+ security checks
- Port scanning (configurable)
- TLS/SSL fingerprinting
- Technology detection (Wappalyzer-style)
- WAF detection (Cloudflare, Akamai, etc.)
- Security header analysis
- JavaScript secrets extraction
- Admin panel & API discovery
- Backup file detection
- robots.txt & sitemap.xml checks

### 🎯 Subdomain Takeover Detection
- 110+ fingerprints (AWS, Azure, GitHub Pages, Heroku, etc.)
- CNAME validation
- Dead DNS detection

### 🤖 AI-Powered Analysis (NEW!)
- Local AI using Ollama - No API costs, complete privacy
- Real-time CVE detection via function calling (queries NVD database)
- Cascade architecture: phi3.5 (fast triage) + qwen2.5-coder (deep analysis)
- JavaScript security analysis
- HTTP response anomaly detection
- Executive summary reports

### 📊 Output Formats
- Pretty terminal output with colors
- JSON export
- CSV export
- TXT (simple subdomain list)
- Silent mode for piping

## 🚀 Installation

bash
go install github.com/Vyntral/god-eye@latest

## 📖 Quick Start

bash
# Basic scan
god-eye -d example.com

# With AI analysis
god-eye -d example.com --enable-ai

# Only active hosts
god-eye -d example.com --active

# Export to JSON
god-eye -d example.com -o results.json -f json

## 🎯 Use Cases
- Bug bounty reconnaissance
- Penetration testing
- Security audits
- Attack surface mapping
- Red team operations

## ⚠️ Legal Notice
This tool is for authorized security testing only. Users must obtain explicit permission before scanning any targets. Unauthorized access is illegal.

## 📄 License
MIT License with additional security tool terms - see LICENSE file

## 🙏 Credits
Built with ❤️ by Vyntral for Orizon
Powered by Go, Ollama, and the security community

---

🤖 Generated with Claude Code
https://claude.com/claude-code

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-20 10:41:05 +01:00

233 lines
4.6 KiB
Go

package dns
import (
"encoding/json"
"fmt"
"net/http"
"strings"
"time"
"github.com/miekg/dns"
"god-eye/internal/config"
)
func ResolveSubdomain(subdomain string, resolvers []string, timeout int) []string {
c := dns.Client{
Timeout: time.Duration(timeout) * time.Second,
}
m := dns.Msg{}
m.SetQuestion(dns.Fqdn(subdomain), dns.TypeA)
for _, resolver := range resolvers {
r, _, err := c.Exchange(&m, resolver)
if err != nil || r == nil {
continue
}
var ips []string
for _, ans := range r.Answer {
if a, ok := ans.(*dns.A); ok {
ips = append(ips, a.A.String())
}
}
if len(ips) > 0 {
return ips
}
}
return nil
}
func CheckWildcard(domain string, resolvers []string) []string {
// Test multiple random patterns for better wildcard detection
patterns := []string{
fmt.Sprintf("random%d.%s", time.Now().UnixNano(), domain),
fmt.Sprintf("xyz%d.%s", time.Now().UnixNano()%1000000, domain),
fmt.Sprintf("nonexistent-%s.%s", "abc123xyz", domain),
}
allIPs := make(map[string]int)
for _, pattern := range patterns {
ips := ResolveSubdomain(pattern, resolvers, 3)
for _, ip := range ips {
allIPs[ip]++
}
}
// If same IP(s) appear in multiple patterns, it's a wildcard
var wildcardIPs []string
for ip, count := range allIPs {
if count >= 2 {
wildcardIPs = append(wildcardIPs, ip)
}
}
return wildcardIPs
}
func ResolveCNAME(subdomain string, resolvers []string, timeout int) string {
c := dns.Client{
Timeout: time.Duration(timeout) * time.Second,
}
m := dns.Msg{}
m.SetQuestion(dns.Fqdn(subdomain), dns.TypeCNAME)
for _, resolver := range resolvers {
r, _, err := c.Exchange(&m, resolver)
if err != nil || r == nil {
continue
}
for _, ans := range r.Answer {
if cname, ok := ans.(*dns.CNAME); ok {
return strings.TrimSuffix(cname.Target, ".")
}
}
}
return ""
}
func ResolvePTR(ip string, resolvers []string, timeout int) string {
c := dns.Client{
Timeout: time.Duration(timeout) * time.Second,
}
// Convert IP to reverse DNS format
parts := strings.Split(ip, ".")
if len(parts) != 4 {
return ""
}
reverseIP := fmt.Sprintf("%s.%s.%s.%s.in-addr.arpa.", parts[3], parts[2], parts[1], parts[0])
m := dns.Msg{}
m.SetQuestion(reverseIP, dns.TypePTR)
for _, resolver := range resolvers {
r, _, err := c.Exchange(&m, resolver)
if err != nil || r == nil {
continue
}
for _, ans := range r.Answer {
if ptr, ok := ans.(*dns.PTR); ok {
return strings.TrimSuffix(ptr.Ptr, ".")
}
}
}
return ""
}
func ResolveMX(domain string, resolvers []string, timeout int) []string {
c := dns.Client{
Timeout: time.Duration(timeout) * time.Second,
}
m := dns.Msg{}
m.SetQuestion(dns.Fqdn(domain), dns.TypeMX)
for _, resolver := range resolvers {
r, _, err := c.Exchange(&m, resolver)
if err != nil || r == nil {
continue
}
var records []string
for _, ans := range r.Answer {
if mx, ok := ans.(*dns.MX); ok {
records = append(records, strings.TrimSuffix(mx.Mx, "."))
}
}
if len(records) > 0 {
return records
}
}
return nil
}
func ResolveTXT(domain string, resolvers []string, timeout int) []string {
c := dns.Client{
Timeout: time.Duration(timeout) * time.Second,
}
m := dns.Msg{}
m.SetQuestion(dns.Fqdn(domain), dns.TypeTXT)
for _, resolver := range resolvers {
r, _, err := c.Exchange(&m, resolver)
if err != nil || r == nil {
continue
}
var records []string
for _, ans := range r.Answer {
if txt, ok := ans.(*dns.TXT); ok {
for _, t := range txt.Txt {
// Limit length for display
if len(t) > 100 {
t = t[:97] + "..."
}
records = append(records, t)
}
}
}
if len(records) > 0 {
return records
}
}
return nil
}
func ResolveNS(domain string, resolvers []string, timeout int) []string {
c := dns.Client{
Timeout: time.Duration(timeout) * time.Second,
}
m := dns.Msg{}
m.SetQuestion(dns.Fqdn(domain), dns.TypeNS)
for _, resolver := range resolvers {
r, _, err := c.Exchange(&m, resolver)
if err != nil || r == nil {
continue
}
var records []string
for _, ans := range r.Answer {
if ns, ok := ans.(*dns.NS); ok {
records = append(records, strings.TrimSuffix(ns.Ns, "."))
}
}
if len(records) > 0 {
return records
}
}
return nil
}
func GetIPInfo(ip string) (*config.IPInfo, error) {
client := &http.Client{Timeout: 5 * time.Second}
url := fmt.Sprintf("http://ip-api.com/json/%s?fields=as,org,country,city", ip)
resp, err := client.Get(url)
if err != nil {
return nil, err
}
defer resp.Body.Close()
var info config.IPInfo
if err := json.NewDecoder(resp.Body).Decode(&info); err != nil {
return nil, err
}
return &info, nil
}