diff --git a/modules/http_proxy/http_proxy.go b/modules/http_proxy/http_proxy.go index 90007b9f..7519a411 100644 --- a/modules/http_proxy/http_proxy.go +++ b/modules/http_proxy/http_proxy.go @@ -2,6 +2,8 @@ package http_proxy import ( "github.com/bettercap/bettercap/session" + + "github.com/evilsocket/islazy/str" ) type HttpProxy struct { @@ -38,6 +40,12 @@ func NewHttpProxy(s *session.Session) *HttpProxy { "", "URL, path or javascript code to inject into every HTML page.")) + mod.AddParam(session.NewStringParameter("http.proxy.blacklist", "", "", + "Comma separated list of hostnames to skip while proxying (wildcard expressions can be used).")) + + mod.AddParam(session.NewStringParameter("http.proxy.whitelist", "", "", + "Comma separated list of hostnames to proxy if the blacklist is used (wildcard expressions can be used).")) + mod.AddParam(session.NewBoolParameter("http.proxy.sslstrip", "false", "Enable or disable SSL stripping.")) @@ -77,6 +85,8 @@ func (mod *HttpProxy) Configure() error { var scriptPath string var stripSSL bool var jsToInject string + var blacklist string + var whitelist string if mod.Running() { return session.ErrAlreadyStarted @@ -92,8 +102,15 @@ func (mod *HttpProxy) Configure() error { return err } else if err, jsToInject = mod.StringParam("http.proxy.injectjs"); err != nil { return err + } else if err, blacklist = mod.StringParam("http.proxy.blacklist"); err != nil { + return err + } else if err, whitelist = mod.StringParam("http.proxy.whitelist"); err != nil { + return err } + mod.proxy.Blacklist = str.Comma(blacklist) + mod.proxy.Whitelist = str.Comma(whitelist) + return mod.proxy.Configure(address, proxyPort, httpPort, scriptPath, jsToInject, stripSSL) } diff --git a/modules/http_proxy/http_proxy_base.go b/modules/http_proxy/http_proxy_base.go index 8acaf564..7d77b7ba 100644 --- a/modules/http_proxy/http_proxy_base.go +++ b/modules/http_proxy/http_proxy_base.go @@ -11,6 +11,7 @@ import ( "net" "net/http" "net/url" + "path/filepath" "strconv" "strings" "time" @@ -41,6 +42,8 @@ type HTTPProxy struct { Script *HttpProxyScript CertFile string KeyFile string + Blacklist []string + Whitelist []string jsHook string isTLS bool @@ -61,13 +64,15 @@ func stripPort(s string) string { func NewHTTPProxy(s *session.Session) *HTTPProxy { p := &HTTPProxy{ - Name: "http.proxy", - Proxy: goproxy.NewProxyHttpServer(), - sess: s, - stripper: NewSSLStripper(s, false), - isTLS: false, - Server: nil, - tag: session.AsTag("http.proxy"), + Name: "http.proxy", + Proxy: goproxy.NewProxyHttpServer(), + sess: s, + stripper: NewSSLStripper(s, false), + isTLS: false, + Server: nil, + Blacklist: make([]string, 0), + Whitelist: make([]string, 0), + tag: session.AsTag("http.proxy"), } p.Proxy.Verbose = false @@ -111,20 +116,41 @@ func (p *HTTPProxy) Fatal(format string, args ...interface{}) { } func (p *HTTPProxy) doProxy(req *http.Request) bool { - blacklist := []string{ - "localhost", - "127.0.0.1", - } - if req.Host == "" { p.Error("got request with empty host: %v", req) return false } - host := strings.Split(req.Host, ":")[0] - for _, blacklisted := range blacklist { - if host == blacklisted { - p.Error("got request with blacklisted host: %s", req.Host) + hostname := strings.Split(req.Host, ":")[0] + for _, local := range []string{"localhost", "127.0.0.1"} { + if hostname == local { + p.Error("got request with localed host: %s", req.Host) + return false + } + } + + return true +} + +func (p *HTTPProxy) shouldProxy(req *http.Request) bool { + hostname := strings.Split(req.Host, ":")[0] + + // check for the whitelist + for _, expr := range p.Whitelist { + if matched, err := filepath.Match(expr, hostname); err != nil { + p.Error("error while using proxy whitelist expression '%s': %v", expr, err) + } else if matched { + p.Debug("hostname '%s' matched whitelisted element '%s'", hostname, expr) + return true + } + } + + // then the blacklist + for _, expr := range p.Blacklist { + if matched, err := filepath.Match(expr, hostname); err != nil { + p.Error("error while using proxy blacklist expression '%s': %v", expr, err) + } else if matched { + p.Debug("hostname '%s' matched blacklisted element '%s'", hostname, expr) return false } } diff --git a/modules/http_proxy/http_proxy_base_filters.go b/modules/http_proxy/http_proxy_base_filters.go index d8ad23ce..52bd6e69 100644 --- a/modules/http_proxy/http_proxy_base_filters.go +++ b/modules/http_proxy/http_proxy_base_filters.go @@ -19,32 +19,34 @@ func (p *HTTPProxy) fixRequestHeaders(req *http.Request) { } func (p *HTTPProxy) onRequestFilter(req *http.Request, ctx *goproxy.ProxyCtx) (*http.Request, *http.Response) { - p.Debug("< %s %s %s%s", req.RemoteAddr, req.Method, req.Host, req.URL.Path) + if p.shouldProxy(req) { + p.Debug("< %s %s %s%s", req.RemoteAddr, req.Method, req.Host, req.URL.Path) - p.fixRequestHeaders(req) + p.fixRequestHeaders(req) - redir := p.stripper.Preprocess(req, ctx) - if redir != nil { - // we need to redirect the user in order to make - // some session cookie expire - return req, redir - } + redir := p.stripper.Preprocess(req, ctx) + if redir != nil { + // we need to redirect the user in order to make + // some session cookie expire + return req, redir + } - // do we have a proxy script? - if p.Script == nil { - return req, nil - } + // do we have a proxy script? + if p.Script == nil { + return req, nil + } - // run the module OnRequest callback if defined - jsreq, jsres := p.Script.OnRequest(req) - if jsreq != nil { - // the request has been changed by the script - p.logRequestAction(req, jsreq) - return jsreq.ToRequest(), nil - } else if jsres != nil { - // a fake response has been returned by the script - p.logResponseAction(req, jsres) - return req, jsres.ToResponse(req) + // run the module OnRequest callback if defined + jsreq, jsres := p.Script.OnRequest(req) + if jsreq != nil { + // the request has been changed by the script + p.logRequestAction(req, jsreq) + return jsreq.ToRequest(), nil + } else if jsres != nil { + // a fake response has been returned by the script + p.logResponseAction(req, jsres) + return req, jsres.ToResponse(req) + } } return req, nil @@ -123,28 +125,30 @@ func (p *HTTPProxy) onResponseFilter(res *http.Response, ctx *goproxy.ProxyCtx) return nil } - p.Debug("> %s %s %s%s", res.Request.RemoteAddr, res.Request.Method, res.Request.Host, res.Request.URL.Path) + if p.shouldProxy(res.Request) { + p.Debug("> %s %s %s%s", res.Request.RemoteAddr, res.Request.Method, res.Request.Host, res.Request.URL.Path) - p.fixResponseHeaders(res) + p.fixResponseHeaders(res) - p.stripper.Process(res, ctx) + p.stripper.Process(res, ctx) - // do we have a proxy script? - if p.Script != nil { - _, jsres := p.Script.OnResponse(res) - if jsres != nil { - // the response has been changed by the script - p.logResponseAction(res.Request, jsres) - return jsres.ToResponse(res.Request) + // do we have a proxy script? + if p.Script != nil { + _, jsres := p.Script.OnResponse(res) + if jsres != nil { + // the response has been changed by the script + p.logResponseAction(res.Request, jsres) + return jsres.ToResponse(res.Request) + } } - } - // inject javascript code if specified and needed - if doInject, cType := p.isScriptInjectable(res); doInject { - if err, injectedResponse := p.doScriptInjection(res, cType); err != nil { - p.Error("error while injecting javascript: %s", err) - } else if injectedResponse != nil { - return injectedResponse + // inject javascript code if specified and needed + if doInject, cType := p.isScriptInjectable(res); doInject { + if err, injectedResponse := p.doScriptInjection(res, cType); err != nil { + p.Error("error while injecting javascript: %s", err) + } else if injectedResponse != nil { + return injectedResponse + } } } diff --git a/modules/https_proxy/https_proxy.go b/modules/https_proxy/https_proxy.go index 25a74d08..27a26cf1 100644 --- a/modules/https_proxy/https_proxy.go +++ b/modules/https_proxy/https_proxy.go @@ -6,6 +6,7 @@ import ( "github.com/bettercap/bettercap/tls" "github.com/evilsocket/islazy/fs" + "github.com/evilsocket/islazy/str" ) type HttpsProxy struct { @@ -58,6 +59,12 @@ func NewHttpsProxy(s *session.Session) *HttpsProxy { "", "Path of a proxy JS script.")) + mod.AddParam(session.NewStringParameter("https.proxy.blacklist", "", "", + "Comma separated list of hostnames to skip while proxying (wildcard expressions can be used).")) + + mod.AddParam(session.NewStringParameter("https.proxy.whitelist", "", "", + "Comma separated list of hostnames to proxy if the blacklist is used (wildcard expressions can be used).")) + mod.AddHandler(session.NewModuleHandler("https.proxy on", "", "Start HTTPS proxy.", func(args []string) error { @@ -95,6 +102,8 @@ func (mod *HttpsProxy) Configure() error { var keyFile string var stripSSL bool var jsToInject string + var whitelist string + var blacklist string if mod.Running() { return session.ErrAlreadyStarted @@ -118,8 +127,15 @@ func (mod *HttpsProxy) Configure() error { return err } else if err, jsToInject = mod.StringParam("https.proxy.injectjs"); err != nil { return err + } else if err, blacklist = mod.StringParam("https.proxy.blacklist"); err != nil { + return err + } else if err, whitelist = mod.StringParam("https.proxy.whitelist"); err != nil { + return err } + mod.proxy.Blacklist = str.Comma(blacklist) + mod.proxy.Whitelist = str.Comma(whitelist) + if !fs.Exists(certFile) || !fs.Exists(keyFile) { err, cfg := tls.CertConfigFromModule("https.proxy", mod.SessionModule) if err != nil {