From 6c3157e9c45d864bfb693d8403c82ff571821cbc Mon Sep 17 00:00:00 2001 From: evilsocket Date: Tue, 14 Aug 2018 17:12:22 +0200 Subject: [PATCH] new: implemented http.proxy.injectjs and https.proxy.injectjs to inject javascript code, files or URLs without a proxy module --- modules/http_proxy.go | 10 ++++++- modules/http_proxy_base.go | 24 ++++++++++++++--- modules/http_proxy_base_filters.go | 42 +++++++++++++++++++++++++----- modules/https_proxy.go | 10 ++++++- 4 files changed, 74 insertions(+), 12 deletions(-) diff --git a/modules/http_proxy.go b/modules/http_proxy.go index 876d3665..cdd42f56 100644 --- a/modules/http_proxy.go +++ b/modules/http_proxy.go @@ -33,6 +33,11 @@ func NewHttpProxy(s *session.Session) *HttpProxy { "", "Path of a proxy JS script.")) + p.AddParam(session.NewStringParameter("http.proxy.injectjs", + "", + "", + "URL, path or javascript code to inject into every HTML page.")) + p.AddParam(session.NewBoolParameter("http.proxy.sslstrip", "false", "Enable or disable SSL stripping.")) @@ -71,6 +76,7 @@ func (p *HttpProxy) Configure() error { var httpPort int var scriptPath string var stripSSL bool + var jsToInject string if p.Running() { return session.ErrAlreadyStarted @@ -84,9 +90,11 @@ func (p *HttpProxy) Configure() error { return err } else if err, stripSSL = p.BoolParam("http.proxy.sslstrip"); err != nil { return err + } else if err, jsToInject = p.StringParam("http.proxy.injectjs"); err != nil { + return err } - return p.proxy.Configure(address, proxyPort, httpPort, scriptPath, stripSSL) + return p.proxy.Configure(address, proxyPort, httpPort, scriptPath, jsToInject, stripSSL) } func (p *HttpProxy) Start() error { diff --git a/modules/http_proxy_base.go b/modules/http_proxy_base.go index 86816471..6677c365 100644 --- a/modules/http_proxy_base.go +++ b/modules/http_proxy_base.go @@ -40,6 +40,7 @@ type HTTPProxy struct { CertFile string KeyFile string + jsHook string isTLS bool isRunning bool stripper *SSLStripper @@ -106,12 +107,29 @@ func (p *HTTPProxy) doProxy(req *http.Request) bool { return true } -func (p *HTTPProxy) Configure(address string, proxyPort int, httpPort int, scriptPath string, stripSSL bool) error { +func (p *HTTPProxy) Configure(address string, proxyPort int, httpPort int, scriptPath string, jsToInject string, stripSSL bool) error { var err error p.stripper.Enable(stripSSL) p.Address = address + if strings.HasPrefix(jsToInject, "http://") || strings.HasPrefix(jsToInject, "https://") { + p.jsHook = fmt.Sprintf("", jsToInject) + } else if core.Exists(jsToInject) { + if data, err := ioutil.ReadFile(jsToInject); err != nil { + return err + } else { + jsToInject = string(data) + } + } + + if p.jsHook == "" && jsToInject != "" { + if strings.HasPrefix(jsToInject, "", jsToInject) + } + p.jsHook = fmt.Sprintf("%s", jsToInject) + } + if scriptPath != "" { if err, p.Script = LoadHttpProxyScript(scriptPath, p.sess); err != nil { return err @@ -187,8 +205,8 @@ func TLSConfigFromCA(ca *tls.Certificate) func(host string, ctx *goproxy.ProxyCt } } -func (p *HTTPProxy) ConfigureTLS(address string, proxyPort int, httpPort int, scriptPath string, certFile string, keyFile string, stripSSL bool) (err error) { - if p.Configure(address, proxyPort, httpPort, scriptPath, stripSSL); err != nil { +func (p *HTTPProxy) ConfigureTLS(address string, proxyPort int, httpPort int, scriptPath string, certFile string, keyFile string, jsToInject string, stripSSL bool) (err error) { + if p.Configure(address, proxyPort, httpPort, scriptPath, jsToInject, stripSSL); err != nil { return err } diff --git a/modules/http_proxy_base_filters.go b/modules/http_proxy_base_filters.go index c946346d..aa5615a6 100644 --- a/modules/http_proxy_base_filters.go +++ b/modules/http_proxy_base_filters.go @@ -1,6 +1,7 @@ package modules import ( + "io/ioutil" "net/http" "strings" @@ -40,6 +41,17 @@ func (p *HTTPProxy) onRequestFilter(req *http.Request, ctx *goproxy.ProxyCtx) (* return req, nil } +func getContentType(res *http.Response) string { + for name, values := range res.Header { + for _, value := range values { + if strings.ToLower(name) == "content-type" { + return value + } + } + } + return "" +} + func (p *HTTPProxy) onResponseFilter(res *http.Response, ctx *goproxy.ProxyCtx) *http.Response { // sometimes it happens ¯\_(ツ)_/¯ if res == nil { @@ -52,15 +64,31 @@ func (p *HTTPProxy) onResponseFilter(res *http.Response, ctx *goproxy.ProxyCtx) p.stripper.Process(res, ctx) // do we have a proxy script? - if p.Script == nil { - return res + 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) + } } - _, 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 cType := getContentType(res); p.jsHook != "" && strings.Contains(cType, "text/html") { + log.Info("(%s) > injecting javascript (%d bytes) into %s for %s", core.Green(p.Name), len(p.jsHook), core.Yellow(req.Host+req.URL.Path), core.Bold(req.RemoteAddr)) + defer res.Body.Close() + + raw, _ := ioutil.ReadAll(res.Body) + html := strings.Replace(string(raw), "", p.jsHook, -1) + + newResp := goproxy.NewResponse(req, cType, res.StatusCode, html) + for k, vv := range res.Header { + for _, v := range vv { + newResp.Header.Add(k, v) + } + } + + return newResp } return res diff --git a/modules/https_proxy.go b/modules/https_proxy.go index b8ee65f8..218033e5 100644 --- a/modules/https_proxy.go +++ b/modules/https_proxy.go @@ -35,6 +35,11 @@ func NewHttpsProxy(s *session.Session) *HttpsProxy { "false", "Enable or disable SSL stripping.")) + p.AddParam(session.NewStringParameter("https.proxy.injectjs", + "", + "", + "URL, path or javascript code to inject into every HTML page.")) + p.AddParam(session.NewStringParameter("https.proxy.certificate", "~/.bettercap-ca.cert.pem", "", @@ -86,6 +91,7 @@ func (p *HttpsProxy) Configure() error { var certFile string var keyFile string var stripSSL bool + var jsToInject string if p.Running() { return session.ErrAlreadyStarted @@ -107,6 +113,8 @@ func (p *HttpsProxy) Configure() error { return err } else if err, scriptPath = p.StringParam("https.proxy.script"); err != nil { return err + } else if err, jsToInject = p.StringParam("https.proxy.injectjs"); err != nil { + return err } if !core.Exists(certFile) || !core.Exists(keyFile) { @@ -120,7 +128,7 @@ func (p *HttpsProxy) Configure() error { log.Info("Loading proxy certification authority TLS certificate from %s", certFile) } - return p.proxy.ConfigureTLS(address, proxyPort, httpPort, scriptPath, certFile, keyFile, stripSSL) + return p.proxy.ConfigureTLS(address, proxyPort, httpPort, scriptPath, certFile, keyFile, jsToInject, stripSSL) } func (p *HttpsProxy) Start() error {