mirror of
https://github.com/bettercap/bettercap
synced 2025-07-05 20:42:09 -07:00
merge
This commit is contained in:
commit
88d813543a
10 changed files with 7453 additions and 49 deletions
|
@ -44,14 +44,21 @@ func (mod *EventsStream) viewZeroConfEvent(output io.Writer, e session.Event) {
|
||||||
instPart = fmt.Sprintf(" and instances %s", strings.Join(instances, ", "))
|
instPart = fmt.Sprintf(" and instances %s", strings.Join(instances, ", "))
|
||||||
}
|
}
|
||||||
|
|
||||||
fmt.Fprintf(output, "[%s] [%s] %s is browsing (%s) for services %s%s\n",
|
textPart := ""
|
||||||
|
if len(event.Text) > 0 {
|
||||||
|
textPart = fmt.Sprintf("\n text records: %s\n", strings.Join(event.Text, ", "))
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt.Fprintf(output, "[%s] [%s] %s is browsing (%s) for services %s%s\n%s",
|
||||||
e.Time.Format(mod.timeFormat),
|
e.Time.Format(mod.timeFormat),
|
||||||
tui.Green(e.Tag),
|
tui.Green(e.Tag),
|
||||||
source,
|
source,
|
||||||
ops.Ternary(event.Query.QR, "RESPONSE", "QUERY"),
|
ops.Ternary(event.Query.QR, "RESPONSE", "QUERY"),
|
||||||
strings.Join(services, ", "),
|
strings.Join(services, ", "),
|
||||||
instPart,
|
instPart,
|
||||||
|
textPart,
|
||||||
)
|
)
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
fmt.Fprintf(output, "[%s] [%s] %v\n", e.Time.Format(mod.timeFormat), tui.Green(e.Tag), e)
|
fmt.Fprintf(output, "[%s] [%s] %v\n", e.Time.Format(mod.timeFormat), tui.Green(e.Tag), e)
|
||||||
}
|
}
|
||||||
|
|
|
@ -25,7 +25,13 @@ var TCP_HANDLERS = map[string]Handler{
|
||||||
TLS: true,
|
TLS: true,
|
||||||
Handle: ippClientHandler,
|
Handle: ippClientHandler,
|
||||||
},
|
},
|
||||||
// TODO: _http at least
|
"_http": {
|
||||||
|
Handle: httpClientHandler,
|
||||||
|
},
|
||||||
|
"_https": {
|
||||||
|
TLS: true,
|
||||||
|
Handle: httpClientHandler,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
type Acceptor struct {
|
type Acceptor struct {
|
||||||
|
@ -42,6 +48,7 @@ type Acceptor struct {
|
||||||
ctxCancel context.CancelFunc
|
ctxCancel context.CancelFunc
|
||||||
handler Handler
|
handler Handler
|
||||||
ippAttributes map[string]string
|
ippAttributes map[string]string
|
||||||
|
httpPaths map[string]string
|
||||||
}
|
}
|
||||||
|
|
||||||
type HandlerContext struct {
|
type HandlerContext struct {
|
||||||
|
@ -52,9 +59,10 @@ type HandlerContext struct {
|
||||||
srvPort int
|
srvPort int
|
||||||
srvTLS bool
|
srvTLS bool
|
||||||
ippAttributes map[string]string
|
ippAttributes map[string]string
|
||||||
|
httpPaths map[string]string
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewAcceptor(mod *ZeroGod, service string, srvHost string, port uint16, tlsConfig *tls.Config, ippAttributes map[string]string) *Acceptor {
|
func NewAcceptor(mod *ZeroGod, service string, srvHost string, port uint16, tlsConfig *tls.Config, ippAttributes map[string]string, httpPaths map[string]string) *Acceptor {
|
||||||
context, ctcCancel := context.WithCancel(context.Background())
|
context, ctcCancel := context.WithCancel(context.Background())
|
||||||
proto := ops.Ternary(strings.Contains(service, "_tcp"), "tcp", "udp").(string)
|
proto := ops.Ternary(strings.Contains(service, "_tcp"), "tcp", "udp").(string)
|
||||||
|
|
||||||
|
@ -67,11 +75,14 @@ func NewAcceptor(mod *ZeroGod, service string, srvHost string, port uint16, tlsC
|
||||||
ctxCancel: ctcCancel,
|
ctxCancel: ctcCancel,
|
||||||
srvHost: srvHost,
|
srvHost: srvHost,
|
||||||
ippAttributes: ippAttributes,
|
ippAttributes: ippAttributes,
|
||||||
|
httpPaths: httpPaths,
|
||||||
}
|
}
|
||||||
|
|
||||||
for svcName, svcHandler := range TCP_HANDLERS {
|
for svcName, svcHandler := range TCP_HANDLERS {
|
||||||
if strings.Contains(service, svcName) {
|
if strings.Contains(service, svcName) {
|
||||||
acceptor.tlsConfig = tlsConfig
|
if svcHandler.TLS {
|
||||||
|
acceptor.tlsConfig = tlsConfig
|
||||||
|
}
|
||||||
acceptor.handler = svcHandler
|
acceptor.handler = svcHandler
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
@ -81,7 +92,7 @@ func NewAcceptor(mod *ZeroGod, service string, srvHost string, port uint16, tlsC
|
||||||
mod.Warning("no protocol handler found for service %s, using generic %s dump handler", tui.Yellow(service), proto)
|
mod.Warning("no protocol handler found for service %s, using generic %s dump handler", tui.Yellow(service), proto)
|
||||||
acceptor.handler.Handle = handleGenericTCP
|
acceptor.handler.Handle = handleGenericTCP
|
||||||
} else {
|
} else {
|
||||||
mod.Info("found %s %s protocol handler", proto, tui.Green(service))
|
mod.Info("found %s %s protocol handler (tls=%v)", proto, tui.Green(service), acceptor.tlsConfig != nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
return &acceptor
|
return &acceptor
|
||||||
|
@ -114,6 +125,7 @@ func (a *Acceptor) startTCP() (err error) {
|
||||||
srvPort: int(a.port),
|
srvPort: int(a.port),
|
||||||
srvTLS: a.tlsConfig != nil,
|
srvTLS: a.tlsConfig != nil,
|
||||||
ippAttributes: a.ippAttributes,
|
ippAttributes: a.ippAttributes,
|
||||||
|
httpPaths: a.httpPaths,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -172,7 +172,7 @@ func (mod *ZeroGod) startAdvertiser(fileName string) error {
|
||||||
for _, svc := range advertiser.Services {
|
for _, svc := range advertiser.Services {
|
||||||
// if no external responder has been specified
|
// if no external responder has been specified
|
||||||
if svc.Responder == "" {
|
if svc.Responder == "" {
|
||||||
acceptor := NewAcceptor(mod, svc.FullName(), hostName, uint16(svc.Port), tlsConfig, svc.IPP)
|
acceptor := NewAcceptor(mod, svc.FullName(), hostName, uint16(svc.Port), tlsConfig, svc.IPP, svc.HTTP)
|
||||||
if err := acceptor.Start(); err != nil {
|
if err := acceptor.Start(); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
|
@ -27,6 +27,7 @@ type BrowsingEvent struct {
|
||||||
Endpoint *network.Endpoint `json:"endpoint"`
|
Endpoint *network.Endpoint `json:"endpoint"`
|
||||||
Services []string `json:"services"`
|
Services []string `json:"services"`
|
||||||
Instances []string `json:"instances"`
|
Instances []string `json:"instances"`
|
||||||
|
Text []string `json:"text"`
|
||||||
Query layers.DNS `json:"query"`
|
Query layers.DNS `json:"query"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -258,11 +259,12 @@ func (mod *ZeroGod) onPacket(pkt gopacket.Packet) {
|
||||||
}
|
}
|
||||||
|
|
||||||
instances := make([]string, 0)
|
instances := make([]string, 0)
|
||||||
|
text := make([]string, 0)
|
||||||
for _, answer := range append(append(dns.Answers, dns.Additionals...), dns.Authorities...) {
|
for _, answer := range append(append(dns.Answers, dns.Additionals...), dns.Authorities...) {
|
||||||
if answer.Class == layers.DNSClassIN && answer.Type == layers.DNSTypePTR {
|
if answer.Class == layers.DNSClassIN && answer.Type == layers.DNSTypePTR {
|
||||||
instances = append(instances, string(answer.PTR))
|
instances = append(instances, string(answer.PTR))
|
||||||
} else {
|
} else if answer.Type == layers.DNSTypeTXT {
|
||||||
instances = append(instances, answer.String())
|
text = append(text, string(answer.TXT))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -271,6 +273,7 @@ func (mod *ZeroGod) onPacket(pkt gopacket.Packet) {
|
||||||
Query: dns,
|
Query: dns,
|
||||||
Services: services,
|
Services: services,
|
||||||
Instances: instances,
|
Instances: instances,
|
||||||
|
Text: text,
|
||||||
Endpoint: mod.Session.Lan.GetByIp(srcIP.String()),
|
Endpoint: mod.Session.Lan.GetByIp(srcIP.String()),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
104
modules/zerogod/zerogod_http_handler.go
Normal file
104
modules/zerogod/zerogod_http_handler.go
Normal file
|
@ -0,0 +1,104 @@
|
||||||
|
package zerogod
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bufio"
|
||||||
|
"bytes"
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"net/http"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/evilsocket/islazy/tui"
|
||||||
|
)
|
||||||
|
|
||||||
|
func httpGenericHandler(ctx *HandlerContext) (shouldQuit bool, clientIP string, req *http.Request, err error) {
|
||||||
|
clientIP = strings.SplitN(ctx.client.RemoteAddr().String(), ":", 2)[0]
|
||||||
|
|
||||||
|
buf := make([]byte, 4096)
|
||||||
|
// read raw request
|
||||||
|
read, err := ctx.client.Read(buf)
|
||||||
|
if err != nil {
|
||||||
|
if err == io.EOF {
|
||||||
|
ctx.mod.Debug("EOF, client %s disconnected", clientIP)
|
||||||
|
return true, clientIP, nil, nil
|
||||||
|
}
|
||||||
|
ctx.mod.Warning("error while reading from %v: %v", clientIP, err)
|
||||||
|
return true, clientIP, nil, err
|
||||||
|
} else if read == 0 {
|
||||||
|
ctx.mod.Warning("error while reading from %v: no data", clientIP)
|
||||||
|
return true, clientIP, nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
raw_req := buf[0:read]
|
||||||
|
|
||||||
|
ctx.mod.Debug("read %d bytes from %v:\n%s\n", read, clientIP, Dump(raw_req))
|
||||||
|
|
||||||
|
// parse as http
|
||||||
|
reader := bufio.NewReader(bytes.NewReader(raw_req))
|
||||||
|
httpRequest, err := http.ReadRequest(reader)
|
||||||
|
if err != nil {
|
||||||
|
ctx.mod.Error("error while parsing http request from %v: %v\n%s", clientIP, err, Dump(raw_req))
|
||||||
|
return true, clientIP, nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return false, clientIP, httpRequest, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func httpLogRequest(ctx *HandlerContext, clientIP string, httpRequest *http.Request) {
|
||||||
|
clientUA := httpRequest.UserAgent()
|
||||||
|
ctx.mod.Info("%v (%s) > %s %s",
|
||||||
|
clientIP,
|
||||||
|
tui.Green(clientUA),
|
||||||
|
tui.Bold(httpRequest.Method),
|
||||||
|
tui.Yellow(httpRequest.RequestURI))
|
||||||
|
}
|
||||||
|
|
||||||
|
func httpClientHandler(ctx *HandlerContext) {
|
||||||
|
defer ctx.client.Close()
|
||||||
|
|
||||||
|
shouldQuit, clientIP, httpRequest, err := httpGenericHandler(ctx)
|
||||||
|
if shouldQuit {
|
||||||
|
return
|
||||||
|
} else if err != nil {
|
||||||
|
ctx.mod.Error("%v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
httpLogRequest(ctx, clientIP, httpRequest)
|
||||||
|
|
||||||
|
respStatusCode := 404
|
||||||
|
respStatus := "Not Found"
|
||||||
|
respBody := `<html>
|
||||||
|
<head><title>Not Found</title></head>
|
||||||
|
<body>
|
||||||
|
<center><h1>Not Found</h1></center>
|
||||||
|
</body>
|
||||||
|
</html>`
|
||||||
|
|
||||||
|
// see if anything in config matches
|
||||||
|
for path, body := range ctx.httpPaths {
|
||||||
|
if httpRequest.RequestURI == path {
|
||||||
|
respStatusCode = 200
|
||||||
|
respStatus = "OK"
|
||||||
|
respBody = body
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
response := fmt.Sprintf(`HTTP/1.1 %d %s
|
||||||
|
Content-Type: text/html; charset=utf-8
|
||||||
|
Content-Length: %d
|
||||||
|
Connection: close
|
||||||
|
|
||||||
|
%s`,
|
||||||
|
respStatusCode,
|
||||||
|
respStatus,
|
||||||
|
len(respBody),
|
||||||
|
respBody,
|
||||||
|
)
|
||||||
|
|
||||||
|
if _, err = ctx.client.Write([]byte(response)); err != nil {
|
||||||
|
ctx.mod.Error("error while writing http response data: %v", err)
|
||||||
|
} else {
|
||||||
|
ctx.mod.Debug("sent %d of http response to %v", len(response), ctx.client.RemoteAddr())
|
||||||
|
}
|
||||||
|
}
|
|
@ -67,7 +67,7 @@ func ippOnGetJobAttributes(ctx *HandlerContext, ipp_req *ipp.Request) {
|
||||||
}
|
}
|
||||||
ipp_resp.OperationAttributes["job-originating-user-name"] = []ipp.Attribute{
|
ipp_resp.OperationAttributes["job-originating-user-name"] = []ipp.Attribute{
|
||||||
{
|
{
|
||||||
Value: "bettercap", // TODO: check if this must match the actual job user from a print operation
|
Value: "bettercap",
|
||||||
Tag: ipp.TagName,
|
Tag: ipp.TagName,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,12 +1,7 @@
|
||||||
package zerogod
|
package zerogod
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bufio"
|
|
||||||
"bytes"
|
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
|
||||||
"net/http"
|
|
||||||
"strings"
|
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/evilsocket/islazy/tui"
|
"github.com/evilsocket/islazy/tui"
|
||||||
|
@ -42,40 +37,17 @@ type PrintData struct {
|
||||||
func ippClientHandler(ctx *HandlerContext) {
|
func ippClientHandler(ctx *HandlerContext) {
|
||||||
defer ctx.client.Close()
|
defer ctx.client.Close()
|
||||||
|
|
||||||
clientIP := strings.SplitN(ctx.client.RemoteAddr().String(), ":", 2)[0]
|
shouldQuit, clientIP, httpRequest, err := httpGenericHandler(ctx)
|
||||||
|
if shouldQuit {
|
||||||
buf := make([]byte, 4096)
|
|
||||||
|
|
||||||
// read raw request
|
|
||||||
read, err := ctx.client.Read(buf)
|
|
||||||
if err != nil {
|
|
||||||
if err == io.EOF {
|
|
||||||
ctx.mod.Debug("EOF, client %s disconnected", clientIP)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
ctx.mod.Warning("error while reading from %v: %v", clientIP, err)
|
|
||||||
return
|
|
||||||
} else if read == 0 {
|
|
||||||
ctx.mod.Warning("error while reading from %v: no data", clientIP)
|
|
||||||
return
|
return
|
||||||
|
} else if err != nil {
|
||||||
|
ctx.mod.Error("%v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
raw_req := buf[0:read]
|
clientUA := httpRequest.UserAgent()
|
||||||
|
|
||||||
ctx.mod.Debug("read %d bytes from %v:\n%s\n", read, clientIP, Dump(raw_req))
|
|
||||||
|
|
||||||
// parse as http
|
|
||||||
reader := bufio.NewReader(bytes.NewReader(raw_req))
|
|
||||||
http_req, err := http.ReadRequest(reader)
|
|
||||||
if err != nil {
|
|
||||||
ctx.mod.Error("error while parsing http request from %v: %v\n%s", clientIP, err, Dump(raw_req))
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
clientUA := http_req.UserAgent()
|
|
||||||
ctx.mod.Info("%v -> %s", clientIP, tui.Green(clientUA))
|
ctx.mod.Info("%v -> %s", clientIP, tui.Green(clientUA))
|
||||||
|
|
||||||
ipp_body, err := ippReadRequestBody(ctx, http_req)
|
ipp_body, err := ippReadRequestBody(ctx, httpRequest)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
ctx.mod.Error("%v", err)
|
ctx.mod.Error("%v", err)
|
||||||
return
|
return
|
||||||
|
@ -84,7 +56,7 @@ func ippClientHandler(ctx *HandlerContext) {
|
||||||
// parse as IPP
|
// parse as IPP
|
||||||
ipp_req, err := ipp.NewRequestDecoder(ipp_body).Decode(nil)
|
ipp_req, err := ipp.NewRequestDecoder(ipp_body).Decode(nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
ctx.mod.Error("error while parsing ipp request from %v: %v -> %++v", clientIP, err, *http_req)
|
ctx.mod.Error("error while parsing ipp request from %v: %v -> %++v", clientIP, err, *httpRequest)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -118,7 +90,7 @@ func ippClientHandler(ctx *HandlerContext) {
|
||||||
ippOnGetJobs(ctx, ipp_req)
|
ippOnGetJobs(ctx, ipp_req)
|
||||||
// Print-Job
|
// Print-Job
|
||||||
case 0x0002:
|
case 0x0002:
|
||||||
ippOnPrintJob(ctx, http_req, ipp_req)
|
ippOnPrintJob(ctx, httpRequest, ipp_req)
|
||||||
// Get-Job-Attributes
|
// Get-Job-Attributes
|
||||||
case 0x0009:
|
case 0x0009:
|
||||||
ippOnGetJobAttributes(ctx, ipp_req)
|
ippOnGetJobAttributes(ctx, ipp_req)
|
||||||
|
|
7291
modules/zerogod/zerogod_known_services.go
Normal file
7291
modules/zerogod/zerogod_known_services.go
Normal file
File diff suppressed because it is too large
Load diff
|
@ -17,6 +17,7 @@ type ServiceData struct {
|
||||||
Records []string `yaml:"records,omitempty"` // Service DNS text records
|
Records []string `yaml:"records,omitempty"` // Service DNS text records
|
||||||
Responder string `yaml:"responder,omitempty"` // Optional IP to use instead of our tcp acceptor
|
Responder string `yaml:"responder,omitempty"` // Optional IP to use instead of our tcp acceptor
|
||||||
IPP map[string]string `yaml:"ipp,omitempty"` // Optional IPP attributes map
|
IPP map[string]string `yaml:"ipp,omitempty"` // Optional IPP attributes map
|
||||||
|
HTTP map[string]string `yaml:"http,omitempty"` // Optional HTTP URIs map
|
||||||
|
|
||||||
server *zeroconf.Server
|
server *zeroconf.Server
|
||||||
}
|
}
|
||||||
|
|
|
@ -30,11 +30,25 @@ func (mod *ZeroGod) show(filter string, withData bool) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, svc := range entry.Services {
|
for _, svc := range entry.Services {
|
||||||
fmt.Fprintf(mod.Session.Events.Stdout, " %s (%s) [%v / %v]:%s\n",
|
ip := ""
|
||||||
|
if len(svc.AddrIPv4) > 0 {
|
||||||
|
ip = svc.AddrIPv4[0].String()
|
||||||
|
} else if len(svc.AddrIPv6) > 0 {
|
||||||
|
ip = svc.AddrIPv6[0].String()
|
||||||
|
} else {
|
||||||
|
ip = svc.HostName
|
||||||
|
}
|
||||||
|
|
||||||
|
svcDesc := ""
|
||||||
|
svcName := strings.SplitN(svc.Service, ".", 2)[0]
|
||||||
|
if desc, found := KNOWN_SERVICES[svcName]; found {
|
||||||
|
svcDesc = tui.Dim(fmt.Sprintf(" %s", desc))
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt.Fprintf(mod.Session.Events.Stdout, " %s%s %s:%s\n",
|
||||||
tui.Green(svc.ServiceInstanceName()),
|
tui.Green(svc.ServiceInstanceName()),
|
||||||
tui.Dim(svc.HostName),
|
svcDesc,
|
||||||
svc.AddrIPv4,
|
ip,
|
||||||
svc.AddrIPv6,
|
|
||||||
tui.Red(fmt.Sprintf("%d", svc.Port)),
|
tui.Red(fmt.Sprintf("%d", svc.Port)),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue