Commit 5f274c29 authored by Sophie Brun's avatar Sophie Brun

New upstream version 2.15

parent f31c7fa8
......@@ -2,7 +2,7 @@ sudo: false
language: go
go:
- 1.9.x
# - 1.9.x
- 1.10.x
- 1.11.x
- master
......
......@@ -59,20 +59,21 @@
revision = "2ce16c963a8ac5bd6af851d4877e38701346983f"
[[projects]]
digest = "1:88e0bcc18d131d663b1d1c449e91207bcc008978eb3eee7ac4a12ef9a8c8924c"
digest = "1:c706034658cd03896bcde87e0770048bb1443378d18932d5897c3d7f3e44133b"
name = "github.com/evilsocket/islazy"
packages = [
"data",
"fs",
"log",
"ops",
"plugin",
"str",
"tui",
"zip",
]
pruneopts = "UT"
revision = "cbdab98bdf66f776cf87f90f51328c7b41348125"
version = "v1.9.3"
revision = "268495ba2f4621f397a274dc33b9296553db855d"
version = "v1.10.0"
[[projects]]
branch = "master"
......@@ -120,20 +121,12 @@
revision = "v1.1.16"
[[projects]]
digest = "1:c79fb010be38a59d657c48c6ba1d003a8aa651fa56b579d959d74573b7dff8e1"
name = "github.com/gorilla/context"
packages = ["."]
pruneopts = "UT"
revision = "08b5f424b9271eedf6f9f0ce86cb9396ed337a42"
version = "v1.1.1"
[[projects]]
digest = "1:e73f5b0152105f18bc131fba127d9949305c8693f8a762588a82a48f61756f5f"
digest = "1:ca59b1175189b3f0e9f1793d2c350114be36eaabbe5b9f554b35edee1de50aea"
name = "github.com/gorilla/mux"
packages = ["."]
pruneopts = "UT"
revision = "e3702bed27f0d39777b0b37b664b6280e8ef8fbf"
version = "v1.6.2"
revision = "a7962380ca08b5a188038c69871b8d3fbdf31e89"
version = "v1.7.0"
[[projects]]
digest = "1:7b5c6e2eeaa9ae5907c391a91c132abfd5c9e8a784a341b5625e750c67e6825d"
......@@ -153,11 +146,11 @@
[[projects]]
branch = "master"
digest = "1:afaa86f5ab9275b1c5cccb3343fa3b7ea77045572a59e9f97d36fd67d14fbe62"
digest = "1:45da610fe81bb89b25555d0111fa338dcdbf2346afdb2b7296c8c49e554a9d32"
name = "github.com/jpillora/go-tld"
packages = ["."]
pruneopts = "UT"
revision = "4bfc8d9a90b591e101a56265afc2239359fb0810"
revision = "f16ca3b7b383d3f0373109cac19147de3e8ae2d1"
[[projects]]
digest = "1:4701b2acabe16722ecb1e387d39741a29269386bfc4ba6283ecda362d289eff1"
......@@ -168,12 +161,12 @@
version = "v0.9.0"
[[projects]]
digest = "1:c658e84ad3916da105a761660dcaeb01e63416c8ec7bc62256a9b411a05fcd67"
digest = "1:0f96ec4151a24d7bfd4298fc13cc320a000e31b4e5431cf88e3ffc961db846fd"
name = "github.com/mattn/go-colorable"
packages = ["."]
pruneopts = "UT"
revision = "167de6bfdfba052fa6b2d3664c8f5272e23c9072"
version = "v0.0.9"
revision = "efa589957cd060542a26d2dd7832fd6a6c6c3ade"
version = "v0.1.0"
[[projects]]
digest = "1:0981502f9816113c9c8c4ac301583841855c8cf4da8c72f696b3ebedf6d0e4e5"
......@@ -257,15 +250,15 @@
name = "golang.org/x/net"
packages = ["bpf"]
pruneopts = "UT"
revision = "915654e7eabcea33ae277abbecf52f0d8b7a9fdc"
revision = "65e2d4e15006aab9813ff8769e768bbf4bb667a0"
[[projects]]
branch = "master"
digest = "1:f6f6d9d6f80c9e32acc0f4f3b904e0b9f5b18a7757c2ef941121bd79a10e7bdf"
digest = "1:8b466798e96432c23185ca32826702885299f94eb644c9a8dedb79771dff383a"
name = "golang.org/x/sys"
packages = ["unix"]
pruneopts = "UT"
revision = "11f53e03133963fb11ae0588e08b5e0b85be8be5"
revision = "3b5209105503162ded1863c307ac66fec31120dd"
[[projects]]
digest = "1:9935525a8c49b8434a0b0a54e1980e94a6fae73aaff45c5d33ba8dff69de123e"
......@@ -291,6 +284,7 @@
"github.com/evilsocket/islazy/data",
"github.com/evilsocket/islazy/fs",
"github.com/evilsocket/islazy/log",
"github.com/evilsocket/islazy/ops",
"github.com/evilsocket/islazy/plugin",
"github.com/evilsocket/islazy/str",
"github.com/evilsocket/islazy/tui",
......
# Gopkg.toml example
#
# Refer to https://golang.github.io/dep/docs/Gopkg.toml.html
# for detailed Gopkg.toml documentation.
#
# required = ["github.com/user/thing/cmd/thing"]
# ignored = ["github.com/user/project/pkgX", "bitbucket.org/user/project/pkgA/pkgY"]
#
# [[constraint]]
# name = "github.com/user/project"
# version = "1.0.0"
#
# [[constraint]]
# name = "github.com/user/project2"
# branch = "dev"
# source = "github.com/myfork/project2"
#
# [[override]]
# name = "github.com/x/y"
# version = "2.4.0"
#
# [prune]
# non-go = false
# go-tests = true
# unused-packages = true
[[constraint]]
name = "github.com/evilsocket/islazy"
version = "1.9.1"
......
......@@ -13,6 +13,12 @@
## How to Install
<p align="center">
<a href="https://snapcraft.io/bettercap" target="_blank">
<img alt="Get it from the Snap Store" src="https://snapcraft.io/static/images/badges/en/snap-store-white.svg" />
</a>
</p>
A [precompiled version is available](https://github.com/bettercap/bettercap/releases) for each release, alternatively you can use the latest version of the source code from this repository in order to build your own binary.
Make sure you have a correctly configured **Go >= 1.8** environment, that `$GOPATH/bin` is in `$PATH`, that the `libpcap-dev` and `libnetfilter-queue-dev` (this one is only required on Linux) package installed for your system and then:
......
......@@ -2,7 +2,7 @@ package core
const (
Name = "bettercap"
Version = "2.14"
Version = "2.15"
Author = "Simone 'evilsocket' Margaritelli"
Website = "https://bettercap.org/"
)
......@@ -4,6 +4,7 @@ import "flag"
type Options struct {
InterfaceName *string
Gateway *string
Caplet *string
AutoStart *string
Debug *bool
......@@ -19,6 +20,7 @@ type Options struct {
func ParseOptions() (Options, error) {
o := Options{
InterfaceName: flag.String("iface", "", "Network interface to bind to, if empty the default interface will be auto selected."),
Gateway: flag.String("gateway-override","","Use the provided IP address instead of the default gateway. If not specified or invalid, the default gateway will be used."),
AutoStart: flag.String("autostart", "events.stream, net.recon", "Comma separated list of modules to auto start."),
Caplet: flag.String("caplet", "", "Read commands from this file and execute them in the interactive session."),
Debug: flag.Bool("debug", false, "Print debug messages."),
......
......@@ -35,31 +35,8 @@ func main() {
fmt.Printf("%s (type '%s' for a list of commands)\n\n", tui.Bold(appName), tui.Bold("help"))
sess.Register(modules.NewEventsStream(sess))
sess.Register(modules.NewTicker(sess))
sess.Register(modules.NewUpdateModule(sess))
sess.Register(modules.NewCapletsModule(sess))
sess.Register(modules.NewMacChanger(sess))
sess.Register(modules.NewProber(sess))
sess.Register(modules.NewDiscovery(sess))
sess.Register(modules.NewArpSpoofer(sess))
sess.Register(modules.NewDHCP6Spoofer(sess))
sess.Register(modules.NewDNSSpoofer(sess))
sess.Register(modules.NewSniffer(sess))
sess.Register(modules.NewPacketProxy(sess))
sess.Register(modules.NewAnyProxy(sess))
sess.Register(modules.NewTcpProxy(sess))
sess.Register(modules.NewHttpProxy(sess))
sess.Register(modules.NewHttpsProxy(sess))
sess.Register(modules.NewHttpServer(sess))
sess.Register(modules.NewHttpsServer(sess))
sess.Register(modules.NewRestAPI(sess))
sess.Register(modules.NewWOL(sess))
sess.Register(modules.NewWiFiModule(sess))
sess.Register(modules.NewBLERecon(sess))
sess.Register(modules.NewSynScanner(sess))
sess.Register(modules.NewGPS(sess))
sess.Register(modules.NewMySQLServer(sess))
// Load all modules
modules.LoadModules(sess)
if err = sess.Start(); err != nil {
log.Fatal("%s", err)
......
package modules
package any_proxy
import (
"github.com/bettercap/bettercap/firewall"
"github.com/bettercap/bettercap/log"
"github.com/bettercap/bettercap/session"
)
......@@ -12,66 +11,66 @@ type AnyProxy struct {
}
func NewAnyProxy(s *session.Session) *AnyProxy {
p := &AnyProxy{
mod := &AnyProxy{
SessionModule: session.NewSessionModule("any.proxy", s),
}
p.AddParam(session.NewStringParameter("any.proxy.iface",
mod.AddParam(session.NewStringParameter("any.proxy.iface",
session.ParamIfaceName,
"",
"Interface to redirect packets from."))
p.AddParam(session.NewStringParameter("any.proxy.protocol",
mod.AddParam(session.NewStringParameter("any.proxy.protocol",
"TCP",
"(TCP|UDP)",
"Proxy protocol."))
p.AddParam(session.NewIntParameter("any.proxy.src_port",
mod.AddParam(session.NewIntParameter("any.proxy.src_port",
"80",
"Remote port to redirect when the module is activated."))
p.AddParam(session.NewStringParameter("any.proxy.src_address",
mod.AddParam(session.NewStringParameter("any.proxy.src_address",
"",
"",
"Leave empty to intercept any source address."))
p.AddParam(session.NewStringParameter("any.proxy.dst_address",
mod.AddParam(session.NewStringParameter("any.proxy.dst_address",
session.ParamIfaceAddress,
session.IPv4Validator,
"Address where the proxy is listening."))
p.AddParam(session.NewIntParameter("any.proxy.dst_port",
mod.AddParam(session.NewIntParameter("any.proxy.dst_port",
"8080",
"Port where the proxy is listening."))
p.AddHandler(session.NewModuleHandler("any.proxy on", "",
mod.AddHandler(session.NewModuleHandler("any.proxy on", "",
"Start the custom proxy redirection.",
func(args []string) error {
return p.Start()
return mod.Start()
}))
p.AddHandler(session.NewModuleHandler("any.proxy off", "",
mod.AddHandler(session.NewModuleHandler("any.proxy off", "",
"Stop the custom proxy redirection.",
func(args []string) error {
return p.Stop()
return mod.Stop()
}))
return p
return mod
}
func (p *AnyProxy) Name() string {
func (mod *AnyProxy) Name() string {
return "any.proxy"
}
func (p *AnyProxy) Description() string {
func (mod *AnyProxy) Description() string {
return "A firewall redirection to any custom proxy."
}
func (p *AnyProxy) Author() string {
return "Simone Margaritelli <evilsocket@protonmail.com>"
func (mod *AnyProxy) Author() string {
return "Simone Margaritelli <evilsocket@gmail.com>"
}
func (p *AnyProxy) Configure() error {
func (mod *AnyProxy) Configure() error {
var err error
var srcPort int
var dstPort int
......@@ -80,62 +79,62 @@ func (p *AnyProxy) Configure() error {
var srcAddress string
var dstAddress string
if p.Running() {
if mod.Running() {
return session.ErrAlreadyStarted
} else if err, iface = p.StringParam("any.proxy.iface"); err != nil {
} else if err, iface = mod.StringParam("any.proxy.iface"); err != nil {
return err
} else if err, protocol = p.StringParam("any.proxy.protocol"); err != nil {
} else if err, protocol = mod.StringParam("any.proxy.protocol"); err != nil {
return err
} else if err, srcPort = p.IntParam("any.proxy.src_port"); err != nil {
} else if err, srcPort = mod.IntParam("any.proxy.src_port"); err != nil {
return err
} else if err, dstPort = p.IntParam("any.proxy.dst_port"); err != nil {
} else if err, dstPort = mod.IntParam("any.proxy.dst_port"); err != nil {
return err
} else if err, srcAddress = p.StringParam("any.proxy.src_address"); err != nil {
} else if err, srcAddress = mod.StringParam("any.proxy.src_address"); err != nil {
return err
} else if err, dstAddress = p.StringParam("any.proxy.dst_address"); err != nil {
} else if err, dstAddress = mod.StringParam("any.proxy.dst_address"); err != nil {
return err
}
if !p.Session.Firewall.IsForwardingEnabled() {
log.Info("Enabling forwarding.")
p.Session.Firewall.EnableForwarding(true)
if !mod.Session.Firewall.IsForwardingEnabled() {
mod.Info("Enabling forwarding.")
mod.Session.Firewall.EnableForwarding(true)
}
p.Redirection = firewall.NewRedirection(iface,
mod.Redirection = firewall.NewRedirection(iface,
protocol,
srcPort,
dstAddress,
dstPort)
if srcAddress != "" {
p.Redirection.SrcAddress = srcAddress
mod.Redirection.SrcAddress = srcAddress
}
if err := p.Session.Firewall.EnableRedirection(p.Redirection, true); err != nil {
if err := mod.Session.Firewall.EnableRedirection(mod.Redirection, true); err != nil {
return err
}
log.Info("Applied redirection %s", p.Redirection.String())
mod.Info("Applied redirection %s", mod.Redirection.String())
return nil
}
func (p *AnyProxy) Start() error {
if err := p.Configure(); err != nil {
func (mod *AnyProxy) Start() error {
if err := mod.Configure(); err != nil {
return err
}
return p.SetRunning(true, func() {})
return mod.SetRunning(true, func() {})
}
func (p *AnyProxy) Stop() error {
if p.Redirection != nil {
log.Info("Disabling redirection %s", p.Redirection.String())
if err := p.Session.Firewall.EnableRedirection(p.Redirection, false); err != nil {
func (mod *AnyProxy) Stop() error {
if mod.Redirection != nil {
mod.Info("Disabling redirection %s", mod.Redirection.String())
if err := mod.Session.Firewall.EnableRedirection(mod.Redirection, false); err != nil {
return err
}
p.Redirection = nil
mod.Redirection = nil
}
return p.SetRunning(false, func() {})
return mod.SetRunning(false, func() {})
}
package modules
package api_rest
import (
"context"
......@@ -6,7 +6,6 @@ import (
"net/http"
"time"
"github.com/bettercap/bettercap/log"
"github.com/bettercap/bettercap/session"
"github.com/bettercap/bettercap/tls"
......@@ -30,7 +29,7 @@ type RestAPI struct {
}
func NewRestAPI(s *session.Session) *RestAPI {
api := &RestAPI{
mod := &RestAPI{
SessionModule: session.NewSessionModule("api.rest", s),
server: &http.Server{},
quit: make(chan bool),
......@@ -42,59 +41,59 @@ func NewRestAPI(s *session.Session) *RestAPI {
},
}
api.AddParam(session.NewStringParameter("api.rest.address",
mod.AddParam(session.NewStringParameter("api.rest.address",
session.ParamIfaceAddress,
session.IPv4Validator,
"Address to bind the API REST server to."))
api.AddParam(session.NewIntParameter("api.rest.port",
mod.AddParam(session.NewIntParameter("api.rest.port",
"8081",
"Port to bind the API REST server to."))
api.AddParam(session.NewStringParameter("api.rest.alloworigin",
api.allowOrigin,
mod.AddParam(session.NewStringParameter("api.rest.alloworigin",
mod.allowOrigin,
"",
"Value of the Access-Control-Allow-Origin header of the API server."))
api.AddParam(session.NewStringParameter("api.rest.username",
mod.AddParam(session.NewStringParameter("api.rest.username",
"",
"",
"API authentication username."))
api.AddParam(session.NewStringParameter("api.rest.password",
mod.AddParam(session.NewStringParameter("api.rest.password",
"",
"",
"API authentication password."))
api.AddParam(session.NewStringParameter("api.rest.certificate",
mod.AddParam(session.NewStringParameter("api.rest.certificate",
"",
"",
"API TLS certificate."))
tls.CertConfigToModule("api.rest", &api.SessionModule, tls.DefaultLegitConfig)
tls.CertConfigToModule("api.rest", &mod.SessionModule, tls.DefaultLegitConfig)
api.AddParam(session.NewStringParameter("api.rest.key",
mod.AddParam(session.NewStringParameter("api.rest.key",
"",
"",
"API TLS key"))
api.AddParam(session.NewBoolParameter("api.rest.websocket",
mod.AddParam(session.NewBoolParameter("api.rest.websocket",
"false",
"If true the /api/events route will be available as a websocket endpoint instead of HTTPS."))
api.AddHandler(session.NewModuleHandler("api.rest on", "",
mod.AddHandler(session.NewModuleHandler("api.rest on", "",
"Start REST API server.",
func(args []string) error {
return api.Start()
return mod.Start()
}))
api.AddHandler(session.NewModuleHandler("api.rest off", "",
mod.AddHandler(session.NewModuleHandler("api.rest off", "",
"Stop REST API server.",
func(args []string) error {
return api.Stop()
return mod.Stop()
}))
return api
return mod
}
type JSSessionRequest struct {
......@@ -105,113 +104,113 @@ type JSSessionResponse struct {
Error string `json:"error"`
}
func (api *RestAPI) Name() string {
func (mod *RestAPI) Name() string {
return "api.rest"
}
func (api *RestAPI) Description() string {
func (mod *RestAPI) Description() string {
return "Expose a RESTful API."
}
func (api *RestAPI) Author() string {
return "Simone Margaritelli <evilsocket@protonmail.com>"
func (mod *RestAPI) Author() string {
return "Simone Margaritelli <evilsocket@gmail.com>"
}
func (api *RestAPI) isTLS() bool {
return api.certFile != "" && api.keyFile != ""
func (mod *RestAPI) isTLS() bool {
return mod.certFile != "" && mod.keyFile != ""
}
func (api *RestAPI) Configure() error {
func (mod *RestAPI) Configure() error {
var err error
var ip string
var port int
if api.Running() {
if mod.Running() {
return session.ErrAlreadyStarted
} else if err, ip = api.StringParam("api.rest.address"); err != nil {
} else if err, ip = mod.StringParam("api.rest.address"); err != nil {
return err
} else if err, port = api.IntParam("api.rest.port"); err != nil {
} else if err, port = mod.IntParam("api.rest.port"); err != nil {
return err
} else if err, api.allowOrigin = api.StringParam("api.rest.alloworigin"); err != nil {
} else if err, mod.allowOrigin = mod.StringParam("api.rest.alloworigin"); err != nil {
return err
} else if err, api.certFile = api.StringParam("api.rest.certificate"); err != nil {
} else if err, mod.certFile = mod.StringParam("api.rest.certificate"); err != nil {
return err
} else if api.certFile, err = fs.Expand(api.certFile); err != nil {
} else if mod.certFile, err = fs.Expand(mod.certFile); err != nil {
return err
} else if err, api.keyFile = api.StringParam("api.rest.key"); err != nil {
} else if err, mod.keyFile = mod.StringParam("api.rest.key"); err != nil {
return err
} else if api.keyFile, err = fs.Expand(api.keyFile); err != nil {
} else if mod.keyFile, err = fs.Expand(mod.keyFile); err != nil {
return err
} else if err, api.username = api.StringParam("api.rest.username"); err != nil {
} else if err, mod.username = mod.StringParam("api.rest.username"); err != nil {
return err
} else if err, api.password = api.StringParam("api.rest.password"); err != nil {
} else if err, mod.password = mod.StringParam("api.rest.password"); err != nil {
return err
} else if err, api.useWebsocket = api.BoolParam("api.rest.websocket"); err != nil {
} else if err, mod.useWebsocket = mod.BoolParam("api.rest.websocket"); err != nil {
return err
}
if api.isTLS() {
if !fs.Exists(api.certFile) || !fs.Exists(api.keyFile) {
err, cfg := tls.CertConfigFromModule("api.rest", api.SessionModule)
if mod.isTLS() {
if !fs.Exists(mod.certFile) || !fs.Exists(mod.keyFile) {
err, cfg := tls.CertConfigFromModule("api.rest", mod.SessionModule)
if err != nil {
return err
}
log.Debug("%+v", cfg)
log.Info("generating TLS key to %s", api.keyFile)
log.Info("generating TLS certificate to %s", api.certFile)
if err := tls.Generate(cfg, api.certFile, api.keyFile); err != nil {
mod.Debug("%+v", cfg)
mod.Info("generating TLS key to %s", mod.keyFile)
mod.Info("generating TLS certificate to %s", mod.certFile)
if err := tls.Generate(cfg, mod.certFile, mod.keyFile); err != nil {
return err
}
} else {
log.Info("loading TLS key from %s", api.keyFile)
log.Info("loading TLS certificate from %s", api.certFile)
mod.Info("loading TLS key from %s", mod.keyFile)
mod.Info("loading TLS certificate from %s", mod.certFile)
}
}
api.server.Addr = fmt.Sprintf("%s:%d", ip, port)
mod.server.Addr = fmt.Sprintf("%s:%d", ip, port)
router := mux.NewRouter()
router.HandleFunc("/api/events", api.eventsRoute)
router.HandleFunc("/api/session", api.sessionRoute)
router.HandleFunc("/api/session/ble", api.sessionRoute)
router.HandleFunc("/api/session/ble/{mac}", api.sessionRoute)
router.HandleFunc("/api/session/env", api.sessionRoute)
router.HandleFunc("/api/session/gateway", api.sessionRoute)
router.HandleFunc("/api/session/interface", api.sessionRoute)
router.HandleFunc("/api/session/modules", api.sessionRoute)
router.HandleFunc("/api/session/lan", api.sessionRoute)
router.HandleFunc("/api/session/lan/{mac}", api.sessionRoute)
router.HandleFunc("/api/session/options", api.sessionRoute)
router.HandleFunc("/api/session/packets", api.sessionRoute)
router.HandleFunc("/api/session/started-at", api.sessionRoute)
router.HandleFunc("/api/session/wifi", api.sessionRoute)
router.HandleFunc("/api/session/wifi/{mac}", api.sessionRoute)
api.server.Handler = router
if api.username == "" || api.password == "" {
log.Warning("api.rest.username and/or api.rest.password parameters are empty, authentication is disabled.")
router.HandleFunc("/api/events", mod.eventsRoute)
router.HandleFunc("/api/session", mod.sessionRoute)
router.HandleFunc("/api/session/ble", mod.sessionRoute)
router.HandleFunc("/api/session/ble/{mac}", mod.sessionRoute)
router.HandleFunc("/api/session/env", mod.sessionRoute)
router.HandleFunc("/api/session/gateway", mod.sessionRoute)
router.HandleFunc("/api/session/interface", mod.sessionRoute)
router.HandleFunc("/api/session/modules", mod.sessionRoute)