From 56bac8070027040f3d029067ec3ac4a815a56d5f Mon Sep 17 00:00:00 2001 From: zomasec Date: Fri, 19 Apr 2024 21:02:11 +0200 Subject: [PATCH] used gofmt into all the files --- pkg/corser/corser.go | 151 ++++++++++++++++++++----------------------- pkg/corser/tester.go | 50 +++++++------- pkg/pocgen/pocgen.go | 9 ++- runner/runner.go | 63 +++++++++--------- templates/nullpoc.go | 2 +- templates/poc.go | 4 +- test/corser_test.go | 50 +++++++------- utils/files.go | 15 ++--- utils/http.go | 2 +- utils/utils.go | 14 ++-- 10 files changed, 168 insertions(+), 192 deletions(-) diff --git a/pkg/corser/corser.go b/pkg/corser/corser.go index 62943c3..d2a1437 100644 --- a/pkg/corser/corser.go +++ b/pkg/corser/corser.go @@ -17,70 +17,68 @@ import ( type Result struct { URL string `json:"url"` - Vulnerable bool - Payload string `json:"payload"` - Details []string `json:"details"` - ReqData *PreFlightData `json:"request_data"` - ErrorMessage string + Vulnerable bool + Payload string `json:"payload"` + Details []string `json:"details"` + ReqData *PreFlightData `json:"request_data"` + ErrorMessage string } type Scanner struct { - URL string - Origin string - Method string - Cookies string - Header string + URL string + Origin string + Method string + Cookies string + Header string DeepScan bool NoColor bool - Payloads []string - Timeout int - Host *Host - Client *http.Client - Result *Result - + Payloads []string + Timeout int + Host *Host + Client *http.Client + Result *Result } -type PreFlightData struct{ - ACAO string - ACAC string +type PreFlightData struct { + ACAO string + ACAC string Headers []string Methods []string - } type Host struct { - Full string - Domain string - TLD string + Full string + Domain string + TLD string Subdomain string } -func NewScanner(url, method, header, origin, cookies string,isDeep bool, timeout int) *Scanner { - +func NewScanner(url, method, header, origin, cookies string, isDeep bool, timeout int) *Scanner { + transport := &http.Transport{ TLSClientConfig: &tls.Config{InsecureSkipVerify: true}, Dial: (&net.Dialer{ - Timeout: 5 * time.Second, + Timeout: 5 * time.Second, KeepAlive: 5 * time.Second, }).Dial, - TLSHandshakeTimeout: 5 * time.Second, + TLSHandshakeTimeout: 5 * time.Second, } client := http.Client{ Timeout: time.Duration(timeout) * time.Second, Transport: transport, } - + return &Scanner{ - URL: url, - Origin: origin, - Method: method, - Cookies: cookies, - Timeout: timeout, - Header: header, + URL: url, + Origin: origin, + Method: method, + Cookies: cookies, + Timeout: timeout, + Header: header, DeepScan: isDeep, - Client: &client, - Result: &Result{ - URL: url, + Client: &client, + Result: &Result{ + URL: url, Details: make([]string, 0), ReqData: &PreFlightData{}, }, @@ -93,31 +91,31 @@ func (s *Scanner) Scan() *Result { if s.Result.ErrorMessage != "" { return &Result{ - URL: s.URL, - Vulnerable: false, - Details: []string{}, + URL: s.URL, + Vulnerable: false, + Details: []string{}, ErrorMessage: fmt.Sprintf("URL not alive or an error in request : %s", s.Result.ErrorMessage), } } s.RequestCheck() - + deduplicateDetails(s.Result) return s.Result } func deduplicateDetails(result *Result) { - detailsMap := make(map[string]bool) - uniqueDetails := []string{} + detailsMap := make(map[string]bool) + uniqueDetails := []string{} - for _, detail := range result.Details { - if _, exists := detailsMap[detail]; !exists { - detailsMap[detail] = true - uniqueDetails = append(uniqueDetails, detail) - } - } + for _, detail := range result.Details { + if _, exists := detailsMap[detail]; !exists { + detailsMap[detail] = true + uniqueDetails = append(uniqueDetails, detail) + } + } - result.Details = uniqueDetails + result.Details = uniqueDetails } func (s *Scanner) RequestCheck() { @@ -148,8 +146,7 @@ func (s *Scanner) RequestCheck() { } func (s *Scanner) performRequest(payload string, mutex *sync.Mutex) { - - + req, err := http.NewRequest(s.Method, s.URL, nil) if err != nil { mutex.Lock() @@ -159,7 +156,7 @@ func (s *Scanner) performRequest(payload string, mutex *sync.Mutex) { } req.Header.Add("Origin", payload) - + if s.Header != "" { key, value, err := utils.ParseHeader(s.Header) if err != nil { @@ -169,12 +166,11 @@ func (s *Scanner) performRequest(payload string, mutex *sync.Mutex) { req.Header.Add(key, value) } - + if s.Cookies != "" { req.Header.Add("Cookie", s.Cookies) } - resp, err := s.Client.Do(req) if err != nil { mutex.Lock() @@ -185,14 +181,14 @@ func (s *Scanner) performRequest(payload string, mutex *sync.Mutex) { defer resp.Body.Close() _, err = io.Copy(io.Discard, resp.Body) - if err != nil { + if err != nil { s.Result.ErrorMessage = err.Error() - return - } + return + } acao := resp.Header.Get("Access-Control-Allow-Origin") acac := resp.Header.Get("Access-Control-Allow-Credentials") - + vulnerable, details := evaluateResponse(payload, acao, acac) if vulnerable { mutex.Lock() @@ -204,15 +200,15 @@ func (s *Scanner) performRequest(payload string, mutex *sync.Mutex) { } func evaluateResponse(payload, acao, acac string) (bool, []string) { - details := make([]string, 0) - + details := make([]string, 0) + if vulnerable, detail := checkOriginReflected(payload, acao, acac); vulnerable { details = append(details, detail) } if vulnerable, detail := checkWildCard(acao); vulnerable { - + details = append(details, detail) - } + } if vulnerable, detail := checkNullOriginAllowed(acao); vulnerable { details = append(details, detail) } @@ -223,20 +219,19 @@ func evaluateResponse(payload, acao, acac string) (bool, []string) { return false, []string{} } - // checkOriginReflected checks for specific CORS misconfigurations involving the Access-Control-Allow-Origin (ACAO) // and Access-Control-Allow-Credentials (ACAC) headers. func checkOriginReflected(payload, acao, acac string) (bool, string) { // Check for ACAO reflecting the Origin or ACAC set to true. - var detail string + var detail string if acao == payload || acac == "true" { - + if acac == "" { - detail = fmt.Sprintf("%sACAO Header:%s %s",logz.Green, logz.NC, acao) + detail = fmt.Sprintf("%sACAO Header:%s %s", logz.Green, logz.NC, acao) } else { - detail = fmt.Sprintf("%sACAO Header:%s %s, ACAC Header: %s",logz.Green, logz.NC, acao, acac) + detail = fmt.Sprintf("%sACAO Header:%s %s, ACAC Header: %s", logz.Green, logz.NC, acao, acac) } - + return true, detail } @@ -248,7 +243,7 @@ func checkWildCard(acao string) (bool, string) { if acao == "*" { details := fmt.Sprintf("Wildcard ACAO header found. %s", acao) - return true, details + return true, details } // No misconfiguration detected. return false, "" @@ -256,26 +251,25 @@ func checkWildCard(acao string) (bool, string) { // preflightRequestCheck performs a preflight request to see how it's handled. func (s *Scanner) preflightRequest() { - + req, err := http.NewRequest("OPTIONS", s.URL, nil) if err != nil { s.Result.ErrorMessage = err.Error() - return + return } - resp, err := s.Client.Do(req) if err != nil { s.Result.ErrorMessage = err.Error() - return + return } defer resp.Body.Close() _, err = io.Copy(io.Discard, resp.Body) - if err != nil { + if err != nil { s.Result.ErrorMessage = err.Error() - return - } + return + } s.Result.ReqData.ACAO = resp.Header.Get("Access-Control-Allow-Origin") s.Result.ReqData.ACAC = resp.Header.Get("Access-Control-Allow-Credentials") @@ -285,7 +279,6 @@ func (s *Scanner) preflightRequest() { s.Result.ReqData.Headers = utils.ParseHeaders(resp.Header.Get("Access-Control-Request-Headers")) - } func checkNullOriginAllowed(acao string) (bool, string) { @@ -295,5 +288,3 @@ func checkNullOriginAllowed(acao string) (bool, string) { } return false, "" } - - diff --git a/pkg/corser/tester.go b/pkg/corser/tester.go index 762adfe..a11e0f4 100644 --- a/pkg/corser/tester.go +++ b/pkg/corser/tester.go @@ -6,9 +6,9 @@ import ( ) func NetParser(url string) (*Host, error) { - + URL, err := tld.Parse(url) - + if err != nil { return nil, err } @@ -24,13 +24,13 @@ func NetParser(url string) (*Host, error) { domain = fmt.Sprintf("%s.", domain) } - + topLevelDomain := URL.TLD return &Host{ - Full: fmt.Sprintf("%s%s%s", subdomain, domain, topLevelDomain ), - Domain: domain, - TLD: topLevelDomain, + Full: fmt.Sprintf("%s%s%s", subdomain, domain, topLevelDomain), + Domain: domain, + TLD: topLevelDomain, Subdomain: subdomain, }, nil } @@ -41,7 +41,6 @@ func (s *Scanner) JoinTwoice() { s.Payloads = append(s.Payloads, fmt.Sprintf("https://%s%s%s", org.Domain, s.Host.Domain, s.Host.TLD)) } - func (s *Scanner) anyOrigin() { s.Payloads = append(s.Payloads, "https://zomasec.io") } @@ -49,17 +48,17 @@ func (s *Scanner) anyOrigin() { func (s *Scanner) Prefix() { org, _ := NetParser(s.Origin) - + // payload => https://target.com.zomasec.io s.Payloads = append(s.Payloads, fmt.Sprintf("https://%s%s.%s", s.Host.Domain, s.Host.TLD, org.Full)) - + } func (s *Scanner) Wildcard() { org, _ := NetParser(s.Origin) // Don't forget to use netParser // payload => https://zomasec.io/sub.target.com - s.Payloads = append(s.Payloads, fmt.Sprintf("https://%s/%s", org.Full, s.Host.Full)) + s.Payloads = append(s.Payloads, fmt.Sprintf("https://%s/%s", org.Full, s.Host.Full)) } @@ -68,8 +67,8 @@ func (s *Scanner) Suffix() { // Don't forget to use netParser // payload => https://zomasec.io.target.com - s.Payloads = append(s.Payloads, fmt.Sprintf("https://%s.%s%s", org.Full ,s.Host.Domain, s.Host.TLD)) - + s.Payloads = append(s.Payloads, fmt.Sprintf("https://%s.%s%s", org.Full, s.Host.Domain, s.Host.TLD)) + } func (s *Scanner) Null() { @@ -87,27 +86,24 @@ func (s *Scanner) SpecialChars() { // Remove some of them if they will do the same thing chars := []string{"_", "-", "{", "}", "^", "%60", "!", "~", "`", ";", "|", "&", "(", ")", "*", "'", "\"", "$", "=", "+", "%0b"} // payload : https://website.com`.attacker.com/ - for _, char := range chars { - s.Payloads = append(s.Payloads, fmt.Sprintf("https://%s%s.%s",s.Host.Full, char, org.Full)) - } + for _, char := range chars { + s.Payloads = append(s.Payloads, fmt.Sprintf("https://%s%s.%s", s.Host.Full, char, org.Full)) + } } - // PortManipulation adds different ports to test origin handling func (s *Scanner) PortManipulation() { - org, _ := NetParser(s.Origin) - ports := []string{"8080", "443", "80"} - for _, port := range ports { - portOrigin := fmt.Sprintf("https://%s:%s", org.Full, port) - s.Payloads = append(s.Payloads, portOrigin) - } + org, _ := NetParser(s.Origin) + ports := []string{"8080", "443", "80"} + for _, port := range ports { + portOrigin := fmt.Sprintf("https://%s:%s", org.Full, port) + s.Payloads = append(s.Payloads, portOrigin) + } } - // SubdomainFlipping switches subdomain positions func (s *Scanner) SubdomainFlipping() { - org, _ := NetParser(s.Origin) - flippedOrigin := fmt.Sprintf("https://%s%s.%s", org.TLD, org.Subdomain, org.Domain) - s.Payloads = append(s.Payloads, flippedOrigin) + org, _ := NetParser(s.Origin) + flippedOrigin := fmt.Sprintf("https://%s%s.%s", org.TLD, org.Subdomain, org.Domain) + s.Payloads = append(s.Payloads, flippedOrigin) } - diff --git a/pkg/pocgen/pocgen.go b/pkg/pocgen/pocgen.go index b6d7911..bb5ada6 100644 --- a/pkg/pocgen/pocgen.go +++ b/pkg/pocgen/pocgen.go @@ -2,8 +2,8 @@ package pocgen import ( "bytes" - "html/template" "github.com/zomasec/corser/templates" + "html/template" "os" ) @@ -13,7 +13,7 @@ type Config struct { TargetURL string Params string SetRequestHeader string - CustomOrigin string // This field can dictate which template to use + CustomOrigin string // This field can dictate which template to use } // GeneratePoC generates an HTML page as a string that acts as a PoC for CORS misconfigurations. @@ -27,7 +27,7 @@ func GeneratePoC(config *Config) (string, error) { } else { tmpl, err = template.New("POC-File").Parse(templates.POC) } - + if err != nil { return "", err } @@ -50,7 +50,6 @@ func SavePoCToFile(config *Config, filename string) error { return os.WriteFile(filename, []byte(html), 0644) } - // package pocgen // import ( @@ -66,7 +65,7 @@ func SavePoCToFile(config *Config, filename string) error { // TargetURL string // Params string // SetRequestHeader string -// CustomOrigin string +// CustomOrigin string // } // // GeneratePoC generates an HTML page as a string that acts as a PoC for CORS misconfigurations. diff --git a/runner/runner.go b/runner/runner.go index 47817a1..3055da5 100644 --- a/runner/runner.go +++ b/runner/runner.go @@ -12,63 +12,62 @@ import ( ) var ( - logger = logz.DefaultLogs() + logger = logz.DefaultLogs() userLog = logz.DefaultLogs() ) // Runner coordinates scans, now also includes origin and headers for customization. type Runner struct { - URLs []string - Origin string - Method string - Cookies string - DeepScan bool - Verbose bool - Timeout int - CLevel int - Header string - PocFile string + URLs []string + Origin string + Method string + Cookies string + DeepScan bool + Verbose bool + Timeout int + CLevel int + Header string + PocFile string OutputFile string - Output *Output + Output *Output } type Output struct { - Results []*corser.Result `json:"result"` + Results []*corser.Result `json:"result"` } func (r *Runner) parseResultToJSON() error { - - jsonData, err := json.MarshalIndent(r.Output, "", " ") + + jsonData, err := json.MarshalIndent(r.Output, "", " ") if err != nil { logger.ERROR("Error Marshaling the output file") return err } - if err := utils.OutputJSONFile(r.OutputFile, utils.RemoveANSICodes(string(jsonData))); err != nil { return err } - return nil + return nil } // NewRunner creates a new Runner instance capable of scanning multiple URLs with custom settings. func NewRunner(urls []string, method, header, origin, cookies string, isDeep, verbose bool, timeout, cLevel int, pocFile, outputFile string) *Runner { return &Runner{ - URLs: urls, - Origin: origin, - Method: method, - Cookies: cookies, - Timeout: timeout, - CLevel: cLevel, - DeepScan: isDeep, - Verbose: verbose, - Header: header, + URLs: urls, + Origin: origin, + Method: method, + Cookies: cookies, + Timeout: timeout, + CLevel: cLevel, + DeepScan: isDeep, + Verbose: verbose, + Header: header, OutputFile: outputFile, - PocFile: pocFile, - Output: &Output{ + PocFile: pocFile, + Output: &Output{ Results: make([]*corser.Result, 0), - }, + }, } } @@ -93,10 +92,10 @@ func (r *Runner) Start() error { if result.Vulnerable && len(result.Details) > 0 { if r.OutputFile != "" { - + r.Output.Results = append(r.Output.Results, result) } - + logz.NewLogger("vuln", logz.Blue, result.URL).Log() for _, detail := range result.Details { fmt.Printf("\t %s-%s %s%s%s\n", logz.Yellow, logz.NC, logz.Green, detail, logz.NC) @@ -134,4 +133,4 @@ func (r *Runner) Start() error { userLog.ERROR("Error cannot create the file to output result in it : %s", err.Error()) } return nil -} \ No newline at end of file +} diff --git a/templates/nullpoc.go b/templates/nullpoc.go index 8f3c287..e0c9289 100644 --- a/templates/nullpoc.go +++ b/templates/nullpoc.go @@ -1,6 +1,6 @@ package templates + var ( - POCNull = ` diff --git a/templates/poc.go b/templates/poc.go index b8da4ae..c0fed07 100644 --- a/templates/poc.go +++ b/templates/poc.go @@ -1,8 +1,7 @@ package templates - var ( - POC = ` + POC = `