mirror of
https://github.com/bettercap/bettercap
synced 2025-08-13 18:26:57 -07:00
new: implemented GET /api/events route (ref #5).
This commit is contained in:
parent
ee4b783015
commit
269d7d845b
14 changed files with 172 additions and 38 deletions
|
@ -1,6 +1,7 @@
|
|||
# change these!
|
||||
set api.rest.username bcap
|
||||
set api.rest.password bcap
|
||||
# set api.rest.port 8082
|
||||
|
||||
net.probe on
|
||||
net.recon on
|
||||
|
|
5
main.go
5
main.go
|
@ -1,6 +1,7 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"runtime"
|
||||
"strings"
|
||||
|
||||
|
@ -20,8 +21,8 @@ func main() {
|
|||
panic(err)
|
||||
}
|
||||
|
||||
log.Infof("Starting %s v%s\n", core.Name, core.Version)
|
||||
log.Infof("Build: date=%s os=%s arch=%s\n", core.BuildDate, runtime.GOOS, runtime.GOARCH)
|
||||
fmt.Printf("%s v%s\n", core.Name, core.Version)
|
||||
fmt.Printf("Build: date=%s os=%s arch=%s\n\n", core.BuildDate, runtime.GOOS, runtime.GOARCH)
|
||||
|
||||
sess.Register(session_modules.NewProber(sess))
|
||||
sess.Register(session_modules.NewDiscovery(sess))
|
||||
|
|
|
@ -8,19 +8,19 @@ import (
|
|||
"github.com/evilsocket/bettercap-ng/core"
|
||||
)
|
||||
|
||||
type OnHostResolvedCallback func(e *Endpoint)
|
||||
type Endpoint struct {
|
||||
IP net.IP
|
||||
HW net.HardwareAddr
|
||||
IpAddress string
|
||||
SubnetBits uint32
|
||||
IpAddressUint32 uint32
|
||||
HwAddress string
|
||||
Hostname string
|
||||
Vendor string
|
||||
IP net.IP `json:"-"`
|
||||
HW net.HardwareAddr `json:"-"`
|
||||
IpAddress string `json:"address"`
|
||||
SubnetBits uint32 `json:"-"`
|
||||
IpAddressUint32 uint32 `json:"-"`
|
||||
HwAddress string `json:"mac"`
|
||||
Hostname string `json:"hostname"`
|
||||
Vendor string `json:"vendor"`
|
||||
ResolvedCallback OnHostResolvedCallback `json:"-"`
|
||||
}
|
||||
|
||||
type OnHostResolvedAction func(e *Endpoint)
|
||||
|
||||
func NewEndpointNoResolve(ip, mac, name string, bits uint32) *Endpoint {
|
||||
hw, err := net.ParseMAC(mac)
|
||||
if err != nil {
|
||||
|
@ -36,6 +36,7 @@ func NewEndpointNoResolve(ip, mac, name string, bits uint32) *Endpoint {
|
|||
HwAddress: mac,
|
||||
Hostname: name,
|
||||
Vendor: OuiLookup(mac),
|
||||
ResolvedCallback: nil,
|
||||
}
|
||||
|
||||
return e
|
||||
|
@ -48,7 +49,10 @@ func NewEndpoint(ip, mac string) *Endpoint {
|
|||
go func() {
|
||||
if names, err := net.LookupAddr(e.IpAddress); err == nil {
|
||||
e.Hostname = names[0]
|
||||
log.Debugf("Endpoint %s is now known as %s\n", e.IpAddress, core.Green(e.Hostname))
|
||||
if e.ResolvedCallback != nil {
|
||||
// log.Debugf("Endpoint %s is now known as %s\n", e.IpAddress, core.Green(e.Hostname))
|
||||
e.ResolvedCallback(e)
|
||||
}
|
||||
}
|
||||
}()
|
||||
|
||||
|
|
|
@ -11,13 +11,15 @@ type Environment struct {
|
|||
Padding int `json:"-"`
|
||||
Storage map[string]string `json:"storage"`
|
||||
lock *sync.Mutex
|
||||
sess *Session
|
||||
}
|
||||
|
||||
func NewEnvironment() *Environment {
|
||||
func NewEnvironment(s *Session) *Environment {
|
||||
env := &Environment{
|
||||
Padding: 0,
|
||||
Storage: make(map[string]string),
|
||||
lock: &sync.Mutex{},
|
||||
sess: s,
|
||||
}
|
||||
|
||||
return env
|
||||
|
@ -39,6 +41,14 @@ func (env *Environment) Set(name, value string) string {
|
|||
old, _ := env.Storage[name]
|
||||
env.Storage[name] = value
|
||||
|
||||
env.sess.Events.Add("env.change", struct {
|
||||
name string
|
||||
value string
|
||||
}{
|
||||
name,
|
||||
value,
|
||||
})
|
||||
|
||||
width := len(name)
|
||||
if width > env.Padding {
|
||||
env.Padding = width
|
||||
|
|
53
session/events.go
Normal file
53
session/events.go
Normal file
|
@ -0,0 +1,53 @@
|
|||
package session
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/evilsocket/bettercap-ng/core"
|
||||
)
|
||||
|
||||
type Event struct {
|
||||
Tag string `json:"tag"`
|
||||
Time time.Time `json:"time"`
|
||||
Data interface{} `json:"data"`
|
||||
}
|
||||
|
||||
func NewEvent(tag string, data interface{}) Event {
|
||||
return Event{
|
||||
Tag: tag,
|
||||
Time: time.Now(),
|
||||
Data: data,
|
||||
}
|
||||
}
|
||||
|
||||
func (e Event) Print() {
|
||||
fmt.Printf("[%s] [%s] [%s] %+v\n", e.Time, core.Bold("event"), core.Green(e.Tag), e.Data)
|
||||
}
|
||||
|
||||
type EventPool struct {
|
||||
events []Event
|
||||
lock *sync.Mutex
|
||||
}
|
||||
|
||||
func NewEventPool() *EventPool {
|
||||
return &EventPool{
|
||||
events: make([]Event, 0),
|
||||
lock: &sync.Mutex{},
|
||||
}
|
||||
}
|
||||
|
||||
func (p *EventPool) Add(tag string, data interface{}) {
|
||||
p.lock.Lock()
|
||||
defer p.lock.Unlock()
|
||||
e := NewEvent(tag, data)
|
||||
p.events = append([]Event{e}, p.events...)
|
||||
e.Print()
|
||||
}
|
||||
|
||||
func (p *EventPool) Events() []Event {
|
||||
p.lock.Lock()
|
||||
defer p.lock.Unlock()
|
||||
return p.events
|
||||
}
|
|
@ -18,16 +18,18 @@ type Module interface {
|
|||
}
|
||||
|
||||
type SessionModule struct {
|
||||
Session *Session
|
||||
Started bool
|
||||
StatusLock *sync.Mutex
|
||||
Name string `json:"name"`
|
||||
Session *Session `json:"-"`
|
||||
Started bool `json:"started"`
|
||||
StatusLock *sync.Mutex `json:"-"`
|
||||
|
||||
handlers []ModuleHandler
|
||||
params map[string]*ModuleParam
|
||||
}
|
||||
|
||||
func NewSessionModule(s *Session) SessionModule {
|
||||
func NewSessionModule(name string, s *Session) SessionModule {
|
||||
m := SessionModule{
|
||||
Name: name,
|
||||
Session: s,
|
||||
Started: false,
|
||||
StatusLock: &sync.Mutex{},
|
||||
|
@ -70,6 +72,12 @@ func (m *SessionModule) SetRunning(running bool) {
|
|||
m.StatusLock.Lock()
|
||||
defer m.StatusLock.Unlock()
|
||||
m.Started = running
|
||||
|
||||
if running {
|
||||
m.Session.Events.Add("mod.started", m.Name)
|
||||
} else {
|
||||
m.Session.Events.Add("mod.stopped", m.Name)
|
||||
}
|
||||
}
|
||||
|
||||
func (m *SessionModule) OnSessionStarted(s *Session) {
|
||||
|
|
|
@ -5,6 +5,7 @@ import (
|
|||
"encoding/json"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/evilsocket/bettercap-ng/core"
|
||||
|
@ -20,7 +21,7 @@ type RestAPI struct {
|
|||
|
||||
func NewRestAPI(s *session.Session) *RestAPI {
|
||||
api := &RestAPI{
|
||||
SessionModule: session.NewSessionModule(s),
|
||||
SessionModule: session.NewSessionModule("api.rest", s),
|
||||
server: &http.Server{},
|
||||
username: "",
|
||||
password: "",
|
||||
|
@ -58,6 +59,7 @@ func NewRestAPI(s *session.Session) *RestAPI {
|
|||
}))
|
||||
|
||||
http.HandleFunc("/api/session", api.sessRoute)
|
||||
http.HandleFunc("/api/events", api.eventsRoute)
|
||||
|
||||
return api
|
||||
}
|
||||
|
@ -113,6 +115,45 @@ func (api *RestAPI) sessRoute(w http.ResponseWriter, r *http.Request) {
|
|||
}
|
||||
}
|
||||
|
||||
func (api *RestAPI) eventsRoute(w http.ResponseWriter, r *http.Request) {
|
||||
if api.checkAuth(w, r) == false {
|
||||
return
|
||||
}
|
||||
|
||||
if r.Method == "GET" {
|
||||
var err error
|
||||
|
||||
events := api.Session.Events.Events()
|
||||
nmax := len(events)
|
||||
n := nmax
|
||||
|
||||
keys, ok := r.URL.Query()["n"]
|
||||
if len(keys) == 1 && ok {
|
||||
sn := keys[0]
|
||||
n, err = strconv.Atoi(sn)
|
||||
if err == nil {
|
||||
if n > nmax {
|
||||
n = nmax
|
||||
}
|
||||
} else {
|
||||
n = nmax
|
||||
}
|
||||
}
|
||||
|
||||
js, err := json.Marshal(events[0:n])
|
||||
if err != nil {
|
||||
log.Errorf("Error while returning events: %s", err)
|
||||
http.Error(w, err.Error(), http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
w.Write(js)
|
||||
} else {
|
||||
http.Error(w, "Not Found", 404)
|
||||
}
|
||||
}
|
||||
|
||||
func (api RestAPI) checkAuth(w http.ResponseWriter, r *http.Request) bool {
|
||||
if api.Authenticated(w, r) == false {
|
||||
log.Warningf("Unauthenticated access!")
|
||||
|
|
|
@ -17,7 +17,7 @@ type ArpSpoofer struct {
|
|||
|
||||
func NewArpSpoofer(s *session.Session) *ArpSpoofer {
|
||||
p := &ArpSpoofer{
|
||||
SessionModule: session.NewSessionModule(s),
|
||||
SessionModule: session.NewSessionModule("arp.spoof", s),
|
||||
Done: make(chan bool),
|
||||
}
|
||||
|
||||
|
|
|
@ -38,7 +38,7 @@ func (p HttpProxy) logAction(req *http.Request, jsres *JSResponse) {
|
|||
|
||||
func NewHttpProxy(s *session.Session) *HttpProxy {
|
||||
p := &HttpProxy{
|
||||
SessionModule: session.NewSessionModule(s),
|
||||
SessionModule: session.NewSessionModule("http.proxy", s),
|
||||
proxy: nil,
|
||||
address: "",
|
||||
redirection: nil,
|
||||
|
|
|
@ -15,7 +15,7 @@ type Prober struct {
|
|||
|
||||
func NewProber(s *session.Session) *Prober {
|
||||
p := &Prober{
|
||||
SessionModule: session.NewSessionModule(s),
|
||||
SessionModule: session.NewSessionModule("net.probe", s),
|
||||
}
|
||||
|
||||
p.AddParam(session.NewIntParameter("net.probe.throttle",
|
||||
|
|
|
@ -18,7 +18,7 @@ type Discovery struct {
|
|||
|
||||
func NewDiscovery(s *session.Session) *Discovery {
|
||||
d := &Discovery{
|
||||
SessionModule: session.NewSessionModule(s),
|
||||
SessionModule: session.NewSessionModule("net.recon", s),
|
||||
|
||||
refresh: 1,
|
||||
before: nil,
|
||||
|
|
|
@ -117,7 +117,7 @@ type Sniffer struct {
|
|||
|
||||
func NewSniffer(s *session.Session) *Sniffer {
|
||||
sniff := &Sniffer{
|
||||
SessionModule: session.NewSessionModule(s),
|
||||
SessionModule: session.NewSessionModule("net.sniffer", s),
|
||||
Stats: nil,
|
||||
}
|
||||
|
||||
|
|
|
@ -32,25 +32,30 @@ type Session struct {
|
|||
Input *readline.Instance `json:"-"`
|
||||
Active bool `json:"active"`
|
||||
|
||||
// Watcher *discovery.Watcher
|
||||
CoreHandlers []CommandHandler `json:"-"`
|
||||
Modules []Module `json:"-"`
|
||||
HelpPadding int `json:"-"`
|
||||
|
||||
Events *EventPool `json:"-"`
|
||||
}
|
||||
|
||||
func New() (*Session, error) {
|
||||
var err error
|
||||
|
||||
s := &Session{
|
||||
Env: NewEnvironment(),
|
||||
Env: nil,
|
||||
Active: false,
|
||||
Queue: nil,
|
||||
|
||||
CoreHandlers: make([]CommandHandler, 0),
|
||||
Modules: make([]Module, 0),
|
||||
HelpPadding: 0,
|
||||
|
||||
Events: NewEventPool(),
|
||||
}
|
||||
|
||||
s.Env = NewEnvironment(s)
|
||||
|
||||
if s.Options, err = core.ParseOptions(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -265,6 +270,8 @@ func (s *Session) setupInput() error {
|
|||
}
|
||||
|
||||
func (s *Session) Close() {
|
||||
s.Events.Add("session.closing", nil)
|
||||
|
||||
for _, m := range s.Modules {
|
||||
m.OnSessionEnded(s)
|
||||
}
|
||||
|
@ -311,7 +318,7 @@ func (s *Session) Start() error {
|
|||
|
||||
log.Debugf("[%sgateway%s] %s\n", core.GREEN, core.RESET, s.Gateway)
|
||||
|
||||
s.Targets = NewTargets(s.Interface, s.Gateway)
|
||||
s.Targets = NewTargets(s, s.Interface, s.Gateway)
|
||||
s.Firewall = firewall.Make()
|
||||
|
||||
if err := s.setupInput(); err != nil {
|
||||
|
@ -354,6 +361,8 @@ func (s *Session) Start() error {
|
|||
m.OnSessionStarted(s)
|
||||
}
|
||||
|
||||
s.Events.Add("session.started", nil)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
|
|
|
@ -14,14 +14,16 @@ import (
|
|||
var log = logging.MustGetLogger("mitm")
|
||||
|
||||
type Targets struct {
|
||||
Session *Session `json:"-"`
|
||||
Interface *net.Endpoint
|
||||
Gateway *net.Endpoint
|
||||
Targets map[string]*net.Endpoint
|
||||
lock sync.Mutex
|
||||
}
|
||||
|
||||
func NewTargets(iface, gateway *net.Endpoint) *Targets {
|
||||
func NewTargets(s *Session, iface, gateway *net.Endpoint) *Targets {
|
||||
return &Targets{
|
||||
Session: s,
|
||||
Interface: iface,
|
||||
Gateway: gateway,
|
||||
Targets: make(map[string]*net.Endpoint),
|
||||
|
@ -33,7 +35,7 @@ func (tp *Targets) Remove(ip, mac string) {
|
|||
defer tp.lock.Unlock()
|
||||
|
||||
if e, found := tp.Targets[mac]; found {
|
||||
log.Infof("[%slost%s] %s\n", core.RED, core.RESET, e)
|
||||
tp.Session.Events.Add("target-lost", e)
|
||||
delete(tp.Targets, mac)
|
||||
return
|
||||
}
|
||||
|
@ -69,9 +71,14 @@ func (tp *Targets) AddIfNotExist(ip, mac string) *net.Endpoint {
|
|||
}
|
||||
|
||||
e := net.NewEndpoint(ip, mac)
|
||||
log.Infof("[%snew%s] %s\n", core.GREEN, core.RESET, e)
|
||||
e.ResolvedCallback = func(e *net.Endpoint) {
|
||||
tp.Session.Events.Add("target.resolved", e)
|
||||
}
|
||||
|
||||
tp.Targets[mac] = e
|
||||
|
||||
tp.Session.Events.Add("target.new", e)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue