mirror of
https://github.com/mariocandela/beelzebub.git
synced 2025-07-01 18:47:26 -04:00
Compare commits
39 Commits
Author | SHA1 | Date | |
---|---|---|---|
59f40a166b | |||
93d7804ba3 | |||
24b4153e77 | |||
1d90c83678 | |||
67829655f4 | |||
9ad21e138b | |||
8ab11e6ac2 | |||
965942609d | |||
b8d77983ee | |||
b332f85230 | |||
b1de020de8 | |||
05b49051db | |||
3555ea9d3b | |||
d4fe0f96bd | |||
6e26f76c51 | |||
b2a7a527ff | |||
1c650882b6 | |||
ada0a9b8f0 | |||
ccd160f7b0 | |||
67d9ea7168 | |||
b441f8f9ab | |||
0b9aa8b965 | |||
c7bd863b36 | |||
e2d1cc6087 | |||
5bb7a96b39 | |||
ab7cefdb18 | |||
34159ca06f | |||
fd2bbe6be6 | |||
9076dfa47c | |||
2b90c4a1f5 | |||
90004e7d84 | |||
9e042e33f5 | |||
5e5d0494a9 | |||
d77aa0c8a0 | |||
3733c902b9 | |||
07ffdd839f | |||
1f48f4dff5 | |||
88a96a7efd | |||
34a80b06f3 |
5
.github/workflows/ci.yml
vendored
5
.github/workflows/ci.yml
vendored
@ -51,6 +51,11 @@ jobs:
|
||||
exit 1
|
||||
fi
|
||||
|
||||
- name: Upload coverage reports to Codecov
|
||||
uses: codecov/codecov-action@v3
|
||||
env:
|
||||
CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }}
|
||||
|
||||
- name: Start integration test dependencies
|
||||
run: |
|
||||
make test.dependencies.start
|
||||
|
12
README.md
12
README.md
@ -1,6 +1,10 @@
|
||||
# Beelzebub
|
||||
|
||||
[](https://github.com/mariocandela/beelzebub/actions/workflows/ci.yml) [](https://github.com/mariocandela/beelzebub/actions/workflows/docker-image.yml) [](https://github.com/mariocandela/beelzebub/actions/workflows/codeql.yml)
|
||||
[](https://goreportcard.com/report/github.com/mariocandela/beelzebub/v3)
|
||||
[](https://codecov.io/gh/mariocandela/beelzebub)
|
||||
[](https://pkg.go.dev/github.com/mariocandela/beelzebub/v3)
|
||||
[](https://github.com/avelino/awesome-go)
|
||||
|
||||
## Overview
|
||||
|
||||
@ -8,9 +12,9 @@ Beelzebub is an advanced honeypot framework designed to provide a highly secure
|
||||
|
||||
<img src="https://beelzebub.netlify.app/go-beelzebub.png" alt="Beelzebub Logo" width="200"/>
|
||||
|
||||
## OpenAI GPT Integration
|
||||
## LLM Honeypot
|
||||
|
||||
Learn how to integrate Beelzebub with OpenAI GPT-3 by referring to our comprehensive guide on Medium: [Medium Article](https://medium.com/@mario.candela.personal/how-to-build-a-highly-effective-honeypot-with-beelzebub-and-chatgpt-a2f0f05b3e1)
|
||||
Learn how to integrate Beelzebub with LLM OpenAI by referring to our comprehensive guide on Medium: [Medium Article](https://medium.com/@mario.candela.personal/how-to-build-a-highly-effective-honeypot-with-beelzebub-and-chatgpt-a2f0f05b3e1)
|
||||
|
||||
## Telegram Bot for Real-Time Attacks
|
||||
|
||||
@ -90,7 +94,9 @@ $ make test.unit
|
||||
To run integration tests:
|
||||
|
||||
```bash
|
||||
$ make test.dependencies.start
|
||||
$ make test.integration
|
||||
$ make test.dependencies.down
|
||||
```
|
||||
|
||||
## Key Features
|
||||
@ -218,7 +224,7 @@ serverName: "ubuntu"
|
||||
passwordRegex: "^(root|qwerty|Smoker666|123456|jenkins|minecraft|sinus|alex|postgres|Ly123456)$"
|
||||
deadlineTimeoutSeconds: 60
|
||||
plugin:
|
||||
openAPIChatGPTSecretKey: "Your OpenAI Secret Key"
|
||||
openAISecretKey: "Your OpenAI Secret Key"
|
||||
```
|
||||
|
||||
###### SSH Honeypot on Port 22
|
||||
|
@ -3,10 +3,10 @@ package builder
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"github.com/mariocandela/beelzebub/parser"
|
||||
"github.com/mariocandela/beelzebub/protocols"
|
||||
"github.com/mariocandela/beelzebub/protocols/strategies"
|
||||
"github.com/mariocandela/beelzebub/tracer"
|
||||
"github.com/mariocandela/beelzebub/v3/parser"
|
||||
"github.com/mariocandela/beelzebub/v3/protocols"
|
||||
"github.com/mariocandela/beelzebub/v3/protocols/strategies"
|
||||
"github.com/mariocandela/beelzebub/v3/tracer"
|
||||
"io"
|
||||
"net/http"
|
||||
"os"
|
||||
|
@ -3,8 +3,9 @@ package builder
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"github.com/mariocandela/beelzebub/parser"
|
||||
"github.com/mariocandela/beelzebub/tracer"
|
||||
"github.com/mariocandela/beelzebub/v3/parser"
|
||||
"github.com/mariocandela/beelzebub/v3/plugins"
|
||||
"github.com/mariocandela/beelzebub/v3/tracer"
|
||||
|
||||
amqp "github.com/rabbitmq/amqp091-go"
|
||||
log "github.com/sirupsen/logrus"
|
||||
@ -37,6 +38,10 @@ func (d *Director) BuildBeelzebub(beelzebubCoreConfigurations *parser.BeelzebubC
|
||||
}
|
||||
}
|
||||
|
||||
if beelzebubCoreConfigurations.Core.Tracings.BeelzebubCloud.Enabled {
|
||||
d.builder.setTraceStrategy(d.beelzebubCloudStrategy)
|
||||
}
|
||||
|
||||
return d.builder.build(), nil
|
||||
}
|
||||
|
||||
@ -47,6 +52,27 @@ func (d *Director) standardOutStrategy(event tracer.Event) {
|
||||
}).Info("New Event")
|
||||
}
|
||||
|
||||
func (d *Director) beelzebubCloudStrategy(event tracer.Event) {
|
||||
log.WithFields(log.Fields{
|
||||
"status": event.Status,
|
||||
"event": event,
|
||||
}).Info("New Event")
|
||||
|
||||
conf := d.builder.beelzebubCoreConfigurations.Core.Tracings.BeelzebubCloud
|
||||
|
||||
beelzebubCloud := plugins.InitBeelzebubCloud(conf.URI, conf.AuthToken)
|
||||
|
||||
result, err := beelzebubCloud.SendEvent(event)
|
||||
if err != nil {
|
||||
log.Error(err.Error())
|
||||
} else {
|
||||
log.WithFields(log.Fields{
|
||||
"status": result,
|
||||
"event": event,
|
||||
}).Debug("Event published on beelzebub cloud")
|
||||
}
|
||||
}
|
||||
|
||||
func (d *Director) rabbitMQTraceStrategy(event tracer.Event) {
|
||||
log.WithFields(log.Fields{
|
||||
"status": event.Status,
|
||||
|
@ -8,6 +8,10 @@ core:
|
||||
rabbit-mq:
|
||||
enabled: false
|
||||
uri: ""
|
||||
beelzebub-cloud:
|
||||
enabled: false
|
||||
uri: ""
|
||||
auth-token: ""
|
||||
prometheus:
|
||||
path: "/metrics"
|
||||
port: ":2112"
|
||||
|
@ -4,10 +4,10 @@ address: ":2222"
|
||||
description: "SSH interactive ChatGPT"
|
||||
commands:
|
||||
- regex: "^(.+)$"
|
||||
plugin: "OpenAIGPTLinuxTerminal"
|
||||
plugin: "LLMHoneypot"
|
||||
serverVersion: "OpenSSH"
|
||||
serverName: "ubuntu"
|
||||
passwordRegex: "^(root|qwerty|Smoker666|123456|jenkins|minecraft|sinus|alex|postgres|Ly123456)$"
|
||||
deadlineTimeoutSeconds: 60
|
||||
plugin:
|
||||
openAPIChatGPTSecretKey: ""
|
||||
openAISecretKey: ""
|
33
go.mod
33
go.mod
@ -1,18 +1,18 @@
|
||||
module github.com/mariocandela/beelzebub
|
||||
module github.com/mariocandela/beelzebub/v3
|
||||
|
||||
go 1.20
|
||||
|
||||
require (
|
||||
github.com/gliderlabs/ssh v0.3.5
|
||||
github.com/go-resty/resty/v2 v2.9.1
|
||||
github.com/google/uuid v1.3.1
|
||||
github.com/gliderlabs/ssh v0.3.7
|
||||
github.com/go-resty/resty/v2 v2.13.1
|
||||
github.com/google/uuid v1.6.0
|
||||
github.com/jarcoal/httpmock v1.3.1
|
||||
github.com/melbahja/goph v1.4.0
|
||||
github.com/prometheus/client_golang v1.17.0
|
||||
github.com/rabbitmq/amqp091-go v1.9.0
|
||||
github.com/prometheus/client_golang v1.19.1
|
||||
github.com/rabbitmq/amqp091-go v1.10.0
|
||||
github.com/sirupsen/logrus v1.9.3
|
||||
github.com/stretchr/testify v1.8.4
|
||||
golang.org/x/crypto v0.14.0
|
||||
github.com/stretchr/testify v1.9.0
|
||||
golang.org/x/crypto v0.24.0
|
||||
gopkg.in/yaml.v3 v3.0.1
|
||||
)
|
||||
|
||||
@ -21,17 +21,16 @@ require (
|
||||
github.com/beorn7/perks v1.0.1 // indirect
|
||||
github.com/cespare/xxhash/v2 v2.2.0 // indirect
|
||||
github.com/davecgh/go-spew v1.1.1 // indirect
|
||||
github.com/golang/protobuf v1.5.3 // indirect
|
||||
github.com/kr/fs v0.1.0 // indirect
|
||||
github.com/matttproud/golang_protobuf_extensions v1.0.4 // indirect
|
||||
github.com/kr/text v0.2.0 // indirect
|
||||
github.com/pkg/errors v0.9.1 // indirect
|
||||
github.com/pkg/sftp v1.13.5 // indirect
|
||||
github.com/pmezard/go-difflib v1.0.0 // indirect
|
||||
github.com/prometheus/client_model v0.4.1-0.20230718164431-9a2bf3000d16 // indirect
|
||||
github.com/prometheus/common v0.44.0 // indirect
|
||||
github.com/prometheus/procfs v0.11.1 // indirect
|
||||
golang.org/x/net v0.15.0 // indirect
|
||||
golang.org/x/sys v0.13.0 // indirect
|
||||
golang.org/x/term v0.13.0 // indirect
|
||||
google.golang.org/protobuf v1.31.0 // indirect
|
||||
github.com/prometheus/client_model v0.5.0 // indirect
|
||||
github.com/prometheus/common v0.48.0 // indirect
|
||||
github.com/prometheus/procfs v0.12.0 // indirect
|
||||
golang.org/x/net v0.25.0 // indirect
|
||||
golang.org/x/sys v0.21.0 // indirect
|
||||
golang.org/x/term v0.21.0 // indirect
|
||||
google.golang.org/protobuf v1.33.0 // indirect
|
||||
)
|
||||
|
105
go.sum
105
go.sum
@ -4,32 +4,24 @@ github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM=
|
||||
github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=
|
||||
github.com/cespare/xxhash/v2 v2.2.0 h1:DC2CZ1Ep5Y4k3ZQ899DldepgrayRUGE6BBZ/cd9Cj44=
|
||||
github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
|
||||
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
|
||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/gliderlabs/ssh v0.3.5 h1:OcaySEmAQJgyYcArR+gGGTHCyE7nvhEMTlYY+Dp8CpY=
|
||||
github.com/gliderlabs/ssh v0.3.5/go.mod h1:8XB4KraRrX39qHhT6yxPsHedjA08I/uBVwj4xC+/+z4=
|
||||
github.com/go-resty/resty/v2 v2.9.1 h1:PIgGx4VrHvag0juCJ4dDv3MiFRlDmP0vicBucwf+gLM=
|
||||
github.com/go-resty/resty/v2 v2.9.1/go.mod h1:4/GYJVjh9nhkhGR6AUNW3XhpDYNUr+Uvy9gV/VGZIy4=
|
||||
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||
github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
|
||||
github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg=
|
||||
github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
|
||||
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38=
|
||||
github.com/google/uuid v1.3.1 h1:KjJaJ9iWZ3jOFZIf1Lqf4laDRCasjl0BCmnEGxkdLb4=
|
||||
github.com/google/uuid v1.3.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||
github.com/gliderlabs/ssh v0.3.7 h1:iV3Bqi942d9huXnzEF2Mt+CY9gLu8DNM4Obd+8bODRE=
|
||||
github.com/gliderlabs/ssh v0.3.7/go.mod h1:zpHEXBstFnQYtGnB8k8kQLol82umzn/2/snG7alWVD8=
|
||||
github.com/go-resty/resty/v2 v2.13.1 h1:x+LHXBI2nMB1vqndymf26quycC4aggYJ7DECYbiz03g=
|
||||
github.com/go-resty/resty/v2 v2.13.1/go.mod h1:GznXlLxkq6Nh4sU59rPmUw3VtgpO3aS96ORAI6Q7d+0=
|
||||
github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
|
||||
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
|
||||
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||
github.com/jarcoal/httpmock v1.3.1 h1:iUx3whfZWVf3jT01hQTO/Eo5sAYtB2/rqaUuOtpInww=
|
||||
github.com/jarcoal/httpmock v1.3.1/go.mod h1:3yb8rc4BI7TCBhFY8ng0gjuLKJNquuDNiPaZjnENuYg=
|
||||
github.com/kr/fs v0.1.0 h1:Jskdu9ieNAYnjxsi0LbQp1ulIKZV1LAFgK1tWhpZgl8=
|
||||
github.com/kr/fs v0.1.0/go.mod h1:FFnZGqtBN9Gxj7eW1uZ42v5BccTP0vu6NEaFoC2HwRg=
|
||||
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
|
||||
github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
|
||||
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
|
||||
github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE=
|
||||
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
|
||||
github.com/matttproud/golang_protobuf_extensions v1.0.4 h1:mmDVorXM7PCGKw94cs5zkfA9PSy5pEvNWRP0ET0TIVo=
|
||||
github.com/matttproud/golang_protobuf_extensions v1.0.4/go.mod h1:BSXmuO+STAnVfrANrmjBb36TMTDstsz7MSK+HVaYKv4=
|
||||
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
|
||||
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
|
||||
github.com/maxatome/go-testdeep v1.12.0 h1:Ql7Go8Tg0C1D/uMMX59LAoYK7LffeJQ6X2T04nTH68g=
|
||||
github.com/melbahja/goph v1.4.0 h1:z0PgDbBFe66lRYl3v5dGb9aFgPy0kotuQ37QOwSQFqs=
|
||||
github.com/melbahja/goph v1.4.0/go.mod h1:uG+VfK2Dlhk+O32zFrRlc3kYKTlV6+BtvPWd/kK7U68=
|
||||
@ -39,49 +31,44 @@ github.com/pkg/sftp v1.13.5 h1:a3RLUqkyjYRtBTZJZ1VRrKbN3zhuPLlUc3sphVz81go=
|
||||
github.com/pkg/sftp v1.13.5/go.mod h1:wHDZ0IZX6JcBYRK1TH9bcVq8G7TLpVHYIGJRFnmPfxg=
|
||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/prometheus/client_golang v1.17.0 h1:rl2sfwZMtSthVU752MqfjQozy7blglC+1SOtjMAMh+Q=
|
||||
github.com/prometheus/client_golang v1.17.0/go.mod h1:VeL+gMmOAxkS2IqfCq0ZmHSL+LjWfWDUmp1mBz9JgUY=
|
||||
github.com/prometheus/client_model v0.4.1-0.20230718164431-9a2bf3000d16 h1:v7DLqVdK4VrYkVD5diGdl4sxJurKJEMnODWRJlxV9oM=
|
||||
github.com/prometheus/client_model v0.4.1-0.20230718164431-9a2bf3000d16/go.mod h1:oMQmHW1/JoDwqLtg57MGgP/Fb1CJEYF2imWWhWtMkYU=
|
||||
github.com/prometheus/common v0.44.0 h1:+5BrQJwiBB9xsMygAB3TNvpQKOwlkc25LbISbrdOOfY=
|
||||
github.com/prometheus/common v0.44.0/go.mod h1:ofAIvZbQ1e/nugmZGz4/qCb9Ap1VoSTIO7x0VV9VvuY=
|
||||
github.com/prometheus/procfs v0.11.1 h1:xRC8Iq1yyca5ypa9n1EZnWZkt7dwcoRPQwX/5gwaUuI=
|
||||
github.com/prometheus/procfs v0.11.1/go.mod h1:eesXgaPo1q7lBpVMoMy0ZOFTth9hBn4W/y0/p/ScXhY=
|
||||
github.com/rabbitmq/amqp091-go v1.9.0 h1:qrQtyzB4H8BQgEuJwhmVQqVHB9O4+MNDJCCAcpc3Aoo=
|
||||
github.com/rabbitmq/amqp091-go v1.9.0/go.mod h1:+jPrT9iY2eLjRaMSRHUhc3z14E/l85kv/f+6luSD3pc=
|
||||
github.com/prometheus/client_golang v1.19.1 h1:wZWJDwK+NameRJuPGDhlnFgx8e8HN3XHQeLaYJFJBOE=
|
||||
github.com/prometheus/client_golang v1.19.1/go.mod h1:mP78NwGzrVks5S2H6ab8+ZZGJLZUq1hoULYBAYBw1Ho=
|
||||
github.com/prometheus/client_model v0.5.0 h1:VQw1hfvPvk3Uv6Qf29VrPF32JB6rtbgI6cYPYQjL0Qw=
|
||||
github.com/prometheus/client_model v0.5.0/go.mod h1:dTiFglRmd66nLR9Pv9f0mZi7B7fk5Pm3gvsjB5tr+kI=
|
||||
github.com/prometheus/common v0.48.0 h1:QO8U2CdOzSn1BBsmXJXduaaW+dY/5QLjfB8svtSzKKE=
|
||||
github.com/prometheus/common v0.48.0/go.mod h1:0/KsvlIEfPQCQ5I2iNSAWKPZziNCvRs5EC6ILDTlAPc=
|
||||
github.com/prometheus/procfs v0.12.0 h1:jluTpSng7V9hY0O2R9DzzJHYb2xULk9VTR1V1R/k6Bo=
|
||||
github.com/prometheus/procfs v0.12.0/go.mod h1:pcuDEFsWDnvcgNzo4EEweacyhjeA9Zk3cnaOZAZEfOo=
|
||||
github.com/rabbitmq/amqp091-go v1.10.0 h1:STpn5XsHlHGcecLmMFCtg7mqq0RnD+zFr4uzukfVhBw=
|
||||
github.com/rabbitmq/amqp091-go v1.10.0/go.mod h1:Hy4jKW5kQART1u+JkDTF9YYOQUHXqMuhrgxOEeS7G4o=
|
||||
github.com/rogpeppe/go-internal v1.10.0 h1:TMyTOH3F/DB16zRVcYyreMH6GnZZrwQVAoYjRBZyWFQ=
|
||||
github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ=
|
||||
github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ=
|
||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
|
||||
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
|
||||
github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk=
|
||||
github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
|
||||
github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg=
|
||||
github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
|
||||
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
|
||||
go.uber.org/goleak v1.2.1 h1:NBol2c7O1ZokfZ0LEU9K6Whx/KnwvepVetCUhtKja4A=
|
||||
go.uber.org/goleak v1.2.1/go.mod h1:qlT2yGI9QafXHhZZLxlSuNsMw3FFLxBr+tBRlmO1xH4=
|
||||
go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto=
|
||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
|
||||
golang.org/x/crypto v0.0.0-20211215153901-e495a2d5b3d3/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
|
||||
golang.org/x/crypto v0.0.0-20220826181053-bd7e27e6170d/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
|
||||
golang.org/x/crypto v0.6.0/go.mod h1:OFC/31mSvZgRz0V1QTNCzfAI1aIRzbiufJtkMIlEp58=
|
||||
golang.org/x/crypto v0.13.0/go.mod h1:y6Z2r+Rw4iayiXXAIxJIDAJ1zMW4yaTpebo8fPOliYc=
|
||||
golang.org/x/crypto v0.14.0 h1:wBqGXzWJW6m1XrIKlAH0Hs1JJ7+9KBwnIO8v66Q9cHc=
|
||||
golang.org/x/crypto v0.14.0/go.mod h1:MVFd36DqK4CsrnJYDkBA3VC4m2GkXAM0PvzMCn4JQf4=
|
||||
golang.org/x/crypto v0.19.0/go.mod h1:Iy9bg/ha4yyC70EfRS8jz+B6ybOBKMaSxLj6P6oBDfU=
|
||||
golang.org/x/crypto v0.23.0/go.mod h1:CKFgDieR+mRhux2Lsu27y0fO304Db0wZe70UKqHu0v8=
|
||||
golang.org/x/crypto v0.24.0 h1:mnl8DM0o513X8fdIkmyFE/5hTYxbwYOjDS/+rK6qpRI=
|
||||
golang.org/x/crypto v0.24.0/go.mod h1:Z1PMYSOR5nyMcyAVAIQSKCDwalqy85Aqn1x3Ws4L5DM=
|
||||
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
|
||||
golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
|
||||
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
|
||||
golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||
golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
|
||||
golang.org/x/net v0.0.0-20220826154423-83b083e8dc8b/go.mod h1:YDH+HFinaLZZlnHAfSS6ZXJJ9M9t4Dl22yv3iI2vPwk=
|
||||
golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
|
||||
golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg=
|
||||
golang.org/x/net v0.15.0 h1:ugBLEUaxABaB5AJqW9enI0ACdci2RUd4eP51NTBvuJ8=
|
||||
golang.org/x/net v0.15.0/go.mod h1:idbUs1IY1+zTqbi8yxTbhexhEEk5ur9LInksu6HrEpk=
|
||||
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/net v0.21.0/go.mod h1:bIjVDfnllIU7BJ2DNgfnXvpSvtn8VRwhlsaeUTyUS44=
|
||||
golang.org/x/net v0.25.0 h1:d/OCCoBEUq33pjydKrGQhw7IlUPI2Oylr+8qLx49kac=
|
||||
golang.org/x/net v0.25.0/go.mod h1:JkAGAh7GEvH74S6FOH42FLoXpXbE/aqXSrIQjXgsiwM=
|
||||
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
@ -93,42 +80,38 @@ golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBc
|
||||
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220728004956-3c1f35247d10/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220825204002-c680a09ffe64/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.13.0 h1:Af8nKPmuFypiUBjVoU9V20FiaFXOcuZI21p0ycVYYGE=
|
||||
golang.org/x/sys v0.13.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/sys v0.20.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/sys v0.21.0 h1:rF+pYz3DAGSQAxAu1CbC7catZg4ebC4UIeIhKxBZvws=
|
||||
golang.org/x/sys v0.21.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
||||
golang.org/x/term v0.0.0-20220722155259-a9ba230a4035/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
||||
golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k=
|
||||
golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo=
|
||||
golang.org/x/term v0.12.0/go.mod h1:owVbMEjm3cBLCHdkQu9b1opXd4ETQWc3BhuQGKgXgvU=
|
||||
golang.org/x/term v0.13.0 h1:bb+I9cTfFazGW51MZqBVmZy7+JEJMouUHTUSKVQLBek=
|
||||
golang.org/x/term v0.13.0/go.mod h1:LTmsnFJwVN6bCy1rVCoS+qHT1HhALEFxKncY3WNNh4U=
|
||||
golang.org/x/term v0.17.0/go.mod h1:lLRBjIVuehSbZlaOtGMbcMncT+aqLLLmKrsjNrUguwk=
|
||||
golang.org/x/term v0.20.0/go.mod h1:8UkIAJTvZgivsXaD6/pH6U9ecQzZ45awqEOzuCvwpFY=
|
||||
golang.org/x/term v0.21.0 h1:WVXCp+/EBEHOj53Rvu+7KiT/iElMrO8ACK16SMZ3jaA=
|
||||
golang.org/x/term v0.21.0/go.mod h1:ooXLefLobQVslOqselCNF4SxFAaoS6KujMbsGzSDmX0=
|
||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
|
||||
golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
|
||||
golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
|
||||
golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
|
||||
golang.org/x/time v0.0.0-20211116232009-f0f3c7e86c11 h1:GZokNIeuVkl3aZHJchRrr13WCsols02MLUcz1U9is6M=
|
||||
golang.org/x/time v0.0.0-20211116232009-f0f3c7e86c11/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
|
||||
golang.org/x/text v0.15.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
|
||||
golang.org/x/time v0.5.0 h1:o7cqy6amK/52YcAKIPlM3a+Fpj35zvRj2TP+e1xFSfk=
|
||||
golang.org/x/time v0.5.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM=
|
||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
|
||||
golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU=
|
||||
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
|
||||
google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
|
||||
google.golang.org/protobuf v1.31.0 h1:g0LDEJHgrBl9N9r17Ru3sqWhkIx2NB67okBHPwC7hs8=
|
||||
google.golang.org/protobuf v1.31.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
|
||||
google.golang.org/protobuf v1.33.0 h1:uNO2rsAINq/JlFpSdYEKIZ0uKD/R9cpdv0T+yoGwGmI=
|
||||
google.golang.org/protobuf v1.33.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
|
||||
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
||||
|
@ -2,9 +2,9 @@ package integration
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"github.com/mariocandela/beelzebub/builder"
|
||||
"github.com/mariocandela/beelzebub/parser"
|
||||
"github.com/mariocandela/beelzebub/tracer"
|
||||
"github.com/mariocandela/beelzebub/v3/builder"
|
||||
"github.com/mariocandela/beelzebub/v3/parser"
|
||||
"github.com/mariocandela/beelzebub/v3/tracer"
|
||||
"net"
|
||||
"net/http"
|
||||
"os"
|
||||
|
4
main.go
4
main.go
@ -2,8 +2,8 @@ package main
|
||||
|
||||
import (
|
||||
"flag"
|
||||
"github.com/mariocandela/beelzebub/builder"
|
||||
"github.com/mariocandela/beelzebub/parser"
|
||||
"github.com/mariocandela/beelzebub/v3/builder"
|
||||
"github.com/mariocandela/beelzebub/v3/parser"
|
||||
|
||||
log "github.com/sirupsen/logrus"
|
||||
)
|
||||
|
@ -1,8 +1,8 @@
|
||||
// Package parser is responsible for parsing the configurations of the core and honeypot service
|
||||
package parser
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
@ -11,6 +11,7 @@ import (
|
||||
"gopkg.in/yaml.v3"
|
||||
)
|
||||
|
||||
// BeelzebubCoreConfigurations is the struct that contains the configurations of the core
|
||||
type BeelzebubCoreConfigurations struct {
|
||||
Core struct {
|
||||
Logging Logging `yaml:"logging"`
|
||||
@ -19,6 +20,7 @@ type BeelzebubCoreConfigurations struct {
|
||||
}
|
||||
}
|
||||
|
||||
// Logging is the struct that contains the configurations of the logging
|
||||
type Logging struct {
|
||||
Debug bool `yaml:"debug"`
|
||||
DebugReportCaller bool `yaml:"debugReportCaller"`
|
||||
@ -26,10 +28,17 @@ type Logging struct {
|
||||
LogsPath string `yaml:"logsPath,omitempty"`
|
||||
}
|
||||
|
||||
// Tracings is the struct that contains the configurations of the tracings
|
||||
type Tracings struct {
|
||||
RabbitMQ `yaml:"rabbit-mq"`
|
||||
RabbitMQ `yaml:"rabbit-mq"`
|
||||
BeelzebubCloud `yaml:"beelzebub-cloud"`
|
||||
}
|
||||
|
||||
type BeelzebubCloud struct {
|
||||
Enabled bool `yaml:"enabled"`
|
||||
URI string `yaml:"uri"`
|
||||
AuthToken string `yaml:"auth-token"`
|
||||
}
|
||||
type RabbitMQ struct {
|
||||
Enabled bool `yaml:"enabled"`
|
||||
URI string `yaml:"uri"`
|
||||
@ -40,9 +49,10 @@ type Prometheus struct {
|
||||
}
|
||||
|
||||
type Plugin struct {
|
||||
OpenAPIChatGPTSecretKey string `yaml:"openAPIChatGPTSecretKey"`
|
||||
OpenAISecretKey string `yaml:"openAISecretKey"`
|
||||
}
|
||||
|
||||
// BeelzebubServiceConfiguration is the struct that contains the configurations of the honeypot service
|
||||
type BeelzebubServiceConfiguration struct {
|
||||
ApiVersion string `yaml:"apiVersion"`
|
||||
Protocol string `yaml:"protocol"`
|
||||
@ -57,6 +67,7 @@ type BeelzebubServiceConfiguration struct {
|
||||
Plugin Plugin `yaml:"plugin"`
|
||||
}
|
||||
|
||||
// Command is the struct that contains the configurations of the commands
|
||||
type Command struct {
|
||||
Regex string `yaml:"regex"`
|
||||
Handler string `yaml:"handler"`
|
||||
@ -86,6 +97,7 @@ func Init(configurationsCorePath, configurationsServicesDirectory string) *confi
|
||||
}
|
||||
}
|
||||
|
||||
// ReadConfigurationsCore is the method that reads the configurations of the core from files
|
||||
func (bp configurationsParser) ReadConfigurationsCore() (*BeelzebubCoreConfigurations, error) {
|
||||
buf, err := bp.readFileBytesByFilePathDependency(bp.configurationsCorePath)
|
||||
if err != nil {
|
||||
@ -101,6 +113,7 @@ func (bp configurationsParser) ReadConfigurationsCore() (*BeelzebubCoreConfigura
|
||||
return beelzebubConfiguration, nil
|
||||
}
|
||||
|
||||
// ReadConfigurationsServices is the method that reads the configurations of the honeypot services from files
|
||||
func (bp configurationsParser) ReadConfigurationsServices() ([]BeelzebubServiceConfiguration, error) {
|
||||
services, err := bp.gelAllFilesNameByDirNameDependency(bp.configurationsServicesDirectory)
|
||||
if err != nil {
|
||||
@ -127,7 +140,7 @@ func (bp configurationsParser) ReadConfigurationsServices() ([]BeelzebubServiceC
|
||||
}
|
||||
|
||||
func gelAllFilesNameByDirName(dirName string) ([]string, error) {
|
||||
files, err := ioutil.ReadDir(dirName)
|
||||
files, err := os.ReadDir(dirName)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -2,6 +2,7 @@ package parser
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"os"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
@ -18,7 +19,11 @@ core:
|
||||
tracings:
|
||||
rabbit-mq:
|
||||
enabled: true
|
||||
uri: "amqp://user:password@localhost/"`)
|
||||
uri: "amqp://user:password@localhost/"
|
||||
beelzebub-cloud:
|
||||
enabled: true
|
||||
uri: "amqp://user:password@localhost/"
|
||||
auth-token: "iejfdjsl-aosdajosoidaj-dunfkjnfkjsdnkn"`)
|
||||
return configurationsCoreBytes, nil
|
||||
}
|
||||
|
||||
@ -84,6 +89,9 @@ func TestReadConfigurationsCoreValid(t *testing.T) {
|
||||
assert.Equal(t, coreConfigurations.Core.Logging.LogsPath, "./logs")
|
||||
assert.Equal(t, coreConfigurations.Core.Tracings.RabbitMQ.Enabled, true)
|
||||
assert.Equal(t, coreConfigurations.Core.Tracings.RabbitMQ.URI, "amqp://user:password@localhost/")
|
||||
assert.Equal(t, coreConfigurations.Core.Tracings.BeelzebubCloud.Enabled, true)
|
||||
assert.Equal(t, coreConfigurations.Core.Tracings.BeelzebubCloud.URI, "amqp://user:password@localhost/")
|
||||
assert.Equal(t, coreConfigurations.Core.Tracings.BeelzebubCloud.AuthToken, "iejfdjsl-aosdajosoidaj-dunfkjnfkjsdnkn")
|
||||
}
|
||||
|
||||
func TestReadConfigurationsServicesFail(t *testing.T) {
|
||||
@ -118,3 +126,54 @@ func TestReadConfigurationsServicesValid(t *testing.T) {
|
||||
assert.Equal(t, len(firstBeelzebubServiceConfiguration.Commands[0].Headers), 1)
|
||||
assert.Equal(t, firstBeelzebubServiceConfiguration.Commands[0].Headers[0], "Content-Type: text/html")
|
||||
}
|
||||
|
||||
func TestGelAllFilesNameByDirName(t *testing.T) {
|
||||
|
||||
var dir = t.TempDir()
|
||||
|
||||
files, err := gelAllFilesNameByDirName(dir)
|
||||
|
||||
assert.Nil(t, err)
|
||||
assert.Equal(t, 0, len(files))
|
||||
}
|
||||
|
||||
func TestGelAllFilesNameByDirNameFiles(t *testing.T) {
|
||||
|
||||
var dir = t.TempDir()
|
||||
|
||||
testFiles := []string{"file1.yaml", "file2.yaml", "file3.txt", "subdir", "file4.yaml"}
|
||||
for _, filename := range testFiles {
|
||||
filePath := dir + "/" + filename
|
||||
file, err := os.Create(filePath)
|
||||
assert.NoError(t, err)
|
||||
file.Close()
|
||||
}
|
||||
|
||||
files, err := gelAllFilesNameByDirName(dir)
|
||||
|
||||
assert.Nil(t, err)
|
||||
assert.Equal(t, 3, len(files))
|
||||
}
|
||||
|
||||
func TestGelAllFilesNameByDirNameError(t *testing.T) {
|
||||
|
||||
files, err := gelAllFilesNameByDirName("nosuchfile")
|
||||
|
||||
assert.Nil(t, files)
|
||||
assert.Equal(t, "open nosuchfile: no such file or directory", err.Error())
|
||||
}
|
||||
|
||||
func TestReadFileBytesByFilePath(t *testing.T) {
|
||||
|
||||
var dir = t.TempDir()
|
||||
filePath := dir + "/test.yaml"
|
||||
|
||||
f, err := os.Create(filePath)
|
||||
assert.NoError(t, err)
|
||||
f.Close()
|
||||
|
||||
bytes, err := readFileBytesByFilePath(filePath)
|
||||
assert.NoError(t, err)
|
||||
|
||||
assert.Equal(t, "", string(bytes))
|
||||
}
|
||||
|
49
plugins/beelzebub-cloud.go
Normal file
49
plugins/beelzebub-cloud.go
Normal file
@ -0,0 +1,49 @@
|
||||
package plugins
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"github.com/go-resty/resty/v2"
|
||||
"github.com/mariocandela/beelzebub/v3/tracer"
|
||||
log "github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
type beelzebubCloud struct {
|
||||
URI string
|
||||
AuthToken string
|
||||
client *resty.Client
|
||||
}
|
||||
|
||||
func InitBeelzebubCloud(uri, authToken string) *beelzebubCloud {
|
||||
return &beelzebubCloud{
|
||||
URI: uri,
|
||||
AuthToken: authToken,
|
||||
client: resty.New(),
|
||||
}
|
||||
}
|
||||
|
||||
func (beelzebubCloud *beelzebubCloud) SendEvent(event tracer.Event) (bool, error) {
|
||||
requestJson, err := json.Marshal(event)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
if beelzebubCloud.AuthToken == "" {
|
||||
return false, errors.New("authToken is empty")
|
||||
}
|
||||
|
||||
response, err := beelzebubCloud.client.R().
|
||||
SetHeader("Content-Type", "application/json").
|
||||
SetBody(requestJson).
|
||||
SetHeader("Authorization", beelzebubCloud.AuthToken).
|
||||
SetResult(&gptResponse{}).
|
||||
Post(beelzebubCloud.URI)
|
||||
|
||||
log.Debug(response)
|
||||
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
return response.StatusCode() == 200, nil
|
||||
}
|
71
plugins/beelzebub-cloud_test.go
Normal file
71
plugins/beelzebub-cloud_test.go
Normal file
@ -0,0 +1,71 @@
|
||||
package plugins
|
||||
|
||||
import (
|
||||
"github.com/go-resty/resty/v2"
|
||||
"github.com/jarcoal/httpmock"
|
||||
"github.com/mariocandela/beelzebub/v3/tracer"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"net/http"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestBuildSendEventFailValidation(t *testing.T) {
|
||||
beelzebubCloud := InitBeelzebubCloud("", "")
|
||||
|
||||
_, err := beelzebubCloud.SendEvent(tracer.Event{})
|
||||
|
||||
assert.Equal(t, "authToken is empty", err.Error())
|
||||
}
|
||||
|
||||
func TestBuildSendEventWithResults(t *testing.T) {
|
||||
client := resty.New()
|
||||
httpmock.ActivateNonDefault(client.GetClient())
|
||||
defer httpmock.DeactivateAndReset()
|
||||
|
||||
uri := "localhost:8081/events"
|
||||
|
||||
// Given
|
||||
httpmock.RegisterResponder("POST", uri,
|
||||
func(req *http.Request) (*http.Response, error) {
|
||||
resp, err := httpmock.NewJsonResponse(200, &tracer.Event{})
|
||||
if err != nil {
|
||||
return httpmock.NewStringResponse(500, ""), nil
|
||||
}
|
||||
return resp, nil
|
||||
},
|
||||
)
|
||||
|
||||
beelzebubCloud := InitBeelzebubCloud(uri, "sdjdnklfjndslkjanfk")
|
||||
beelzebubCloud.client = client
|
||||
|
||||
//When
|
||||
result, err := beelzebubCloud.SendEvent(tracer.Event{})
|
||||
|
||||
//Then
|
||||
assert.Equal(t, true, result)
|
||||
assert.Nil(t, err)
|
||||
}
|
||||
|
||||
func TestBuildSendEventErro(t *testing.T) {
|
||||
client := resty.New()
|
||||
httpmock.ActivateNonDefault(client.GetClient())
|
||||
defer httpmock.DeactivateAndReset()
|
||||
|
||||
uri := "localhost:8081/events"
|
||||
|
||||
// Given
|
||||
httpmock.RegisterResponder("POST", uri,
|
||||
func(req *http.Request) (*http.Response, error) {
|
||||
return httpmock.NewStringResponse(500, ""), nil
|
||||
},
|
||||
)
|
||||
|
||||
beelzebubCloud := InitBeelzebubCloud(uri, "sdjdnklfjndslkjanfk")
|
||||
beelzebubCloud.client = client
|
||||
|
||||
//When
|
||||
result, _ := beelzebubCloud.SendEvent(tracer.Event{})
|
||||
|
||||
//Then
|
||||
assert.Equal(t, false, result)
|
||||
}
|
@ -3,39 +3,28 @@ package plugins
|
||||
import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
log "github.com/sirupsen/logrus"
|
||||
|
||||
"github.com/go-resty/resty/v2"
|
||||
"github.com/mariocandela/beelzebub/v3/tracer"
|
||||
|
||||
log "github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
const (
|
||||
// Reference: https://www.engraved.blog/building-a-virtual-machine-inside/
|
||||
promptVirtualizeLinuxTerminal = "I want you to act as a Linux terminal. I will type commands and you will reply with what the terminal should show. I want you to only reply with the terminal output inside one unique code block, and nothing else. Do no write explanations. Do not type commands unless I instruct you to do so.\n\nA:pwd\n\nQ:/home/user\n\n"
|
||||
ChatGPTPluginName = "OpenAIGPTLinuxTerminal"
|
||||
openAIGPTEndpoint = "https://api.openai.com/v1/completions"
|
||||
)
|
||||
systemPromptVirtualizeLinuxTerminal = "You will act as an Ubuntu Linux terminal. The user will type commands, and you are to reply with what the terminal should show. Your responses must be contained within a single code block. Do not provide explanations or type commands unless explicitly instructed by the user. Your entire response/output is going to consist of a simple text with \n for new line, and you will NOT wrap it within string md markers"
|
||||
systemPromptVirtualizeHTTPServer = "You will act as an unsecure HTTP Server with multiple vulnerability like aws and git credentials stored into root http directory. The user will send HTTP requests, and you are to reply with what the server should show. Do not provide explanations or type commands unless explicitly instructed by the user."
|
||||
ChatGPTPluginName = "LLMHoneypot"
|
||||
openAIGPTEndpoint = "https://api.openai.com/v1/chat/completions"
|
||||
)
|
||||
|
||||
type History struct {
|
||||
Input, Output string
|
||||
}
|
||||
|
||||
type OpenAIGPTVirtualTerminal struct {
|
||||
Histories []History
|
||||
OpenAPIChatGPTSecretKey string
|
||||
client *resty.Client
|
||||
}
|
||||
|
||||
func (openAIGPTVirtualTerminal *OpenAIGPTVirtualTerminal) InjectDependency() {
|
||||
if openAIGPTVirtualTerminal.client == nil {
|
||||
openAIGPTVirtualTerminal.client = resty.New()
|
||||
}
|
||||
type openAIVirtualHoneypot struct {
|
||||
Histories []Message
|
||||
openAIKey string
|
||||
client *resty.Client
|
||||
protocol tracer.Protocol
|
||||
}
|
||||
|
||||
type Choice struct {
|
||||
Text string `json:"text"`
|
||||
Message Message `json:"message"`
|
||||
Index int `json:"index"`
|
||||
Logprobs interface{} `json:"logprobs"`
|
||||
FinishReason string `json:"finish_reason"`
|
||||
@ -55,53 +44,106 @@ type gptResponse struct {
|
||||
}
|
||||
|
||||
type gptRequest struct {
|
||||
Model string `json:"model"`
|
||||
Prompt string `json:"prompt"`
|
||||
Temperature int `json:"temperature"`
|
||||
MaxTokens int `json:"max_tokens"`
|
||||
TopP int `json:"top_p"`
|
||||
FrequencyPenalty int `json:"frequency_penalty"`
|
||||
PresencePenalty int `json:"presence_penalty"`
|
||||
Stop []string `json:"stop"`
|
||||
Model string `json:"model"`
|
||||
Messages []Message `json:"messages"`
|
||||
}
|
||||
|
||||
func buildPrompt(histories []History, command string) string {
|
||||
var sb strings.Builder
|
||||
type Message struct {
|
||||
Role string `json:"role"`
|
||||
Content string `json:"content"`
|
||||
}
|
||||
|
||||
sb.WriteString(promptVirtualizeLinuxTerminal)
|
||||
type Role int
|
||||
|
||||
for _, history := range histories {
|
||||
sb.WriteString(fmt.Sprintf("A:%s\n\nQ:%s\n\n", history.Input, history.Output))
|
||||
const (
|
||||
SYSTEM Role = iota
|
||||
USER
|
||||
ASSISTANT
|
||||
)
|
||||
|
||||
func (role Role) String() string {
|
||||
return [...]string{"system", "user", "assistant"}[role]
|
||||
}
|
||||
|
||||
func Init(history []Message, openAIKey string, protocol tracer.Protocol) *openAIVirtualHoneypot {
|
||||
return &openAIVirtualHoneypot{
|
||||
Histories: history,
|
||||
openAIKey: openAIKey,
|
||||
client: resty.New(),
|
||||
protocol: protocol,
|
||||
}
|
||||
// Append command to evaluate
|
||||
sb.WriteString(fmt.Sprintf("A:%s\n\nQ:", command))
|
||||
|
||||
return sb.String()
|
||||
}
|
||||
|
||||
func (openAIGPTVirtualTerminal *OpenAIGPTVirtualTerminal) GetCompletions(command string) (string, error) {
|
||||
func buildPrompt(histories []Message, protocol tracer.Protocol, command string) ([]Message, error) {
|
||||
var messages []Message
|
||||
|
||||
switch protocol {
|
||||
case tracer.SSH:
|
||||
messages = append(messages, Message{
|
||||
Role: SYSTEM.String(),
|
||||
Content: systemPromptVirtualizeLinuxTerminal,
|
||||
})
|
||||
messages = append(messages, Message{
|
||||
Role: USER.String(),
|
||||
Content: "pwd",
|
||||
})
|
||||
messages = append(messages, Message{
|
||||
Role: ASSISTANT.String(),
|
||||
Content: "/home/user",
|
||||
})
|
||||
for _, history := range histories {
|
||||
messages = append(messages, history)
|
||||
}
|
||||
case tracer.HTTP:
|
||||
messages = append(messages, Message{
|
||||
Role: SYSTEM.String(),
|
||||
Content: systemPromptVirtualizeHTTPServer,
|
||||
})
|
||||
messages = append(messages, Message{
|
||||
Role: USER.String(),
|
||||
Content: "GET /index.html",
|
||||
})
|
||||
messages = append(messages, Message{
|
||||
Role: ASSISTANT.String(),
|
||||
Content: "<html><body>Hello, World!</body></html>",
|
||||
})
|
||||
default:
|
||||
return nil, errors.New("no prompt for protocol selected")
|
||||
}
|
||||
messages = append(messages, Message{
|
||||
Role: USER.String(),
|
||||
Content: command,
|
||||
})
|
||||
|
||||
return messages, nil
|
||||
}
|
||||
|
||||
func (openAIVirtualHoneypot *openAIVirtualHoneypot) GetCompletions(command string) (string, error) {
|
||||
var err error
|
||||
|
||||
prompt, err := buildPrompt(openAIVirtualHoneypot.Histories, openAIVirtualHoneypot.protocol, command)
|
||||
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
requestJson, err := json.Marshal(gptRequest{
|
||||
Model: "text-davinci-003",
|
||||
Prompt: buildPrompt(openAIGPTVirtualTerminal.Histories, command),
|
||||
Temperature: 0,
|
||||
MaxTokens: 100,
|
||||
TopP: 1,
|
||||
FrequencyPenalty: 0,
|
||||
PresencePenalty: 0,
|
||||
Stop: []string{"\n"},
|
||||
Model: "gpt-4o",
|
||||
Messages: prompt,
|
||||
})
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
if openAIGPTVirtualTerminal.OpenAPIChatGPTSecretKey == "" {
|
||||
return "", errors.New("OpenAPIChatGPTSecretKey is empty")
|
||||
if openAIVirtualHoneypot.openAIKey == "" {
|
||||
return "", errors.New("openAIKey is empty")
|
||||
}
|
||||
|
||||
response, err := openAIGPTVirtualTerminal.client.R().
|
||||
log.Debug(string(requestJson))
|
||||
response, err := openAIVirtualHoneypot.client.R().
|
||||
SetHeader("Content-Type", "application/json").
|
||||
SetBody(requestJson).
|
||||
SetAuthToken(openAIGPTVirtualTerminal.OpenAPIChatGPTSecretKey).
|
||||
SetAuthToken(openAIVirtualHoneypot.openAIKey).
|
||||
SetResult(&gptResponse{}).
|
||||
Post(openAIGPTEndpoint)
|
||||
|
||||
@ -113,5 +155,5 @@ func (openAIGPTVirtualTerminal *OpenAIGPTVirtualTerminal) GetCompletions(command
|
||||
return "", errors.New("no choices")
|
||||
}
|
||||
|
||||
return response.Result().(*gptResponse).Choices[0].Text, nil
|
||||
return response.Result().(*gptResponse).Choices[0].Message.Content, nil
|
||||
}
|
||||
|
@ -3,50 +3,63 @@ package plugins
|
||||
import (
|
||||
"github.com/go-resty/resty/v2"
|
||||
"github.com/jarcoal/httpmock"
|
||||
"github.com/mariocandela/beelzebub/v3/tracer"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"net/http"
|
||||
"testing"
|
||||
)
|
||||
|
||||
const SystemPromptLen = 4
|
||||
|
||||
func TestBuildPromptEmptyHistory(t *testing.T) {
|
||||
//Given
|
||||
var histories []History
|
||||
var histories []Message
|
||||
command := "pwd"
|
||||
|
||||
//When
|
||||
prompt := buildPrompt(histories, command)
|
||||
prompt, err := buildPrompt(histories, tracer.SSH, command)
|
||||
|
||||
//Then
|
||||
assert.Equal(t,
|
||||
"I want you to act as a Linux terminal. I will type commands and you will reply with what the terminal should show. I want you to only reply with the terminal output inside one unique code block, and nothing else. Do no write explanations. Do not type commands unless I instruct you to do so.\n\nA:pwd\n\nQ:/home/user\n\nA:pwd\n\nQ:",
|
||||
prompt)
|
||||
assert.Nil(t, err)
|
||||
assert.Equal(t, SystemPromptLen, len(prompt))
|
||||
}
|
||||
|
||||
func TestBuildPromptWithHistory(t *testing.T) {
|
||||
//Given
|
||||
var histories = []History{
|
||||
var histories = []Message{
|
||||
{
|
||||
Input: "cat hello.txt",
|
||||
Output: "world",
|
||||
},
|
||||
{
|
||||
Input: "echo 1234",
|
||||
Output: "1234",
|
||||
Role: "cat hello.txt",
|
||||
Content: "world",
|
||||
},
|
||||
}
|
||||
|
||||
command := "pwd"
|
||||
|
||||
//When
|
||||
prompt := buildPrompt(histories, command)
|
||||
prompt, err := buildPrompt(histories, tracer.SSH, command)
|
||||
|
||||
//Then
|
||||
assert.Equal(t,
|
||||
"I want you to act as a Linux terminal. I will type commands and you will reply with what the terminal should show. I want you to only reply with the terminal output inside one unique code block, and nothing else. Do no write explanations. Do not type commands unless I instruct you to do so.\n\nA:pwd\n\nQ:/home/user\n\nA:cat hello.txt\n\nQ:world\n\nA:echo 1234\n\nQ:1234\n\nA:pwd\n\nQ:",
|
||||
prompt)
|
||||
assert.Nil(t, err)
|
||||
assert.Equal(t, SystemPromptLen+1, len(prompt))
|
||||
}
|
||||
|
||||
func TestBuildGetCompletions(t *testing.T) {
|
||||
func TestBuildGetCompletionsFailValidation(t *testing.T) {
|
||||
openAIGPTVirtualTerminal := Init(make([]Message, 0), "", tracer.SSH)
|
||||
|
||||
_, err := openAIGPTVirtualTerminal.GetCompletions("test")
|
||||
|
||||
assert.Equal(t, "openAIKey is empty", err.Error())
|
||||
}
|
||||
|
||||
func TestBuildGetCompletionsFailValidationStrategyType(t *testing.T) {
|
||||
openAIGPTVirtualTerminal := Init(make([]Message, 0), "", tracer.TCP)
|
||||
|
||||
_, err := openAIGPTVirtualTerminal.GetCompletions("test")
|
||||
|
||||
assert.Equal(t, "no prompt for protocol selected", err.Error())
|
||||
}
|
||||
|
||||
func TestBuildGetCompletionsSSHWithResults(t *testing.T) {
|
||||
client := resty.New()
|
||||
httpmock.ActivateNonDefault(client.GetClient())
|
||||
defer httpmock.DeactivateAndReset()
|
||||
@ -57,7 +70,10 @@ func TestBuildGetCompletions(t *testing.T) {
|
||||
resp, err := httpmock.NewJsonResponse(200, &gptResponse{
|
||||
Choices: []Choice{
|
||||
{
|
||||
Text: "prova.txt",
|
||||
Message: Message{
|
||||
Role: SYSTEM.String(),
|
||||
Content: "prova.txt",
|
||||
},
|
||||
},
|
||||
},
|
||||
})
|
||||
@ -68,10 +84,8 @@ func TestBuildGetCompletions(t *testing.T) {
|
||||
},
|
||||
)
|
||||
|
||||
openAIGPTVirtualTerminal := OpenAIGPTVirtualTerminal{
|
||||
OpenAPIChatGPTSecretKey: "sdjdnklfjndslkjanfk",
|
||||
client: client,
|
||||
}
|
||||
openAIGPTVirtualTerminal := Init(make([]Message, 0), "sdjdnklfjndslkjanfk", tracer.SSH)
|
||||
openAIGPTVirtualTerminal.client = client
|
||||
|
||||
//When
|
||||
str, err := openAIGPTVirtualTerminal.GetCompletions("ls")
|
||||
@ -80,3 +94,95 @@ func TestBuildGetCompletions(t *testing.T) {
|
||||
assert.Nil(t, err)
|
||||
assert.Equal(t, "prova.txt", str)
|
||||
}
|
||||
|
||||
func TestBuildGetCompletionsSSHWithoutResults(t *testing.T) {
|
||||
client := resty.New()
|
||||
httpmock.ActivateNonDefault(client.GetClient())
|
||||
defer httpmock.DeactivateAndReset()
|
||||
|
||||
// Given
|
||||
httpmock.RegisterResponder("POST", openAIGPTEndpoint,
|
||||
func(req *http.Request) (*http.Response, error) {
|
||||
resp, err := httpmock.NewJsonResponse(200, &gptResponse{
|
||||
Choices: []Choice{},
|
||||
})
|
||||
if err != nil {
|
||||
return httpmock.NewStringResponse(500, ""), nil
|
||||
}
|
||||
return resp, nil
|
||||
},
|
||||
)
|
||||
|
||||
openAIGPTVirtualTerminal := Init(make([]Message, 0), "sdjdnklfjndslkjanfk", tracer.SSH)
|
||||
openAIGPTVirtualTerminal.client = client
|
||||
|
||||
//When
|
||||
_, err := openAIGPTVirtualTerminal.GetCompletions("ls")
|
||||
|
||||
//Then
|
||||
assert.Equal(t, "no choices", err.Error())
|
||||
}
|
||||
|
||||
func TestBuildGetCompletionsHTTPWithResults(t *testing.T) {
|
||||
client := resty.New()
|
||||
httpmock.ActivateNonDefault(client.GetClient())
|
||||
defer httpmock.DeactivateAndReset()
|
||||
|
||||
// Given
|
||||
httpmock.RegisterResponder("POST", openAIGPTEndpoint,
|
||||
func(req *http.Request) (*http.Response, error) {
|
||||
resp, err := httpmock.NewJsonResponse(200, &gptResponse{
|
||||
Choices: []Choice{
|
||||
{
|
||||
Message: Message{
|
||||
Role: SYSTEM.String(),
|
||||
Content: "[default]\nregion = us-west-2\noutput = json",
|
||||
},
|
||||
},
|
||||
},
|
||||
})
|
||||
if err != nil {
|
||||
return httpmock.NewStringResponse(500, ""), nil
|
||||
}
|
||||
return resp, nil
|
||||
},
|
||||
)
|
||||
|
||||
openAIGPTVirtualTerminal := Init(make([]Message, 0), "sdjdnklfjndslkjanfk", tracer.HTTP)
|
||||
openAIGPTVirtualTerminal.client = client
|
||||
|
||||
//When
|
||||
str, err := openAIGPTVirtualTerminal.GetCompletions("GET /.aws/credentials")
|
||||
|
||||
//Then
|
||||
assert.Nil(t, err)
|
||||
assert.Equal(t, "[default]\nregion = us-west-2\noutput = json", str)
|
||||
}
|
||||
|
||||
func TestBuildGetCompletionsHTTPWithoutResults(t *testing.T) {
|
||||
client := resty.New()
|
||||
httpmock.ActivateNonDefault(client.GetClient())
|
||||
defer httpmock.DeactivateAndReset()
|
||||
|
||||
// Given
|
||||
httpmock.RegisterResponder("POST", openAIGPTEndpoint,
|
||||
func(req *http.Request) (*http.Response, error) {
|
||||
resp, err := httpmock.NewJsonResponse(200, &gptResponse{
|
||||
Choices: []Choice{},
|
||||
})
|
||||
if err != nil {
|
||||
return httpmock.NewStringResponse(500, ""), nil
|
||||
}
|
||||
return resp, nil
|
||||
},
|
||||
)
|
||||
|
||||
openAIGPTVirtualTerminal := Init(make([]Message, 0), "sdjdnklfjndslkjanfk", tracer.HTTP)
|
||||
openAIGPTVirtualTerminal.client = client
|
||||
|
||||
//When
|
||||
_, err := openAIGPTVirtualTerminal.GetCompletions("GET /.aws/credentials")
|
||||
|
||||
//Then
|
||||
assert.Equal(t, "no choices", err.Error())
|
||||
}
|
||||
|
@ -1,10 +1,12 @@
|
||||
// Package protocols is responsible for managing the different protocols
|
||||
package protocols
|
||||
|
||||
import (
|
||||
"github.com/mariocandela/beelzebub/parser"
|
||||
"github.com/mariocandela/beelzebub/tracer"
|
||||
"github.com/mariocandela/beelzebub/v3/parser"
|
||||
"github.com/mariocandela/beelzebub/v3/tracer"
|
||||
)
|
||||
|
||||
// ServiceStrategy is the common interface that each protocol honeypot implements
|
||||
type ServiceStrategy interface {
|
||||
Init(beelzebubServiceConfiguration parser.BeelzebubServiceConfiguration, tracer tracer.Tracer) error
|
||||
}
|
||||
@ -14,10 +16,11 @@ type ProtocolManager struct {
|
||||
tracer tracer.Tracer
|
||||
}
|
||||
|
||||
func InitProtocolManager(tracerStrategy tracer.Strategy, strategy ServiceStrategy) *ProtocolManager {
|
||||
// InitProtocolManager is the method that initializes the protocol manager, receving the concrete tracer and the concrete service
|
||||
func InitProtocolManager(tracerStrategy tracer.Strategy, serviceStrategy ServiceStrategy) *ProtocolManager {
|
||||
return &ProtocolManager{
|
||||
tracer: tracer.Init(tracerStrategy),
|
||||
strategy: strategy,
|
||||
tracer: tracer.GetInstance(tracerStrategy),
|
||||
strategy: serviceStrategy,
|
||||
}
|
||||
}
|
||||
|
||||
@ -25,6 +28,7 @@ func (pm *ProtocolManager) SetProtocolStrategy(strategy ServiceStrategy) {
|
||||
pm.strategy = strategy
|
||||
}
|
||||
|
||||
// InitService is the method that initializes the honeypot
|
||||
func (pm *ProtocolManager) InitService(beelzebubServiceConfiguration parser.BeelzebubServiceConfiguration) error {
|
||||
return pm.strategy.Init(beelzebubServiceConfiguration, pm.tracer)
|
||||
}
|
||||
|
@ -2,8 +2,8 @@ package protocols
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"github.com/mariocandela/beelzebub/parser"
|
||||
"github.com/mariocandela/beelzebub/tracer"
|
||||
"github.com/mariocandela/beelzebub/v3/parser"
|
||||
"github.com/mariocandela/beelzebub/v3/tracer"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"testing"
|
||||
)
|
||||
|
@ -2,8 +2,9 @@ package strategies
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/mariocandela/beelzebub/parser"
|
||||
"github.com/mariocandela/beelzebub/tracer"
|
||||
"github.com/mariocandela/beelzebub/v3/parser"
|
||||
"github.com/mariocandela/beelzebub/v3/plugins"
|
||||
"github.com/mariocandela/beelzebub/v3/tracer"
|
||||
"io"
|
||||
"net/http"
|
||||
"regexp"
|
||||
@ -31,8 +32,24 @@ func (httpStrategy HTTPStrategy) Init(beelzebubServiceConfiguration parser.Beelz
|
||||
}
|
||||
|
||||
if matched {
|
||||
responseHTTPBody := command.Handler
|
||||
|
||||
if command.Plugin == plugins.ChatGPTPluginName {
|
||||
openAIGPTVirtualTerminal := plugins.Init(make([]plugins.Message, 0), beelzebubServiceConfiguration.Plugin.OpenAISecretKey, tracer.HTTP)
|
||||
|
||||
command := fmt.Sprintf("%s %s", request.Method, request.RequestURI)
|
||||
|
||||
if completions, err := openAIGPTVirtualTerminal.GetCompletions(command); err != nil {
|
||||
log.Errorf("Error GetCompletions: %s, %s", command, err.Error())
|
||||
responseHTTPBody = "404 Not Found!"
|
||||
} else {
|
||||
responseHTTPBody = completions
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
setResponseHeaders(responseWriter, command.Headers, command.StatusCode)
|
||||
fmt.Fprintf(responseWriter, command.Handler)
|
||||
fmt.Fprintf(responseWriter, responseHTTPBody)
|
||||
break
|
||||
}
|
||||
}
|
||||
|
@ -2,10 +2,11 @@ package strategies
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/mariocandela/beelzebub/parser"
|
||||
"github.com/mariocandela/beelzebub/plugins"
|
||||
"github.com/mariocandela/beelzebub/tracer"
|
||||
"github.com/mariocandela/beelzebub/v3/parser"
|
||||
"github.com/mariocandela/beelzebub/v3/plugins"
|
||||
"github.com/mariocandela/beelzebub/v3/tracer"
|
||||
"regexp"
|
||||
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
@ -41,7 +42,7 @@ func (sshStrategy *SSHStrategy) Init(beelzebubServiceConfiguration parser.Beelze
|
||||
})
|
||||
|
||||
term := terminal.NewTerminal(sess, buildPrompt(sess.User(), beelzebubServiceConfiguration.ServerName))
|
||||
var histories []plugins.History
|
||||
var histories []plugins.Message
|
||||
for {
|
||||
commandInput, err := term.ReadLine()
|
||||
if err != nil {
|
||||
@ -62,8 +63,7 @@ func (sshStrategy *SSHStrategy) Init(beelzebubServiceConfiguration parser.Beelze
|
||||
commandOutput := command.Handler
|
||||
|
||||
if command.Plugin == plugins.ChatGPTPluginName {
|
||||
openAIGPTVirtualTerminal := plugins.OpenAIGPTVirtualTerminal{Histories: histories, OpenAPIChatGPTSecretKey: beelzebubServiceConfiguration.Plugin.OpenAPIChatGPTSecretKey}
|
||||
openAIGPTVirtualTerminal.InjectDependency()
|
||||
openAIGPTVirtualTerminal := plugins.Init(histories, beelzebubServiceConfiguration.Plugin.OpenAISecretKey, tracer.SSH)
|
||||
|
||||
if commandOutput, err = openAIGPTVirtualTerminal.GetCompletions(commandInput); err != nil {
|
||||
log.Errorf("Error GetCompletions: %s, %s", commandInput, err.Error())
|
||||
@ -71,7 +71,8 @@ func (sshStrategy *SSHStrategy) Init(beelzebubServiceConfiguration parser.Beelze
|
||||
}
|
||||
}
|
||||
|
||||
histories = append(histories, plugins.History{Input: commandInput, Output: commandOutput})
|
||||
histories = append(histories, plugins.Message{Role: plugins.USER.String(), Content: commandInput})
|
||||
histories = append(histories, plugins.Message{Role: plugins.ASSISTANT.String(), Content: commandOutput})
|
||||
|
||||
term.Write(append([]byte(commandOutput), '\n'))
|
||||
|
||||
@ -124,7 +125,7 @@ func (sshStrategy *SSHStrategy) Init(beelzebubServiceConfiguration parser.Beelze
|
||||
log.WithFields(log.Fields{
|
||||
"port": beelzebubServiceConfiguration.Address,
|
||||
"commands": len(beelzebubServiceConfiguration.Commands),
|
||||
}).Infof("Init service %s", beelzebubServiceConfiguration.Protocol)
|
||||
}).Infof("GetInstance service %s", beelzebubServiceConfiguration.Protocol)
|
||||
return nil
|
||||
}
|
||||
|
||||
|
@ -2,8 +2,8 @@ package strategies
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/mariocandela/beelzebub/parser"
|
||||
"github.com/mariocandela/beelzebub/tracer"
|
||||
"github.com/mariocandela/beelzebub/v3/parser"
|
||||
"github.com/mariocandela/beelzebub/v3/tracer"
|
||||
"net"
|
||||
"time"
|
||||
|
||||
|
117
tracer/tracer.go
117
tracer/tracer.go
@ -1,13 +1,16 @@
|
||||
// Package tracer is responsible for tracing the events that occur in the honeypots
|
||||
package tracer
|
||||
|
||||
import (
|
||||
log "github.com/sirupsen/logrus"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/prometheus/client_golang/prometheus"
|
||||
"github.com/prometheus/client_golang/prometheus/promauto"
|
||||
log "github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
// Workers is the number of workers that will
|
||||
const Workers = 5
|
||||
|
||||
type Event struct {
|
||||
@ -44,8 +47,8 @@ const (
|
||||
TCP
|
||||
)
|
||||
|
||||
func (status Protocol) String() string {
|
||||
return [...]string{"HTTP", "SSH", "TCP"}[status]
|
||||
func (protocol Protocol) String() string {
|
||||
return [...]string{"HTTP", "SSH", "TCP"}[protocol]
|
||||
}
|
||||
|
||||
const (
|
||||
@ -66,49 +69,60 @@ type Tracer interface {
|
||||
}
|
||||
|
||||
type tracer struct {
|
||||
strategy Strategy
|
||||
eventsChan chan Event
|
||||
strategy Strategy
|
||||
eventsChan chan Event
|
||||
eventsTotal prometheus.Counter
|
||||
eventsSSHTotal prometheus.Counter
|
||||
eventsTCPTotal prometheus.Counter
|
||||
eventsHTTPTotal prometheus.Counter
|
||||
}
|
||||
|
||||
var (
|
||||
eventsTotal = promauto.NewCounter(prometheus.CounterOpts{
|
||||
Namespace: "beelzebub",
|
||||
Name: "events_total",
|
||||
Help: "The total number of events",
|
||||
})
|
||||
eventsSSHTotal = promauto.NewCounter(prometheus.CounterOpts{
|
||||
Namespace: "beelzebub",
|
||||
Name: "ssh_events_total",
|
||||
Help: "The total number of SSH events",
|
||||
})
|
||||
eventsTCPTotal = promauto.NewCounter(prometheus.CounterOpts{
|
||||
Namespace: "beelzebub",
|
||||
Name: "tcp_events_total",
|
||||
Help: "The total number of TCP events",
|
||||
})
|
||||
eventsHTTPTotal = promauto.NewCounter(prometheus.CounterOpts{
|
||||
Namespace: "beelzebub",
|
||||
Name: "http_events_total",
|
||||
Help: "The total number of HTTP events",
|
||||
})
|
||||
)
|
||||
var lock = &sync.Mutex{}
|
||||
var singleton *tracer
|
||||
|
||||
func Init(strategy Strategy) *tracer {
|
||||
tracer := &tracer{
|
||||
strategy: strategy,
|
||||
eventsChan: make(chan Event, Workers),
|
||||
}
|
||||
|
||||
for i := 0; i < Workers; i++ {
|
||||
go func(i int) {
|
||||
log.Debug("Init trace worker: ", i)
|
||||
for event := range tracer.eventsChan {
|
||||
tracer.strategy(event)
|
||||
func GetInstance(defaultStrategy Strategy) *tracer {
|
||||
if singleton == nil {
|
||||
lock.Lock()
|
||||
defer lock.Unlock()
|
||||
// This is to prevent expensive lock operations every time the GetInstance method is called
|
||||
if singleton == nil {
|
||||
singleton = &tracer{
|
||||
strategy: defaultStrategy,
|
||||
eventsChan: make(chan Event, Workers),
|
||||
eventsTotal: promauto.NewCounter(prometheus.CounterOpts{
|
||||
Namespace: "beelzebub",
|
||||
Name: "events_total",
|
||||
Help: "The total number of events",
|
||||
}),
|
||||
eventsSSHTotal: promauto.NewCounter(prometheus.CounterOpts{
|
||||
Namespace: "beelzebub",
|
||||
Name: "ssh_events_total",
|
||||
Help: "The total number of SSH events",
|
||||
}),
|
||||
eventsTCPTotal: promauto.NewCounter(prometheus.CounterOpts{
|
||||
Namespace: "beelzebub",
|
||||
Name: "tcp_events_total",
|
||||
Help: "The total number of TCP events",
|
||||
}),
|
||||
eventsHTTPTotal: promauto.NewCounter(prometheus.CounterOpts{
|
||||
Namespace: "beelzebub",
|
||||
Name: "http_events_total",
|
||||
Help: "The total number of HTTP events",
|
||||
}),
|
||||
}
|
||||
}(i)
|
||||
|
||||
for i := 0; i < Workers; i++ {
|
||||
go func(i int) {
|
||||
log.Debug("Trace worker: ", i)
|
||||
for event := range singleton.eventsChan {
|
||||
singleton.strategy(event)
|
||||
}
|
||||
}(i)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return tracer
|
||||
return singleton
|
||||
}
|
||||
|
||||
func (tracer *tracer) setStrategy(strategy Strategy) {
|
||||
@ -120,14 +134,17 @@ func (tracer *tracer) TraceEvent(event Event) {
|
||||
|
||||
tracer.eventsChan <- event
|
||||
|
||||
eventsTotal.Inc()
|
||||
|
||||
switch event.Protocol {
|
||||
case HTTP.String():
|
||||
eventsHTTPTotal.Inc()
|
||||
case SSH.String():
|
||||
eventsSSHTotal.Inc()
|
||||
case TCP.String():
|
||||
eventsTCPTotal.Inc()
|
||||
}
|
||||
tracer.updatePrometheusCounters(event.Protocol)
|
||||
}
|
||||
|
||||
func (tracer *tracer) updatePrometheusCounters(protocol string) {
|
||||
switch protocol {
|
||||
case HTTP.String():
|
||||
tracer.eventsHTTPTotal.Inc()
|
||||
case SSH.String():
|
||||
tracer.eventsSSHTotal.Inc()
|
||||
case TCP.String():
|
||||
tracer.eventsTCPTotal.Inc()
|
||||
}
|
||||
tracer.eventsTotal.Inc()
|
||||
}
|
||||
|
@ -1,6 +1,7 @@
|
||||
package tracer
|
||||
|
||||
import (
|
||||
"github.com/prometheus/client_golang/prometheus"
|
||||
"sync"
|
||||
"testing"
|
||||
|
||||
@ -10,7 +11,7 @@ import (
|
||||
func TestInit(t *testing.T) {
|
||||
mockStrategy := func(event Event) {}
|
||||
|
||||
tracer := Init(mockStrategy)
|
||||
tracer := GetInstance(mockStrategy)
|
||||
|
||||
assert.NotNil(t, tracer.strategy)
|
||||
}
|
||||
@ -25,7 +26,9 @@ func TestTraceEvent(t *testing.T) {
|
||||
eventCalled = event
|
||||
}
|
||||
|
||||
tracer := Init(mockStrategy)
|
||||
tracer := GetInstance(mockStrategy)
|
||||
|
||||
tracer.strategy = mockStrategy
|
||||
|
||||
wg.Add(1)
|
||||
tracer.TraceEvent(Event{
|
||||
@ -51,7 +54,7 @@ func TestSetStrategy(t *testing.T) {
|
||||
eventCalled = event
|
||||
}
|
||||
|
||||
tracer := Init(mockStrategy)
|
||||
tracer := GetInstance(mockStrategy)
|
||||
|
||||
tracer.setStrategy(mockStrategy)
|
||||
|
||||
@ -75,3 +78,42 @@ func TestStringStatus(t *testing.T) {
|
||||
assert.Equal(t, Stateless.String(), "Stateless")
|
||||
assert.Equal(t, Interaction.String(), "Interaction")
|
||||
}
|
||||
|
||||
type mockCounter struct {
|
||||
prometheus.Metric
|
||||
prometheus.Collector
|
||||
inc func()
|
||||
add func(float64)
|
||||
}
|
||||
|
||||
var counter = 0
|
||||
|
||||
func (m mockCounter) Inc() {
|
||||
counter += 1
|
||||
}
|
||||
|
||||
func (m mockCounter) Add(f float64) {
|
||||
counter = int(f)
|
||||
}
|
||||
|
||||
func TestUpdatePrometheusCounters(t *testing.T) {
|
||||
mockStrategy := func(event Event) {}
|
||||
|
||||
tracer := &tracer{
|
||||
strategy: mockStrategy,
|
||||
eventsChan: make(chan Event, Workers),
|
||||
eventsTotal: mockCounter{},
|
||||
eventsSSHTotal: mockCounter{},
|
||||
eventsTCPTotal: mockCounter{},
|
||||
eventsHTTPTotal: mockCounter{},
|
||||
}
|
||||
|
||||
tracer.updatePrometheusCounters(SSH.String())
|
||||
assert.Equal(t, 2, counter)
|
||||
|
||||
tracer.updatePrometheusCounters(HTTP.String())
|
||||
assert.Equal(t, 4, counter)
|
||||
|
||||
tracer.updatePrometheusCounters(TCP.String())
|
||||
assert.Equal(t, 6, counter)
|
||||
}
|
||||
|
Reference in New Issue
Block a user