diff --git a/.gitignore b/.gitignore index 6228180..b3d8a55 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,2 @@ -events.log -.env \ No newline at end of file +.env +vuln-config.yaml \ No newline at end of file diff --git a/README.md b/README.md index 006261b..42d7bb1 100644 --- a/README.md +++ b/README.md @@ -65,21 +65,22 @@ psql -h localhost -p 5432 -U admin -V 'sslmode=disable' 3. **Storage of HTTP Request Headers:** A table named `http_request` is generated to capture HTTP requests. This table stores the attack ID, HTTP request method, and User-Agent. If an attacker sends an HTTP request via PUT or POST, the request body is saved in the Payload folder, with a maximum size of 100 MB. The associated HTTP body table contains the columns Content-Type and "Payload size". If the request is sent via a hidden contact form, the attacker's email address and name are stored in the `http_spam` table. ### 6. HTTP Endpoints -- Provides attack events details and statistics via HTTP endpoints on port `1112`. + +Provides attack events details and statistics via HTTP endpoints on port `1112`. + | Path | Description | | ----------------------- | -------------------------------------------------------------------------------------------------------- | -| /realtime | Provides real-time data on ongoing attacks and activities being recorded using Server-Side Events (SSE). | -| /latest-attacks | Provides latest attacks of each honeypot | -| /stats/count-in-24hours | Provides the number of attacks in the last 24 hours measured per hour | -| /stats/count-in-7days | Provides the number of attacks in the last 7 days measured per day | -| /stats/count-in-6months | Provides the number of attacks in the last 6 months measured per month | -| /stats/country | Provides statistics on the number of attacks originating from different countries. | -| /stats/ip | Provides statistics on the number of attacks originating from different IP addresses. | -| /stats/username | Provides statistics on the usernames used in login attempts. | -| /stats/password | Provides statistics on the passwords used in login attempts. | -| /stats/port | Provides statistics on the number of attacks per port. | -| /stats/path | Provides statistics on the HTTP paths accessed during attacks. | - +| `/realtime` | Provides real-time data on ongoing attacks and activities being recorded using Server-Side Events (SSE). | +| `/latest-attacks` | Provides latest attacks of each honeypot | +| `/stats/count-in-24hours` | Provides the number of attacks in the last 24 hours measured per hour | +| `/stats/count-in-7days` | Provides the number of attacks in the last 7 days measured per day | +| `/stats/count-in-6months` | Provides the number of attacks in the last 6 months measured per month | +| `/stats/country` | Provides statistics on the number of attacks originating from different countries. | +| `/stats/ip` | Provides statistics on the number of attacks originating from different IP addresses. | +| `/stats/username` | Provides statistics on the usernames used in login attempts. | +| `/stats/password` | Provides statistics on the passwords used in login attempts. | +| `/stats/port` | Provides statistics on the number of attacks per port. | +| `/stats/path` | Provides statistics on the HTTP paths accessed during attacks. | ## Installation @@ -100,23 +101,20 @@ cp .env.example .env 5. You can run the honeypot by executing the following command: ```bash - go run main.go - ``` 6. There is even a Makefile included in the project, so you can simply run: ```bash - make - ``` -This starts the honeypot. +This starts the honeypot. ## Configuration ### Vulnerability on honeypot + Vulnerabilities of HTTP Honeypot and SSH can be configured as follows: ```yaml http: @@ -126,6 +124,7 @@ http: ssh: ServerVersion: "SSH-2.0-OpenSSH_5.8p2" ``` + ### DB-IP The honeypot uses the [DB-IP](https://db-ip.com/) service to determine the geolocation of the IP addresses that interact with it. The db-ip lite database is included in the project and needs to be updated regularly. The link to download the latest version can be found [here](https://db-ip.com/db/download/ip-to-country-lite). The file needs to be extracted and placed in the `root` folder. The file name should be `dbip-country.csv`. diff --git a/cmd/main.go b/cmd/main.go index 07d7baf..4100bfc 100644 --- a/cmd/main.go +++ b/cmd/main.go @@ -33,7 +33,7 @@ func main() { // Load the .env file err = godotenv.Load(".env") if err != nil { - slog.Warn("Error loading .env file: %s", err) + slog.Warn("Error loading .env file", "err", err) } postgresqlDB := store.PostgreSQL{} @@ -50,6 +50,11 @@ func main() { httpHoneypot := honeypot.NewHTTP(honeypot.HTTPConfig{ Port: 80, + HTTPSConfig: honeypot.HTTPSConfig{ + Port: 443, + CertFile: "cert.pem", + KeyFile: "key.pem", + }, }) err = httpHoneypot.Start() if err != nil { @@ -73,17 +78,17 @@ func main() { } tcpHoneypot := honeypot.NewTCP(honeypot.MostUsedTCPPorts()) - udpHoneypot := honeypot.NewUDP(honeypot.MostUsedUDPPorts()) + // udpHoneypot := honeypot.NewUDP(honeypot.MostUsedUDPPorts()) err = tcpHoneypot.Start() if err != nil { panic(err) } - err = udpHoneypot.Start() - if err != nil { - panic(err) - } + // err = udpHoneypot.Start() + // if err != nil { + // panic(err) + // } httpTransport := transport.NewHTTP(transport.HTTPConfig{ Port: 1112, @@ -97,12 +102,19 @@ func main() { dbIp := dbip.NewIpToCountry("dbip-country.csv") // listen for SET events - setChannel := pipeline.Map(pipeline.Merge(sshHoneypot.GetSETChannel(), tcpHoneypot.GetSETChannel(), udpHoneypot.GetSETChannel(), httpHoneypot.GetSETChannel(), postgresHoneypot.GetSETChannel()), func(input types.Set) (types.Set, error) { - input.COUNTRY = dbIp.Lookup(net.ParseIP(input.SUB)) - input.HONEYPOT = string(os.Getenv("HONEYPOT_NAME")) - return input, nil - }) - + setChannel := + pipeline.Map( + pipeline.Merge( + sshHoneypot.GetSETChannel(), + httpHoneypot.GetSETChannel(), + tcpHoneypot.GetSETChannel(), + // udpHoneypot.GetSETChannel(), + postgresHoneypot.GetSETChannel()), + func(input types.Set) (types.Set, error) { + input.COUNTRY = dbIp.Lookup(net.ParseIP(input.SUB)) + input.HONEYPOT = string(os.Getenv("HONEYPOT_NAME")) + return input, nil + }) // save everything, which is send over the setChannel inside the database pipeline.Pipe(setChannel, dbChan) dbSubscription := postgresqlDB.SubscribeToDBChanges() diff --git a/go.mod b/go.mod index d764875..4097a2e 100644 --- a/go.mod +++ b/go.mod @@ -31,6 +31,7 @@ require ( github.com/pkg/errors v0.9.1 // indirect github.com/sagikazarmark/locafero v0.4.0 // indirect github.com/sagikazarmark/slog-shim v0.1.0 // indirect + github.com/sethvargo/go-password v0.3.1 // indirect github.com/shopspring/decimal v1.4.0 // indirect github.com/sourcegraph/conc v0.3.0 // indirect github.com/spf13/afero v1.11.0 // indirect diff --git a/go.sum b/go.sum index bb37cc0..7926590 100644 --- a/go.sum +++ b/go.sum @@ -55,6 +55,8 @@ github.com/sagikazarmark/locafero v0.4.0 h1:HApY1R9zGo4DBgr7dqsTH/JJxLTTsOt7u6ke github.com/sagikazarmark/locafero v0.4.0/go.mod h1:Pe1W6UlPYUk/+wc/6KFhbORCfqzgYEpgQ3O5fPuL3H4= github.com/sagikazarmark/slog-shim v0.1.0 h1:diDBnUNK9N/354PgrxMywXnAwEr1QZcOr6gto+ugjYE= github.com/sagikazarmark/slog-shim v0.1.0/go.mod h1:SrcSrq8aKtyuqEI1uvTDTK1arOWRIczQRv+GVI1AkeQ= +github.com/sethvargo/go-password v0.3.1 h1:WqrLTjo7X6AcVYfC6R7GtSyuUQR9hGyAj/f1PYQZCJU= +github.com/sethvargo/go-password v0.3.1/go.mod h1:rXofC1zT54N7R8K/h1WDUdkf9BOx5OptoxrMBcrXzvs= github.com/shopspring/decimal v1.4.0 h1:bxl37RwXBklmTi0C79JfXCEBD1cqqHt0bbgBAGFp81k= github.com/shopspring/decimal v1.4.0/go.mod h1:gawqmDU56v4yIKSwfBSFip1HdCCXN8/+DMd9qYNcwME= github.com/sourcegraph/conc v0.3.0 h1:OQTbbt6P72L20UqAkXXuLOj79LfEanQ+YQFNpLA9ySo= diff --git a/json-schema/credential-theft.json b/json-schema/credential-theft.json new file mode 100644 index 0000000..b22b755 --- /dev/null +++ b/json-schema/credential-theft.json @@ -0,0 +1,35 @@ +{ + "$schema": "https://json-schema.org/draft/2019-09/schema", + "$id": "https://github.com/l3montree-dev/oh-my-honeypot/json-schema/credential_theft.json", + "type": "object", + "default": {}, + "title": "Root Schema", + "required": [ + "ssh_pw", + "db_pw" + ], + "properties": { + "ssh_pw": { + "type": "string", + "default": "", + "title": "The password Schema", + "examples": [ + "123456" + ] + }, + "db_pw": { + "type": "string", + "default": "", + "title": "The password Schema", + "examples": [ + "123456" + ] + } + }, + "examples": [ + { + "ssh_pw": "1234567", + "db_pw": "123456" + } + ] +} \ No newline at end of file diff --git a/packages/honeypot/honeypot.go b/packages/honeypot/honeypot.go index e294a4f..0468335 100644 --- a/packages/honeypot/honeypot.go +++ b/packages/honeypot/honeypot.go @@ -11,9 +11,10 @@ import ( ) const ( - PortEventID = "https://github.com/l3montree-dev/oh-my-honeypot/json-schema/port-scanning.json" - LoginEventID = "https://github.com/l3montree-dev/oh-my-honeypot/json-schema/ssh-login-attempt.json" - HTTPEventID = "https://github.com/l3montree-dev/oh-my-honeypot/json-schema/http-request.json" + PortEventID = "https://github.com/l3montree-dev/oh-my-honeypot/json-schema/port-scanning.json" + LoginEventID = "https://github.com/l3montree-dev/oh-my-honeypot/json-schema/ssh-login-attempt.json" + HTTPEventID = "https://github.com/l3montree-dev/oh-my-honeypot/json-schema/http-request.json" + CredentialEventID = "https://github.com/l3montree-dev/oh-my-honeypot/json-schema/credential-theft.json" ) type Honeypot interface { diff --git a/packages/honeypot/http.go b/packages/honeypot/http.go index 2953c5a..7e02ea5 100644 --- a/packages/honeypot/http.go +++ b/packages/honeypot/http.go @@ -2,8 +2,10 @@ package honeypot import ( "fmt" - "io" + "log" + "sort" + "log/slog" "net" "net/http" @@ -11,110 +13,351 @@ import ( "time" "github.com/google/uuid" - "github.com/l3montree-dev/oh-my-honeypot/packages/types" "github.com/l3montree-dev/oh-my-honeypot/packages/utils" + "github.com/sethvargo/go-password/password" "github.com/spf13/viper" ) +type httpsHoneypot struct { + port int + cert string + key string +} + type httpHoneypot struct { port int // setChan is the channel the honeypot is posting SET events to. setChan chan types.Set + httpsHoneypot +} + +type HTTPSConfig struct { + Port int + CertFile string + KeyFile string } type HTTPConfig struct { Port int + HTTPSConfig } +const headTemplate = ` + + + +
+ + +