From 543192afbe1bbf0175dc82e50cacfd0dcfc70376 Mon Sep 17 00:00:00 2001 From: Kevin Pham Date: Tue, 21 Nov 2023 10:45:29 -0600 Subject: [PATCH] support js URL rewriting; support post req --- cmd/main.go | 3 +- .../rewrite_http_resource_urls.go | 51 ++++++++++++++----- ...ce_urls.js => rewrite_js_resource_urls.js} | 24 +++++++-- 3 files changed, 60 insertions(+), 18 deletions(-) rename proxychain/responsemodifers/{monkey_patch_resource_urls.js => rewrite_js_resource_urls.js} (67%) diff --git a/cmd/main.go b/cmd/main.go index 9671012..24c4895 100644 --- a/cmd/main.go +++ b/cmd/main.go @@ -87,7 +87,7 @@ func main() { app := fiber.New( fiber.Config{ Prefork: *prefork, - GETOnly: true, + GETOnly: false, }, ) @@ -138,5 +138,6 @@ func main() { } app.Get("/*", handlers.NewProxySiteHandler(proxyOpts)) + app.Post("/*", handlers.NewProxySiteHandler(proxyOpts)) log.Fatal(app.Listen(":" + *port)) } diff --git a/proxychain/responsemodifers/rewrite_http_resource_urls.go b/proxychain/responsemodifers/rewrite_http_resource_urls.go index 90c8aaa..5596a27 100644 --- a/proxychain/responsemodifers/rewrite_http_resource_urls.go +++ b/proxychain/responsemodifers/rewrite_http_resource_urls.go @@ -2,9 +2,11 @@ package responsemodifers import ( "bytes" + _ "embed" "fmt" "io" "ladder/proxychain" + "log" "net/url" "strings" @@ -19,7 +21,7 @@ func init() { "src": true, "href": true, "action": true, - "srcset": true, // TODO: fix + "srcset": true, "poster": true, "data": true, "cite": true, @@ -45,17 +47,19 @@ type HTMLResourceURLRewriter struct { tokenBuffer *bytes.Buffer currentTokenIndex int currentTokenProcessed bool + proxyURL string // ladder URL, not proxied site URL } // NewHTMLResourceURLRewriter creates a new instance of HTMLResourceURLRewriter. // It initializes the tokenizer with the provided source and sets the proxy URL. -func NewHTMLResourceURLRewriter(src io.ReadCloser, baseURL *url.URL) *HTMLResourceURLRewriter { +func NewHTMLResourceURLRewriter(src io.ReadCloser, baseURL *url.URL, proxyURL string) *HTMLResourceURLRewriter { return &HTMLResourceURLRewriter{ tokenizer: html.NewTokenizer(src), currentToken: html.Token{}, currentTokenIndex: 0, tokenBuffer: new(bytes.Buffer), baseURL: baseURL, + proxyURL: proxyURL, } } @@ -90,11 +94,18 @@ func (r *HTMLResourceURLRewriter) Read(p []byte) (int, error) { // patch tokens with URLs isTokenWithAttribute := r.currentToken.Type == html.StartTagToken || r.currentToken.Type == html.SelfClosingTagToken if isTokenWithAttribute { - patchResourceURL(&r.currentToken, r.baseURL) + patchResourceURL(&r.currentToken, r.baseURL, r.proxyURL) } r.tokenBuffer.Reset() r.tokenBuffer.WriteString(r.currentToken.String()) + + // inject \n", script), + ) +} + // Root-relative URLs: These are relative to the root path and start with a "/". func handleRootRelativePath(attr *html.Attribute, baseURL *url.URL) { // doublecheck this is a valid relative URL @@ -126,7 +148,7 @@ func handleRootRelativePath(attr *html.Attribute, baseURL *url.URL) { attr.Val = url.QueryEscape(attr.Val) attr.Val = fmt.Sprintf("/%s", attr.Val) - //log.Printf("root rel url rewritten-> '%s'='%s'", attr.Key, attr.Val) + log.Printf("root rel url rewritten-> '%s'='%s'", attr.Key, attr.Val) } // Document-relative URLs: These are relative to the current document's path and don't start with a "/". @@ -140,14 +162,14 @@ func handleDocumentRelativePath(attr *html.Attribute, baseURL *url.URL) { ) attr.Val = url.QueryEscape(attr.Val) attr.Val = fmt.Sprintf("/%s", attr.Val) - //log.Printf("doc rel url rewritten-> '%s'='%s'", attr.Key, attr.Val) + log.Printf("doc rel url rewritten-> '%s'='%s'", attr.Key, attr.Val) } // Protocol-relative URLs: These start with "//" and will use the same protocol (http or https) as the current page. func handleProtocolRelativePath(attr *html.Attribute, baseURL *url.URL) { attr.Val = strings.TrimPrefix(attr.Val, "/") handleRootRelativePath(attr, baseURL) - //log.Printf("proto rel url rewritten-> '%s'='%s'", attr.Key, attr.Val) + log.Printf("proto rel url rewritten-> '%s'='%s'", attr.Key, attr.Val) } func handleAbsolutePath(attr *html.Attribute, baseURL *url.URL) { @@ -165,7 +187,7 @@ func handleAbsolutePath(attr *html.Attribute, baseURL *url.URL) { strings.TrimPrefix(attr.Val, "/"), ), ) - //log.Printf("abs url rewritten-> '%s'='%s'", attr.Key, attr.Val) + log.Printf("abs url rewritten-> '%s'='%s'", attr.Key, attr.Val) } func handleSrcSet(attr *html.Attribute, baseURL *url.URL) { @@ -196,18 +218,21 @@ func handleSrcSet(attr *html.Attribute, baseURL *url.URL) { attr.Val = fmt.Sprintf("%s,", attr.Val) } attr.Val = strings.TrimSuffix(attr.Val, ",") + + log.Printf("srcset url rewritten-> '%s'='%s'", attr.Key, attr.Val) } -// TODO: figure out how to handle these -// srcset -func patchResourceURL(token *html.Token, baseURL *url.URL) { +func patchResourceURL(token *html.Token, baseURL *url.URL, proxyURL string) { for i := range token.Attr { attr := &token.Attr[i] switch { - // dont touch attributes except for the ones we defined + // don't touch attributes except for the ones we defined case !AttributesToRewrite[attr.Key]: continue + // don't double-overwrite the url + case strings.HasPrefix(attr.Val, proxyURL): + continue case attr.Key == "srcset": handleSrcSet(attr, baseURL) continue @@ -255,8 +280,10 @@ func RewriteHTMLResourceURLs() proxychain.ResponseModification { if !strings.HasPrefix(ct, "text/html") { return nil } + originalURI := chain.Context.Request().URI() + proxyURL := fmt.Sprintf("%s://%s", originalURI.Scheme(), originalURI.Host()) - chain.Response.Body = NewHTMLResourceURLRewriter(chain.Response.Body, chain.Request.URL) + chain.Response.Body = NewHTMLResourceURLRewriter(chain.Response.Body, chain.Request.URL, proxyURL) return nil } } diff --git a/proxychain/responsemodifers/monkey_patch_resource_urls.js b/proxychain/responsemodifers/rewrite_js_resource_urls.js similarity index 67% rename from proxychain/responsemodifers/monkey_patch_resource_urls.js rename to proxychain/responsemodifers/rewrite_js_resource_urls.js index dadeaa0..1d31ca4 100644 --- a/proxychain/responsemodifers/monkey_patch_resource_urls.js +++ b/proxychain/responsemodifers/rewrite_js_resource_urls.js @@ -3,21 +3,26 @@ // fetch("/relative_script.js") -> fetch("http://localhost:8080/relative_script.js") (() => { function rewriteURL(url) { + oldUrl = url if (!url) return url - if (url.startsWith(window.location.origin)) return url + proxyOrigin = globalThis.window.location.origin + if (url.startsWith(proxyOrigin)) return url + + const origin = (new URL(decodeURI(globalThis.window.location.pathname.substring(1)))).origin if (url.startsWith("//")) { - url = `${window.location.origin}/${encodeURIComponent(url.substring(2))}`; + url = `/${origin}/${encodeURIComponent(url.substring(2))}`; } else if (url.startsWith("/")) { - url = `${window.location.origin}/${encodeURIComponent(url.substring(1))}`; + url = `/${origin}/${encodeURIComponent(url.substring(1))}`; } else if (url.startsWith("http://") || url.startsWith("https://")) { - url = `${window.location.origin}/${encodeURIComponent(url)}`; + url = `/${origin}/${encodeURIComponent(url)}`; } + console.log(`rewrite JS URL: ${oldUrl} -> ${url}`) return url; }; // monkey patch fetch - const oldFetch = globalThis.fetch ; + const oldFetch = globalThis.fetch; globalThis.fetch = async (url, init) => { return oldFetch(rewriteURL(url), init) } @@ -27,7 +32,16 @@ XMLHttpRequest.prototype.open = function(method, url, async = true, user = null, password = null) { return oldOpen.call(this, method, rewriteURL(url), async, user, password); }; + const oldSend = XMLHttpRequest.prototype.send; + XMLHttpRequest.prototype.send = function(method, url) { + return oldSend.call(this, method, rewriteURL(url)); + }; + // monkey patch service worker registration + const oldRegister = ServiceWorkerContainer.prototype.register; + ServiceWorkerContainer.prototype.register = function(scriptURL, options) { + return oldRegister.call(this, rewriteURL(scriptURL), options) + } // Monkey patch setter methods const elements = [