mirror of
https://github.com/bettercap/bettercap.git
synced 2024-11-08 06:30:13 -08:00
269 lines
6.8 KiB
Go
269 lines
6.8 KiB
Go
package wifi
|
|
|
|
import (
|
|
"bufio"
|
|
"errors"
|
|
"fmt"
|
|
"os"
|
|
"sync/atomic"
|
|
"time"
|
|
|
|
"github.com/bettercap/bettercap/v2/network"
|
|
"github.com/evilsocket/islazy/async"
|
|
"github.com/evilsocket/islazy/ops"
|
|
"github.com/evilsocket/islazy/str"
|
|
)
|
|
|
|
var (
|
|
errRecon = errors.New("turn off wifi.recon first")
|
|
errAlreadyRunning = errors.New("bruteforce already running")
|
|
errNotRunning = errors.New("bruteforce not running")
|
|
)
|
|
|
|
type bruteforceJob struct {
|
|
running *atomic.Bool
|
|
done *atomic.Uint64
|
|
iface string
|
|
essid string
|
|
password string
|
|
timeout time.Duration
|
|
}
|
|
|
|
type BruteforceSuccess struct {
|
|
Iface string
|
|
Target string
|
|
Password string
|
|
Elapsed time.Duration
|
|
}
|
|
|
|
type bruteforceConfig struct {
|
|
running atomic.Bool
|
|
queue *async.WorkQueue
|
|
done atomic.Uint64
|
|
todo uint64
|
|
target string
|
|
wordlist string
|
|
workers int
|
|
timeout int
|
|
wide bool
|
|
stop_at_first bool
|
|
|
|
passwords []string
|
|
targets []string
|
|
}
|
|
|
|
func NewBruteForceConfig() *bruteforceConfig {
|
|
return &bruteforceConfig{
|
|
wordlist: "/usr/share/dict/words",
|
|
passwords: make([]string, 0),
|
|
targets: make([]string, 0),
|
|
workers: 1,
|
|
wide: false,
|
|
stop_at_first: true,
|
|
timeout: 15,
|
|
queue: nil,
|
|
done: atomic.Uint64{},
|
|
todo: 0,
|
|
}
|
|
}
|
|
|
|
func (bruteforce *bruteforceConfig) setup(mod *WiFiModule) (err error) {
|
|
if bruteforce.running.Load() {
|
|
return errAlreadyRunning
|
|
} else if err, bruteforce.target = mod.StringParam("wifi.bruteforce.target"); err != nil {
|
|
return err
|
|
} else if err, bruteforce.wordlist = mod.StringParam("wifi.bruteforce.wordlist"); err != nil {
|
|
return err
|
|
} else if err, bruteforce.workers = mod.IntParam("wifi.bruteforce.workers"); err != nil {
|
|
return err
|
|
} else if err, bruteforce.timeout = mod.IntParam("wifi.bruteforce.timeout"); err != nil {
|
|
return err
|
|
} else if err, bruteforce.wide = mod.BoolParam("wifi.bruteforce.wide"); err != nil {
|
|
return err
|
|
} else if err, bruteforce.stop_at_first = mod.BoolParam("wifi.bruteforce.stop_at_first"); err != nil {
|
|
return err
|
|
}
|
|
|
|
// load targets
|
|
bruteforce.targets = make([]string, 0)
|
|
|
|
if bruteforce.target == "" {
|
|
// all visible APs
|
|
for _, ap := range mod.Session.WiFi.List() {
|
|
if !ap.IsOpen() {
|
|
target := ap.ESSID()
|
|
if target == "<hidden>" || target == "" {
|
|
target = ap.BSSID()
|
|
}
|
|
bruteforce.targets = append(bruteforce.targets, target)
|
|
}
|
|
}
|
|
} else {
|
|
bruteforce.targets = str.Comma(bruteforce.target)
|
|
}
|
|
|
|
nTargets := len(bruteforce.targets)
|
|
if nTargets == 0 {
|
|
return fmt.Errorf("no target selected with wifi.bruteforce.target='%s'", bruteforce.target)
|
|
}
|
|
|
|
mod.Info("selected %d target%s to bruteforce", nTargets, ops.Ternary(nTargets > 1, "s", ""))
|
|
|
|
// load wordlist
|
|
bruteforce.passwords = make([]string, 0)
|
|
fp, err := os.Open(bruteforce.wordlist)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
defer fp.Close()
|
|
|
|
scanner := bufio.NewScanner(fp)
|
|
scanner.Split(bufio.ScanLines)
|
|
for scanner.Scan() {
|
|
line := str.Trim(scanner.Text())
|
|
if line != "" {
|
|
bruteforce.passwords = append(bruteforce.passwords, line)
|
|
}
|
|
}
|
|
|
|
mod.Info("loaded %d passwords from %s", len(bruteforce.passwords), bruteforce.wordlist)
|
|
|
|
mod.Info("starting %d workers ...", mod.bruteforce.workers)
|
|
|
|
bruteforce.queue = async.NewQueue(mod.bruteforce.workers, mod.bruteforceWorker)
|
|
|
|
bruteforce.running.Store(true)
|
|
|
|
return
|
|
}
|
|
|
|
func (mod *WiFiModule) bruteforceWorker(arg async.Job) {
|
|
job := arg.(bruteforceJob)
|
|
defer job.done.Add(1)
|
|
|
|
mod.Debug("got job %+v", job)
|
|
|
|
if job.running.Load() {
|
|
start := time.Now()
|
|
|
|
if authenticated, err := wifiBruteforce(mod, job); err != nil {
|
|
mod.Error("%v", err)
|
|
// stop on error
|
|
job.running.Store(false)
|
|
} else if authenticated {
|
|
// send event
|
|
mod.Session.Events.Add("wifi.bruteforce.success", BruteforceSuccess{
|
|
Elapsed: time.Since(start),
|
|
Iface: job.iface,
|
|
Target: job.essid,
|
|
Password: job.password,
|
|
})
|
|
if mod.bruteforce.stop_at_first {
|
|
// stop if stop_at_first==true
|
|
job.running.Store(false)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
func (mod *WiFiModule) showBruteforceProgress() {
|
|
progress := 100.0 * (float64(mod.bruteforce.done.Load()) / float64(mod.bruteforce.todo))
|
|
mod.State.Store("bruteforce.progress", progress)
|
|
|
|
if mod.bruteforce.running.Load() {
|
|
mod.Info("[%.2f%%] performed %d of %d bruteforcing attempts",
|
|
progress,
|
|
mod.bruteforce.done.Load(),
|
|
mod.bruteforce.todo)
|
|
}
|
|
}
|
|
|
|
func (mod *WiFiModule) startBruteforce() (err error) {
|
|
var ifName string
|
|
|
|
if mod.Running() {
|
|
return errRecon
|
|
} else if err = mod.bruteforce.setup(mod); err != nil {
|
|
return err
|
|
} else if err, ifName = mod.StringParam("wifi.interface"); err != nil {
|
|
return err
|
|
} else if ifName == "" {
|
|
mod.iface = mod.Session.Interface
|
|
ifName = mod.iface.Name()
|
|
} else if mod.iface, err = network.FindInterface(ifName); err != nil {
|
|
return fmt.Errorf("could not find interface %s: %v", ifName, err)
|
|
} else if mod.iface == nil {
|
|
return fmt.Errorf("could not find interface %s", ifName)
|
|
}
|
|
|
|
mod.Info("using interface %s", ifName)
|
|
|
|
mod.bruteforce.todo = uint64(len(mod.bruteforce.passwords) * len(mod.bruteforce.targets))
|
|
mod.bruteforce.done.Store(0)
|
|
|
|
mod.Info("bruteforce running ...")
|
|
|
|
go func() {
|
|
go func() {
|
|
if mod.bruteforce.wide {
|
|
for _, password := range mod.bruteforce.passwords {
|
|
for _, essid := range mod.bruteforce.targets {
|
|
if mod.bruteforce.running.Load() {
|
|
mod.bruteforce.queue.Add(async.Job(bruteforceJob{
|
|
running: &mod.bruteforce.running,
|
|
done: &mod.bruteforce.done,
|
|
iface: mod.iface.Name(),
|
|
essid: essid,
|
|
password: password,
|
|
timeout: time.Second * time.Duration(mod.bruteforce.timeout),
|
|
}))
|
|
}
|
|
}
|
|
}
|
|
} else {
|
|
for _, essid := range mod.bruteforce.targets {
|
|
for _, password := range mod.bruteforce.passwords {
|
|
if mod.bruteforce.running.Load() {
|
|
mod.bruteforce.queue.Add(async.Job(bruteforceJob{
|
|
running: &mod.bruteforce.running,
|
|
done: &mod.bruteforce.done,
|
|
iface: mod.iface.Name(),
|
|
essid: essid,
|
|
password: password,
|
|
timeout: time.Second * time.Duration(mod.bruteforce.timeout),
|
|
}))
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}()
|
|
|
|
for mod.bruteforce.running.Load() && mod.bruteforce.done.Load() < mod.bruteforce.todo {
|
|
time.Sleep(time.Second * time.Duration(mod.bruteforce.timeout))
|
|
mod.showBruteforceProgress()
|
|
}
|
|
|
|
mod.bruteforce.running.Store(false)
|
|
|
|
if mod.bruteforce.done.Load() == mod.bruteforce.todo {
|
|
mod.Info("bruteforcing completed")
|
|
} else {
|
|
mod.Info("bruteforcing stopped")
|
|
}
|
|
}()
|
|
|
|
return nil
|
|
}
|
|
|
|
func (mod *WiFiModule) stopBruteforce() error {
|
|
if !mod.bruteforce.running.Load() {
|
|
return errNotRunning
|
|
}
|
|
|
|
mod.Info("stopping bruteforcing ...")
|
|
|
|
mod.bruteforce.running.Store(false)
|
|
|
|
return nil
|
|
}
|