Skip to content

Commit

Permalink
new: gateway.change event for MITM monitoring
Browse files Browse the repository at this point in the history
  • Loading branch information
evilsocket committed Apr 10, 2021
1 parent 43a93fd commit c47e3f6
Show file tree
Hide file tree
Showing 8 changed files with 144 additions and 5 deletions.
5 changes: 4 additions & 1 deletion _example/example.js
Original file line number Diff line number Diff line change
Expand Up @@ -36,4 +36,7 @@ onEvent('wifi.client.handshake', onHandshake);
onEvent('wifi.ap.new', onNewAP);

// register for new nodes in the graph
onEvent('graph.node.new', onNewNode);
onEvent('graph.node.new', onNewNode);

// register for gateway changes
onEvent('gateway.change', onGatewayChange)
11 changes: 11 additions & 0 deletions _example/functions.js
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,17 @@ function onNewNode(event) {
}
}

function onGatewayChange(event) {
var change = event.data;

var message = '🚨 Detected ' + change.type + ' gateway change, possible MITM attack:\n\n' +
'Prev: ' + change.prev.ip + ' (' + change.prev.mac + ")\n" +
'New: ' + change.new.ip + ' (' + change.new.mac + ")";

// send to telegram bot
sendMessage(message);
}

function onTick(event) {
run('wifi.probe ' + fakeBSSID + ' ' + fakeESSID);
}
2 changes: 2 additions & 0 deletions modules/events_stream/events_view.go
Original file line number Diff line number Diff line change
Expand Up @@ -129,6 +129,8 @@ func (mod *EventsStream) Render(output io.Writer, e session.Event) {
mod.viewUpdateEvent(output, e)
} else if strings.HasPrefix(e.Tag, "graph.") {
mod.viewGraphEvent(output, e)
} else if e.Tag == "gateway.change" {
mod.viewGatewayEvent(output, e)
} else if e.Tag != "tick" {
fmt.Fprintf(output, "[%s] [%s] %v\n", e.Time.Format(mod.timeFormat), tui.Green(e.Tag), e)
}
Expand Down
23 changes: 23 additions & 0 deletions modules/events_stream/events_view_gateway.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
package events_stream

import (
"fmt"
"io"

"github.com/bettercap/bettercap/session"

"github.com/evilsocket/islazy/tui"
)

func (mod *EventsStream) viewGatewayEvent(output io.Writer, e session.Event) {
change := e.Data.(session.GatewayChange)

fmt.Fprintf(output, "[%s] [%s] %s gateway changed: '%s' (%s) -> '%s' (%s)\n",
e.Time.Format(mod.timeFormat),
tui.Red(e.Tag),
string(change.Type),
change.Prev.IP,
change.Prev.MAC,
change.New.IP,
change.New.MAC)
}
2 changes: 1 addition & 1 deletion network/arp_parser_linux.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ package network

import "regexp"

var ArpTableParser = regexp.MustCompile(`^([a-f\d\.:]+)\s+dev\s+(\w+)\s+\w+\s+([a-f0-9:]{17})\s+\w+$`)
var ArpTableParser = regexp.MustCompile(`^([a-f\d\.:]+)\s+dev\s+(\w+)\s+\w+\s+([a-f0-9:]{17})\s+.+$`)
var ArpTableTokens = 4
var ArpTableTokenIndex = []int{1, 3, 2}
var ArpCmd = "ip"
Expand Down
6 changes: 3 additions & 3 deletions routing/route.go
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
package routing

type RouteType int
type RouteType string

const (
IPv4 RouteType = 0
IPv6 RouteType = 1
IPv4 RouteType = "IPv4"
IPv6 RouteType = "IPv6"
)

type Route struct {
Expand Down
4 changes: 4 additions & 0 deletions session/session.go
Original file line number Diff line number Diff line change
Expand Up @@ -255,8 +255,12 @@ func (s *Session) Start() error {
s.Events.Log(level, "%s", err.Error())
}

// we are the gateway
if s.Gateway == nil || s.Gateway.IpAddress == s.Interface.IpAddress {
s.Gateway = s.Interface
} else {
// start monitoring for gateway changes
go s.routeMon()
}

s.Firewall = firewall.Make(s.Interface)
Expand Down
96 changes: 96 additions & 0 deletions session/session_routing.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
package session

import (
"github.com/bettercap/bettercap/network"
"github.com/bettercap/bettercap/routing"
"github.com/evilsocket/islazy/log"
"time"
)

type gateway struct {
IP string `json:"ip"`
MAC string `json:"mac"`
}

type GatewayChange struct {
Type string `json:"type"`
Prev gateway `json:"prev"`
New gateway `json:"new"`
}

func (s *Session) routeMon() {
var err error
var gw4 *network.Endpoint
var gwIP6, gwMAC6 string

s.Events.Log(log.INFO, "gateway monitor started ...")

gw4 = s.Gateway

gwIP6, err = routing.Gateway(routing.IPv6, s.Interface.Name())
if err != nil {
s.Events.Log(log.ERROR, "error getting ipv6 gateway: %v", err)
} else if gwIP6 != "" {
gwMAC6, err = network.ArpLookup(s.Interface.Name(), gwIP6, true)
if err != nil {
s.Events.Log(log.DEBUG, "error getting %s ipv6 gateway mac: %v", gwIP6, err)
}
}

for {
s.Events.Log(log.DEBUG, "[gw] ipv4=%s(%s) ipv6=%s(%s)", gw4.IP, gw4.HwAddress, gwIP6, gwMAC6)

time.Sleep(5 * time.Second)

gw4now, err := network.FindGateway(s.Interface)
if err != nil {
s.Events.Log(log.ERROR, "error getting ipv4 gateway: %v", err)
} else if gw4now == nil {
s.Events.Log(log.ERROR, "null ipv4 gateway")
} else {
if gw4now.IpAddress != gw4.IpAddress || gw4now.HwAddress != gw4.HwAddress {
s.Events.Add("gateway.change", GatewayChange{
Type: string(routing.IPv4),
Prev: gateway{
IP: gw4.IpAddress,
MAC: gw4.HwAddress,
},
New: gateway{
IP: gw4now.IpAddress,
MAC: gw4now.HwAddress,
},
})
}
}

gw4 = gw4now

gwMAC6now := ""
gwIP6now, err := routing.Gateway(routing.IPv6, s.Interface.Name())
if err != nil {
s.Events.Log(log.ERROR, "error getting ipv6 gateway: %v", err)
} else if gwIP6now != "" {
gwMAC6now, err = network.ArpLookup(s.Interface.Name(), gwIP6now, true)
if err != nil {
s.Events.Log(log.DEBUG, "error getting %s ipv6 gateway mac: %v", gwIP6now, err)
}
}

if gwIP6now != gwIP6 || gwMAC6now != gwMAC6 {
s.Events.Add("gateway.change", GatewayChange{
Type: string(routing.IPv6),
Prev: gateway{
IP: gwIP6,
MAC: gwMAC6,
},
New: gateway{
IP: gwIP6now,
MAC: gwMAC6now,
},
})
}

gwIP6 = gwIP6now
gwMAC6 = gwMAC6now
}
}

0 comments on commit c47e3f6

Please sign in to comment.