Merge pull request #1 from GoSecure/rdp-target

Added targets and queue number support to rdp proxy
This commit is contained in:
Maxime Carbonneau 2019-05-08 13:31:17 -04:00 committed by GitHub
commit 2dcae9e859
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23

View file

@ -5,9 +5,11 @@ import (
"os/exec"
"io/ioutil"
golog "log"
"net"
"syscall"
"github.com/bettercap/bettercap/core"
"github.com/bettercap/bettercap/network"
"github.com/bettercap/bettercap/session"
"github.com/chifflier/nfqueue-go/nfqueue"
@ -24,6 +26,7 @@ type RdpProxy struct {
startPort int
cmd string
active map[string]exec.Cmd
targets []net.IP
}
var mod *RdpProxy
@ -31,6 +34,7 @@ var mod *RdpProxy
func NewRdpProxy(s *session.Session) *RdpProxy {
mod = &RdpProxy{
SessionModule: session.NewSessionModule("rdp.proxy", s),
targets: make([]net.IP, 0),
done: make(chan bool),
queue: nil,
queueNum: 0,
@ -52,9 +56,10 @@ 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.port", "3389", "RDP port to intercept."))
mod.AddParam(session.NewIntParameter("rdp.proxy.start", "40000", "Starting port for pyrdp sessionss"))
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.out", "./", "", "The output directory for PyRDP artifcats."))
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."))
return mod
}
@ -67,12 +72,24 @@ func (mod RdpProxy) Description() string {
}
func (mod RdpProxy) Author() string {
return "Alexandre Beaulieu <alex@segfault.me>"
return "Alexandre Beaulieu <alex@segfault.me> && Maxime Carbonneau <pourliver@gmail.com>"
}
func (mod *RdpProxy) isTarget(ip string) bool {
for _, addr := range mod.targets {
if addr.String() == ip {
return true
}
}
return false
}
// Adds the firewall rule for proxy instance.
func (mod *RdpProxy) doProxy(addr string, port string, enable bool) (err error) {
_, err = core.Exec("iptables", []string { "-t", "nat",
_, err = core.Exec("iptables", []string{
"-t", "nat",
"-I", "BCAPRDP", "1",
"-d", addr,
"-p", "tcp",
@ -83,6 +100,18 @@ func (mod *RdpProxy) doProxy(addr string, port string, enable bool) (err error)
return
}
func (mod *RdpProxy) doReturn(dst string, dport gopacket.Endpoint, enable bool) (err error) {
_, err = core.Exec("iptables", []string{
"-t", "nat",
"-I", "BCAPRDP", "1",
"-p", "tcp",
"-d", dst,
"--dport", fmt.Sprintf("%v", dport),
"-j", "RETURN",
})
return
}
func (mod *RdpProxy) configureFirewall(enable bool) (err error) {
rules := [][]string{}
@ -92,9 +121,10 @@ func (mod *RdpProxy) configureFirewall(enable bool) (err error) {
{ "-t", "nat", "-I", "PREROUTING", "1", "-j", "BCAPRDP" },
{ "-t", "nat", "-A", "BCAPRDP",
"-p", "tcp", "-m", "tcp", "--dport", fmt.Sprintf("%d", mod.port),
"-j", "NFQUEUE", "--queue-num", "0", "--queue-bypass",
"-j", "NFQUEUE", "--queue-num", fmt.Sprintf("%d", mod.queueNum), "--queue-bypass",
},
}
} else if !enable {
rules = [][]string{
{ "-t", "nat", "-D", "PREROUTING", "-j", "BCAPRDP" },
@ -113,6 +143,8 @@ func (mod *RdpProxy) configureFirewall(enable bool) (err error) {
}
func (mod *RdpProxy) Configure() (err error) {
var targets string
golog.SetOutput(ioutil.Discard)
mod.destroyQueue()
@ -123,11 +155,16 @@ func (mod *RdpProxy) Configure() (err error) {
return
} else if err, mod.queueNum = mod.IntParam("rdp.proxy.queue.num"); err != nil {
return
} else if err, targets = mod.StringParam("rdp.proxy.targets"); err != nil {
return
} else if mod.targets, _, err = network.ParseTargets(targets, mod.Session.Lan.Aliases()); err != nil {
return
} else if _, err = exec.LookPath(mod.cmd); err != nil {
return
}
mod.Info("Starting RDP Proxy")
mod.Debug("Targets=%v", mod.targets)
// Create the NFQUEUE handler.
mod.queue = new(nfqueue.Queue)
@ -156,6 +193,7 @@ func (mod *RdpProxy) handleRdpConnection(payload *nfqueue.Payload) int {
src, sport := p.NetworkLayer().NetworkFlow().Src(), p.TransportLayer().TransportFlow().Src()
dst, dport := p.NetworkLayer().NetworkFlow().Dst(), p.TransportLayer().TransportFlow().Dst()
if mod.isTarget(dst.String()) {
// TODO: Don't log here and connect a pipe to the process instead.
mod.Info("CONNECT [%s:%v -> %v:%v]", src, sport, dst, dport)
target := fmt.Sprintf("%v:%v", dst, dport)
@ -182,9 +220,16 @@ func (mod *RdpProxy) handleRdpConnection(payload *nfqueue.Payload) int {
mod.active[target] = *cmd
mod.startPort += 1
}
} else {
mod.Info("Non-target, won't intercept [%s:%v -> %v:%v]", src, sport, dst, dport)
// Add an exception in the firewall to avoid intercepting packets to this destination and port
mod.doReturn(dst.String(), dport, true)
}
// Force a retransmit to trigger the new firewall rules. (TODO: Find a more efficient way to do this.)
payload.SetVerdict(nfqueue.NF_DROP)
return 0
}
@ -212,8 +257,6 @@ func (mod *RdpProxy) Start() error {
}
func (mod *RdpProxy) Stop() error {
return mod.SetRunning(false, func() {
mod.queue.StopLoop()
mod.configureFirewall(false)
@ -234,4 +277,3 @@ func (mod *RdpProxy) destroyQueue() {
mod.queue.Close()
mod.queue = nil
}