requestAbsoluteURI tests sending absolute URI in the request line. Some proxies parse the path differently when given an absolute URI vs a relative one.
(options RequestOptions)
| 2805 | // requestAbsoluteURI tests sending absolute URI in the request line. |
| 2806 | // Some proxies parse the path differently when given an absolute URI vs a relative one. |
| 2807 | func requestAbsoluteURI(options RequestOptions) { |
| 2808 | if !isCurlAvailable() { |
| 2809 | log.Printf("[!] Skipping absolute URI technique: curl not found in PATH") |
| 2810 | return |
| 2811 | } |
| 2812 | |
| 2813 | parsedURL, err := url.Parse(options.uri) |
| 2814 | if err != nil { |
| 2815 | log.Println(err) |
| 2816 | return |
| 2817 | } |
| 2818 | |
| 2819 | // Preserve the original path+query exactly as provided (keeps encoding and query string). |
| 2820 | pathAndQuery := parsedURL.RequestURI() // e.g., /admin?foo=bar |
| 2821 | |
| 2822 | // Build payloads: absolute URI forms that might confuse proxies. |
| 2823 | // Each label shows the curl command to reproduce. |
| 2824 | payloads := buildAbsoluteURIPayloads(parsedURL, pathAndQuery) |
| 2825 | |
| 2826 | proxyValue := "" |
| 2827 | if options.proxy != nil { |
| 2828 | proxyValue = options.proxy.String() |
| 2829 | } |
| 2830 | |
| 2831 | connectURL := parsedURL.Scheme + "://" + parsedURL.Host + pathAndQuery |
| 2832 | |
| 2833 | for _, requestTarget := range payloads { |
| 2834 | args := []string{"-i", "-s", "--request-target", requestTarget} |
| 2835 | if proxyValue != "" { |
| 2836 | args = append(args, "-x", proxyValue) |
| 2837 | } |
| 2838 | if options.redirect { |
| 2839 | args = append(args, "-L") |
| 2840 | } |
| 2841 | args = append(args, "--insecure") |
| 2842 | // Use the original host for the actual connection |
| 2843 | args = append(args, connectURL) |
| 2844 | |
| 2845 | ctx, cancel := context.WithTimeout(context.Background(), time.Duration(options.timeout)*time.Millisecond) |
| 2846 | cmd := exec.CommandContext(ctx, "curl", args...) |
| 2847 | out, err := cmd.Output() |
| 2848 | cancel() |
| 2849 | if err != nil { |
| 2850 | logVerbose("[!] Absolute URI curl failed:", err) |
| 2851 | continue |
| 2852 | } |
| 2853 | |
| 2854 | // Show the curl command so the user can reproduce the bypass |
| 2855 | label := "curl --request-target '" + requestTarget + "' " + connectURL |
| 2856 | res := parseCurlOutput(string(out), label) |
| 2857 | if res.statusCode == 0 { |
| 2858 | continue |
| 2859 | } |
| 2860 | res.line = "request-target: " + requestTarget |
| 2861 | attachCurlReplay(&res, args, label, options.timeout) |
| 2862 | printResponse(res, "absolute-uri") |
| 2863 | } |
| 2864 | } |
no test coverage detected