mirror of
https://github.com/bettercap/bettercap
synced 2025-07-31 04:00:09 -07:00
yeah i should have done this before, i know
This commit is contained in:
commit
0091ffdbb3
33 changed files with 25678 additions and 0 deletions
264
session/modules/http_proxy.go
Normal file
264
session/modules/http_proxy.go
Normal file
|
@ -0,0 +1,264 @@
|
|||
package session_modules
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/op/go-logging"
|
||||
"net/http"
|
||||
"regexp"
|
||||
"strings"
|
||||
|
||||
"github.com/elazarl/goproxy"
|
||||
"github.com/elazarl/goproxy/ext/html"
|
||||
|
||||
"github.com/evilsocket/bettercap/firewall"
|
||||
"github.com/evilsocket/bettercap/session"
|
||||
)
|
||||
|
||||
var log = logging.MustGetLogger("mitm")
|
||||
|
||||
type ProxyFilter struct {
|
||||
Type string
|
||||
Expression string
|
||||
Replace string
|
||||
Compiled *regexp.Regexp
|
||||
}
|
||||
|
||||
func tokenize(s string, sep byte, n int) (error, []string) {
|
||||
filtered := make([]string, 0)
|
||||
tokens := strings.Split(s, string(sep))
|
||||
|
||||
for _, t := range tokens {
|
||||
if t != "" {
|
||||
filtered = append(filtered, t)
|
||||
}
|
||||
}
|
||||
|
||||
if len(filtered) != n {
|
||||
return fmt.Errorf("Could not split '%s' by '%s'.", s, string(sep)), filtered
|
||||
} else {
|
||||
return nil, filtered
|
||||
}
|
||||
}
|
||||
|
||||
func NewProxyFilter(type_, expression string) (error, *ProxyFilter) {
|
||||
err, tokens := tokenize(expression, expression[0], 2)
|
||||
if err != nil {
|
||||
return err, nil
|
||||
}
|
||||
|
||||
filter := &ProxyFilter{
|
||||
Type: type_,
|
||||
Expression: tokens[0],
|
||||
Replace: tokens[1],
|
||||
Compiled: nil,
|
||||
}
|
||||
|
||||
if filter.Compiled, err = regexp.Compile(filter.Expression); err != nil {
|
||||
return err, nil
|
||||
}
|
||||
|
||||
return nil, filter
|
||||
}
|
||||
|
||||
func (f *ProxyFilter) Process(req *http.Request, response_body string) string {
|
||||
orig := response_body
|
||||
filtered := f.Compiled.ReplaceAllString(orig, f.Replace)
|
||||
|
||||
// TODO: this sucks
|
||||
if orig != filtered {
|
||||
log.Infof("%s > Applied %s-filtering to %d of response body.", req.RemoteAddr, f.Type, len(filtered))
|
||||
}
|
||||
|
||||
return filtered
|
||||
}
|
||||
|
||||
type HttpProxy struct {
|
||||
session.SessionModule
|
||||
|
||||
address string
|
||||
redirection *firewall.Redirection
|
||||
server http.Server
|
||||
proxy *goproxy.ProxyHttpServer
|
||||
|
||||
pre_filter *ProxyFilter
|
||||
post_filter *ProxyFilter
|
||||
}
|
||||
|
||||
func NewHttpProxy(s *session.Session) *HttpProxy {
|
||||
p := &HttpProxy{
|
||||
SessionModule: session.NewSessionModule(s),
|
||||
proxy: goproxy.NewProxyHttpServer(),
|
||||
address: "",
|
||||
redirection: nil,
|
||||
pre_filter: nil,
|
||||
post_filter: nil,
|
||||
}
|
||||
|
||||
p.AddParam(session.NewIntParameter("http.port", "80", "", "HTTP port to redirect when the proxy is activated."))
|
||||
p.AddParam(session.NewIntParameter("http.proxy.port", "8080", "", "Port to bind the HTTP proxy to."))
|
||||
p.AddParam(session.NewStringParameter("http.proxy.address", "<interface address>", `^(?:[0-9]{1,3}\.){3}[0-9]{1,3}$`, "Address to bind the HTTP proxy to."))
|
||||
p.AddParam(session.NewStringParameter("http.proxy.post.filter", "", "", "SED like syntax to replace things in the response ( example |</head>|<script src='...'></script></head>| )."))
|
||||
|
||||
p.AddHandler(session.NewModuleHandler("http.proxy (on|off)", "^http\\.proxy (on|off)$",
|
||||
"Start/stop HTTP proxy.",
|
||||
func(args []string) error {
|
||||
if args[0] == "on" {
|
||||
return p.Start()
|
||||
} else {
|
||||
return p.Stop()
|
||||
}
|
||||
}))
|
||||
|
||||
p.proxy.NonproxyHandler = http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {
|
||||
if p.doProxy(req) == true {
|
||||
req.URL.Scheme = "http"
|
||||
req.URL.Host = req.Host
|
||||
|
||||
// TODO: p.pre_filter.Process
|
||||
|
||||
p.proxy.ServeHTTP(w, req)
|
||||
} else {
|
||||
log.Infof("Skipping %s\n", req.Host)
|
||||
}
|
||||
})
|
||||
|
||||
p.proxy.OnResponse(goproxy_html.IsHtml).Do(goproxy_html.HandleString(func(body string, ctx *goproxy.ProxyCtx) string {
|
||||
if p.post_filter != nil {
|
||||
body = p.post_filter.Process(ctx.Req, body)
|
||||
}
|
||||
return body
|
||||
}))
|
||||
|
||||
return p
|
||||
}
|
||||
|
||||
func (p HttpProxy) Name() string {
|
||||
return "HTTP Proxy"
|
||||
}
|
||||
|
||||
func (p HttpProxy) Description() string {
|
||||
return "A full featured HTTP proxy that can be used to inject malicious contents into webpages, all HTTP traffic will be redirected to it."
|
||||
}
|
||||
|
||||
func (p HttpProxy) Author() string {
|
||||
return "Simone Margaritelli <evilsocket@protonmail.com>"
|
||||
}
|
||||
|
||||
func (p HttpProxy) OnSessionStarted(s *session.Session) {
|
||||
// refresh the address after session has been created
|
||||
s.Env.Set("http.proxy.address", s.Interface.IpAddress)
|
||||
}
|
||||
|
||||
func (p HttpProxy) OnSessionEnded(s *session.Session) {
|
||||
if p.Running() {
|
||||
p.Stop()
|
||||
}
|
||||
}
|
||||
|
||||
func (p *HttpProxy) Start() error {
|
||||
var http_port int
|
||||
var proxy_port int
|
||||
|
||||
if p.Running() == true {
|
||||
return fmt.Errorf("HTTP proxy already started.")
|
||||
}
|
||||
|
||||
if err, v := p.Param("http.proxy.address").Get(p.Session); err != nil {
|
||||
return err
|
||||
} else {
|
||||
p.address = v.(string)
|
||||
}
|
||||
|
||||
if err, v := p.Param("http.proxy.port").Get(p.Session); err != nil {
|
||||
return err
|
||||
} else {
|
||||
proxy_port = v.(int)
|
||||
}
|
||||
|
||||
if err, v := p.Param("http.port").Get(p.Session); err != nil {
|
||||
return err
|
||||
} else {
|
||||
http_port = v.(int)
|
||||
}
|
||||
|
||||
p.post_filter = nil
|
||||
if err, v := p.Param("http.proxy.post.filter").Get(p.Session); err != nil {
|
||||
return err
|
||||
} else {
|
||||
expression := v.(string)
|
||||
if expression != "" {
|
||||
if err, p.post_filter = NewProxyFilter("post", expression); err != nil {
|
||||
return err
|
||||
} else {
|
||||
log.Debug("Proxy POST filter set to '%s'.", expression)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if p.Session.Firewall.IsForwardingEnabled() == false {
|
||||
p.Session.Firewall.EnableForwarding(true)
|
||||
}
|
||||
|
||||
p.redirection = firewall.NewRedirection(p.Session.Interface.Name(),
|
||||
"TCP",
|
||||
http_port,
|
||||
p.address,
|
||||
proxy_port)
|
||||
|
||||
if err := p.Session.Firewall.EnableRedirection(p.redirection, true); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
address := fmt.Sprintf("%s:%d", p.address, proxy_port)
|
||||
log.Infof("Starting proxy on %s.\n", address)
|
||||
|
||||
p.server = http.Server{Addr: address, Handler: p.proxy}
|
||||
go func() {
|
||||
p.SetRunning(true)
|
||||
if err := p.server.ListenAndServe(); err != nil {
|
||||
p.SetRunning(false)
|
||||
log.Warning(err)
|
||||
}
|
||||
}()
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (p *HttpProxy) Stop() error {
|
||||
if p.Running() == true {
|
||||
p.SetRunning(false)
|
||||
p.server.Shutdown(nil)
|
||||
log.Info("HTTP proxy stopped.\n")
|
||||
if p.redirection != nil {
|
||||
if err := p.Session.Firewall.EnableRedirection(p.redirection, false); err != nil {
|
||||
return err
|
||||
}
|
||||
p.redirection = nil
|
||||
}
|
||||
return nil
|
||||
} else {
|
||||
return fmt.Errorf("HTTP proxy stopped.")
|
||||
}
|
||||
}
|
||||
|
||||
func (p *HttpProxy) doProxy(req *http.Request) bool {
|
||||
blacklist := []string{
|
||||
"localhost",
|
||||
"127.0.0.1",
|
||||
p.address,
|
||||
}
|
||||
|
||||
if req.Host == "" {
|
||||
log.Errorf("Got request with empty host: %v\n", req)
|
||||
return false
|
||||
}
|
||||
|
||||
for _, blacklisted := range blacklist {
|
||||
if strings.HasPrefix(req.Host, blacklisted) {
|
||||
log.Errorf("Got request with blacklisted host: %s\n", req.Host)
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue