mirror of
https://github.com/bettercap/bettercap
synced 2025-08-21 14:03:17 -07:00
Serial modem module, first draft
This commit is contained in:
parent
3ac520c744
commit
188a209c93
2 changed files with 668 additions and 0 deletions
666
modules/modem/modem.go
Normal file
666
modules/modem/modem.go
Normal file
|
@ -0,0 +1,666 @@
|
||||||
|
/*
|
||||||
|
# Bettercap Serial Modem Module
|
||||||
|
|
||||||
|
### Preface :
|
||||||
|
@evilsocket recently added the C2 module and I thought "Hey! wouldn't be fun (and socially irresponsible)
|
||||||
|
if we could control bettercap over a 3g/4g network connection? Well friends here ya go!
|
||||||
|
|
||||||
|
This module depends on modemmanager. Some USB modems require mode-switching to behave as a serial
|
||||||
|
interface - if this is you (Huaweii and others) you'll need usb_modeswitch. The mod is very rough
|
||||||
|
around the edges and could definitely do for a refactor by someone good who actually knows what
|
||||||
|
they are doing.
|
||||||
|
|
||||||
|
### What works :
|
||||||
|
|
||||||
|
* Configure APN for network connectivity
|
||||||
|
* Display some groovy modem info
|
||||||
|
* Send / receive SMS message
|
||||||
|
* Read / clear SMS message from SIM
|
||||||
|
|
||||||
|
|
||||||
|
### What hasn't been tested?
|
||||||
|
|
||||||
|
* Every modem that is not the Huaweii E303C
|
||||||
|
* When things fail like if SIM is missing or cannot register on network or pretty much everything
|
||||||
|
|
||||||
|
|
||||||
|
### Future things?
|
||||||
|
|
||||||
|
* C2 over SMS (like the IRC module except different)
|
||||||
|
* Templating modem output for whatever reason
|
||||||
|
|
||||||
|
|
||||||
|
### What kinda data does this provide?
|
||||||
|
|
||||||
|
A lot, some of it very cool like current cell tower and operator, ICCID, IMEI, tons of stuff,.
|
||||||
|
Here's what mmcli kinda looks like with some fields redacted :
|
||||||
|
|
||||||
|
-----------------------------
|
||||||
|
General | dbus path: /org/freedesktop/ModemManager1/Modem/1
|
||||||
|
| device id: 0000000000000000000000000000000000000000
|
||||||
|
-----------------------------
|
||||||
|
Hardware | manufacturer: huawei
|
||||||
|
| model: E303C
|
||||||
|
| firmware revision: 21.157.01.01.18
|
||||||
|
| supported: gsm-umts
|
||||||
|
| current: gsm-umts
|
||||||
|
| equipment id: 000000000000000
|
||||||
|
-----------------------------
|
||||||
|
System | device: /sys/devices/pci0000:00/0000:00:1d.0/usb2/2-1/2-1.3/2-1.3.4/2-1.3.4.2
|
||||||
|
| drivers: option1
|
||||||
|
| plugin: Huawei
|
||||||
|
| primary port: ttyUSB2
|
||||||
|
| ports: ttyUSB2 (at), ttyUSB3 (at)
|
||||||
|
-----------------------------
|
||||||
|
Status | unlock retries: sim-pin (5), sim-puk (10), sim-pin2 (5), sim-puk2 (10)
|
||||||
|
| state: connected
|
||||||
|
| power state: on
|
||||||
|
| access tech: umts
|
||||||
|
| signal quality: 58% (recent)
|
||||||
|
-----------------------------
|
||||||
|
Modes | supported: allowed: 2g, 3g; preferred: none
|
||||||
|
| allowed: 2g, 3g; preferred: 2g
|
||||||
|
| allowed: 2g, 3g; preferred: 3g
|
||||||
|
| allowed: 2g; preferred: none
|
||||||
|
| allowed: 3g; preferred: none
|
||||||
|
| current: allowed: 2g, 3g; preferred: 3g
|
||||||
|
-----------------------------
|
||||||
|
IP | supported: ipv4, ipv6, ipv4v6
|
||||||
|
-----------------------------
|
||||||
|
3GPP | imei: 000000000000000
|
||||||
|
| operator id: 000000
|
||||||
|
| operator name: Stupid Expensive Mobile Carrier Inc.
|
||||||
|
| registration: home
|
||||||
|
-----------------------------
|
||||||
|
SIM | dbus path: /org/freedesktop/ModemManager1/SIM/1
|
||||||
|
-----------------------------
|
||||||
|
Bearer | dbus path: /org/freedesktop/ModemManager1/Bearer/2
|
||||||
|
|
||||||
|
|
||||||
|
### Dragons! Everywhere!
|
||||||
|
|
||||||
|
This module does NOT connect you to the internet - it simply registers the modem with the carrier.
|
||||||
|
If your modem appears as /dev/cdc-* a network interface will be created by the kernel and you can
|
||||||
|
request DHCP. If your modem inerface looks like /dev/ttyUSB* I have no idea if this will work, it will
|
||||||
|
probably use PPP or something, dunno - try it out send me a report or whatever :)
|
||||||
|
|
||||||
|
Despite having a config option for PIN it doesn't do anything lol; the SIM's I've tested do not
|
||||||
|
need any of that junk but if yours does well I'm sorry but I'm a loner Dotty, a rebel.
|
||||||
|
|
||||||
|
I don't think this module should be responsible for configuring your network iface but maybe I'm wrong.
|
||||||
|
If you think I am wrong ask the boss @evilsocket and mabs he'll do a thing about it.
|
||||||
|
|
||||||
|
## This module should be considered very unstable && I am NOT responsible for your phone bill ##
|
||||||
|
|
||||||
|
You have been warned! <3
|
||||||
|
*/
|
||||||
|
|
||||||
|
package modem
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bufio"
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
"os/exec"
|
||||||
|
"strings"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/bettercap/bettercap/modules/events_stream"
|
||||||
|
"github.com/bettercap/bettercap/session"
|
||||||
|
"github.com/evilsocket/islazy/log"
|
||||||
|
)
|
||||||
|
|
||||||
|
type settings struct {
|
||||||
|
device string
|
||||||
|
apn string
|
||||||
|
pin string
|
||||||
|
}
|
||||||
|
|
||||||
|
var mmcliPath string
|
||||||
|
|
||||||
|
type Modem struct {
|
||||||
|
session.SessionModule
|
||||||
|
|
||||||
|
settings settings
|
||||||
|
stream *events_stream.EventsStream
|
||||||
|
eventBus session.EventBus
|
||||||
|
quit chan bool
|
||||||
|
|
||||||
|
Modem *MMCLIModem
|
||||||
|
Location *ModemLocation
|
||||||
|
Messages map[string]*SMS
|
||||||
|
SIM *SIM
|
||||||
|
Bearer *Bearer
|
||||||
|
}
|
||||||
|
|
||||||
|
// MMCLIModem converts the output of mmclie -m {modem} from JSON to struct
|
||||||
|
type MMCLIModem struct {
|
||||||
|
Modem struct {
|
||||||
|
ThreeGpp struct {
|
||||||
|
EnabledLocks []interface{} `json:"enabled-locks"`
|
||||||
|
Eps struct {
|
||||||
|
InitialBearer struct {
|
||||||
|
DbusPath string `json:"dbus-path"`
|
||||||
|
Settings struct {
|
||||||
|
Apn string `json:"apn"`
|
||||||
|
IPType string `json:"ip-type"`
|
||||||
|
Password string `json:"password"`
|
||||||
|
User string `json:"user"`
|
||||||
|
} `json:"settings"`
|
||||||
|
} `json:"initial-bearer"`
|
||||||
|
UeModeOperation string `json:"ue-mode-operation"`
|
||||||
|
} `json:"eps"`
|
||||||
|
Imei string `json:"imei"`
|
||||||
|
OperatorCode string `json:"operator-code"`
|
||||||
|
OperatorName string `json:"operator-name"`
|
||||||
|
Pco string `json:"pco"`
|
||||||
|
RegistrationState string `json:"registration-state"`
|
||||||
|
} `json:"3gpp"`
|
||||||
|
Cdma struct {
|
||||||
|
ActivationState string `json:"activation-state"`
|
||||||
|
Cdma1XRegistrationState string `json:"cdma1x-registration-state"`
|
||||||
|
Esn string `json:"esn"`
|
||||||
|
EvdoRegistrationState string `json:"evdo-registration-state"`
|
||||||
|
Meid string `json:"meid"`
|
||||||
|
Nid string `json:"nid"`
|
||||||
|
Sid string `json:"sid"`
|
||||||
|
} `json:"cdma"`
|
||||||
|
DbusPath string `json:"dbus-path"`
|
||||||
|
Generic struct {
|
||||||
|
AccessTechnologies []interface{} `json:"access-technologies"`
|
||||||
|
Bearers []interface{} `json:"bearers"`
|
||||||
|
CarrierConfiguration string `json:"carrier-configuration"`
|
||||||
|
CarrierConfigurationRevision string `json:"carrier-configuration-revision"`
|
||||||
|
CurrentBands []interface{} `json:"current-bands"`
|
||||||
|
CurrentCapabilities []string `json:"current-capabilities"`
|
||||||
|
CurrentModes string `json:"current-modes"`
|
||||||
|
Device string `json:"device"`
|
||||||
|
DeviceIdentifier string `json:"device-identifier"`
|
||||||
|
Drivers []string `json:"drivers"`
|
||||||
|
EquipmentIdentifier string `json:"equipment-identifier"`
|
||||||
|
HardwareRevision string `json:"hardware-revision"`
|
||||||
|
Manufacturer string `json:"manufacturer"`
|
||||||
|
Model string `json:"model"`
|
||||||
|
OwnNumbers []interface{} `json:"own-numbers"`
|
||||||
|
Plugin string `json:"plugin"`
|
||||||
|
Ports []string `json:"ports"`
|
||||||
|
PowerState string `json:"power-state"`
|
||||||
|
PrimaryPort string `json:"primary-port"`
|
||||||
|
Revision string `json:"revision"`
|
||||||
|
SignalQuality struct {
|
||||||
|
Recent string `json:"recent"`
|
||||||
|
Value string `json:"value"`
|
||||||
|
} `json:"signal-quality"`
|
||||||
|
Sim string `json:"sim"`
|
||||||
|
State string `json:"state"`
|
||||||
|
StateFailedReason string `json:"state-failed-reason"`
|
||||||
|
SupportedBands []interface{} `json:"supported-bands"`
|
||||||
|
SupportedCapabilities []string `json:"supported-capabilities"`
|
||||||
|
SupportedIPFamilies []string `json:"supported-ip-families"`
|
||||||
|
SupportedModes []string `json:"supported-modes"`
|
||||||
|
UnlockRequired string `json:"unlock-required"`
|
||||||
|
UnlockRetries []string `json:"unlock-retries"`
|
||||||
|
} `json:"generic"`
|
||||||
|
} `json:"modem"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type eventContext struct {
|
||||||
|
Session *session.Session
|
||||||
|
Event session.Event
|
||||||
|
}
|
||||||
|
|
||||||
|
// SIM converts the output of mmcli --sim {path} from JSON into a struct
|
||||||
|
type SIM struct {
|
||||||
|
Sim struct {
|
||||||
|
DbusPath string `json:"dbus-path"`
|
||||||
|
Properties struct {
|
||||||
|
EmergencyNumbers []interface{} `json:"emergency-numbers"`
|
||||||
|
Iccid string `json:"iccid"`
|
||||||
|
Imsi string `json:"imsi"`
|
||||||
|
OperatorCode string `json:"operator-code"`
|
||||||
|
OperatorName string `json:"operator-name"`
|
||||||
|
} `json:"properties"`
|
||||||
|
} `json:"sim"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// ModemList converts the output of mmcli -L from JSON into a struct
|
||||||
|
type ModemList struct {
|
||||||
|
ModemList []string `json:"modem-list"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// SMSList is a list of SMS messages as strings
|
||||||
|
type SMSList struct {
|
||||||
|
ModemMessagingSms []string `json:"modem.messaging.sms"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// SMS converts the output of mmcli -m {modem} -s {SIM} from JSON to struct
|
||||||
|
type SMS struct {
|
||||||
|
Sms struct {
|
||||||
|
Content struct {
|
||||||
|
Data string `json:"data"`
|
||||||
|
Number string `json:"number"`
|
||||||
|
Text string `json:"text"`
|
||||||
|
} `json:"content"`
|
||||||
|
DbusPath string `json:"dbus-path"`
|
||||||
|
Properties struct {
|
||||||
|
Class string `json:"class"`
|
||||||
|
DeliveryReport string `json:"delivery-report"`
|
||||||
|
DeliveryState string `json:"delivery-state"`
|
||||||
|
DischargeTimestamp string `json:"discharge-timestamp"`
|
||||||
|
MessageReference string `json:"message-reference"`
|
||||||
|
PduType string `json:"pdu-type"`
|
||||||
|
ServiceCategory string `json:"service-category"`
|
||||||
|
Smsc string `json:"smsc"`
|
||||||
|
State string `json:"state"`
|
||||||
|
Storage string `json:"storage"`
|
||||||
|
TeleserviceID string `json:"teleservice-id"`
|
||||||
|
Timestamp string `json:"timestamp"`
|
||||||
|
Validity string `json:"validity"`
|
||||||
|
} `json:"properties"`
|
||||||
|
} `json:"sms"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// ModemLocation converts the output of mmcli --location-get from JSON to struct
|
||||||
|
type ModemLocation struct {
|
||||||
|
Modem struct {
|
||||||
|
Location struct {
|
||||||
|
ThreeGpp struct {
|
||||||
|
Cid string `json:"cid"`
|
||||||
|
Lac string `json:"lac"`
|
||||||
|
Mcc string `json:"mcc"`
|
||||||
|
Mnc string `json:"mnc"`
|
||||||
|
Tac string `json:"tac"`
|
||||||
|
} `json:"3gpp"`
|
||||||
|
CdmaBs struct {
|
||||||
|
Latitude string `json:"latitude"`
|
||||||
|
Longitude string `json:"longitude"`
|
||||||
|
} `json:"cdma-bs"`
|
||||||
|
Gps struct {
|
||||||
|
Altitude string `json:"altitude"`
|
||||||
|
Latitude string `json:"latitude"`
|
||||||
|
Longitude string `json:"longitude"`
|
||||||
|
Nmea []interface{} `json:"nmea"`
|
||||||
|
Utc string `json:"utc"`
|
||||||
|
} `json:"gps"`
|
||||||
|
} `json:"location"`
|
||||||
|
} `json:"modem"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// Bearer converts the output of mmcli -b {bearer} from JSON to struct
|
||||||
|
type Bearer struct {
|
||||||
|
Bearer struct {
|
||||||
|
DbusPath string `json:"dbus-path"`
|
||||||
|
Ipv4Config struct {
|
||||||
|
Address string `json:"address"`
|
||||||
|
DNS []string `json:"dns"`
|
||||||
|
Gateway string `json:"gateway"`
|
||||||
|
Method string `json:"method"`
|
||||||
|
Mtu string `json:"mtu"`
|
||||||
|
Prefix string `json:"prefix"`
|
||||||
|
} `json:"ipv4-config"`
|
||||||
|
Ipv6Config struct {
|
||||||
|
Address string `json:"address"`
|
||||||
|
DNS []interface{} `json:"dns"`
|
||||||
|
Gateway string `json:"gateway"`
|
||||||
|
Method string `json:"method"`
|
||||||
|
Mtu string `json:"mtu"`
|
||||||
|
Prefix string `json:"prefix"`
|
||||||
|
} `json:"ipv6-config"`
|
||||||
|
Properties struct {
|
||||||
|
AllowedAuth []interface{} `json:"allowed-auth"`
|
||||||
|
Apn string `json:"apn"`
|
||||||
|
IPType string `json:"ip-type"`
|
||||||
|
Password string `json:"password"`
|
||||||
|
RmProtocol string `json:"rm-protocol"`
|
||||||
|
Roaming string `json:"roaming"`
|
||||||
|
User string `json:"user"`
|
||||||
|
} `json:"properties"`
|
||||||
|
Stats struct {
|
||||||
|
BytesRx string `json:"bytes-rx"`
|
||||||
|
BytesTx string `json:"bytes-tx"`
|
||||||
|
Duration string `json:"duration"`
|
||||||
|
} `json:"stats"`
|
||||||
|
Status struct {
|
||||||
|
Connected string `json:"connected"`
|
||||||
|
Interface string `json:"interface"`
|
||||||
|
IPTimeout string `json:"ip-timeout"`
|
||||||
|
Suspended string `json:"suspended"`
|
||||||
|
} `json:"status"`
|
||||||
|
Type string `json:"type"`
|
||||||
|
} `json:"bearer"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewModem makes a shiny new modem
|
||||||
|
func NewModem(s *session.Session) *Modem {
|
||||||
|
|
||||||
|
mod := &Modem{
|
||||||
|
SessionModule: session.NewSessionModule("modem", s),
|
||||||
|
stream: events_stream.NewEventsStream(s),
|
||||||
|
quit: make(chan bool),
|
||||||
|
settings: settings{},
|
||||||
|
Messages: make(map[string]*SMS),
|
||||||
|
}
|
||||||
|
|
||||||
|
mod.AddParam(session.NewStringParameter("modem.apn",
|
||||||
|
mod.settings.apn,
|
||||||
|
"",
|
||||||
|
"APN"))
|
||||||
|
|
||||||
|
mod.AddParam(session.NewStringParameter("modem.pin",
|
||||||
|
mod.settings.pin,
|
||||||
|
"",
|
||||||
|
"PIN for SIM card"))
|
||||||
|
|
||||||
|
mod.AddHandler(session.NewModuleHandler("modem on",
|
||||||
|
"",
|
||||||
|
"Start the modem module.",
|
||||||
|
func(args []string) error {
|
||||||
|
return mod.Start()
|
||||||
|
}))
|
||||||
|
|
||||||
|
mod.AddHandler(session.NewModuleHandler("modem off",
|
||||||
|
"",
|
||||||
|
"Stop the modem module.",
|
||||||
|
func(args []string) error {
|
||||||
|
return mod.Stop()
|
||||||
|
}))
|
||||||
|
|
||||||
|
mod.AddHandler(session.NewModuleHandler("modem.show", "",
|
||||||
|
"Display modem connection and location information.",
|
||||||
|
func(args []string) error {
|
||||||
|
return mod.Show()
|
||||||
|
}))
|
||||||
|
|
||||||
|
mod.AddHandler(session.NewModuleHandler("modem.sms.show", "",
|
||||||
|
"Display SMS messages.",
|
||||||
|
func(args []string) error {
|
||||||
|
return mod.ReadSMS()
|
||||||
|
}))
|
||||||
|
|
||||||
|
mod.AddHandler(session.NewModuleHandler("modem.sms.clear", "",
|
||||||
|
"Clear/delete SMS messages.",
|
||||||
|
func(args []string) error {
|
||||||
|
return mod.ClearSMS()
|
||||||
|
}))
|
||||||
|
|
||||||
|
mod.AddHandler(session.NewModuleHandler("modem.sms.send NUMBER MESSAGE",
|
||||||
|
"modem.sms.send ([^\\s]+) (.+)",
|
||||||
|
"Send an SMS message.",
|
||||||
|
func(args []string) error {
|
||||||
|
var number, message string
|
||||||
|
if ok := args[0]; ok != "" {
|
||||||
|
number = ok
|
||||||
|
}
|
||||||
|
if ok := args[1]; ok != "" {
|
||||||
|
message = strings.Join(args[1:], " ")
|
||||||
|
}
|
||||||
|
mod.SendSMS(number, message)
|
||||||
|
mod.Debug("SMS sent to %s", number)
|
||||||
|
return nil
|
||||||
|
}))
|
||||||
|
|
||||||
|
return mod
|
||||||
|
}
|
||||||
|
|
||||||
|
func (mod *Modem) Name() string {
|
||||||
|
return "modem"
|
||||||
|
}
|
||||||
|
|
||||||
|
func (mod *Modem) Description() string {
|
||||||
|
return "A ModemManager module that can send and receive SMS messages, connect to 3g/4g carrier and display connection info."
|
||||||
|
}
|
||||||
|
|
||||||
|
func (mod *Modem) Author() string {
|
||||||
|
return "https://github.com/aster1sk"
|
||||||
|
}
|
||||||
|
|
||||||
|
func (mod *Modem) Configure() (err error) {
|
||||||
|
|
||||||
|
if mod.Running() {
|
||||||
|
return session.ErrAlreadyStarted(mod.Name())
|
||||||
|
}
|
||||||
|
|
||||||
|
if err, mod.settings.device = mod.StringParam("modem.apn"); err != nil {
|
||||||
|
return err
|
||||||
|
} else if err, mod.settings.pin = mod.StringParam("modem.pin"); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
mod.eventBus = mod.Session.Events.Listen()
|
||||||
|
|
||||||
|
if log.Level == log.DEBUG {
|
||||||
|
// @TODO maybe make this work
|
||||||
|
}
|
||||||
|
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (mod *Modem) onEvent(e session.Event) {
|
||||||
|
|
||||||
|
if mod.Session.EventsIgnoreList.Ignored(e) {
|
||||||
|
mod.Info("%v", e.Data)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func (mod *Modem) Start() error {
|
||||||
|
|
||||||
|
if err := mod.Configure(); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// This kinda feels against bettercap conventions
|
||||||
|
go mod.ReadModemData()
|
||||||
|
|
||||||
|
return mod.SetRunning(true, func() {
|
||||||
|
for mod.Running() {
|
||||||
|
var e session.Event
|
||||||
|
select {
|
||||||
|
case e = <-mod.eventBus:
|
||||||
|
mod.onEvent(e)
|
||||||
|
case <-mod.quit:
|
||||||
|
mod.Debug("got quit")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// Stop stops the modem module
|
||||||
|
func (mod *Modem) Stop() error {
|
||||||
|
mod.Info("Stopping modem %s", mod.settings.device)
|
||||||
|
// @TODO mmcli disable?
|
||||||
|
return mod.SetRunning(false, func() {
|
||||||
|
mod.quit <- true
|
||||||
|
mod.Session.Events.Unlisten(mod.eventBus)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// Show displays information about the modem :
|
||||||
|
func (mod *Modem) Show() error {
|
||||||
|
// @TODO tabular output is ideal here like the wifi.show functionality, not sure how
|
||||||
|
// There is a lot of cool / interesting stuff in here like cell tower ID etc, perhaps this should be templated?
|
||||||
|
mod.Printf("Registered : '%s' Carrier : '%s' ICCID : %s RSSI %s%% \n",
|
||||||
|
mod.Modem.Modem.ThreeGpp.RegistrationState,
|
||||||
|
mod.Modem.Modem.ThreeGpp.OperatorName,
|
||||||
|
mod.SIM.Sim.Properties.Iccid,
|
||||||
|
mod.Modem.Modem.Generic.SignalQuality.Value,
|
||||||
|
)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// SendSMS sends an SMS to {number} with {message}
|
||||||
|
func (mod *Modem) SendSMS(number, message string) error {
|
||||||
|
|
||||||
|
if number == "" || message == "" {
|
||||||
|
return fmt.Errorf("number and message required")
|
||||||
|
}
|
||||||
|
|
||||||
|
// @TODO shell escape message and number else pwnd!
|
||||||
|
cmd := fmt.Sprintf(`%s -m %s --messaging-create-sms=text="%s",number="%s"`,
|
||||||
|
mmcliPath,
|
||||||
|
mod.Modem.Modem.DbusPath,
|
||||||
|
message,
|
||||||
|
number,
|
||||||
|
)
|
||||||
|
|
||||||
|
mod.Info(runCommand(cmd))
|
||||||
|
|
||||||
|
for s, x := range mod.Messages {
|
||||||
|
m := mod.Modem.Modem.DbusPath
|
||||||
|
if x.Sms.Properties.State == "--" {
|
||||||
|
/* I'm pretty sure this works universally, definitely requires further testing.
|
||||||
|
Send the message if it's not 'sent' or 'received' state.
|
||||||
|
This probably needs some better error handling */
|
||||||
|
mod.Info(runCommand(fmt.Sprintf("%s -m %s -s %s --send", mmcliPath, m, s)))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// ReadSMS displays sent and received SMS messages
|
||||||
|
func (mod *Modem) ReadSMS() error {
|
||||||
|
// @TODO tabular output is ideal here like the wifi.show functionality, not sure how
|
||||||
|
for _, msg := range mod.Messages {
|
||||||
|
mod.Info("from %s : %s (%s)", msg.Sms.Content.Number, msg.Sms.Content.Text, msg.Sms.Properties.State)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// ClearSMS will purge all messages from SIM and module
|
||||||
|
func (mod *Modem) ClearSMS() error {
|
||||||
|
for s := range mod.Messages {
|
||||||
|
m := mod.Modem.Modem.DbusPath
|
||||||
|
mod.Info(runCommand(fmt.Sprintf("%s -m %s --messaging-delete-sms=%s", mmcliPath, m, s)))
|
||||||
|
delete(mod.Messages, s)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// ReadModemData reads data from the modem
|
||||||
|
func (mod *Modem) ReadModemData() {
|
||||||
|
|
||||||
|
if p, ok := exec.LookPath("mmcli"); ok == nil {
|
||||||
|
mmcliPath = p
|
||||||
|
} else {
|
||||||
|
// Is the the correct way to do this? This is a panic() case
|
||||||
|
mod.Error("Could not find mmcli")
|
||||||
|
mod.Stop()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Probably best to use the built-in ticker from bettercap but that REEKS of effort.
|
||||||
|
for range time.Tick(time.Second * 1) {
|
||||||
|
|
||||||
|
// This is one gnarly long function that should probably be split up into different parts
|
||||||
|
out := runCommand(mmcliPath + " -L -J")
|
||||||
|
var modemList ModemList
|
||||||
|
json.Unmarshal([]byte(out), &modemList)
|
||||||
|
|
||||||
|
for _, m := range modemList.ModemList {
|
||||||
|
|
||||||
|
out = runCommand(fmt.Sprintf("%s -m %s -J", mmcliPath, m))
|
||||||
|
var modem MMCLIModem
|
||||||
|
json.Unmarshal([]byte(out), &modem)
|
||||||
|
mod.settings.device = modem.Modem.DbusPath
|
||||||
|
|
||||||
|
switch modem.Modem.Generic.State {
|
||||||
|
|
||||||
|
case "disabled":
|
||||||
|
runCommand(fmt.Sprintf("%s -m %s -e", mmcliPath, m))
|
||||||
|
|
||||||
|
case "registered":
|
||||||
|
operCode := modem.Modem.ThreeGpp.OperatorCode
|
||||||
|
_ = operCode
|
||||||
|
cmd := fmt.Sprintf(`%s -m %s --simple-connect=apn=%s`, mmcliPath, m, mod.settings.apn)
|
||||||
|
runCommand(cmd)
|
||||||
|
|
||||||
|
case "connected":
|
||||||
|
bearers := modem.Modem.Generic.Bearers
|
||||||
|
runCommand(fmt.Sprintf("%s --modem-set-enable-signal -m %s -J", mmcliPath, m))
|
||||||
|
for _, b := range bearers {
|
||||||
|
cmd1 := fmt.Sprintf("%s -b %s -J", mmcliPath, b)
|
||||||
|
out = runCommand(cmd1)
|
||||||
|
var bearer Bearer
|
||||||
|
json.Unmarshal([]byte(out), &bearer)
|
||||||
|
|
||||||
|
i := 1
|
||||||
|
for _, d := range bearer.Bearer.Ipv4Config.DNS {
|
||||||
|
dnsTxt := fmt.Sprintf(" DNS Server %d", i)
|
||||||
|
_ = d
|
||||||
|
_ = dnsTxt
|
||||||
|
i++
|
||||||
|
}
|
||||||
|
|
||||||
|
s := modem.Modem.Generic.Sim
|
||||||
|
out = runCommand(fmt.Sprintf("%s --sim %s -J", mmcliPath, s))
|
||||||
|
var sim SIM
|
||||||
|
json.Unmarshal([]byte(out), &sim)
|
||||||
|
|
||||||
|
out = runCommand(fmt.Sprintf("%s --location-get -m %s -J", mmcliPath, m))
|
||||||
|
var location ModemLocation
|
||||||
|
json.Unmarshal([]byte(out), &location)
|
||||||
|
|
||||||
|
out = runCommand(fmt.Sprintf("%s -m %s --messaging-list-sms -J", mmcliPath, m))
|
||||||
|
var smsl SMSList
|
||||||
|
json.Unmarshal([]byte(out), &smsl)
|
||||||
|
|
||||||
|
smss := make(map[string]*SMS)
|
||||||
|
|
||||||
|
var msgCount int
|
||||||
|
for _, s := range smsl.ModemMessagingSms {
|
||||||
|
msgCount++
|
||||||
|
out = runCommand(fmt.Sprintf("%s -m %s -s %s -J", mmcliPath, m, s))
|
||||||
|
var sms SMS
|
||||||
|
json.Unmarshal([]byte(out), &sms)
|
||||||
|
smss[s] = &sms
|
||||||
|
}
|
||||||
|
if len(mod.Messages) != msgCount {
|
||||||
|
mod.ReadSMS()
|
||||||
|
}
|
||||||
|
|
||||||
|
// @TODO likely a buttload of race conditions happening here ¯\_(ツ)_/¯
|
||||||
|
mod.Messages = smss
|
||||||
|
mod.Location = &location
|
||||||
|
mod.SIM = &sim
|
||||||
|
mod.Bearer = &bearer
|
||||||
|
mod.Modem = &modem
|
||||||
|
|
||||||
|
/* Maybe these events should be configurable for example :
|
||||||
|
if rssi != previous rssi -> print msg
|
||||||
|
*/
|
||||||
|
if mod.Modem.Modem.Generic.Device != modem.Modem.Generic.Device {
|
||||||
|
evt := session.NewEvent("modem.device", mod.Modem)
|
||||||
|
mod.Info("%v", evt)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// runCommand is a terrible thing and should be replaced with the better one that bettercap uses for !eval
|
||||||
|
func runCommand(command string) string {
|
||||||
|
parts := strings.Fields(command)
|
||||||
|
baseCmd := parts[0]
|
||||||
|
cmdArgs := parts[1:]
|
||||||
|
cmd := exec.Command(baseCmd, cmdArgs...)
|
||||||
|
r, _ := cmd.StdoutPipe()
|
||||||
|
cmd.Stderr = cmd.Stdout
|
||||||
|
scanner := bufio.NewScanner(r)
|
||||||
|
err := cmd.Start()
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
var output string
|
||||||
|
for scanner.Scan() {
|
||||||
|
output += scanner.Text()
|
||||||
|
}
|
||||||
|
cmd.Wait()
|
||||||
|
return output
|
||||||
|
}
|
||||||
|
|
||||||
|
// superflous comment for sloc win
|
|
@ -18,6 +18,7 @@ import (
|
||||||
"github.com/bettercap/bettercap/modules/https_server"
|
"github.com/bettercap/bettercap/modules/https_server"
|
||||||
"github.com/bettercap/bettercap/modules/mac_changer"
|
"github.com/bettercap/bettercap/modules/mac_changer"
|
||||||
"github.com/bettercap/bettercap/modules/mdns_server"
|
"github.com/bettercap/bettercap/modules/mdns_server"
|
||||||
|
"github.com/bettercap/bettercap/modules/modem"
|
||||||
"github.com/bettercap/bettercap/modules/mysql_server"
|
"github.com/bettercap/bettercap/modules/mysql_server"
|
||||||
"github.com/bettercap/bettercap/modules/net_probe"
|
"github.com/bettercap/bettercap/modules/net_probe"
|
||||||
"github.com/bettercap/bettercap/modules/net_recon"
|
"github.com/bettercap/bettercap/modules/net_recon"
|
||||||
|
@ -61,6 +62,7 @@ func LoadModules(sess *session.Session) {
|
||||||
sess.Register(wol.NewWOL(sess))
|
sess.Register(wol.NewWOL(sess))
|
||||||
sess.Register(hid.NewHIDRecon(sess))
|
sess.Register(hid.NewHIDRecon(sess))
|
||||||
sess.Register(c2.NewC2(sess))
|
sess.Register(c2.NewC2(sess))
|
||||||
|
sess.Register(modem.NewModem(sess))
|
||||||
|
|
||||||
sess.Register(caplets.NewCapletsModule(sess))
|
sess.Register(caplets.NewCapletsModule(sess))
|
||||||
sess.Register(update.NewUpdateModule(sess))
|
sess.Register(update.NewUpdateModule(sess))
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue