Compare commits

...

10 Commits

Author SHA1 Message Date
8963bbc86d Fix: mapping LLMModel for SSH inline, removed old comments on docker-c… (#168)
Fix mapping LLMModel for SSH inline, removed old comments on docker-compose.yml
2025-02-20 22:41:28 +01:00
44ec44ea5c Fix LLM model name typo 2025-02-20 18:20:17 +01:00
38297faed2 Feat: Refactoring LLM Plugin, update docs. (#165)
Refactoring LLM Plugin, update docs.
2025-02-16 22:48:59 +01:00
8703d1afda Fix: llm plugin OpenAI generates random plaintext (hallucinations) (#163)
* Add tests to adopt TDD.

* Fix bug, LLM hallucinations
2025-02-16 16:27:10 +01:00
db804474d3 Add support for TLS based HTTP connections. (#158)
* Add support for TLS based HTTP connections, With Unit Tests.
2025-02-13 20:54:22 +01:00
48dd70d523 Build(deps): Bump golang.org/x/crypto from 0.32.0 to 0.33.0 (#157) 2025-02-10 07:07:41 +01:00
4813685834 Bump github.com/go-resty/resty/v2 from 2.16.4 to 2.16.5 (#156)
Bumps [github.com/go-resty/resty/v2](https://github.com/go-resty/resty) from 2.16.4 to 2.16.5.
- [Release notes](https://github.com/go-resty/resty/releases)
- [Commits](https://github.com/go-resty/resty/compare/v2.16.4...v2.16.5)

---
updated-dependencies:
- dependency-name: github.com/go-resty/resty/v2
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-01-24 08:32:45 +01:00
6f6acb212b Bump github.com/go-resty/resty/v2 from 2.16.3 to 2.16.4 (#155)
Bumps [github.com/go-resty/resty/v2](https://github.com/go-resty/resty) from 2.16.3 to 2.16.4.
- [Release notes](https://github.com/go-resty/resty/releases)
- [Commits](https://github.com/go-resty/resty/compare/v2.16.3...v2.16.4)

---
updated-dependencies:
- dependency-name: github.com/go-resty/resty/v2
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-01-21 08:16:54 +01:00
99c7287c02 Feat: Refactoring plugin:LLM honeypot custom prompt (#154)
refactoring LLM honeypot custom prompt
2025-01-16 08:46:13 +01:00
c3d2ff885d Feat: LLM Honeypot allow specifying the custom prompt #152 (#153)
* implement new feature, custom prompt

* Add doc for custom prompt
2025-01-14 08:45:30 +01:00
13 changed files with 369 additions and 108 deletions

View File

@ -211,9 +211,9 @@ commands:
#### Example SSH Honeypot #### Example SSH Honeypot
###### Honeypot LLM Honeypots ###### LLM Honeypots
Example with OpenAI GPT-4: Follow a SSH LLM Honeypot using OpenAI as provider LLM:
```yaml ```yaml
apiVersion: "v1" apiVersion: "v1"
@ -228,11 +228,12 @@ serverName: "ubuntu"
passwordRegex: "^(root|qwerty|Smoker666|123456|jenkins|minecraft|sinus|alex|postgres|Ly123456)$" passwordRegex: "^(root|qwerty|Smoker666|123456|jenkins|minecraft|sinus|alex|postgres|Ly123456)$"
deadlineTimeoutSeconds: 60 deadlineTimeoutSeconds: 60
plugin: plugin:
llmModel: "gpt4-o" llmProvider: "openai"
llmModel: "gpt-4o" #Models https://platform.openai.com/docs/models
openAISecretKey: "sk-proj-123456" openAISecretKey: "sk-proj-123456"
``` ```
Example with Ollama Llama3: Examples with local Ollama instance using model codellama:7b:
```yaml ```yaml
apiVersion: "v1" apiVersion: "v1"
@ -247,9 +248,30 @@ serverName: "ubuntu"
passwordRegex: "^(root|qwerty|Smoker666|123456|jenkins|minecraft|sinus|alex|postgres|Ly123456)$" passwordRegex: "^(root|qwerty|Smoker666|123456|jenkins|minecraft|sinus|alex|postgres|Ly123456)$"
deadlineTimeoutSeconds: 60 deadlineTimeoutSeconds: 60
plugin: plugin:
llmModel: "llama3" llmProvider: "ollama"
llmModel: "codellama:7b" #Models https://ollama.com/search
host: "http://example.com/api/chat" #default http://localhost:11434/api/chat host: "http://example.com/api/chat" #default http://localhost:11434/api/chat
``` ```
Example with custom prompt:
```yaml
apiVersion: "v1"
protocol: "ssh"
address: ":2222"
description: "SSH interactive OpenAI GPT-4"
commands:
- regex: "^(.+)$"
plugin: "LLMHoneypot"
serverVersion: "OpenSSH"
serverName: "ubuntu"
passwordRegex: "^(root|qwerty|Smoker666|123456|jenkins|minecraft|sinus|alex|postgres|Ly123456)$"
deadlineTimeoutSeconds: 60
plugin:
llmProvider: "openai"
llmModel: "gpt-4o"
openAISecretKey: "sk-proj-123456"
prompt: "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."
```
###### SSH Honeypot on Port 22 ###### SSH Honeypot on Port 22

View File

@ -7,7 +7,9 @@ commands:
plugin: "LLMHoneypot" plugin: "LLMHoneypot"
serverVersion: "OpenSSH" serverVersion: "OpenSSH"
serverName: "ubuntu" serverName: "ubuntu"
passwordRegex: "^(root|qwerty|Smoker666|123456|jenkins|minecraft|sinus|alex|postgres|Ly123456)$" passwordRegex: "^(root|qwerty|Smoker666|123456|jenkins|minecraft|sinus|alex|postgres|Ly123456|1234)$"
deadlineTimeoutSeconds: 6000 deadlineTimeoutSeconds: 6000
plugin: plugin:
llmModel: "llama3" llmProvider: "openai"
llmModel: "gpt-4o"
openAISecretKey: "sk-proj-12345"

View File

@ -3,17 +3,16 @@ version: "3.9"
services: services:
beelzebub: beelzebub:
build: . build: .
#network_mode: host # Not work on Mac OS
container_name: beelzebub container_name: beelzebub
restart: always restart: always
ports: # Remove me, if you use configuration network_mode: host ports:
- "22:22" - "22:22"
- "2222:2222" - "2222:2222"
- "8080:8080" - "8080:8080"
- "8081:8081" - "8081:8081"
- "80:80" - "80:80"
- "3306:3306" - "3306:3306"
- "2112:2112" # Prometheus openmetrics - "2112:2112" #Prometheus Open Metrics
environment: environment:
RABBITMQ_URI: ${RABBITMQ_URI} RABBITMQ_URI: ${RABBITMQ_URI}
volumes: volumes:

8
go.mod
View File

@ -4,7 +4,7 @@ go 1.20
require ( require (
github.com/gliderlabs/ssh v0.3.8 github.com/gliderlabs/ssh v0.3.8
github.com/go-resty/resty/v2 v2.16.3 github.com/go-resty/resty/v2 v2.16.5
github.com/google/uuid v1.6.0 github.com/google/uuid v1.6.0
github.com/jarcoal/httpmock v1.3.1 github.com/jarcoal/httpmock v1.3.1
github.com/melbahja/goph v1.4.0 github.com/melbahja/goph v1.4.0
@ -12,7 +12,7 @@ require (
github.com/rabbitmq/amqp091-go v1.10.0 github.com/rabbitmq/amqp091-go v1.10.0
github.com/sirupsen/logrus v1.9.3 github.com/sirupsen/logrus v1.9.3
github.com/stretchr/testify v1.10.0 github.com/stretchr/testify v1.10.0
golang.org/x/crypto v0.32.0 golang.org/x/crypto v0.33.0
gopkg.in/yaml.v3 v3.0.1 gopkg.in/yaml.v3 v3.0.1
) )
@ -32,7 +32,7 @@ require (
github.com/prometheus/common v0.55.0 // indirect github.com/prometheus/common v0.55.0 // indirect
github.com/prometheus/procfs v0.15.1 // indirect github.com/prometheus/procfs v0.15.1 // indirect
golang.org/x/net v0.33.0 // indirect golang.org/x/net v0.33.0 // indirect
golang.org/x/sys v0.29.0 // indirect golang.org/x/sys v0.30.0 // indirect
golang.org/x/term v0.28.0 // indirect golang.org/x/term v0.29.0 // indirect
google.golang.org/protobuf v1.34.2 // indirect google.golang.org/protobuf v1.34.2 // indirect
) )

16
go.sum
View File

@ -10,8 +10,8 @@ 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/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/gliderlabs/ssh v0.3.8 h1:a4YXD1V7xMF9g5nTkdfnja3Sxy1PVDCj1Zg4Wb8vY6c= github.com/gliderlabs/ssh v0.3.8 h1:a4YXD1V7xMF9g5nTkdfnja3Sxy1PVDCj1Zg4Wb8vY6c=
github.com/gliderlabs/ssh v0.3.8/go.mod h1:xYoytBv1sV0aL3CavoDuJIQNURXkkfPA/wxQ1pL1fAU= github.com/gliderlabs/ssh v0.3.8/go.mod h1:xYoytBv1sV0aL3CavoDuJIQNURXkkfPA/wxQ1pL1fAU=
github.com/go-resty/resty/v2 v2.16.3 h1:zacNT7lt4b8M/io2Ahj6yPypL7bqx9n1iprfQuodV+E= github.com/go-resty/resty/v2 v2.16.5 h1:hBKqmWrr7uRc3euHVqmh1HTHcKn99Smr7o5spptdhTM=
github.com/go-resty/resty/v2 v2.16.3/go.mod h1:hkJtXbA2iKHzJheXYvQ8snQES5ZLGKMwQ07xAwp/fiA= github.com/go-resty/resty/v2 v2.16.5/go.mod h1:hkJtXbA2iKHzJheXYvQ8snQES5ZLGKMwQ07xAwp/fiA=
github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= 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 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
@ -59,8 +59,8 @@ golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACk
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= 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-20211215153901-e495a2d5b3d3/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
golang.org/x/crypto v0.6.0/go.mod h1:OFC/31mSvZgRz0V1QTNCzfAI1aIRzbiufJtkMIlEp58= golang.org/x/crypto v0.6.0/go.mod h1:OFC/31mSvZgRz0V1QTNCzfAI1aIRzbiufJtkMIlEp58=
golang.org/x/crypto v0.32.0 h1:euUpcYgM8WcP71gNpTqQCn6rC2t6ULUPiOzfWaXVVfc= golang.org/x/crypto v0.33.0 h1:IOBPskki6Lysi0lo9qQvbxiQ+FvsCC/YWOecCHAixus=
golang.org/x/crypto v0.32.0/go.mod h1:ZnnJkOaASj8g0AjIduWNlq2NRxL0PlBrbKVyZ6V/Ugc= golang.org/x/crypto v0.33.0/go.mod h1:bVdXmD7IV/4GdElGPozy6U7lWdRXA4qyRVGJV57uQ5M=
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= 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-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
@ -80,13 +80,13 @@ golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBc
golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/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-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.29.0 h1:TPYlXGxvx1MGTn2GiZDhnjPA9wZzZeGKHHmKhHYvgaU= golang.org/x/sys v0.30.0 h1:QjkSwP/36a20jFYWkSue1YwXzLmsV5Gfq7Eiy72C1uc=
golang.org/x/sys v0.29.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/sys v0.30.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-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-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k=
golang.org/x/term v0.28.0 h1:/Ts8HFuMR2E6IP/jlo7QVLZHggjKQbhu/7H0LJFr3Gg= golang.org/x/term v0.29.0 h1:L6pJp37ocefwRRtYPKSWOWzOtWSxVajvz2ldH/xi3iU=
golang.org/x/term v0.28.0/go.mod h1:Sw/lC2IAUZ92udQNf3WodGtn4k/XoLyZoh8v/8uiwek= golang.org/x/term v0.29.0/go.mod h1:6bl4lRlvVuDgSf3179VpIxBF0o10JUpXWOnI7nErv7s=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= 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.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=

View File

@ -52,6 +52,8 @@ type Plugin struct {
OpenAISecretKey string `yaml:"openAISecretKey"` OpenAISecretKey string `yaml:"openAISecretKey"`
Host string `yaml:"host"` Host string `yaml:"host"`
LLMModel string `yaml:"llmModel"` LLMModel string `yaml:"llmModel"`
LLMProvider string `yaml:"llmProvider"`
Prompt string `yaml:"prompt"`
} }
// BeelzebubServiceConfiguration is the struct that contains the configurations of the honeypot service // BeelzebubServiceConfiguration is the struct that contains the configurations of the honeypot service
@ -67,6 +69,8 @@ type BeelzebubServiceConfiguration struct {
Description string `yaml:"description"` Description string `yaml:"description"`
Banner string `yaml:"banner"` Banner string `yaml:"banner"`
Plugin Plugin `yaml:"plugin"` Plugin Plugin `yaml:"plugin"`
TLSCertPath string `yaml:"tlsCertPath"`
TLSKeyPath string `yaml:"tlsKeyPath"`
} }
// Command is the struct that contains the configurations of the commands // Command is the struct that contains the configurations of the commands

View File

@ -49,6 +49,8 @@ func mockReadfilebytesBeelzebubServiceConfiguration(filePath string) ([]byte, er
apiVersion: "v1" apiVersion: "v1"
protocol: "http" protocol: "http"
address: ":8080" address: ":8080"
tlsCertPath: "/tmp/cert.crt"
tlsKeyPath: "/tmp/cert.key"
commands: commands:
- regex: "wp-admin" - regex: "wp-admin"
handler: "login" handler: "login"
@ -57,7 +59,9 @@ commands:
plugin: plugin:
openAISecretKey: "qwerty" openAISecretKey: "qwerty"
llmModel: "llama3" llmModel: "llama3"
llmProvider: "ollama"
host: "localhost:1563" host: "localhost:1563"
prompt: "hello world"
`) `)
return beelzebubServiceConfiguration, nil return beelzebubServiceConfiguration, nil
} }
@ -132,7 +136,11 @@ func TestReadConfigurationsServicesValid(t *testing.T) {
assert.Equal(t, firstBeelzebubServiceConfiguration.Commands[0].Headers[0], "Content-Type: text/html") assert.Equal(t, firstBeelzebubServiceConfiguration.Commands[0].Headers[0], "Content-Type: text/html")
assert.Equal(t, firstBeelzebubServiceConfiguration.Plugin.OpenAISecretKey, "qwerty") assert.Equal(t, firstBeelzebubServiceConfiguration.Plugin.OpenAISecretKey, "qwerty")
assert.Equal(t, firstBeelzebubServiceConfiguration.Plugin.LLMModel, "llama3") assert.Equal(t, firstBeelzebubServiceConfiguration.Plugin.LLMModel, "llama3")
assert.Equal(t, firstBeelzebubServiceConfiguration.Plugin.LLMProvider, "ollama")
assert.Equal(t, firstBeelzebubServiceConfiguration.Plugin.Host, "localhost:1563") assert.Equal(t, firstBeelzebubServiceConfiguration.Plugin.Host, "localhost:1563")
assert.Equal(t, firstBeelzebubServiceConfiguration.Plugin.Prompt, "hello world")
assert.Equal(t, firstBeelzebubServiceConfiguration.TLSCertPath, "/tmp/cert.crt")
assert.Equal(t, firstBeelzebubServiceConfiguration.TLSKeyPath, "/tmp/cert.key")
} }
func TestGelAllFilesNameByDirName(t *testing.T) { func TestGelAllFilesNameByDirName(t *testing.T) {

View File

@ -85,7 +85,7 @@ func TestGetHoneypotsConfigurationsWithResults(t *testing.T) {
resp, err := httpmock.NewJsonResponse(200, &[]HoneypotConfigResponseDTO{ resp, err := httpmock.NewJsonResponse(200, &[]HoneypotConfigResponseDTO{
{ {
ID: "123456", ID: "123456",
Config: "apiVersion: \"v1\"\nprotocol: \"ssh\"\naddress: \":2222\"\ndescription: \"SSH interactive ChatGPT\"\ncommands:\n - regex: \"^(.+)$\"\n plugin: \"LLMHoneypot\"\nserverVersion: \"OpenSSH\"\nserverName: \"ubuntu\"\npasswordRegex: \"^(root|qwerty|Smoker666|123456|jenkins|minecraft|sinus|alex|postgres|Ly123456)$\"\ndeadlineTimeoutSeconds: 60\nplugin:\n llmModel: \"gpt4-o\"\n openAISecretKey: \"1234\"\n", Config: "apiVersion: \"v1\"\nprotocol: \"ssh\"\naddress: \":2222\"\ndescription: \"SSH interactive ChatGPT\"\ncommands:\n - regex: \"^(.+)$\"\n plugin: \"LLMHoneypot\"\nserverVersion: \"OpenSSH\"\nserverName: \"ubuntu\"\npasswordRegex: \"^(root|qwerty|Smoker666|123456|jenkins|minecraft|sinus|alex|postgres|Ly123456)$\"\ndeadlineTimeoutSeconds: 60\nplugin:\n llmModel: \"gpt-4o\"\n openAISecretKey: \"1234\"\n",
TokenID: "1234567", TokenID: "1234567",
}, },
}) })
@ -120,7 +120,7 @@ func TestGetHoneypotsConfigurationsWithResults(t *testing.T) {
PasswordRegex: "^(root|qwerty|Smoker666|123456|jenkins|minecraft|sinus|alex|postgres|Ly123456)$", PasswordRegex: "^(root|qwerty|Smoker666|123456|jenkins|minecraft|sinus|alex|postgres|Ly123456)$",
DeadlineTimeoutSeconds: 60, DeadlineTimeoutSeconds: 60,
Plugin: parser.Plugin{ Plugin: parser.Plugin{
LLMModel: "gpt4-o", LLMModel: "gpt-4o",
OpenAISecretKey: "1234", OpenAISecretKey: "1234",
}, },
}, },

View File

@ -6,25 +6,28 @@ import (
"fmt" "fmt"
"github.com/go-resty/resty/v2" "github.com/go-resty/resty/v2"
"github.com/mariocandela/beelzebub/v3/tracer" "github.com/mariocandela/beelzebub/v3/tracer"
log "github.com/sirupsen/logrus" log "github.com/sirupsen/logrus"
"regexp"
"strings"
) )
const ( const (
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" 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 note. 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." 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."
LLMPluginName = "LLMHoneypot" LLMPluginName = "LLMHoneypot"
openAIGPTEndpoint = "https://api.openai.com/v1/chat/completions" openAIEndpoint = "https://api.openai.com/v1/chat/completions"
ollamaEndpoint = "http://localhost:11434/api/chat" ollamaEndpoint = "http://localhost:11434/api/chat"
) )
type LLMHoneypot struct { type LLMHoneypot struct {
Histories []Message Histories []Message
OpenAIKey string OpenAIKey string
client *resty.Client client *resty.Client
Protocol tracer.Protocol Protocol tracer.Protocol
Model LLMModel Provider LLMProvider
Host string Model string
Host string
CustomPrompt string
} }
type Choice struct { type Choice struct {
@ -70,21 +73,21 @@ func (role Role) String() string {
return [...]string{"system", "user", "assistant"}[role] return [...]string{"system", "user", "assistant"}[role]
} }
type LLMModel int type LLMProvider int
const ( const (
LLAMA3 LLMModel = iota Ollama LLMProvider = iota
GPT4O OpenAI
) )
func FromStringToLLMModel(llmModel string) (LLMModel, error) { func FromStringToLLMProvider(llmProvider string) (LLMProvider, error) {
switch llmModel { switch strings.ToLower(llmProvider) {
case "llama3": case "ollama":
return LLAMA3, nil return Ollama, nil
case "gpt4-o": case "openai":
return GPT4O, nil return OpenAI, nil
default: default:
return -1, fmt.Errorf("model %s not found", llmModel) return -1, fmt.Errorf("provider %s not found, valid providers: ollama, openai", llmProvider)
} }
} }
@ -95,14 +98,19 @@ func InitLLMHoneypot(config LLMHoneypot) *LLMHoneypot {
return &config return &config
} }
func buildPrompt(histories []Message, protocol tracer.Protocol, command string) ([]Message, error) { func (llmHoneypot *LLMHoneypot) buildPrompt(command string) ([]Message, error) {
var messages []Message var messages []Message
var prompt string
switch protocol { switch llmHoneypot.Protocol {
case tracer.SSH: case tracer.SSH:
prompt = systemPromptVirtualizeLinuxTerminal
if llmHoneypot.CustomPrompt != "" {
prompt = llmHoneypot.CustomPrompt
}
messages = append(messages, Message{ messages = append(messages, Message{
Role: SYSTEM.String(), Role: SYSTEM.String(),
Content: systemPromptVirtualizeLinuxTerminal, Content: prompt,
}) })
messages = append(messages, Message{ messages = append(messages, Message{
Role: USER.String(), Role: USER.String(),
@ -112,13 +120,17 @@ func buildPrompt(histories []Message, protocol tracer.Protocol, command string)
Role: ASSISTANT.String(), Role: ASSISTANT.String(),
Content: "/home/user", Content: "/home/user",
}) })
for _, history := range histories { for _, history := range llmHoneypot.Histories {
messages = append(messages, history) messages = append(messages, history)
} }
case tracer.HTTP: case tracer.HTTP:
prompt = systemPromptVirtualizeHTTPServer
if llmHoneypot.CustomPrompt != "" {
prompt = llmHoneypot.CustomPrompt
}
messages = append(messages, Message{ messages = append(messages, Message{
Role: SYSTEM.String(), Role: SYSTEM.String(),
Content: systemPromptVirtualizeHTTPServer, Content: prompt,
}) })
messages = append(messages, Message{ messages = append(messages, Message{
Role: USER.String(), Role: USER.String(),
@ -143,7 +155,7 @@ func (llmHoneypot *LLMHoneypot) openAICaller(messages []Message) (string, error)
var err error var err error
requestJson, err := json.Marshal(Request{ requestJson, err := json.Marshal(Request{
Model: "gpt-4o", Model: llmHoneypot.Model,
Messages: messages, Messages: messages,
Stream: false, Stream: false,
}) })
@ -156,7 +168,7 @@ func (llmHoneypot *LLMHoneypot) openAICaller(messages []Message) (string, error)
} }
if llmHoneypot.Host == "" { if llmHoneypot.Host == "" {
llmHoneypot.Host = openAIGPTEndpoint llmHoneypot.Host = openAIEndpoint
} }
log.Debug(string(requestJson)) log.Debug(string(requestJson))
@ -175,14 +187,14 @@ func (llmHoneypot *LLMHoneypot) openAICaller(messages []Message) (string, error)
return "", errors.New("no choices") return "", errors.New("no choices")
} }
return response.Result().(*Response).Choices[0].Message.Content, nil return removeQuotes(response.Result().(*Response).Choices[0].Message.Content), nil
} }
func (llmHoneypot *LLMHoneypot) ollamaCaller(messages []Message) (string, error) { func (llmHoneypot *LLMHoneypot) ollamaCaller(messages []Message) (string, error) {
var err error var err error
requestJson, err := json.Marshal(Request{ requestJson, err := json.Marshal(Request{
Model: "llama3", Model: llmHoneypot.Model,
Messages: messages, Messages: messages,
Stream: false, Stream: false,
}) })
@ -206,24 +218,30 @@ func (llmHoneypot *LLMHoneypot) ollamaCaller(messages []Message) (string, error)
} }
log.Debug(response) log.Debug(response)
return response.Result().(*Response).Message.Content, nil return removeQuotes(response.Result().(*Response).Message.Content), nil
} }
func (llmHoneypot *LLMHoneypot) ExecuteModel(command string) (string, error) { func (llmHoneypot *LLMHoneypot) ExecuteModel(command string) (string, error) {
var err error var err error
var prompt []Message
prompt, err := buildPrompt(llmHoneypot.Histories, llmHoneypot.Protocol, command) prompt, err = llmHoneypot.buildPrompt(command)
if err != nil { if err != nil {
return "", err return "", err
} }
switch llmHoneypot.Model { switch llmHoneypot.Provider {
case LLAMA3: case Ollama:
return llmHoneypot.ollamaCaller(prompt) return llmHoneypot.ollamaCaller(prompt)
case GPT4O: case OpenAI:
return llmHoneypot.openAICaller(prompt) return llmHoneypot.openAICaller(prompt)
default: default:
return "", errors.New("no model selected") return "", fmt.Errorf("provider %d not found, valid providers: ollama, openai", llmHoneypot.Provider)
} }
} }
func removeQuotes(content string) string {
regex := regexp.MustCompile("(```( *)?([a-z]*)?(\\n)?)")
return regex.ReplaceAllString(content, "")
}

View File

@ -16,8 +16,13 @@ func TestBuildPromptEmptyHistory(t *testing.T) {
var histories []Message var histories []Message
command := "pwd" command := "pwd"
honeypot := LLMHoneypot{
Histories: histories,
Protocol: tracer.SSH,
}
//When //When
prompt, err := buildPrompt(histories, tracer.SSH, command) prompt, err := honeypot.buildPrompt(command)
//Then //Then
assert.Nil(t, err) assert.Nil(t, err)
@ -35,21 +40,53 @@ func TestBuildPromptWithHistory(t *testing.T) {
command := "pwd" command := "pwd"
honeypot := LLMHoneypot{
Histories: histories,
Protocol: tracer.SSH,
}
//When //When
prompt, err := buildPrompt(histories, tracer.SSH, command) prompt, err := honeypot.buildPrompt(command)
//Then //Then
assert.Nil(t, err) assert.Nil(t, err)
assert.Equal(t, SystemPromptLen+1, len(prompt)) assert.Equal(t, SystemPromptLen+1, len(prompt))
} }
func TestBuildPromptWithCustomPrompt(t *testing.T) {
//Given
var histories = []Message{
{
Role: "cat hello.txt",
Content: "world",
},
}
command := "pwd"
honeypot := LLMHoneypot{
Histories: histories,
Protocol: tracer.SSH,
CustomPrompt: "act as calculator",
}
//When
prompt, err := honeypot.buildPrompt(command)
//Then
assert.Nil(t, err)
assert.Equal(t, prompt[0].Content, "act as calculator")
assert.Equal(t, prompt[0].Role, SYSTEM.String())
}
func TestBuildExecuteModelFailValidation(t *testing.T) { func TestBuildExecuteModelFailValidation(t *testing.T) {
llmHoneypot := LLMHoneypot{ llmHoneypot := LLMHoneypot{
Histories: make([]Message, 0), Histories: make([]Message, 0),
OpenAIKey: "", OpenAIKey: "",
Protocol: tracer.SSH, Protocol: tracer.SSH,
Model: GPT4O, Model: "gpt4-o",
Provider: OpenAI,
} }
openAIGPTVirtualTerminal := InitLLMHoneypot(llmHoneypot) openAIGPTVirtualTerminal := InitLLMHoneypot(llmHoneypot)
@ -59,13 +96,60 @@ func TestBuildExecuteModelFailValidation(t *testing.T) {
assert.Equal(t, "openAIKey is empty", err.Error()) assert.Equal(t, "openAIKey is empty", err.Error())
} }
func TestBuildExecuteModelWithCustomPrompt(t *testing.T) {
client := resty.New()
httpmock.ActivateNonDefault(client.GetClient())
defer httpmock.DeactivateAndReset()
// Given
httpmock.RegisterMatcherResponder("POST", openAIEndpoint,
httpmock.BodyContainsString("hello world"),
func(req *http.Request) (*http.Response, error) {
resp, err := httpmock.NewJsonResponse(200, &Response{
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
},
)
llmHoneypot := LLMHoneypot{
Histories: make([]Message, 0),
OpenAIKey: "sdjdnklfjndslkjanfk",
Protocol: tracer.HTTP,
Model: "gpt4-o",
Provider: OpenAI,
CustomPrompt: "hello world",
}
openAIGPTVirtualTerminal := InitLLMHoneypot(llmHoneypot)
openAIGPTVirtualTerminal.client = client
//When
str, err := openAIGPTVirtualTerminal.ExecuteModel("GET /.aws/credentials")
//Then
assert.Nil(t, err)
assert.Equal(t, "[default]\nregion = us-west-2\noutput = json", str)
}
func TestBuildExecuteModelFailValidationStrategyType(t *testing.T) { func TestBuildExecuteModelFailValidationStrategyType(t *testing.T) {
llmHoneypot := LLMHoneypot{ llmHoneypot := LLMHoneypot{
Histories: make([]Message, 0), Histories: make([]Message, 0),
OpenAIKey: "", OpenAIKey: "",
Protocol: tracer.TCP, Protocol: tracer.TCP,
Model: GPT4O, Model: "gpt4-o",
Provider: OpenAI,
} }
openAIGPTVirtualTerminal := InitLLMHoneypot(llmHoneypot) openAIGPTVirtualTerminal := InitLLMHoneypot(llmHoneypot)
@ -80,7 +164,8 @@ func TestBuildExecuteModelFailValidationModelType(t *testing.T) {
llmHoneypot := LLMHoneypot{ llmHoneypot := LLMHoneypot{
Histories: make([]Message, 0), Histories: make([]Message, 0),
Protocol: tracer.SSH, Protocol: tracer.SSH,
Model: 5, Model: "llama3",
Provider: 5,
} }
openAIGPTVirtualTerminal := InitLLMHoneypot(llmHoneypot) openAIGPTVirtualTerminal := InitLLMHoneypot(llmHoneypot)
@ -98,7 +183,7 @@ func TestBuildExecuteModelSSHWithResultsOpenAI(t *testing.T) {
defer httpmock.DeactivateAndReset() defer httpmock.DeactivateAndReset()
// Given // Given
httpmock.RegisterResponder("POST", openAIGPTEndpoint, httpmock.RegisterResponder("POST", openAIEndpoint,
func(req *http.Request) (*http.Response, error) { func(req *http.Request) (*http.Response, error) {
resp, err := httpmock.NewJsonResponse(200, &Response{ resp, err := httpmock.NewJsonResponse(200, &Response{
Choices: []Choice{ Choices: []Choice{
@ -121,7 +206,8 @@ func TestBuildExecuteModelSSHWithResultsOpenAI(t *testing.T) {
Histories: make([]Message, 0), Histories: make([]Message, 0),
OpenAIKey: "sdjdnklfjndslkjanfk", OpenAIKey: "sdjdnklfjndslkjanfk",
Protocol: tracer.SSH, Protocol: tracer.SSH,
Model: GPT4O, Model: "gpt4-o",
Provider: OpenAI,
} }
openAIGPTVirtualTerminal := InitLLMHoneypot(llmHoneypot) openAIGPTVirtualTerminal := InitLLMHoneypot(llmHoneypot)
@ -159,7 +245,8 @@ func TestBuildExecuteModelSSHWithResultsLLama(t *testing.T) {
llmHoneypot := LLMHoneypot{ llmHoneypot := LLMHoneypot{
Histories: make([]Message, 0), Histories: make([]Message, 0),
Protocol: tracer.SSH, Protocol: tracer.SSH,
Model: LLAMA3, Model: "llama3",
Provider: Ollama,
} }
openAIGPTVirtualTerminal := InitLLMHoneypot(llmHoneypot) openAIGPTVirtualTerminal := InitLLMHoneypot(llmHoneypot)
@ -179,7 +266,7 @@ func TestBuildExecuteModelSSHWithoutResults(t *testing.T) {
defer httpmock.DeactivateAndReset() defer httpmock.DeactivateAndReset()
// Given // Given
httpmock.RegisterResponder("POST", openAIGPTEndpoint, httpmock.RegisterResponder("POST", openAIEndpoint,
func(req *http.Request) (*http.Response, error) { func(req *http.Request) (*http.Response, error) {
resp, err := httpmock.NewJsonResponse(200, &Response{ resp, err := httpmock.NewJsonResponse(200, &Response{
Choices: []Choice{}, Choices: []Choice{},
@ -195,7 +282,8 @@ func TestBuildExecuteModelSSHWithoutResults(t *testing.T) {
Histories: make([]Message, 0), Histories: make([]Message, 0),
OpenAIKey: "sdjdnklfjndslkjanfk", OpenAIKey: "sdjdnklfjndslkjanfk",
Protocol: tracer.SSH, Protocol: tracer.SSH,
Model: GPT4O, Model: "gpt4-o",
Provider: OpenAI,
} }
openAIGPTVirtualTerminal := InitLLMHoneypot(llmHoneypot) openAIGPTVirtualTerminal := InitLLMHoneypot(llmHoneypot)
@ -214,7 +302,7 @@ func TestBuildExecuteModelHTTPWithResults(t *testing.T) {
defer httpmock.DeactivateAndReset() defer httpmock.DeactivateAndReset()
// Given // Given
httpmock.RegisterResponder("POST", openAIGPTEndpoint, httpmock.RegisterResponder("POST", openAIEndpoint,
func(req *http.Request) (*http.Response, error) { func(req *http.Request) (*http.Response, error) {
resp, err := httpmock.NewJsonResponse(200, &Response{ resp, err := httpmock.NewJsonResponse(200, &Response{
Choices: []Choice{ Choices: []Choice{
@ -237,7 +325,8 @@ func TestBuildExecuteModelHTTPWithResults(t *testing.T) {
Histories: make([]Message, 0), Histories: make([]Message, 0),
OpenAIKey: "sdjdnklfjndslkjanfk", OpenAIKey: "sdjdnklfjndslkjanfk",
Protocol: tracer.HTTP, Protocol: tracer.HTTP,
Model: GPT4O, Model: "gpt4-o",
Provider: OpenAI,
} }
openAIGPTVirtualTerminal := InitLLMHoneypot(llmHoneypot) openAIGPTVirtualTerminal := InitLLMHoneypot(llmHoneypot)
@ -257,7 +346,7 @@ func TestBuildExecuteModelHTTPWithoutResults(t *testing.T) {
defer httpmock.DeactivateAndReset() defer httpmock.DeactivateAndReset()
// Given // Given
httpmock.RegisterResponder("POST", openAIGPTEndpoint, httpmock.RegisterResponder("POST", openAIEndpoint,
func(req *http.Request) (*http.Response, error) { func(req *http.Request) (*http.Response, error) {
resp, err := httpmock.NewJsonResponse(200, &Response{ resp, err := httpmock.NewJsonResponse(200, &Response{
Choices: []Choice{}, Choices: []Choice{},
@ -273,7 +362,8 @@ func TestBuildExecuteModelHTTPWithoutResults(t *testing.T) {
Histories: make([]Message, 0), Histories: make([]Message, 0),
OpenAIKey: "sdjdnklfjndslkjanfk", OpenAIKey: "sdjdnklfjndslkjanfk",
Protocol: tracer.HTTP, Protocol: tracer.HTTP,
Model: GPT4O, Model: "gpt4-o",
Provider: OpenAI,
} }
openAIGPTVirtualTerminal := InitLLMHoneypot(llmHoneypot) openAIGPTVirtualTerminal := InitLLMHoneypot(llmHoneypot)
@ -287,14 +377,105 @@ func TestBuildExecuteModelHTTPWithoutResults(t *testing.T) {
} }
func TestFromString(t *testing.T) { func TestFromString(t *testing.T) {
model, err := FromStringToLLMModel("llama3") model, err := FromStringToLLMProvider("openai")
assert.Nil(t, err) assert.Nil(t, err)
assert.Equal(t, LLAMA3, model) assert.Equal(t, OpenAI, model)
model, err = FromStringToLLMModel("gpt4-o") model, err = FromStringToLLMProvider("ollama")
assert.Nil(t, err) assert.Nil(t, err)
assert.Equal(t, GPT4O, model) assert.Equal(t, Ollama, model)
model, err = FromStringToLLMModel("beelzebub-model") model, err = FromStringToLLMProvider("beelzebub-model")
assert.Errorf(t, err, "model beelzebub-model not found") assert.Errorf(t, err, "provider beelzebub-model not found")
}
func TestBuildExecuteModelSSHWithoutPlaintextSection(t *testing.T) {
client := resty.New()
httpmock.ActivateNonDefault(client.GetClient())
defer httpmock.DeactivateAndReset()
// Given
httpmock.RegisterResponder("POST", ollamaEndpoint,
func(req *http.Request) (*http.Response, error) {
resp, err := httpmock.NewJsonResponse(200, &Response{
Message: Message{
Role: SYSTEM.String(),
Content: "```plaintext\n```\n",
},
})
if err != nil {
return httpmock.NewStringResponse(500, ""), nil
}
return resp, nil
},
)
llmHoneypot := LLMHoneypot{
Histories: make([]Message, 0),
Protocol: tracer.SSH,
Model: "llama3",
}
openAIGPTVirtualTerminal := InitLLMHoneypot(llmHoneypot)
openAIGPTVirtualTerminal.client = client
//When
str, err := openAIGPTVirtualTerminal.ExecuteModel("ls")
//Then
assert.Nil(t, err)
assert.Equal(t, "", str)
}
func TestBuildExecuteModelSSHWithoutQuotesSection(t *testing.T) {
client := resty.New()
httpmock.ActivateNonDefault(client.GetClient())
defer httpmock.DeactivateAndReset()
// Given
httpmock.RegisterResponder("POST", ollamaEndpoint,
func(req *http.Request) (*http.Response, error) {
resp, err := httpmock.NewJsonResponse(200, &Response{
Message: Message{
Role: SYSTEM.String(),
Content: "```\n```\n",
},
})
if err != nil {
return httpmock.NewStringResponse(500, ""), nil
}
return resp, nil
},
)
llmHoneypot := LLMHoneypot{
Histories: make([]Message, 0),
Protocol: tracer.SSH,
Model: "llama3",
Provider: Ollama,
}
openAIGPTVirtualTerminal := InitLLMHoneypot(llmHoneypot)
openAIGPTVirtualTerminal.client = client
//When
str, err := openAIGPTVirtualTerminal.ExecuteModel("ls")
//Then
assert.Nil(t, err)
assert.Equal(t, "", str)
}
func TestRemoveQuotes(t *testing.T) {
plaintext := "```plaintext\n```"
bash := "```bash\n```"
onlyQuotes := "```\n```"
complexText := "```plaintext\ntop - 10:30:48 up 1 day, 4:30, 2 users, load average: 0.15, 0.10, 0.08\nTasks: 198 total, 1 running, 197 sleeping, 0 stopped, 0 zombie\n```"
complexText2 := "```\ntop - 15:06:59 up 10 days, 3:17, 1 user, load average: 0.10, 0.09, 0.08\nTasks: 285 total\n```"
assert.Equal(t, "", removeQuotes(plaintext))
assert.Equal(t, "", removeQuotes(bash))
assert.Equal(t, "", removeQuotes(onlyQuotes))
assert.Equal(t, "top - 10:30:48 up 1 day, 4:30, 2 users, load average: 0.15, 0.10, 0.08\nTasks: 198 total, 1 running, 197 sleeping, 0 stopped, 0 zombie\n", removeQuotes(complexText))
assert.Equal(t, "top - 15:06:59 up 10 days, 3:17, 1 user, load average: 0.10, 0.09, 0.08\nTasks: 285 total\n", removeQuotes(complexText2))
} }

View File

@ -2,9 +2,6 @@ package strategies
import ( import (
"fmt" "fmt"
"github.com/mariocandela/beelzebub/v3/parser"
"github.com/mariocandela/beelzebub/v3/plugins"
"github.com/mariocandela/beelzebub/v3/tracer"
"io" "io"
"net" "net"
"net/http" "net/http"
@ -12,6 +9,9 @@ import (
"strings" "strings"
"github.com/google/uuid" "github.com/google/uuid"
"github.com/mariocandela/beelzebub/v3/parser"
"github.com/mariocandela/beelzebub/v3/plugins"
"github.com/mariocandela/beelzebub/v3/tracer"
log "github.com/sirupsen/logrus" log "github.com/sirupsen/logrus"
) )
@ -37,19 +37,21 @@ func (httpStrategy HTTPStrategy) Init(beelzebubServiceConfiguration parser.Beelz
if command.Plugin == plugins.LLMPluginName { if command.Plugin == plugins.LLMPluginName {
llmModel, err := plugins.FromStringToLLMModel(beelzebubServiceConfiguration.Plugin.LLMModel) llmProvider, err := plugins.FromStringToLLMProvider(beelzebubServiceConfiguration.Plugin.LLMProvider)
if err != nil { if err != nil {
log.Errorf("Error fromString: %s", err.Error()) log.Errorf("Error: %s", err.Error())
responseHTTPBody = "404 Not Found!" responseHTTPBody = "404 Not Found!"
} }
llmHoneypot := plugins.LLMHoneypot{ llmHoneypot := plugins.LLMHoneypot{
Histories: make([]plugins.Message, 0), Histories: make([]plugins.Message, 0),
OpenAIKey: beelzebubServiceConfiguration.Plugin.OpenAISecretKey, OpenAIKey: beelzebubServiceConfiguration.Plugin.OpenAISecretKey,
Protocol: tracer.HTTP, Protocol: tracer.HTTP,
Host: beelzebubServiceConfiguration.Plugin.Host, Host: beelzebubServiceConfiguration.Plugin.Host,
Model: llmModel, Model: beelzebubServiceConfiguration.Plugin.LLMModel,
Provider: llmProvider,
CustomPrompt: beelzebubServiceConfiguration.Plugin.Prompt,
} }
llmHoneypotInstance := plugins.InitLLMHoneypot(llmHoneypot) llmHoneypotInstance := plugins.InitLLMHoneypot(llmHoneypot)
@ -66,13 +68,25 @@ func (httpStrategy HTTPStrategy) Init(beelzebubServiceConfiguration parser.Beelz
} }
setResponseHeaders(responseWriter, command.Headers, command.StatusCode) setResponseHeaders(responseWriter, command.Headers, command.StatusCode)
fmt.Fprintf(responseWriter, responseHTTPBody) fmt.Fprint(responseWriter, responseHTTPBody)
break break
} }
} }
}) })
go func() { go func() {
err := http.ListenAndServe(httpStrategy.beelzebubServiceConfiguration.Address, serverMux) var err error
// Launch a TLS supporting server if we are supplied a TLS Key and Certificate.
// If relative paths are supplied, they are relative to the CWD of the binary.
// The can be self-signed, only the client will validate this (or not).
if httpStrategy.beelzebubServiceConfiguration.TLSKeyPath != "" && httpStrategy.beelzebubServiceConfiguration.TLSCertPath != "" {
err = http.ListenAndServeTLS(
httpStrategy.beelzebubServiceConfiguration.Address,
httpStrategy.beelzebubServiceConfiguration.TLSCertPath,
httpStrategy.beelzebubServiceConfiguration.TLSKeyPath,
serverMux)
} else {
err = http.ListenAndServe(httpStrategy.beelzebubServiceConfiguration.Address, serverMux)
}
if err != nil { if err != nil {
log.Errorf("Error during init HTTP Protocol: %s", err.Error()) log.Errorf("Error during init HTTP Protocol: %s", err.Error())
return return
@ -94,7 +108,7 @@ func traceRequest(request *http.Request, tr tracer.Tracer, HoneypotDescription s
} }
host, port, _ := net.SplitHostPort(request.RemoteAddr) host, port, _ := net.SplitHostPort(request.RemoteAddr)
tr.TraceEvent(tracer.Event{ event := tracer.Event{
Msg: "HTTP New request", Msg: "HTTP New request",
RequestURI: request.RequestURI, RequestURI: request.RequestURI,
Protocol: tracer.HTTP.String(), Protocol: tracer.HTTP.String(),
@ -110,7 +124,13 @@ func traceRequest(request *http.Request, tr tracer.Tracer, HoneypotDescription s
SourcePort: port, SourcePort: port,
ID: uuid.New().String(), ID: uuid.New().String(),
Description: HoneypotDescription, Description: HoneypotDescription,
}) }
// Capture the TLS details from the request, if provided.
if request.TLS != nil {
event.Msg = "HTTPS New Request"
event.TLSServerName = request.TLS.ServerName
}
tr.TraceEvent(event)
} }
func mapHeaderToString(headers http.Header) string { func mapHeaderToString(headers http.Header) string {

View File

@ -44,19 +44,22 @@ func (sshStrategy *SSHStrategy) Init(beelzebubServiceConfiguration parser.Beelze
if command.Plugin == plugins.LLMPluginName { if command.Plugin == plugins.LLMPluginName {
llmModel, err := plugins.FromStringToLLMModel(beelzebubServiceConfiguration.Plugin.LLMModel) llmProvider, err := plugins.FromStringToLLMProvider(beelzebubServiceConfiguration.Plugin.LLMProvider)
if err != nil { if err != nil {
log.Errorf("Error fromString: %s", err.Error()) log.Errorf("Error: %s", err.Error())
commandOutput = "command not found" commandOutput = "command not found"
llmProvider = plugins.OpenAI
} }
llmHoneypot := plugins.LLMHoneypot{ llmHoneypot := plugins.LLMHoneypot{
Histories: make([]plugins.Message, 0), Histories: make([]plugins.Message, 0),
OpenAIKey: beelzebubServiceConfiguration.Plugin.OpenAISecretKey, OpenAIKey: beelzebubServiceConfiguration.Plugin.OpenAISecretKey,
Protocol: tracer.SSH, Protocol: tracer.SSH,
Host: beelzebubServiceConfiguration.Plugin.Host, Host: beelzebubServiceConfiguration.Plugin.Host,
Model: llmModel, Model: beelzebubServiceConfiguration.Plugin.LLMModel,
Provider: llmProvider,
CustomPrompt: beelzebubServiceConfiguration.Plugin.Prompt,
} }
llmHoneypotInstance := plugins.InitLLMHoneypot(llmHoneypot) llmHoneypotInstance := plugins.InitLLMHoneypot(llmHoneypot)
@ -129,19 +132,21 @@ func (sshStrategy *SSHStrategy) Init(beelzebubServiceConfiguration parser.Beelze
if command.Plugin == plugins.LLMPluginName { if command.Plugin == plugins.LLMPluginName {
llmModel, err := plugins.FromStringToLLMModel(beelzebubServiceConfiguration.Plugin.LLMModel) llmProvider, err := plugins.FromStringToLLMProvider(beelzebubServiceConfiguration.Plugin.LLMProvider)
if err != nil { if err != nil {
log.Errorf("Error fromString: %s", err.Error()) log.Errorf("Error: %s, fallback OpenAI", err.Error())
commandOutput = "command not found" llmProvider = plugins.OpenAI
} }
llmHoneypot := plugins.LLMHoneypot{ llmHoneypot := plugins.LLMHoneypot{
Histories: histories, Histories: histories,
OpenAIKey: beelzebubServiceConfiguration.Plugin.OpenAISecretKey, OpenAIKey: beelzebubServiceConfiguration.Plugin.OpenAISecretKey,
Protocol: tracer.SSH, Protocol: tracer.SSH,
Host: beelzebubServiceConfiguration.Plugin.Host, Host: beelzebubServiceConfiguration.Plugin.Host,
Model: llmModel, Model: beelzebubServiceConfiguration.Plugin.LLMModel,
Provider: llmProvider,
CustomPrompt: beelzebubServiceConfiguration.Plugin.Prompt,
} }
llmHoneypotInstance := plugins.InitLLMHoneypot(llmHoneypot) llmHoneypotInstance := plugins.InitLLMHoneypot(llmHoneypot)

View File

@ -2,10 +2,11 @@
package tracer package tracer
import ( import (
log "github.com/sirupsen/logrus"
"sync" "sync"
"time" "time"
log "github.com/sirupsen/logrus"
"github.com/prometheus/client_golang/prometheus" "github.com/prometheus/client_golang/prometheus"
"github.com/prometheus/client_golang/prometheus/promauto" "github.com/prometheus/client_golang/prometheus/promauto"
) )
@ -36,6 +37,7 @@ type Event struct {
Description string Description string
SourceIp string SourceIp string
SourcePort string SourcePort string
TLSServerName string
} }
type ( type (