From 854dafbcfa9c647b7d175527611603e3520789e8 Mon Sep 17 00:00:00 2001 From: Kevin Pham Date: Tue, 21 Nov 2023 20:54:09 -0600 Subject: [PATCH] improve js rewriting functionality by not relying on js to get proxy and proxified URLs; direct injection from golang --- handlers/proxy.go | 3 +- .../spoof_referrer_from_baidu_post.go | 2 +- .../spoof_referrer_from_bing_search.go | 3 +- .../spoof_referrer_from_google_search.go | 3 +- .../spoof_referrer_from_linkedin_post.go | 2 +- .../spoof_referrer_from_naver_post.go | 2 +- .../spoof_referrer_from_pinterest_post.go | 2 +- .../spoof_referrer_from_qq_post.go | 2 +- .../spoof_referrer_from_reddit_post.go | 2 +- .../spoof_referrer_from_tumblr_post.go | 2 +- .../spoof_referrer_from_twitter_post.go | 2 +- .../spoof_referrer_from_vkontake_post.go | 2 +- .../spoof_referrer_from_weibo_post.go | 2 +- .../rewrite_js_resource_urls.js | 167 ------------------ .../rewriters/html_resource_url_rewriter.go | 19 +- .../rewriters/js_resource_url_rewriter.js | 6 +- 16 files changed, 38 insertions(+), 183 deletions(-) delete mode 100644 proxychain/responsemodifers/rewrite_js_resource_urls.js diff --git a/handlers/proxy.go b/handlers/proxy.go index c0aac7e..866cdb2 100644 --- a/handlers/proxy.go +++ b/handlers/proxy.go @@ -57,13 +57,14 @@ func NewProxySiteHandler(opts *ProxyOptions) fiber.Handler { SetDebugLogging(opts.Verbose). SetRequestModifications( rx.DeleteOutgoingCookies(), + rx.SpoofReferrerFromTwitterPost(), ). AddResponseModifications( tx.DeleteIncomingCookies(), tx.RewriteHTMLResourceURLs(), ). Execute() - + return proxychain } diff --git a/proxychain/requestmodifers/spoof_referrer_from_baidu_post.go b/proxychain/requestmodifers/spoof_referrer_from_baidu_post.go index b310062..1f6708f 100644 --- a/proxychain/requestmodifers/spoof_referrer_from_baidu_post.go +++ b/proxychain/requestmodifers/spoof_referrer_from_baidu_post.go @@ -10,7 +10,7 @@ import ( // SpoofReferrerFromBaiduSearch modifies the referrer header // pretending to be from a BaiduSearch -func SpoofReferrerFromBaiduSearch(url string) proxychain.RequestModification { +func SpoofReferrerFromBaiduSearch() proxychain.RequestModification { return func(chain *proxychain.ProxyChain) error { // https://www.baidu.com/link?url=5biIeDvUIihawf3Zbbysach2Xn4H3w3FzO6LZKgSs-B5Yt4M4RUFikokOk5zetf2&wd=&eqid=9da80d8208009b8480000706655d5ed6 referrer := fmt.Sprintf("https://baidu.com/link?url=%s", generateRandomBaiduURL()) diff --git a/proxychain/requestmodifers/spoof_referrer_from_bing_search.go b/proxychain/requestmodifers/spoof_referrer_from_bing_search.go index 563ce0e..8b7fb9f 100644 --- a/proxychain/requestmodifers/spoof_referrer_from_bing_search.go +++ b/proxychain/requestmodifers/spoof_referrer_from_bing_search.go @@ -6,13 +6,14 @@ import ( // SpoofReferrerFromBingSearch modifies the referrer header // pretending to be from a bing search site -func SpoofReferrerFromBingSearch(url string) proxychain.RequestModification { +func SpoofReferrerFromBingSearch() proxychain.RequestModification { return func(chain *proxychain.ProxyChain) error { chain.AddRequestModifications( SpoofReferrer("https://www.bing.com/"), SetRequestHeader("sec-fetch-site", "cross-site"), SetRequestHeader("sec-fetch-dest", "document"), SetRequestHeader("sec-fetch-mode", "navigate"), + ModifyQueryParams("utm_source", "bing"), ) return nil } diff --git a/proxychain/requestmodifers/spoof_referrer_from_google_search.go b/proxychain/requestmodifers/spoof_referrer_from_google_search.go index 0c68dfe..7afb246 100644 --- a/proxychain/requestmodifers/spoof_referrer_from_google_search.go +++ b/proxychain/requestmodifers/spoof_referrer_from_google_search.go @@ -6,13 +6,14 @@ import ( // SpoofReferrerFromGoogleSearch modifies the referrer header // pretending to be from a google search site -func SpoofReferrerFromGoogleSearch(url string) proxychain.RequestModification { +func SpoofReferrerFromGoogleSearch() proxychain.RequestModification { return func(chain *proxychain.ProxyChain) error { chain.AddRequestModifications( SpoofReferrer("https://www.google.com/"), SetRequestHeader("sec-fetch-site", "cross-site"), SetRequestHeader("sec-fetch-dest", "document"), SetRequestHeader("sec-fetch-mode", "navigate"), + ModifyQueryParams("utm_source", "google"), ) return nil } diff --git a/proxychain/requestmodifers/spoof_referrer_from_linkedin_post.go b/proxychain/requestmodifers/spoof_referrer_from_linkedin_post.go index 30c26c8..147beb4 100644 --- a/proxychain/requestmodifers/spoof_referrer_from_linkedin_post.go +++ b/proxychain/requestmodifers/spoof_referrer_from_linkedin_post.go @@ -6,7 +6,7 @@ import ( // SpoofReferrerFromLinkedInPost modifies the referrer header // pretending to be from a linkedin post -func SpoofReferrerFromLinkedInPost(url string) proxychain.RequestModification { +func SpoofReferrerFromLinkedInPost() proxychain.RequestModification { return func(chain *proxychain.ProxyChain) error { chain.AddRequestModifications( SpoofReferrer("https://www.linkedin.com/"), diff --git a/proxychain/requestmodifers/spoof_referrer_from_naver_post.go b/proxychain/requestmodifers/spoof_referrer_from_naver_post.go index 9bc32d6..1c3e082 100644 --- a/proxychain/requestmodifers/spoof_referrer_from_naver_post.go +++ b/proxychain/requestmodifers/spoof_referrer_from_naver_post.go @@ -7,7 +7,7 @@ import ( // SpoofReferrerFromNaverSearch modifies the referrer header // pretending to be from a Naver search (popular in South Korea) -func SpoofReferrerFromNaverSearch(url string) proxychain.RequestModification { +func SpoofReferrerFromNaverSearch() proxychain.RequestModification { return func(chain *proxychain.ProxyChain) error { referrer := fmt.Sprintf( "https://search.naver.com/search.naver?where=nexearch&sm=top_hty&fbm=0&ie=utf8&query=%s", diff --git a/proxychain/requestmodifers/spoof_referrer_from_pinterest_post.go b/proxychain/requestmodifers/spoof_referrer_from_pinterest_post.go index 8a3b55b..dedf9c5 100644 --- a/proxychain/requestmodifers/spoof_referrer_from_pinterest_post.go +++ b/proxychain/requestmodifers/spoof_referrer_from_pinterest_post.go @@ -6,7 +6,7 @@ import ( // SpoofReferrerFromPinterestPost modifies the referrer header // pretending to be from a pinterest post -func SpoofReferrerFromPinterestPost(url string) proxychain.RequestModification { +func SpoofReferrerFromPinterestPost() proxychain.RequestModification { return func(chain *proxychain.ProxyChain) error { chain.AddRequestModifications( SpoofReferrer("https://www.pinterest.com/"), diff --git a/proxychain/requestmodifers/spoof_referrer_from_qq_post.go b/proxychain/requestmodifers/spoof_referrer_from_qq_post.go index ce078b1..9f90cd2 100644 --- a/proxychain/requestmodifers/spoof_referrer_from_qq_post.go +++ b/proxychain/requestmodifers/spoof_referrer_from_qq_post.go @@ -6,7 +6,7 @@ import ( // SpoofReferrerFromQQPost modifies the referrer header // pretending to be from a QQ post (popular social media in China) -func SpoofReferrerFromQQPost(url string) proxychain.RequestModification { +func SpoofReferrerFromQQPost() proxychain.RequestModification { return func(chain *proxychain.ProxyChain) error { chain.AddRequestModifications( SpoofReferrer("https://new.qq.com/'"), diff --git a/proxychain/requestmodifers/spoof_referrer_from_reddit_post.go b/proxychain/requestmodifers/spoof_referrer_from_reddit_post.go index b30bf2f..519858a 100644 --- a/proxychain/requestmodifers/spoof_referrer_from_reddit_post.go +++ b/proxychain/requestmodifers/spoof_referrer_from_reddit_post.go @@ -6,7 +6,7 @@ import ( // SpoofReferrerFromRedditPost modifies the referrer header // pretending to be from a reddit post -func SpoofReferrerFromRedditPost(url string) proxychain.RequestModification { +func SpoofReferrerFromRedditPost() proxychain.RequestModification { return func(chain *proxychain.ProxyChain) error { chain.AddRequestModifications( SpoofReferrer("https://www.reddit.com/"), diff --git a/proxychain/requestmodifers/spoof_referrer_from_tumblr_post.go b/proxychain/requestmodifers/spoof_referrer_from_tumblr_post.go index ebe131e..5c47e04 100644 --- a/proxychain/requestmodifers/spoof_referrer_from_tumblr_post.go +++ b/proxychain/requestmodifers/spoof_referrer_from_tumblr_post.go @@ -6,7 +6,7 @@ import ( // SpoofReferrerFromTumblrPost modifies the referrer header // pretending to be from a tumblr post -func SpoofReferrerFromTumblrPost(url string) proxychain.RequestModification { +func SpoofReferrerFromTumblrPost() proxychain.RequestModification { return func(chain *proxychain.ProxyChain) error { chain.AddRequestModifications( SpoofReferrer("https://www.tumblr.com/"), diff --git a/proxychain/requestmodifers/spoof_referrer_from_twitter_post.go b/proxychain/requestmodifers/spoof_referrer_from_twitter_post.go index e5fcb21..c3ae34c 100644 --- a/proxychain/requestmodifers/spoof_referrer_from_twitter_post.go +++ b/proxychain/requestmodifers/spoof_referrer_from_twitter_post.go @@ -6,7 +6,7 @@ import ( // SpoofReferrerFromTwitterPost modifies the referrer header // pretending to be from a twitter post -func SpoofReferrerFromTwitterPost(url string) proxychain.RequestModification { +func SpoofReferrerFromTwitterPost() proxychain.RequestModification { return func(chain *proxychain.ProxyChain) error { chain.AddRequestModifications( SpoofReferrer("https://t.co/"), diff --git a/proxychain/requestmodifers/spoof_referrer_from_vkontake_post.go b/proxychain/requestmodifers/spoof_referrer_from_vkontake_post.go index 6079b30..e05be73 100644 --- a/proxychain/requestmodifers/spoof_referrer_from_vkontake_post.go +++ b/proxychain/requestmodifers/spoof_referrer_from_vkontake_post.go @@ -6,7 +6,7 @@ import ( // SpoofReferrerFromVkontaktePost modifies the referrer header // pretending to be from a vkontakte post (popular in Russia) -func SpoofReferrerFromVkontaktePost(url string) proxychain.RequestModification { +func SpoofReferrerFromVkontaktePost() proxychain.RequestModification { return func(chain *proxychain.ProxyChain) error { chain.AddRequestModifications( SpoofReferrer("https://away.vk.com/"), diff --git a/proxychain/requestmodifers/spoof_referrer_from_weibo_post.go b/proxychain/requestmodifers/spoof_referrer_from_weibo_post.go index 0b1904d..7c7e036 100644 --- a/proxychain/requestmodifers/spoof_referrer_from_weibo_post.go +++ b/proxychain/requestmodifers/spoof_referrer_from_weibo_post.go @@ -8,7 +8,7 @@ import ( // SpoofReferrerFromWeiboPost modifies the referrer header // pretending to be from a Weibo post (popular in China) -func SpoofReferrerFromWeiboPost(url string) proxychain.RequestModification { +func SpoofReferrerFromWeiboPost() proxychain.RequestModification { return func(chain *proxychain.ProxyChain) error { referrer := fmt.Sprintf("http://weibo.com/u/%d", rand.Intn(90001)) chain.AddRequestModifications( diff --git a/proxychain/responsemodifers/rewrite_js_resource_urls.js b/proxychain/responsemodifers/rewrite_js_resource_urls.js deleted file mode 100644 index 900be6f..0000000 --- a/proxychain/responsemodifers/rewrite_js_resource_urls.js +++ /dev/null @@ -1,167 +0,0 @@ -// Overrides the global fetch and XMLHttpRequest open methods to modify the request URLs. -// Also overrides the attribute setter prototype to modify the request URLs -// fetch("/relative_script.js") -> fetch("http://localhost:8080/relative_script.js") -(() => { - const blacklistedSchemes = [ - "ftp:", - "mailto:", - "tel:", - "file:", - "blob:", - "javascript:", - "about:", - "magnet:", - "ws:", - "wss:", - ]; - - function rewriteURL(url) { - const oldUrl = url - if (!url) return url - let isStr = (typeof url.startsWith === 'function') - if (!isStr) return url - // don't rewrite invalid URIs - try { new URL(url) } catch { return url } - - // don't rewrite special URIs - if (blacklistedSchemes.includes(url)) return url; - - // don't double rewrite - const proxyOrigin = globalThis.window.location.origin; - if (url.startsWith(proxyOrigin)) return url; - if (url.startsWith(`/${proxyOrigin}`)) return url; - if (url.startsWith(`/${origin}`)) return url; - - const origin = (new URL(decodeURIComponent(globalThis.window.location.pathname.substring(1)))).origin - //console.log(`proxychain: origin: ${origin} // proxyOrigin: ${proxyOrigin} // original: ${oldUrl}`) - - if (url.startsWith("//")) { - url = `/${origin}/${encodeURIComponent(url.substring(2))}`; - } else if (url.startsWith("/")) { - url = `/${origin}/${encodeURIComponent(url.substring(1))}`; - } else if (url.startsWith(origin)) { - url = `/${encodeURIComponent(url)}` - } else if (url.startsWith("http://") || url.startsWith("https://")) { - url = `/${proxyOrigin}/${encodeURIComponent(url)}`; - } - console.log(`proxychain: rewrite JS URL: ${oldUrl} -> ${url}`) - return url; - }; - - // monkey patch fetch - const oldFetch = globalThis.fetch; - globalThis.fetch = async (url, init) => { - return oldFetch(rewriteURL(url), init) - } - - // monkey patch xmlhttprequest - const oldOpen = XMLHttpRequest.prototype.open; - 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 URL.toString() method - const oldToString = URL.prototype.toString - URL.prototype.toString = function() { - let originalURL = oldToString.call(this) - return rewriteURL(originalURL) - } - - // monkey patch URL.toJSON() method - const oldToJson = URL.prototype.toString - URL.prototype.toString = function() { - let originalURL = oldToJson.call(this) - return rewriteURL(originalURL) - } - - // Monkey patch URL.href getter and setter - const originalHrefDescriptor = Object.getOwnPropertyDescriptor(URL.prototype, 'href'); - Object.defineProperty(URL.prototype, 'href', { - get: function() { - let originalHref = originalHrefDescriptor.get.call(this); - return rewriteURL(originalHref) - }, - set: function(newValue) { - originalHrefDescriptor.set.call(this, rewriteURL(newValue)); - } - }); - - // Monkey patch setter - const elements = [ - { tag: 'a', attribute: 'href' }, - { tag: 'img', attribute: 'src' }, - // { tag: 'img', attribute: 'srcset' }, // TODO: handle srcset - { tag: 'script', attribute: 'src' }, - { tag: 'link', attribute: 'href' }, - { tag: 'link', attribute: 'icon' }, - { tag: 'iframe', attribute: 'src' }, - { tag: 'audio', attribute: 'src' }, - { tag: 'video', attribute: 'src' }, - { tag: 'source', attribute: 'src' }, - // { tag: 'source', attribute: 'srcset' }, // TODO: handle srcset - { tag: 'embed', attribute: 'src' }, - { tag: 'embed', attribute: 'pluginspage' }, - { tag: 'html', attribute: 'manifest' }, - { tag: 'object', attribute: 'src' }, - { tag: 'input', attribute: 'src' }, - { tag: 'track', attribute: 'src' }, - { tag: 'form', attribute: 'action' }, - { tag: 'area', attribute: 'href' }, - { tag: 'base', attribute: 'href' }, - { tag: 'blockquote', attribute: 'cite' }, - { tag: 'del', attribute: 'cite' }, - { tag: 'ins', attribute: 'cite' }, - { tag: 'q', attribute: 'cite' }, - { tag: 'button', attribute: 'formaction' }, - { tag: 'input', attribute: 'formaction' }, - { tag: 'meta', attribute: 'content' }, - { tag: 'object', attribute: 'data' }, - ]; - - elements.forEach(({ tag, attribute }) => { - const proto = document.createElement(tag).constructor.prototype; - const descriptor = Object.getOwnPropertyDescriptor(proto, attribute); - if (descriptor && descriptor.set) { - Object.defineProperty(proto, attribute, { - ...descriptor, - set(value) { - // calling rewriteURL will end up calling a setter for href, - // leading to a recusive loop and a Maximum call stack size exceeded - // error, so we guard against this with a local semaphore flag - const isRewritingSetKey = Symbol.for('isRewritingSet'); - if (!this[isRewritingSetKey]) { - this[isRewritingSetKey] = true; - descriptor.set.call(this, rewriteURL(value)); - //descriptor.set.call(this, value); - this[isRewritingSetKey] = false; - } else { - // Directly set the value without rewriting - descriptor.set.call(this, value); - } - }, - get() { - const isRewritingGetKey = Symbol.for('isRewritingGet'); - if (!this[isRewritingGetKey]) { - this[isRewritingGetKey] = true; - let oldURL = descriptor.get.call(this); - let newURL = rewriteURL(oldURL); - this[isRewritingGetKey] = false; - return newURL - } else { - return descriptor.get.call(this); - } - } - }); - } - }); -})(); \ No newline at end of file diff --git a/proxychain/responsemodifers/rewriters/html_resource_url_rewriter.go b/proxychain/responsemodifers/rewriters/html_resource_url_rewriter.go index 4c4dccd..31e8ffb 100644 --- a/proxychain/responsemodifers/rewriters/html_resource_url_rewriter.go +++ b/proxychain/responsemodifers/rewriters/html_resource_url_rewriter.go @@ -145,7 +145,11 @@ func (r *HTMLResourceURLRewriter) Read(p []byte) (int, error) { // inject \n", script), + ) +} + // possible ad-blocking / bypassing opportunity here func modifyInlineScript(scriptContentBuffer *bytes.Buffer) string { return html.UnescapeString(scriptContentBuffer.String()) diff --git a/proxychain/responsemodifers/rewriters/js_resource_url_rewriter.js b/proxychain/responsemodifers/rewriters/js_resource_url_rewriter.js index d73e690..0562ba0 100644 --- a/proxychain/responsemodifers/rewriters/js_resource_url_rewriter.js +++ b/proxychain/responsemodifers/rewriters/js_resource_url_rewriter.js @@ -27,12 +27,14 @@ if (blacklistedSchemes.includes(url)) return url; // don't double rewrite - const proxyOrigin = globalThis.window.location.origin; + //const proxyOrigin = globalThis.window.location.origin; + const proxyOrigin = `${PROXY_ORIGIN_INJECT_FROM_GOLANG}`; if (url.startsWith(proxyOrigin)) return url; if (url.startsWith(`/${proxyOrigin}`)) return url; if (url.startsWith(`/${origin}`)) return url; - const origin = (new URL(decodeURIComponent(globalThis.window.location.pathname.substring(1)))).origin + //const origin = (new URL(decodeURIComponent(globalThis.window.location.pathname.substring(1)))).origin + const origin = `${ORIGIN_INJECT_FROM_GOLANG}`; //console.log(`proxychain: origin: ${origin} // proxyOrigin: ${proxyOrigin} // original: ${oldUrl}`) if (url.startsWith("//")) {