mirror of
https://github.com/Vyntral/god-eye.git
synced 2026-02-12 16:52:45 +00:00
- Implement 8 specialized AI agents (XSS, SQLi, Auth, API, Crypto, Secrets, Headers, General) - Add fast type-based routing for finding classification - Include OWASP-aligned knowledge bases per agent - Add agent handoff logic for cross-vulnerability detection - Optimize timeouts and parallelism for local LLM - Add new modules: cache, network, fingerprint, secrets, cloud, API, discovery - Update documentation with multi-agent feature
174 lines
4.1 KiB
Go
174 lines
4.1 KiB
Go
package security
|
|
|
|
import (
|
|
"crypto/tls"
|
|
"fmt"
|
|
"net/http"
|
|
"strings"
|
|
"time"
|
|
)
|
|
|
|
// CheckOpenRedirect tests for open redirect vulnerabilities
|
|
func CheckOpenRedirect(subdomain string, timeout int) bool {
|
|
client := &http.Client{
|
|
Timeout: time.Duration(timeout) * time.Second,
|
|
Transport: &http.Transport{
|
|
TLSClientConfig: &tls.Config{InsecureSkipVerify: true},
|
|
},
|
|
CheckRedirect: func(req *http.Request, via []*http.Request) error {
|
|
return http.ErrUseLastResponse
|
|
},
|
|
}
|
|
return CheckOpenRedirectWithClient(subdomain, client)
|
|
}
|
|
|
|
// CheckCORS tests for CORS misconfiguration
|
|
func CheckCORS(subdomain string, timeout int) string {
|
|
client := &http.Client{
|
|
Timeout: time.Duration(timeout) * time.Second,
|
|
Transport: &http.Transport{
|
|
TLSClientConfig: &tls.Config{InsecureSkipVerify: true},
|
|
},
|
|
}
|
|
return CheckCORSWithClient(subdomain, client)
|
|
}
|
|
|
|
// CheckHTTPMethods tests which HTTP methods are allowed
|
|
func CheckHTTPMethods(subdomain string, timeout int) (allowed []string, dangerous []string) {
|
|
client := &http.Client{
|
|
Timeout: time.Duration(timeout) * time.Second,
|
|
Transport: &http.Transport{
|
|
TLSClientConfig: &tls.Config{InsecureSkipVerify: true},
|
|
},
|
|
}
|
|
return CheckHTTPMethodsWithClient(subdomain, client)
|
|
}
|
|
|
|
// WithClient versions for parallel execution with shared client
|
|
|
|
func CheckOpenRedirectWithClient(subdomain string, client *http.Client) bool {
|
|
testPayloads := []string{
|
|
"?url=https://evil.com",
|
|
"?redirect=https://evil.com",
|
|
"?next=https://evil.com",
|
|
"?return=https://evil.com",
|
|
}
|
|
|
|
baseURLs := []string{
|
|
fmt.Sprintf("https://%s", subdomain),
|
|
fmt.Sprintf("http://%s", subdomain),
|
|
}
|
|
|
|
for _, baseURL := range baseURLs {
|
|
for _, payload := range testPayloads {
|
|
testURL := baseURL + payload
|
|
resp, err := client.Get(testURL)
|
|
if err != nil {
|
|
continue
|
|
}
|
|
resp.Body.Close()
|
|
|
|
if resp.StatusCode >= 300 && resp.StatusCode < 400 {
|
|
location := resp.Header.Get("Location")
|
|
// Check if redirect actually goes to evil.com, not just contains it as parameter
|
|
if strings.HasPrefix(location, "https://evil.com") ||
|
|
strings.HasPrefix(location, "http://evil.com") ||
|
|
strings.HasPrefix(location, "//evil.com") {
|
|
return true
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return false
|
|
}
|
|
|
|
func CheckCORSWithClient(subdomain string, client *http.Client) string {
|
|
urls := []string{
|
|
fmt.Sprintf("https://%s", subdomain),
|
|
fmt.Sprintf("http://%s", subdomain),
|
|
}
|
|
|
|
for _, url := range urls {
|
|
req, err := http.NewRequest("GET", url, nil)
|
|
if err != nil {
|
|
continue
|
|
}
|
|
|
|
req.Header.Set("Origin", "https://evil.com")
|
|
|
|
resp, err := client.Do(req)
|
|
if err != nil {
|
|
continue
|
|
}
|
|
resp.Body.Close()
|
|
|
|
acao := resp.Header.Get("Access-Control-Allow-Origin")
|
|
acac := resp.Header.Get("Access-Control-Allow-Credentials")
|
|
|
|
if acao == "*" {
|
|
if acac == "true" {
|
|
return "Wildcard + Credentials"
|
|
}
|
|
return "Wildcard Origin"
|
|
}
|
|
|
|
if acao == "https://evil.com" {
|
|
if acac == "true" {
|
|
return "Origin Reflection + Credentials"
|
|
}
|
|
return "Origin Reflection"
|
|
}
|
|
|
|
if strings.Contains(acao, "null") {
|
|
return "Null Origin Allowed"
|
|
}
|
|
}
|
|
|
|
return ""
|
|
}
|
|
|
|
func CheckHTTPMethodsWithClient(subdomain string, client *http.Client) (allowed []string, dangerous []string) {
|
|
urls := []string{
|
|
fmt.Sprintf("https://%s", subdomain),
|
|
fmt.Sprintf("http://%s", subdomain),
|
|
}
|
|
|
|
dangerousMethods := map[string]bool{
|
|
"PUT": true,
|
|
"DELETE": true,
|
|
"TRACE": true,
|
|
"PATCH": true,
|
|
}
|
|
|
|
for _, url := range urls {
|
|
req, err := http.NewRequest("OPTIONS", url, nil)
|
|
if err != nil {
|
|
continue
|
|
}
|
|
|
|
resp, err := client.Do(req)
|
|
if err != nil {
|
|
continue
|
|
}
|
|
resp.Body.Close()
|
|
|
|
// Only trust the Allow header from OPTIONS response
|
|
// Don't probe individual methods as this causes too many false positives
|
|
allowHeader := resp.Header.Get("Allow")
|
|
if allowHeader != "" {
|
|
for _, method := range strings.Split(allowHeader, ",") {
|
|
method = strings.TrimSpace(method)
|
|
allowed = append(allowed, method)
|
|
if dangerousMethods[method] {
|
|
dangerous = append(dangerous, method)
|
|
}
|
|
}
|
|
return allowed, dangerous
|
|
}
|
|
}
|
|
|
|
// If no Allow header found, don't report anything to avoid false positives
|
|
return allowed, dangerous
|
|
}
|