Merge pull request #4 from GoSecure/rdp-mitm-events

Updated logs for rdp proxy
This commit is contained in:
Alexandre Beaulieu 2019-05-23 10:07:40 -04:00 committed by GitHub
commit d5e5083ed1
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 57 additions and 19 deletions

View file

@ -10,6 +10,7 @@ import (
"github.com/bettercap/bettercap/session" "github.com/bettercap/bettercap/session"
"github.com/bettercap/bettercap/modules/net_sniff" "github.com/bettercap/bettercap/modules/net_sniff"
"github.com/bettercap/bettercap/modules/rdp_proxy"
"github.com/bettercap/bettercap/modules/syn_scan" "github.com/bettercap/bettercap/modules/syn_scan"
"github.com/google/go-github/github" "github.com/google/go-github/github"
@ -84,6 +85,16 @@ func (mod *EventsStream) viewSnifferEvent(e session.Event) {
e.Data.(net_sniff.SnifferEvent).Message) e.Data.(net_sniff.SnifferEvent).Message)
} }
} }
func (mod *EventsStream) viewRDPEvent(e session.Event) {
t := e.Data.(rdp_proxy.RdpProxyEvent)
fmt.Fprintf(mod.output, "[%s] [%s] [%s -> %s] %s\n",
e.Time.Format(mod.timeFormat),
tui.Green(e.Tag),
tui.Bold(t.Source),
tui.Bold(t.Destination),
t.Message)
}
func (mod *EventsStream) viewSynScanEvent(e session.Event) { func (mod *EventsStream) viewSynScanEvent(e session.Event) {
se := e.Data.(syn_scan.SynScanEvent) se := e.Data.(syn_scan.SynScanEvent)
@ -172,6 +183,8 @@ func (mod *EventsStream) View(e session.Event, refresh bool) {
mod.viewModuleEvent(e) mod.viewModuleEvent(e)
} else if strings.HasPrefix(e.Tag, "net.sniff.") { } else if strings.HasPrefix(e.Tag, "net.sniff.") {
mod.viewSnifferEvent(e) mod.viewSnifferEvent(e)
} else if e.Tag == "rdp.proxy" {
mod.viewRDPEvent(e)
} else if e.Tag == "syn.scan" { } else if e.Tag == "syn.scan" {
mod.viewSynScanEvent(e) mod.viewSynScanEvent(e)
} else if e.Tag == "update.available" { } else if e.Tag == "update.available" {

View file

@ -0,0 +1,24 @@
package rdp_proxy
import (
"github.com/bettercap/bettercap/session"
)
type RdpProxyEvent struct {
Source string
Destination string
Message string
}
func NewRdpProxyEvent(src string, dst string, msg string) RdpProxyEvent {
return RdpProxyEvent{
Source: src,
Destination: dst,
Message: msg,
}
}
func (e RdpProxyEvent) Push() {
session.I.Events.Add("rdp.proxy", e)
session.I.Refresh()
}

View file

@ -162,10 +162,7 @@ func (mod *RdpProxy) isNLAEnforced(target string) (nla bool, err error){
return false, nil return false, nil
} }
func (mod *RdpProxy) startProxyInstance(src string, sport string, dst string, dport string) (err error) { func (mod *RdpProxy) startProxyInstance(client string, target string) (err error) {
target := fmt.Sprintf("%s:%s", dst, dport)
ips := fmt.Sprintf("[%s:%s -> %s:%s]", src, sport, dst, dport)
// 3.1. Create a proxy agent and firewall rules. // 3.1. Create a proxy agent and firewall rules.
args := []string{ args := []string{
"-l", fmt.Sprintf("%d", mod.startPort), "-l", fmt.Sprintf("%d", mod.startPort),
@ -181,20 +178,21 @@ func (mod *RdpProxy) startProxyInstance(src string, sport string, dst string, dp
if err := cmd.Start(); err != nil { if err := cmd.Start(); err != nil {
// Wont't handle things like "port already in use" since it happens at runtime // Wont't handle things like "port already in use" since it happens at runtime
mod.Error("PyRDP Start error : %v", err.Error()) mod.Error("PyRDP Start error : %v", err.Error())
mod.Info("Failed to start PyRDP, won't intercept target %s", ips)
NewRdpProxyEvent(client, target, "Failed to start PyRDP, won't intercept target").Push()
return err return err
} }
// Use goroutines to keep logging each instance of PyRDP // Use goroutines to keep logging each instance of PyRDP
go mod.filterLogs(ips, stderrPipe) go mod.filterLogs(client, target, stderrPipe)
mod.active[target] = *cmd mod.active[target] = *cmd
return return
} }
// Filter PyRDP logs to only show those that matches mod.regexp // Filter PyRDP logs to only show those that matches mod.regexp
func (mod *RdpProxy) filterLogs(prefix string, output io.ReadCloser) { func (mod *RdpProxy) filterLogs(src string, dst string, output io.ReadCloser) {
scanner := bufio.NewScanner(output) scanner := bufio.NewScanner(output)
// For every log in the queue // For every log in the queue
@ -207,7 +205,7 @@ func (mod *RdpProxy) filterLogs(prefix string, output io.ReadCloser) {
// Get last element // Get last element
data := chunks[len(chunks) - 1] data := chunks[len(chunks) - 1]
mod.Info("%s %s", prefix, data) NewRdpProxyEvent(src, dst, fmt.Sprintf("%s", data)).Push()
} }
} }
} }
@ -270,14 +268,14 @@ func (mod *RdpProxy) configureFirewall(enable bool) (err error) {
// Fixes a bug that may come up when interrupting the application too quickly. // Fixes a bug that may come up when interrupting the application too quickly.
func (mod *RdpProxy) repairFirewall() (err error) { func (mod *RdpProxy) repairFirewall() (err error) {
rules := [][]string{ rules := [][]string{
{ "-t", "nat", "-D", "PREROUTING", "-j", "BCAPRDP" },
{ "-t", "nat", "-F", "BCAPRDP" }, { "-t", "nat", "-F", "BCAPRDP" },
{ "-t", "nat", "-X", "BCAPRDP" }, { "-t", "nat", "-X", "BCAPRDP" },
} }
// Force a cleaning of previous rules
for _, rule := range rules { for _, rule := range rules {
if _, err = core.Exec("iptables", rule); err != nil { core.Exec("iptables", rule);
return err
}
} }
return return
} }
@ -352,11 +350,10 @@ func (mod *RdpProxy) handleRdpConnection(payload *nfqueue.Payload) int {
src, sport := p.NetworkLayer().NetworkFlow().Src().String(), fmt.Sprintf("%s", p.TransportLayer().TransportFlow().Src()) src, sport := p.NetworkLayer().NetworkFlow().Src().String(), fmt.Sprintf("%s", p.TransportLayer().TransportFlow().Src())
dst, dport := p.NetworkLayer().NetworkFlow().Dst().String(), fmt.Sprintf("%s", p.TransportLayer().TransportFlow().Dst()) dst, dport := p.NetworkLayer().NetworkFlow().Dst().String(), fmt.Sprintf("%s", p.TransportLayer().TransportFlow().Dst())
// TODO : Log everything inside the events stream client := fmt.Sprintf("%s:%s", src, sport)
ips := fmt.Sprintf("[%s:%s -> %s:%s]", src, sport, dst, dport) target := fmt.Sprintf("%s:%s", dst, dport)
if mod.isTarget(dst) { if mod.isTarget(dst) {
target := fmt.Sprintf("%s:%s", 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 {
@ -368,8 +365,10 @@ func (mod *RdpProxy) handleRdpConnection(payload *nfqueue.Payload) int {
// TODO : Find a way to disconnect user right after stealing credentials. // TODO : Find a way to disconnect user right after stealing credentials.
// Start a PyRDP instance to the preconfigured vulnerable host // Start a PyRDP instance to the preconfigured vulnerable host
// and forward packets to the target to this host instead // and forward packets to the target to this host instead
mod.Info("%s Target has NLA enabled and mode REDIRECT, forwarding to the vulnerable host...", ips) NewRdpProxyEvent(client, target, "Target has NLA enabled and mode REDIRECT, forwarding to the vulnerable host...").Push()
err := mod.startProxyInstance(src, sport, mod.redirectIP.String(), fmt.Sprintf("%d", mod.redirectPort))
redirectTarget := fmt.Sprintf("%s:%d", mod.redirectIP.String(), mod.redirectPort)
err := mod.startProxyInstance(client, redirectTarget)
if err != nil { if err != nil {
// Add an exception in the firewall to avoid intercepting packets to this destination and port // Add an exception in the firewall to avoid intercepting packets to this destination and port
@ -383,13 +382,13 @@ func (mod *RdpProxy) handleRdpConnection(payload *nfqueue.Payload) int {
mod.startPort += 1 mod.startPort += 1
default: default:
// Add an exception in the firewall to avoid intercepting packets to this destination and port // Add an exception in the firewall to avoid intercepting packets to this destination and port
mod.Info("%s Target has NLA enabled and mode IGNORE, won't intercept", ips) NewRdpProxyEvent(client, target, "Target has NLA enabled and mode IGNORE, won't intercept").Push()
mod.doReturn(dst, dport) mod.doReturn(dst, dport)
} }
} else { } else {
// Starts a PyRDP instance. // Starts a PyRDP instance.
if err := mod.startProxyInstance(src, sport, dst, dport); err != nil { if err := mod.startProxyInstance(client, target); err != nil {
// Add an exception in the firewall to avoid intercepting packets to this destination and port // Add an exception in the firewall to avoid intercepting packets to this destination and port
mod.doReturn(dst, dport) mod.doReturn(dst, dport)
payload.SetVerdict(nfqueue.NF_DROP) payload.SetVerdict(nfqueue.NF_DROP)
@ -403,7 +402,8 @@ func (mod *RdpProxy) handleRdpConnection(payload *nfqueue.Payload) int {
} }
} }
} else { } else {
mod.Info("Non-target, won't intercept %s", ips) NewRdpProxyEvent(client, target, "Non-target, won't intercept").Push()
// Add an exception in the firewall to avoid intercepting packets to this destination and port // Add an exception in the firewall to avoid intercepting packets to this destination and port
mod.doReturn(dst, dport) mod.doReturn(dst, dport)
@ -424,6 +424,7 @@ func (mod *RdpProxy) Start() error {
if mod.Running() { if mod.Running() {
return session.ErrAlreadyStarted(mod.Name()) return session.ErrAlreadyStarted(mod.Name())
} else if err := mod.Configure(); err != nil { } else if err := mod.Configure(); err != nil {
mod.Error("%s", err.Error())
return err return err
} }