Skip to content
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions config/rules.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,9 @@ rules:
- match: tcp dst port 27017
type: conn_handler
target: mongodb
- match: tcp dst port 9889
type: passthrough
Comment thread
namay26 marked this conversation as resolved.
Outdated
target: passthrough # Will switch to host:ip
- match: tcp
type: conn_handler
target: tcp
Expand Down
3 changes: 3 additions & 0 deletions protocols/protocols.go
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,9 @@ func MapTCPProtocolHandlers(log interfaces.Logger, h interfaces.Honeypot) map[st
protocolHandlers["mongodb"] = func(ctx context.Context, conn net.Conn, md connection.Metadata) error {
return tcp.HandleMongoDB(ctx, conn, md, log, h)
}
protocolHandlers["passthrough"] = func(ctx context.Context, conn net.Conn, md connection.Metadata) error {
return tcp.HandlePassThrough(ctx, conn, md, log, h)
}
protocolHandlers["tcp"] = func(ctx context.Context, conn net.Conn, md connection.Metadata) error {
snip, bufConn, err := Peek(conn, 4)
if err != nil {
Expand Down
113 changes: 113 additions & 0 deletions protocols/tcp/passthrough.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
package tcp

import (
"context"
"fmt"
"io"
"log/slog"
"net"

"github.com/mushorg/glutton/connection"
"github.com/mushorg/glutton/producer"
"github.com/mushorg/glutton/protocols/interfaces"
)

type parsedPassThrough struct {
Direction string `json:"direction,omitempty"`
Payload []byte `json:"payload,omitempty"`
PayloadHash string `json:"payload_hash,omitempty"`
}

type passThroughServer struct {
events []parsedPassThrough
target string
}

Comment thread
glaslos marked this conversation as resolved.
// Dial to the source ip, acting as a proxy between the client and real source by piping the data back and forth w/o interfering w it.
func HandlePassThrough(ctx context.Context, conn net.Conn, md connection.Metadata, logger interfaces.Logger, h interfaces.Honeypot) error {
var err error
defer func() {
if err := h.ProduceTCP("passthrough", conn, md, nil, nil); err != nil {
logger.Error("failed to produce passthrough message", producer.ErrAttr(err))
}
if err := conn.Close(); err != nil {
logger.Error("failed to close incoming connection", slog.String("handler", "passthrough"), producer.ErrAttr(err))
}
}()

srcAddr := conn.RemoteAddr().String()

targetIP := conn.LocalAddr()
Comment thread
namay26 marked this conversation as resolved.
Outdated
destAddr := fmt.Sprintf("%s", targetIP)

fmt.Println("src : ", srcAddr, ", dest : ", destAddr)
Comment thread
namay26 marked this conversation as resolved.
Outdated

if destAddr == "" {
logger.Error("no target defined", slog.String("handler", "passthrough"))
return nil
}

targetConn, err := net.Dial("tcp", string(destAddr))
Comment thread
namay26 marked this conversation as resolved.
Outdated
if err != nil {
logger.Error("failed to connect to the target", slog.String("handler", "passthrough"), slog.String("target", string(destAddr)), producer.ErrAttr(err))
Comment thread
namay26 marked this conversation as resolved.
Outdated
return nil
}
defer targetConn.Close()

logger.Info("starting passthrough", slog.String("source", srcAddr), slog.String("target", string(destAddr)), slog.String("handler", "passthrough"))

errChan := make(chan error, 2)

// Source to target
go func() {
buf := make([]byte, 4096)
for {
n, err := conn.Read(buf)
if err != nil {
errChan <- err
return
}
if n > 0 {
logger.Info("source to target", slog.String("payload", string(buf[:n])))
if _, err := targetConn.Write(buf[:n]); err != nil {
errChan <- err
return
}
}
}
}()

go func() {
buf := make([]byte, 4096)
for {
n, err := targetConn.Read(buf)
if err != nil {
errChan <- err
return
}
if n > 0 {
logger.Info("target to source", slog.String("payload", string(buf[:n])))
if _, err := conn.Write(buf[:n]); err != nil {
errChan <- err
return
}
}

}
}()

// When either of the error is returned or no more data is left to be sent, the go routines exit.
select {
case err := <-errChan:
if err != nil && err != io.EOF {
logger.Error("transfer error", producer.ErrAttr(err))
return err
}
case <-ctx.Done():
logger.Info("context cancelled")
return ctx.Err()
}

logger.Info("Passthrough completed successfully")
return nil
}
9 changes: 6 additions & 3 deletions rules/rules.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ type RuleType int
const (
UserConnHandler RuleType = iota
Drop
Passthrough
)

type Config struct {
Expand All @@ -32,7 +33,7 @@ type Rule struct {
Name string `yaml:"name,omitempty"`

isInit bool
ruleType RuleType
RuleType RuleType
index int
matcher *pcap.BPF
}
Expand All @@ -59,9 +60,11 @@ func (rule *Rule) init(idx int) error {

switch rule.Type {
case "conn_handler":
rule.ruleType = UserConnHandler
rule.RuleType = UserConnHandler
case "passthrough":
rule.RuleType = Passthrough
case "drop":
rule.ruleType = Drop
rule.RuleType = Drop
default:
return fmt.Errorf("unknown rule type: %s", rule.Type)
}
Expand Down