mirror of
https://github.com/bettercap/bettercap
synced 2025-08-22 06:23:18 -07:00
Merge pull request #4 from GoSecure/rdp-mitm-events
Updated logs for rdp proxy
This commit is contained in:
commit
d5e5083ed1
3 changed files with 57 additions and 19 deletions
|
@ -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" {
|
||||||
|
|
24
modules/rdp_proxy/rdp_proxy_event.go
Normal file
24
modules/rdp_proxy/rdp_proxy_event.go
Normal 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()
|
||||||
|
}
|
|
@ -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
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue