diff --git a/.github/dependabot.yml b/.github/dependabot.yml index b444581..3938344 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -1,11 +1,6 @@ -# To get started with Dependabot version updates, you'll need to specify which -# package ecosystems to update and where the package manifests are located. -# Please see the documentation for all configuration options: -# https://docs.github.com/github/administering-a-repository/configuration-options-for-dependency-updates - version: 2 updates: - - package-ecosystem: "gomod" # See documentation for possible values - directory: "/" # Location of package manifests + - package-ecosystem: "gomod" + directory: "/" schedule: interval: "daily" diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 6fc69ca..f43477b 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -40,7 +40,7 @@ jobs: echo "Quality Gate: checking test coverage is above threshold ..." echo "Threshold : $TESTCOVERAGE_THRESHOLD %" # Excluded the concrete strategy - cat coverage.tmp.out | grep -v "secureShellStrategy.go" | grep -v "hypertextTransferProtocolStrategy.go" > coverage.out + cat coverage.tmp.out | grep -v "secureShellStrategy.go" | grep -v "hypertextTransferProtocolStrategy.go" | grep -v "transmissionControlProtocolStrategy.go" > coverage.out totalCoverage=`go tool cover -func=coverage.out | grep total | grep -Eo '[0-9]+\.[0-9]+'` echo "Current test coverage : $totalCoverage %" if (( $(echo "$totalCoverage $TESTCOVERAGE_THRESHOLD" | awk '{print ($1 > $2)}') )); then diff --git a/README.md b/README.md index d587439..35b32dd 100644 --- a/README.md +++ b/README.md @@ -25,6 +25,12 @@ $ go build $ ./beelzebub ``` +Unit Test: + +```bash +$ go test ./... + ``` + ## Example configuration service The configurations are inside the /configurations/services directory, just add a new file for each service/port. @@ -116,6 +122,7 @@ deadlineTimeoutSeconds: 60 - SSH Honeypot - HTTP Honeypot +- TCP Honeypot - Easy to create a new strategy - Easy to extend event tracking logic - Strong code quality @@ -125,7 +132,12 @@ deadlineTimeoutSeconds: 60 ## TODO - telnet -- tcp +- UDP + +# ROADMAP + +- SaaS Platform + ## Documentation diff --git a/configurations/services/tcp-3306.yaml b/configurations/services/tcp-3306.yaml new file mode 100644 index 0000000..b3e9ec5 --- /dev/null +++ b/configurations/services/tcp-3306.yaml @@ -0,0 +1,6 @@ +apiVersion: "v1" +protocol: "tcp" +address: ":3306" +description: "Mysql 8.0.29" +banner: "8.0.29" +deadlineTimeoutSeconds: 10 \ No newline at end of file diff --git a/docker-compose.yml b/docker-compose.yml index 48eb8df..f40a391 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -10,6 +10,7 @@ services: - "22:22" - "8080:8080" - "80:80" + - "3306:3306" environment: RABBITMQ_URI: ${RABBITMQ_URI} volumes: diff --git a/main.go b/main.go index 3b28ee7..60ff49c 100644 --- a/main.go +++ b/main.go @@ -45,6 +45,7 @@ func main() { // Init Protocol strategies secureShellStrategy := &protocols.SecureShellStrategy{} hypertextTransferProtocolStrategy := &protocols.HypertextTransferProtocolStrategy{} + transmissionControlProtocolStrategy := &protocols.TransmissionControlProtocolStrategy{} // Init protocol manager, with simple log on stout trace strategy and default protocol HTTP protocolManager := protocols.InitProtocolManager(traceStrategyStdoutAndRabbitMQ, hypertextTransferProtocolStrategy) @@ -57,6 +58,9 @@ func main() { case "ssh": protocolManager.SetProtocolStrategy(secureShellStrategy) break + case "tcp": + protocolManager.SetProtocolStrategy(transmissionControlProtocolStrategy) + break default: log.Fatalf("Protocol %s not managed", beelzebubServiceConfiguration.Protocol) continue diff --git a/parser/configurationsParser.go b/parser/configurationsParser.go index 8b5e837..11d375f 100644 --- a/parser/configurationsParser.go +++ b/parser/configurationsParser.go @@ -38,6 +38,7 @@ type BeelzebubServiceConfiguration struct { DeadlineTimeoutSeconds int `yaml:"deadlineTimeoutSeconds"` PasswordRegex string `yaml:"passwordRegex"` Description string `yaml:"description"` + Banner string `yaml:"banner"` } type Command struct { diff --git a/protocols/transmissionControlProtocolStrategy.go b/protocols/transmissionControlProtocolStrategy.go new file mode 100644 index 0000000..53b0b96 --- /dev/null +++ b/protocols/transmissionControlProtocolStrategy.go @@ -0,0 +1,57 @@ +package protocols + +import ( + "beelzebub/parser" + "beelzebub/tracer" + "fmt" + "github.com/google/uuid" + log "github.com/sirupsen/logrus" + "net" + "time" +) + +type TransmissionControlProtocolStrategy struct { +} + +func (TCPStrategy *TransmissionControlProtocolStrategy) Init(beelzebubServiceConfiguration parser.BeelzebubServiceConfiguration, tr tracer.Tracer) error { + listen, err := net.Listen("tcp", beelzebubServiceConfiguration.Address) + if err != nil { + log.Errorf("Error during init TCP Protocol: %s", err.Error()) + return err + } + + go func() { + for { + if conn, err := listen.Accept(); err == nil { + go func() { + conn.SetDeadline(time.Now().Add(time.Duration(beelzebubServiceConfiguration.DeadlineTimeoutSeconds) * time.Second)) + conn.Write([]byte(fmt.Sprintf("%s\n", beelzebubServiceConfiguration.Banner))) + + buffer := make([]byte, 1024) + command := "" + + if n, err := conn.Read(buffer); err == nil { + command = string(buffer[:n]) + } + + tr.TraceEvent(tracer.Event{ + Msg: "New TCP attempt", + Protocol: tracer.TCP.String(), + Command: command, + Status: tracer.Stateless.String(), + RemoteAddr: conn.RemoteAddr().String(), + ID: uuid.New().String(), + Description: beelzebubServiceConfiguration.Description, + }) + conn.Close() + }() + } + } + }() + + log.WithFields(log.Fields{ + "port": beelzebubServiceConfiguration.Address, + "banner": beelzebubServiceConfiguration.Banner, + }).Infof("Init service %s", beelzebubServiceConfiguration.Protocol) + return nil +} diff --git a/tracer/tracer.go b/tracer/tracer.go index cc05355..9c6f0d8 100644 --- a/tracer/tracer.go +++ b/tracer/tracer.go @@ -52,10 +52,11 @@ type Protocol int const ( HTTP Protocol = iota SSH + TCP ) func (status Protocol) String() string { - return [...]string{"HTTP", "SSH"}[status] + return [...]string{"HTTP", "SSH", "TCP"}[status] } type Status int