Skip to content

Commit 0fdd47a

Browse files
committed
feat: Integrate gospider as a new module, add Cloudflare Tunnel checks, and introduce new gobot commands for SSRF bypass, fuzzing, and AI.
1 parent dad7d75 commit 0fdd47a

49 files changed

Lines changed: 5000 additions & 4885 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

README.md

Lines changed: 0 additions & 1180 deletions
This file was deleted.

cmd/autoar/main.go

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ import (
2121
"github.com/h0tak88r/AutoAR/internal/modules/depconfusion"
2222
"github.com/h0tak88r/AutoAR/internal/modules/db"
2323
"github.com/h0tak88r/AutoAR/internal/modules/dns"
24+
cf1016mod "github.com/h0tak88r/AutoAR/internal/modules/cf1016"
2425
domainmod "github.com/h0tak88r/AutoAR/internal/modules/domain"
2526
"github.com/h0tak88r/AutoAR/internal/modules/fastlook"
2627
subdomainmod "github.com/h0tak88r/AutoAR/internal/modules/subdomain"
@@ -3144,6 +3145,20 @@ func handleDNSCommand(args []string) error {
31443145
return dns.DNSReaper(domain)
31453146
case "dangling-ip":
31463147
return dns.DanglingIP(domain)
3148+
case "cf1016", "cloudflare-1016":
3149+
result, err := cf1016mod.Run(cf1016mod.Options{
3150+
Domain: domain,
3151+
Threads: 100,
3152+
})
3153+
if err != nil {
3154+
return err
3155+
}
3156+
if len(result.Findings) == 0 {
3157+
fmt.Printf("[cf1016] No Cloudflare 1016 dangling records found for %s\n", domain)
3158+
} else {
3159+
fmt.Printf("[cf1016] Found %d dangling record(s). Results: %s\n", len(result.Findings), result.Output)
3160+
}
3161+
return nil
31473162
default:
31483163
return fmt.Errorf("unknown dns action: %s", sub)
31493164
}

cmd/migrate/main.go

Lines changed: 147 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,147 @@
1+
package main
2+
3+
import (
4+
"database/sql"
5+
"fmt"
6+
"log"
7+
"os"
8+
"strings"
9+
"time"
10+
11+
_ "modernc.org/sqlite"
12+
)
13+
14+
func esc(s string) string {
15+
return "'" + strings.ReplaceAll(s, "'", "''") + "'"
16+
}
17+
18+
func main() {
19+
sqliteDB, err := sql.Open("sqlite", "./bughunt.db?_pragma=foreign_keys(1)&_pragma=journal_mode(WAL)")
20+
if err != nil {
21+
log.Fatalf("Failed to open SQLite: %v", err)
22+
}
23+
defer sqliteDB.Close()
24+
25+
f, err := os.Create("supabase_import.sql")
26+
if err != nil {
27+
log.Fatalf("Failed to create output file: %v", err)
28+
}
29+
defer f.Close()
30+
31+
w := func(s string) { f.WriteString(s + "\n") }
32+
33+
w("-- AutoAR Database Export for Supabase")
34+
w(fmt.Sprintf("-- Generated at: %s", time.Now().Format(time.RFC3339)))
35+
w("-- Instructions: Paste this into the Supabase SQL Editor and run it.")
36+
w("")
37+
w("-- Disable triggers for fast import")
38+
w("SET session_replication_role = replica;")
39+
w("")
40+
41+
// 1. Domains
42+
w("-- DOMAINS TABLE")
43+
rows, _ := sqliteDB.Query(`SELECT id, domain, created_at, updated_at FROM domains`)
44+
count := 0
45+
for rows.Next() {
46+
var id int
47+
var domain string
48+
var created_at, updated_at sql.NullString
49+
rows.Scan(&id, &domain, &created_at, &updated_at)
50+
ca := "NOW()"; if created_at.Valid { ca = esc(created_at.String) }
51+
ua := "NOW()"; if updated_at.Valid { ua = esc(updated_at.String) }
52+
w(fmt.Sprintf("INSERT INTO domains (id, domain, created_at, updated_at) VALUES (%d, %s, %s, %s) ON CONFLICT (domain) DO NOTHING;", id, esc(domain), ca, ua))
53+
count++
54+
}
55+
rows.Close()
56+
w(fmt.Sprintf("SELECT setval('domains_id_seq', COALESCE((SELECT MAX(id) FROM domains), 1));"))
57+
log.Printf("[+] Exported %d domains", count)
58+
w("")
59+
60+
// 2. Subdomains
61+
w("-- SUBDOMAINS TABLE")
62+
rows, _ = sqliteDB.Query(`SELECT id, domain_id, subdomain, is_live, COALESCE(http_url,''), COALESCE(https_url,''), COALESCE(http_status,0), COALESCE(https_status,0), created_at, updated_at FROM subdomains`)
63+
count = 0
64+
for rows.Next() {
65+
var id, domain_id, is_live, http_status, https_status int
66+
var subdomain, http_url, https_url string
67+
var created_at, updated_at sql.NullString
68+
rows.Scan(&id, &domain_id, &subdomain, &is_live, &http_url, &https_url, &http_status, &https_status, &created_at, &updated_at)
69+
ca := "NOW()"; if created_at.Valid { ca = esc(created_at.String) }
70+
ua := "NOW()"; if updated_at.Valid { ua = esc(updated_at.String) }
71+
isLive := "FALSE"; if is_live != 0 { isLive = "TRUE" }
72+
w(fmt.Sprintf("INSERT INTO subdomains (id, domain_id, subdomain, is_live, http_url, https_url, http_status, https_status, created_at, updated_at) VALUES (%d, %d, %s, %s, %s, %s, %d, %d, %s, %s) ON CONFLICT (subdomain) DO NOTHING;", id, domain_id, esc(subdomain), isLive, esc(http_url), esc(https_url), http_status, https_status, ca, ua))
73+
count++
74+
}
75+
rows.Close()
76+
w("SELECT setval('subdomains_id_seq', COALESCE((SELECT MAX(id) FROM subdomains), 1));")
77+
log.Printf("[+] Exported %d subdomains", count)
78+
w("")
79+
80+
// 3. JS Files
81+
w("-- JS_FILES TABLE")
82+
rows, _ = sqliteDB.Query(`SELECT id, subdomain_id, js_url, COALESCE(content_hash,''), COALESCE(last_scanned,''), created_at, updated_at FROM js_files`)
83+
count = 0
84+
for rows.Next() {
85+
var id, subdomain_id int
86+
var js_url, content_hash, last_scanned string
87+
var created_at, updated_at sql.NullString
88+
rows.Scan(&id, &subdomain_id, &js_url, &content_hash, &last_scanned, &created_at, &updated_at)
89+
ca := "NOW()"; if created_at.Valid { ca = esc(created_at.String) }
90+
ua := "NOW()"; if updated_at.Valid { ua = esc(updated_at.String) }
91+
ls := "NOW()"; if last_scanned != "" { ls = esc(last_scanned) }
92+
w(fmt.Sprintf("INSERT INTO js_files (id, subdomain_id, js_url, content_hash, last_scanned, created_at, updated_at) VALUES (%d, %d, %s, %s, %s, %s, %s) ON CONFLICT (js_url) DO NOTHING;", id, subdomain_id, esc(js_url), esc(content_hash), ls, ca, ua))
93+
count++
94+
}
95+
rows.Close()
96+
w("SELECT setval('js_files_id_seq', COALESCE((SELECT MAX(id) FROM js_files), 1));")
97+
log.Printf("[+] Exported %d JS files", count)
98+
w("")
99+
100+
// 4. Keyhack Templates
101+
w("-- KEYHACK_TEMPLATES TABLE")
102+
rows, _ = sqliteDB.Query(`SELECT id, keyname, command_template, COALESCE(method,'GET'), url, COALESCE(header,''), COALESCE(body,''), COALESCE(description,''), COALESCE(notes,''), created_at, updated_at FROM keyhack_templates`)
103+
count = 0
104+
for rows.Next() {
105+
var id int
106+
var keyname, command_template, method, url, header, body, description, notes string
107+
var created_at, updated_at sql.NullString
108+
rows.Scan(&id, &keyname, &command_template, &method, &url, &header, &body, &description, &notes, &created_at, &updated_at)
109+
ca := "NOW()"; if created_at.Valid { ca = esc(created_at.String) }
110+
ua := "NOW()"; if updated_at.Valid { ua = esc(updated_at.String) }
111+
w(fmt.Sprintf("INSERT INTO keyhack_templates (id, keyname, command_template, method, url, header, body, description, notes, created_at, updated_at) VALUES (%d, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s) ON CONFLICT (keyname) DO NOTHING;", id, esc(keyname), esc(command_template), esc(method), esc(url), esc(header), esc(body), esc(description), esc(notes), ca, ua))
112+
count++
113+
}
114+
rows.Close()
115+
w("SELECT setval('keyhack_templates_id_seq', COALESCE((SELECT MAX(id) FROM keyhack_templates), 1));")
116+
log.Printf("[+] Exported %d keyhack templates", count)
117+
w("")
118+
119+
// 5. Scans
120+
w("-- SCANS TABLE")
121+
rows, _ = sqliteDB.Query(`SELECT id, scan_id, scan_type, target, status, COALESCE(channel_id,''), COALESCE(thread_id,''), COALESCE(message_id,''), current_phase, total_phases, COALESCE(phase_name,''), COALESCE(started_at,''), COALESCE(completed_at,''), last_update, COALESCE(command,''), created_at, updated_at FROM scans`)
122+
count = 0
123+
for rows.Next() {
124+
var id, current_phase, total_phases int
125+
var scan_id, scan_type, target, status, channel_id, thread_id, message_id, phase_name, started_at, completed_at, last_update, command string
126+
var created_at, updated_at sql.NullString
127+
rows.Scan(&id, &scan_id, &scan_type, &target, &status, &channel_id, &thread_id, &message_id, &current_phase, &total_phases, &phase_name, &started_at, &completed_at, &last_update, &command, &created_at, &updated_at)
128+
ca := "NOW()"; if created_at.Valid { ca = esc(created_at.String) }
129+
ua := "NOW()"; if updated_at.Valid { ua = esc(updated_at.String) }
130+
sa := "NOW()"; if started_at != "" { sa = esc(started_at) }
131+
w(fmt.Sprintf("INSERT INTO scans (id, scan_id, scan_type, target, status, channel_id, thread_id, message_id, current_phase, total_phases, phase_name, started_at, last_update, command, created_at, updated_at) VALUES (%d, %s, %s, %s, %s, %s, %s, %s, %d, %d, %s, %s, %s, %s, %s, %s) ON CONFLICT (scan_id) DO NOTHING;",
132+
id, esc(scan_id), esc(scan_type), esc(target), esc(status), esc(channel_id), esc(thread_id), esc(message_id), current_phase, total_phases, esc(phase_name), sa, esc(last_update), esc(command), ca, ua))
133+
count++
134+
}
135+
rows.Close()
136+
w("SELECT setval('scans_id_seq', COALESCE((SELECT MAX(id) FROM scans), 1));")
137+
log.Printf("[+] Exported %d scans", count)
138+
w("")
139+
140+
w("-- Re-enable triggers")
141+
w("SET session_replication_role = DEFAULT;")
142+
w("")
143+
w("-- Done!")
144+
145+
log.Printf("[SUCCESS] SQL export written to: supabase_import.sql")
146+
log.Printf("Now: 1) Open Supabase SQL Editor 2) Paste the file contents 3) Click Run")
147+
}

cmd/migrate_rest/main.go

Lines changed: 219 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,219 @@
1+
package main
2+
3+
import (
4+
"bytes"
5+
"database/sql"
6+
"encoding/json"
7+
"fmt"
8+
"io"
9+
"log"
10+
"net/http"
11+
"os"
12+
"time"
13+
14+
_ "modernc.org/sqlite"
15+
)
16+
17+
var (
18+
SupabaseURL = os.Getenv("SUPABASE_URL")
19+
SupabaseKey = os.Getenv("SUPABASE_KEY")
20+
)
21+
22+
func postChunk(table string, records []map[string]interface{}) error {
23+
if len(records) == 0 {
24+
return nil
25+
}
26+
27+
url := fmt.Sprintf("%s/rest/v1/%s", SupabaseURL, table)
28+
29+
jsonData, err := json.Marshal(records)
30+
if err != nil {
31+
return fmt.Errorf("failed to marshal JSON: %v", err)
32+
}
33+
34+
req, err := http.NewRequest("POST", url, bytes.NewBuffer(jsonData))
35+
if err != nil {
36+
return fmt.Errorf("failed to create request: %v", err)
37+
}
38+
39+
req.Header.Set("apikey", SupabaseKey)
40+
req.Header.Set("Authorization", "Bearer "+SupabaseKey)
41+
req.Header.Set("Content-Type", "application/json")
42+
req.Header.Set("Prefer", "resolution=merge-duplicates")
43+
44+
client := &http.Client{Timeout: 30 * time.Second}
45+
resp, err := client.Do(req)
46+
if err != nil {
47+
return fmt.Errorf("request failed: %v", err)
48+
}
49+
defer resp.Body.Close()
50+
51+
if resp.StatusCode >= 400 {
52+
bodyBytes, _ := io.ReadAll(resp.Body)
53+
return fmt.Errorf("API error (status %d): %s", resp.StatusCode, string(bodyBytes))
54+
}
55+
56+
return nil
57+
}
58+
59+
func nullStr(ns sql.NullString) interface{} {
60+
if ns.Valid && ns.String != "" {
61+
return ns.String
62+
}
63+
return nil
64+
}
65+
66+
func nullInt(ni sql.NullInt64) interface{} {
67+
if ni.Valid {
68+
return ni.Int64
69+
}
70+
return nil
71+
}
72+
73+
func main() {
74+
if SupabaseURL == "" || SupabaseKey == "" {
75+
log.Fatal("ERROR: Please set SUPABASE_URL and SUPABASE_KEY (service_role tier) environment variables.")
76+
}
77+
78+
sqliteDB, err := sql.Open("sqlite", "./bughunt.db?_pragma=foreign_keys(1)&_pragma=journal_mode(WAL)")
79+
if err != nil {
80+
log.Fatalf("Failed to open SQLite: %v", err)
81+
}
82+
defer sqliteDB.Close()
83+
84+
const batchSize = 1000
85+
86+
// 1. DOMAINS (Skip, likely already migrated)
87+
// But let's re-run it since merge-duplicates handles it.
88+
fmt.Println("[*] Migrating domains...")
89+
rows, _ := sqliteDB.Query(`SELECT id, domain, created_at, updated_at FROM domains`)
90+
var domainBatch []map[string]interface{}
91+
totalDomains := 0
92+
93+
for rows.Next() {
94+
var id int
95+
var domain string
96+
var ca, ua sql.NullString
97+
rows.Scan(&id, &domain, &ca, &ua)
98+
99+
domainBatch = append(domainBatch, map[string]interface{}{
100+
"id": id,
101+
"domain": domain,
102+
"created_at": nullStr(ca),
103+
"updated_at": nullStr(ua),
104+
})
105+
106+
if len(domainBatch) >= batchSize {
107+
if err := postChunk("domains", domainBatch); err != nil {
108+
log.Fatalf("Failed to post domain chunk: %v", err)
109+
}
110+
totalDomains += len(domainBatch)
111+
domainBatch = nil
112+
}
113+
}
114+
if len(domainBatch) > 0 {
115+
if err := postChunk("domains", domainBatch); err != nil {
116+
log.Fatalf("Failed to post final domain chunk: %v", err)
117+
}
118+
totalDomains += len(domainBatch)
119+
}
120+
rows.Close()
121+
fmt.Printf("[+] Uploaded %d domains\n", totalDomains)
122+
123+
// 2. SUBDOMAINS
124+
fmt.Println("[*] Migrating subdomains (batching 1000 at a time)...")
125+
rows, _ = sqliteDB.Query(`SELECT id, domain_id, subdomain, is_live, http_url, https_url, http_status, https_status, created_at, updated_at FROM subdomains`)
126+
var subBatch []map[string]interface{}
127+
totalSubs := 0
128+
129+
for rows.Next() {
130+
var id, domain_id, is_live int
131+
var http_status, https_status sql.NullInt64
132+
var subdomain string
133+
var ca, ua, h_url, hs_url sql.NullString
134+
135+
rows.Scan(&id, &domain_id, &subdomain, &is_live, &h_url, &hs_url, &http_status, &https_status, &ca, &ua)
136+
137+
subBatch = append(subBatch, map[string]interface{}{
138+
"id": id,
139+
"domain_id": domain_id,
140+
"subdomain": subdomain,
141+
"is_live": is_live != 0,
142+
"http_url": nullStr(h_url),
143+
"https_url": nullStr(hs_url),
144+
"http_status": nullInt(http_status),
145+
"https_status": nullInt(https_status),
146+
"created_at": nullStr(ca),
147+
"updated_at": nullStr(ua),
148+
})
149+
150+
if len(subBatch) >= batchSize {
151+
if err := postChunk("subdomains", subBatch); err != nil {
152+
log.Fatalf("Failed to post subdomain chunk: %v", err)
153+
}
154+
totalSubs += len(subBatch)
155+
fmt.Printf(" ... pushed %d subdomains\n", totalSubs)
156+
subBatch = nil
157+
}
158+
}
159+
if len(subBatch) > 0 {
160+
if err := postChunk("subdomains", subBatch); err != nil {
161+
log.Fatalf("Failed to post final subdomain chunk: %v", err)
162+
}
163+
totalSubs += len(subBatch)
164+
}
165+
rows.Close()
166+
fmt.Printf("[+] Uploaded %d subdomains\n", totalSubs)
167+
168+
// 3. SCANS
169+
fmt.Println("[*] Migrating scans...")
170+
rows, _ = sqliteDB.Query(`SELECT id, scan_id, scan_type, target, status, channel_id, thread_id, message_id, current_phase, total_phases, phase_name, started_at, completed_at, last_update, command, created_at, updated_at FROM scans`)
171+
var scanBatch []map[string]interface{}
172+
totalScans := 0
173+
174+
for rows.Next() {
175+
var id, cp, tp int
176+
var sid, stype, tar, stat, lu string
177+
var cid, tid, mid, pname, sa, ca_at, cmd, ca, ua sql.NullString
178+
179+
rows.Scan(&id, &sid, &stype, &tar, &stat, &cid, &tid, &mid, &cp, &tp, &pname, &sa, &ca_at, &lu, &cmd, &ca, &ua)
180+
181+
scanBatch = append(scanBatch, map[string]interface{}{
182+
"id": id,
183+
"scan_id": sid,
184+
"scan_type": stype,
185+
"target": tar,
186+
"status": stat,
187+
"current_phase": cp,
188+
"total_phases": tp,
189+
"last_update": lu,
190+
"channel_id": nullStr(cid),
191+
"thread_id": nullStr(tid),
192+
"message_id": nullStr(mid),
193+
"phase_name": nullStr(pname),
194+
"started_at": nullStr(sa),
195+
"completed_at": nullStr(ca_at),
196+
"command": nullStr(cmd),
197+
"created_at": nullStr(ca),
198+
"updated_at": nullStr(ua),
199+
})
200+
201+
if len(scanBatch) >= batchSize {
202+
if err := postChunk("scans", scanBatch); err != nil {
203+
log.Fatalf("Failed to post scan chunk: %v", err)
204+
}
205+
totalScans += len(scanBatch)
206+
scanBatch = nil
207+
}
208+
}
209+
if len(scanBatch) > 0 {
210+
if err := postChunk("scans", scanBatch); err != nil {
211+
log.Fatalf("Failed to post final scan chunk: %v", err)
212+
}
213+
totalScans += len(scanBatch)
214+
}
215+
rows.Close()
216+
fmt.Printf("[+] Uploaded %d scans\n", totalScans)
217+
218+
fmt.Println("\n[SUCCESS] REST API Migration completed successfully!")
219+
}

0 commit comments

Comments
 (0)