new: implemented (http|https).proxy.whitelist and (http|https).proxy.blacklist parameters (closes #508)

This commit is contained in:
evilsocket 2019-03-26 14:20:34 +01:00
parent 6785650887
commit cfd93c555a
No known key found for this signature in database
GPG key ID: 1564D7F30393A456
4 changed files with 118 additions and 55 deletions

View file

@ -2,6 +2,8 @@ package http_proxy
import ( import (
"github.com/bettercap/bettercap/session" "github.com/bettercap/bettercap/session"
"github.com/evilsocket/islazy/str"
) )
type HttpProxy struct { type HttpProxy struct {
@ -38,6 +40,12 @@ func NewHttpProxy(s *session.Session) *HttpProxy {
"", "",
"URL, path or javascript code to inject into every HTML page.")) "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", mod.AddParam(session.NewBoolParameter("http.proxy.sslstrip",
"false", "false",
"Enable or disable SSL stripping.")) "Enable or disable SSL stripping."))
@ -77,6 +85,8 @@ func (mod *HttpProxy) Configure() error {
var scriptPath string var scriptPath string
var stripSSL bool var stripSSL bool
var jsToInject string var jsToInject string
var blacklist string
var whitelist string
if mod.Running() { if mod.Running() {
return session.ErrAlreadyStarted return session.ErrAlreadyStarted
@ -92,8 +102,15 @@ func (mod *HttpProxy) Configure() error {
return err return err
} else if err, jsToInject = mod.StringParam("http.proxy.injectjs"); err != nil { } else if err, jsToInject = mod.StringParam("http.proxy.injectjs"); err != nil {
return err 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) return mod.proxy.Configure(address, proxyPort, httpPort, scriptPath, jsToInject, stripSSL)
} }

View file

@ -11,6 +11,7 @@ import (
"net" "net"
"net/http" "net/http"
"net/url" "net/url"
"path/filepath"
"strconv" "strconv"
"strings" "strings"
"time" "time"
@ -41,6 +42,8 @@ type HTTPProxy struct {
Script *HttpProxyScript Script *HttpProxyScript
CertFile string CertFile string
KeyFile string KeyFile string
Blacklist []string
Whitelist []string
jsHook string jsHook string
isTLS bool isTLS bool
@ -61,13 +64,15 @@ func stripPort(s string) string {
func NewHTTPProxy(s *session.Session) *HTTPProxy { func NewHTTPProxy(s *session.Session) *HTTPProxy {
p := &HTTPProxy{ p := &HTTPProxy{
Name: "http.proxy", Name: "http.proxy",
Proxy: goproxy.NewProxyHttpServer(), Proxy: goproxy.NewProxyHttpServer(),
sess: s, sess: s,
stripper: NewSSLStripper(s, false), stripper: NewSSLStripper(s, false),
isTLS: false, isTLS: false,
Server: nil, Server: nil,
tag: session.AsTag("http.proxy"), Blacklist: make([]string, 0),
Whitelist: make([]string, 0),
tag: session.AsTag("http.proxy"),
} }
p.Proxy.Verbose = false p.Proxy.Verbose = false
@ -111,20 +116,41 @@ func (p *HTTPProxy) Fatal(format string, args ...interface{}) {
} }
func (p *HTTPProxy) doProxy(req *http.Request) bool { func (p *HTTPProxy) doProxy(req *http.Request) bool {
blacklist := []string{
"localhost",
"127.0.0.1",
}
if req.Host == "" { if req.Host == "" {
p.Error("got request with empty host: %v", req) p.Error("got request with empty host: %v", req)
return false return false
} }
host := strings.Split(req.Host, ":")[0] hostname := strings.Split(req.Host, ":")[0]
for _, blacklisted := range blacklist { for _, local := range []string{"localhost", "127.0.0.1"} {
if host == blacklisted { if hostname == local {
p.Error("got request with blacklisted host: %s", req.Host) 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 return false
} }
} }

View file

@ -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) { 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) redir := p.stripper.Preprocess(req, ctx)
if redir != nil { if redir != nil {
// we need to redirect the user in order to make // we need to redirect the user in order to make
// some session cookie expire // some session cookie expire
return req, redir return req, redir
} }
// do we have a proxy script? // do we have a proxy script?
if p.Script == nil { if p.Script == nil {
return req, nil return req, nil
} }
// run the module OnRequest callback if defined // run the module OnRequest callback if defined
jsreq, jsres := p.Script.OnRequest(req) jsreq, jsres := p.Script.OnRequest(req)
if jsreq != nil { if jsreq != nil {
// the request has been changed by the script // the request has been changed by the script
p.logRequestAction(req, jsreq) p.logRequestAction(req, jsreq)
return jsreq.ToRequest(), nil return jsreq.ToRequest(), nil
} else if jsres != nil { } else if jsres != nil {
// a fake response has been returned by the script // a fake response has been returned by the script
p.logResponseAction(req, jsres) p.logResponseAction(req, jsres)
return req, jsres.ToResponse(req) return req, jsres.ToResponse(req)
}
} }
return req, nil return req, nil
@ -123,28 +125,30 @@ func (p *HTTPProxy) onResponseFilter(res *http.Response, ctx *goproxy.ProxyCtx)
return nil 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? // do we have a proxy script?
if p.Script != nil { if p.Script != nil {
_, jsres := p.Script.OnResponse(res) _, jsres := p.Script.OnResponse(res)
if jsres != nil { if jsres != nil {
// the response has been changed by the script // the response has been changed by the script
p.logResponseAction(res.Request, jsres) p.logResponseAction(res.Request, jsres)
return jsres.ToResponse(res.Request) return jsres.ToResponse(res.Request)
}
} }
}
// inject javascript code if specified and needed // inject javascript code if specified and needed
if doInject, cType := p.isScriptInjectable(res); doInject { if doInject, cType := p.isScriptInjectable(res); doInject {
if err, injectedResponse := p.doScriptInjection(res, cType); err != nil { if err, injectedResponse := p.doScriptInjection(res, cType); err != nil {
p.Error("error while injecting javascript: %s", err) p.Error("error while injecting javascript: %s", err)
} else if injectedResponse != nil { } else if injectedResponse != nil {
return injectedResponse return injectedResponse
}
} }
} }

View file

@ -6,6 +6,7 @@ import (
"github.com/bettercap/bettercap/tls" "github.com/bettercap/bettercap/tls"
"github.com/evilsocket/islazy/fs" "github.com/evilsocket/islazy/fs"
"github.com/evilsocket/islazy/str"
) )
type HttpsProxy struct { type HttpsProxy struct {
@ -58,6 +59,12 @@ func NewHttpsProxy(s *session.Session) *HttpsProxy {
"", "",
"Path of a proxy JS script.")) "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", "", mod.AddHandler(session.NewModuleHandler("https.proxy on", "",
"Start HTTPS proxy.", "Start HTTPS proxy.",
func(args []string) error { func(args []string) error {
@ -95,6 +102,8 @@ func (mod *HttpsProxy) Configure() error {
var keyFile string var keyFile string
var stripSSL bool var stripSSL bool
var jsToInject string var jsToInject string
var whitelist string
var blacklist string
if mod.Running() { if mod.Running() {
return session.ErrAlreadyStarted return session.ErrAlreadyStarted
@ -118,8 +127,15 @@ func (mod *HttpsProxy) Configure() error {
return err return err
} else if err, jsToInject = mod.StringParam("https.proxy.injectjs"); err != nil { } else if err, jsToInject = mod.StringParam("https.proxy.injectjs"); err != nil {
return err 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) { if !fs.Exists(certFile) || !fs.Exists(keyFile) {
err, cfg := tls.CertConfigFromModule("https.proxy", mod.SessionModule) err, cfg := tls.CertConfigFromModule("https.proxy", mod.SessionModule)
if err != nil { if err != nil {