diff --git a/handlers/proxy.go b/handlers/proxy.go index ee0bf9d..6e3b750 100644 --- a/handlers/proxy.go +++ b/handlers/proxy.go @@ -32,25 +32,27 @@ func NewProxySiteHandler(opts *ProxyOptions) fiber.Handler { SetFiberCtx(c). SetDebugLogging(opts.Verbose). SetRequestModifications( - // rx.SpoofJA3fingerprint(ja3, "Googlebot"), - // rx.MasqueradeAsFacebookBot(), - // rx.MasqueradeAsGoogleBot(), - rx.DeleteOutgoingCookies(), + //rx.SpoofJA3fingerprint(ja3, "Googlebot"), + rx.AddCacheBusterQuery(), + rx.MasqueradeAsGoogleBot(), rx.ForwardRequestHeaders(), - // rx.SpoofReferrerFromGoogleSearch(), - rx.SpoofReferrerFromLinkedInPost(), - // rx.RequestWaybackMachine(), - // rx.RequestArchiveIs(), + rx.DeleteOutgoingCookies(), + rx.SpoofReferrerFromRedditPost(), + //rx.SpoofReferrerFromLinkedInPost(), + //rx.RequestWaybackMachine(), + //rx.RequestArchiveIs(), ). AddResponseModifications( - tx.ForwardResponseHeaders(), + //tx.ForwardResponseHeaders(), + tx.DeleteIncomingCookies(), + tx.DeleteLocalStorageData(), + tx.DeleteSessionStorageData(), tx.BypassCORS(), tx.BypassContentSecurityPolicy(), - // tx.DeleteIncomingCookies(), tx.RewriteHTMLResourceURLs(), tx.PatchTrackerScripts(), tx.PatchDynamicResourceURLs(), - tx.BlockElementRemoval(".article-content"), + //tx.BlockElementRemoval(".article-content"), // tx.SetContentSecurityPolicy("default-src * 'unsafe-inline' 'unsafe-eval' data: blob:;"), ) diff --git a/proxychain/proxychain.go b/proxychain/proxychain.go index 7bd4b90..ceb0712 100644 --- a/proxychain/proxychain.go +++ b/proxychain/proxychain.go @@ -5,6 +5,7 @@ import ( "fmt" http "github.com/bogdanfinn/fhttp" tls_client "github.com/bogdanfinn/tls-client" + profiles "github.com/bogdanfinn/tls-client/profiles" "io" "log" "net/url" @@ -192,15 +193,6 @@ func (chain *ProxyChain) _initializeRequest() (*http.Request, error) { return nil, fmt.Errorf("unsupported request method from client: '%s'", chain.Context.Method()) } - /* - // copy client request headers to upstream request headers - forwardHeaders := func(key []byte, val []byte) { - req.Header.Set(string(key), string(val)) - } - clientHeaders := &chain.Context.Request().Header - clientHeaders.VisitAll(forwardHeaders) - */ - return req, nil } @@ -312,9 +304,10 @@ func (chain *ProxyChain) SetFiberCtx(ctx *fiber.Ctx) *ProxyChain { url, err := chain.extractURL() if err != nil { chain.abortErr = chain.abort(err) + } else { + chain.Request.URL = url + fmt.Printf("extracted URL: %s\n", chain.Request.URL) } - chain.Request.URL = url - fmt.Printf("extracted URL: %s\n", chain.Request.URL) return chain } @@ -359,7 +352,12 @@ func (chain *ProxyChain) abort(err error) error { // defer chain._reset() chain.abortErr = err chain.Context.Response().SetStatusCode(500) - e := fmt.Errorf("ProxyChain error for '%s': %s", chain.Request.URL.String(), err.Error()) + var e error + if chain.Request.URL != nil { + e = fmt.Errorf("ProxyChain error for '%s': %s", chain.Request.URL.String(), err.Error()) + } else { + e = fmt.Errorf("ProxyChain error: '%s'", err.Error()) + } chain.Context.SendString(e.Error()) log.Println(e.Error()) return e @@ -382,8 +380,8 @@ func NewProxyChain() *ProxyChain { options := []tls_client.HttpClientOption{ tls_client.WithTimeoutSeconds(20), - tls_client.WithRandomTLSExtensionOrder(), - // tls_client.WithClientProfile(profiles.Chrome_117), + //tls_client.WithRandomTLSExtensionOrder(), + tls_client.WithClientProfile(profiles.Chrome_117), // tls_client.WithNotFollowRedirects(), // tls_client.WithCookieJar(jar), // create cookieJar instance and pass it as argument } diff --git a/proxychain/requestmodifiers/add_cache_buster_query.go b/proxychain/requestmodifiers/add_cache_buster_query.go new file mode 100644 index 0000000..e60f2e0 --- /dev/null +++ b/proxychain/requestmodifiers/add_cache_buster_query.go @@ -0,0 +1,28 @@ +package requestmodifiers + +import ( + "ladder/proxychain" + "math/rand" +) + +// AddCacheBusterQuery modifies query params to add a random parameter key +// In order to get the upstream network stack to serve a fresh copy of the page. +func AddCacheBusterQuery() proxychain.RequestModification { + return func(chain *proxychain.ProxyChain) error { + chain.AddOnceRequestModifications( + ModifyQueryParams("ord", randomString(15)), + ) + + return nil + } +} + +func randomString(length int) string { + const charset = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789." + + b := make([]byte, length) + for i := range b { + b[i] = charset[rand.Intn(len(charset))] + } + return string(b) +} diff --git a/proxychain/requestmodifiers/modify_query_params.go b/proxychain/requestmodifiers/modify_query_params.go index 3cd84b3..ba817ac 100644 --- a/proxychain/requestmodifiers/modify_query_params.go +++ b/proxychain/requestmodifiers/modify_query_params.go @@ -1,6 +1,7 @@ package requestmodifiers import ( + "fmt" "net/url" "ladder/proxychain" @@ -12,6 +13,7 @@ func ModifyQueryParams(key string, value string) proxychain.RequestModification return func(chain *proxychain.ProxyChain) error { q := chain.Request.URL.Query() chain.Request.URL.RawQuery = modifyQueryParams(key, value, q) + fmt.Println(chain.Request.URL.String()) return nil } } diff --git a/proxychain/responsemodifiers/delete_localstorage_data.go b/proxychain/responsemodifiers/delete_localstorage_data.go new file mode 100644 index 0000000..e214b80 --- /dev/null +++ b/proxychain/responsemodifiers/delete_localstorage_data.go @@ -0,0 +1,28 @@ +package responsemodifiers + +import ( + _ "embed" + "strings" + + "ladder/proxychain" +) + +// DeleteLocalStorageData deletes localstorage cookies. +// If the page works once in a fresh incognito window, but fails +// for subsequent loads, try this response modifier alongside +// DeleteSessionStorageData and DeleteIncomingCookies +func DeleteLocalStorageData() proxychain.ResponseModification { + return func(chain *proxychain.ProxyChain) error { + // don't add rewriter if it's not even html + ct := chain.Response.Header.Get("content-type") + if !strings.HasPrefix(ct, "text/html") { + return nil + } + + chain.AddOnceResponseModifications( + InjectScriptBeforeDOMContentLoaded(`window.sessionStorage.clear()`), + InjectScriptAfterDOMContentLoaded(`window.sessionStorage.clear()`), + ) + return nil + } +} diff --git a/proxychain/responsemodifiers/delete_sessionstorage_data.go b/proxychain/responsemodifiers/delete_sessionstorage_data.go new file mode 100644 index 0000000..d44be33 --- /dev/null +++ b/proxychain/responsemodifiers/delete_sessionstorage_data.go @@ -0,0 +1,28 @@ +package responsemodifiers + +import ( + _ "embed" + "strings" + + "ladder/proxychain" +) + +// DeleteSessionStorageData deletes localstorage cookies. +// If the page works once in a fresh incognito window, but fails +// for subsequent loads, try this response modifier alongside +// DeleteLocalStorageData and DeleteIncomingCookies +func DeleteSessionStorageData() proxychain.ResponseModification { + return func(chain *proxychain.ProxyChain) error { + // don't add rewriter if it's not even html + ct := chain.Response.Header.Get("content-type") + if !strings.HasPrefix(ct, "text/html") { + return nil + } + + chain.AddOnceResponseModifications( + InjectScriptBeforeDOMContentLoaded(`window.sessionStorage.clear()`), + InjectScriptAfterDOMContentLoaded(`window.sessionStorage.clear()`), + ) + return nil + } +} diff --git a/proxychain/responsemodifiers/modify_incoming_cookies.go b/proxychain/responsemodifiers/modify_incoming_cookies.go index f655c94..5ad63cc 100644 --- a/proxychain/responsemodifiers/modify_incoming_cookies.go +++ b/proxychain/responsemodifiers/modify_incoming_cookies.go @@ -13,8 +13,12 @@ import ( // DeleteIncomingCookies prevents ALL cookies from being sent from the proxy server // back down to the client. func DeleteIncomingCookies(_ ...string) proxychain.ResponseModification { - return func(px *proxychain.ProxyChain) error { - px.Response.Header.Del("Set-Cookie") + return func(chain *proxychain.ProxyChain) error { + chain.Response.Header.Del("Set-Cookie") + chain.AddOnceResponseModifications( + InjectScriptBeforeDOMContentLoaded(`document.cookie = ""`), + InjectScriptAfterDOMContentLoaded(`document.cookie = ""`), + ) return nil } } diff --git a/proxychain/ruleset/rule_reqmod_types.gen.go b/proxychain/ruleset/rule_reqmod_types.gen.go index 7f22c3e..f885537 100644 --- a/proxychain/ruleset/rule_reqmod_types.gen.go +++ b/proxychain/ruleset/rule_reqmod_types.gen.go @@ -16,7 +16,11 @@ var rqmModMap map[string]RequestModifierFactory func init() { rqmModMap = make(map[string]RequestModifierFactory) - rqmModMap["ForwardRequestHeaders"] = func(_ ...string) proxychain.RequestModification { + rqmModMap["AddCacheBusterQuery"] = func(_ ...string) proxychain.RequestModification { + return rx.AddCacheBusterQuery() + } + + rqmModMap["ForwardRequestHeaders"] = func(_ ...string) proxychain.RequestModification { return rx.ForwardRequestHeaders() } diff --git a/proxychain/ruleset/rule_resmod_types.gen.go b/proxychain/ruleset/rule_resmod_types.gen.go index f6ec8c0..dfff064 100644 --- a/proxychain/ruleset/rule_resmod_types.gen.go +++ b/proxychain/ruleset/rule_resmod_types.gen.go @@ -36,6 +36,14 @@ func init() { return tx.SetContentSecurityPolicy(params[0]) } + rsmModMap["DeleteLocalStorageData"] = func(_ ...string) proxychain.ResponseModification { + return tx.DeleteLocalStorageData() + } + + rsmModMap["DeleteSessionStorageData"] = func(_ ...string) proxychain.ResponseModification { + return tx.DeleteSessionStorageData() + } + rsmModMap["ForwardResponseHeaders"] = func(_ ...string) proxychain.ResponseModification { return tx.ForwardResponseHeaders() }