From cec41cdfbb2d9b13753b75b7b68dbbabcb6696e4 Mon Sep 17 00:00:00 2001 From: Tom Date: Mon, 30 Aug 2021 21:00:03 -0500 Subject: [PATCH 1/8] Github action fix --- .github/workflows/docker-image.yml | 2 -- 1 file changed, 2 deletions(-) diff --git a/.github/workflows/docker-image.yml b/.github/workflows/docker-image.yml index 4b9d5c7..c3970f2 100644 --- a/.github/workflows/docker-image.yml +++ b/.github/workflows/docker-image.yml @@ -3,8 +3,6 @@ name: Docker Image CI on: push: branches: [ main ] - pull_request: - branches: [ main ] jobs: From 048e0b4bc880bcb881d83a1f14abb98a0a0f971e Mon Sep 17 00:00:00 2001 From: Tom Date: Mon, 30 Aug 2021 21:22:40 -0500 Subject: [PATCH 2/8] non root dockerfile --- Dockerfile | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/Dockerfile b/Dockerfile index d355e35..136f768 100644 --- a/Dockerfile +++ b/Dockerfile @@ -6,11 +6,12 @@ WORKDIR /app COPY . ./ RUN go mod download && go build -o /helix-honeypot +#Final Stage FROM alpine:latest WORKDIR / - -# Until Go Embed stuff COPY --from=build /helix-honeypot /helix-honeypot +RUN addgroup -S helix && adduser -S helix -G helix +USER helix EXPOSE 8000 From 114c5c8e3b8c4450c14207c5e18beecf24baa99b Mon Sep 17 00:00:00 2001 From: Tom Date: Wed, 1 Sep 2021 21:38:22 -0500 Subject: [PATCH 3/8] using latest protobuf --- go.mod | 2 +- handler/openapiHandler.go | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/go.mod b/go.mod index 168b80f..7df24f2 100644 --- a/go.mod +++ b/go.mod @@ -3,8 +3,8 @@ module github.com/zeerg/helix-honeypot go 1.16 require ( - github.com/golang/protobuf v1.5.2 github.com/googleapis/gnostic v0.5.5 github.com/labstack/echo/v4 v4.5.0 github.com/labstack/gommon v0.3.0 + google.golang.org/protobuf v1.26.0 ) diff --git a/handler/openapiHandler.go b/handler/openapiHandler.go index 22072e0..83ff2a8 100644 --- a/handler/openapiHandler.go +++ b/handler/openapiHandler.go @@ -8,7 +8,7 @@ import ( "crypto/sha512" "github.com/labstack/echo/v4" - "github.com/golang/protobuf/proto" + "google.golang.org/protobuf/proto" openapi_v2 "github.com/googleapis/gnostic/openapiv2" ) From d775673fa43e5c331174b6f92991166d166320ed Mon Sep 17 00:00:00 2001 From: Tom Date: Wed, 1 Sep 2021 22:27:15 -0500 Subject: [PATCH 4/8] active defense mode --- ...cesHandler.go => activeDefenseHandlers.go} | 8 +- handler/apiHandler.go | 31 ------- handler/apiModeHandlers.go | 86 +++++++++++++++++++ handler/posthandler.go | 17 ---- handler/rootHandler.go | 16 ---- handler/serviceHandler.go | 23 ----- main.go | 44 ++++++++-- readme.md | 2 +- 8 files changed, 128 insertions(+), 99 deletions(-) rename handler/{resourcesHandler.go => activeDefenseHandlers.go} (73%) delete mode 100644 handler/apiHandler.go create mode 100644 handler/apiModeHandlers.go delete mode 100644 handler/posthandler.go delete mode 100644 handler/rootHandler.go delete mode 100644 handler/serviceHandler.go diff --git a/handler/resourcesHandler.go b/handler/activeDefenseHandlers.go similarity index 73% rename from handler/resourcesHandler.go rename to handler/activeDefenseHandlers.go index 79a8707..b0e93ea 100644 --- a/handler/resourcesHandler.go +++ b/handler/activeDefenseHandlers.go @@ -7,7 +7,7 @@ import ( ) // Pods Handler for default routes etc..Just returns blank -func PodsHandler(c echo.Context) error { +func AdGetHandler(c echo.Context) error { var data map[string]interface{} err := json.Unmarshal(embedGet("empty_list.json"), &data) if err != nil { @@ -15,12 +15,12 @@ func PodsHandler(c echo.Context) error { } return c.JSON(http.StatusOK, data) } -// Handler for any k8s resource like deployments etc. -func ResourceHandler(c echo.Context) error { +func AdPostHandler(c echo.Context) error { json_map := make(map[string]interface{}) err := json.NewDecoder(c.Request().Body).Decode(&json_map) + c.Logger().Print(json_map) if err != nil { c.Logger().Print(err) } - return c.JSON(404, json_map) + return c.JSON(201, json_map) } \ No newline at end of file diff --git a/handler/apiHandler.go b/handler/apiHandler.go deleted file mode 100644 index 051eede..0000000 --- a/handler/apiHandler.go +++ /dev/null @@ -1,31 +0,0 @@ -package handler - -import ( - "github.com/labstack/echo/v4" - "net/http" - "encoding/json" -) -func ApiHandler(c echo.Context) error { - var data map[string]interface{} - err := json.Unmarshal(embedGet("api.json"), &data) - if err != nil { - c.Logger().Print(err) - } - return c.JSON(http.StatusOK, data) -} -func ApiResourceList(c echo.Context) error { - var data map[string]interface{} - err := json.Unmarshal(embedGet("api_resourcelist.json"), &data) - if err != nil { - c.Logger().Print(err) - } - return c.JSON(http.StatusOK, data) -} -func ApiGroupList(c echo.Context) error { - var data map[string]interface{} - err := json.Unmarshal(embedGet("api_grouplist.json"), &data) - if err != nil { - c.Logger().Print(err) - } - return c.JSON(http.StatusOK, data) -} \ No newline at end of file diff --git a/handler/apiModeHandlers.go b/handler/apiModeHandlers.go new file mode 100644 index 0000000..7a1ecb1 --- /dev/null +++ b/handler/apiModeHandlers.go @@ -0,0 +1,86 @@ +package handler + +import ( + "github.com/labstack/echo/v4" + "net/http" + "encoding/json" + "fmt" +) +// ApiHandler returns the api.json embedded file +func ApiHandler(c echo.Context) error { + var data map[string]interface{} + err := json.Unmarshal(embedGet("api.json"), &data) + if err != nil { + c.Logger().Print(err) + } + return c.JSON(http.StatusOK, data) +} +// ApiResourceList returns the api_resourcelist.json embedded file +func ApiResourceList(c echo.Context) error { + var data map[string]interface{} + err := json.Unmarshal(embedGet("api_resourcelist.json"), &data) + if err != nil { + c.Logger().Print(err) + } + return c.JSON(http.StatusOK, data) +} +// ApiGroupList returns the api_grouplist.json embedded file +func ApiGroupList(c echo.Context) error { + var data map[string]interface{} + err := json.Unmarshal(embedGet("api_grouplist.json"), &data) + if err != nil { + c.Logger().Print(err) + } + return c.JSON(http.StatusOK, data) +} +// Root Route Handler +func RootHandler(c echo.Context) error { + var data map[string]interface{} + err := json.Unmarshal(embedGet("root.json"), &data) + if err != nil { + c.Logger().Print(err) + } + return c.JSON(http.StatusOK, data) +} +// Pods Handler for default routes etc..Just returns blank +func PodsHandler(c echo.Context) error { + var data map[string]interface{} + err := json.Unmarshal(embedGet("empty_list.json"), &data) + if err != nil { + c.Logger().Print(err) + } + return c.JSON(http.StatusOK, data) +} +// Handler for any k8s resource like deployments etc. +func ResourceHandler(c echo.Context) error { + json_map := make(map[string]interface{}) + err := json.NewDecoder(c.Request().Body).Decode(&json_map) + if err != nil { + c.Logger().Print(err) + } + return c.JSON(404, json_map) +} +//Pods Handler just returns a 201 and echo's back the post request +func PostHandler(c echo.Context) error { + json_map := make(map[string]interface{}) + err := json.NewDecoder(c.Request().Body).Decode(&json_map) + c.Logger().Print(json_map) + if err != nil { + c.Logger().Print(err) + } + return c.JSON(201, json_map) +} +//Pods Handler +func ServiceHandler(c echo.Context) error { + servicePathBase := "resource_dump/" + service := c.Param("service") + version := c.Param("version") + fileName := "serverresources.json" + filePath := fmt.Sprintf("%s%s/%s/%s", servicePathBase, service, version, fileName) + var data map[string]interface{} + err := json.Unmarshal(embedGet(filePath), &data) + if err != nil { + c.Logger().Print(err) + } + return c.JSON(http.StatusOK, data) +} \ No newline at end of file diff --git a/handler/posthandler.go b/handler/posthandler.go deleted file mode 100644 index a88bc66..0000000 --- a/handler/posthandler.go +++ /dev/null @@ -1,17 +0,0 @@ -package handler - -import ( - "github.com/labstack/echo/v4" - "encoding/json" -) - -//Pods Handler just returns a 201 and echo's back the post request -func PostHandler(c echo.Context) error { - json_map := make(map[string]interface{}) - err := json.NewDecoder(c.Request().Body).Decode(&json_map) - c.Logger().Print(json_map) - if err != nil { - c.Logger().Print(err) - } - return c.JSON(201, json_map) -} diff --git a/handler/rootHandler.go b/handler/rootHandler.go deleted file mode 100644 index e246dec..0000000 --- a/handler/rootHandler.go +++ /dev/null @@ -1,16 +0,0 @@ -package handler - -import ( - "github.com/labstack/echo/v4" - "net/http" - "encoding/json" -) -// Root Route Handler -func RootHandler(c echo.Context) error { - var data map[string]interface{} - err := json.Unmarshal(embedGet("root.json"), &data) - if err != nil { - c.Logger().Print(err) - } - return c.JSON(http.StatusOK, data) -} \ No newline at end of file diff --git a/handler/serviceHandler.go b/handler/serviceHandler.go deleted file mode 100644 index dabd689..0000000 --- a/handler/serviceHandler.go +++ /dev/null @@ -1,23 +0,0 @@ -package handler - -import ( - "github.com/labstack/echo/v4" - "net/http" - "fmt" - "encoding/json" - -) -//Pods Handler -func ServiceHandler(c echo.Context) error { - servicePathBase := "resource_dump/" - service := c.Param("service") - version := c.Param("version") - fileName := "serverresources.json" - filePath := fmt.Sprintf("%s%s/%s/%s", servicePathBase, service, version, fileName) - var data map[string]interface{} - err := json.Unmarshal(embedGet(filePath), &data) - if err != nil { - c.Logger().Print(err) - } - return c.JSON(http.StatusOK, data) -} diff --git a/main.go b/main.go index 1b7fda8..cbc5684 100644 --- a/main.go +++ b/main.go @@ -4,9 +4,24 @@ import ( "github.com/labstack/echo/v4/middleware" "github.com/zeerg/helix-honeypot/router" "github.com/zeerg/helix-honeypot/handler" + "flag" + "fmt" + "os" ) func main() { + // Get the run mode + var runMode string + flag.StringVar(&runMode, "mode", "api", "The run mode for the honeypot [api, ad]") + flag.Parse() + + if len(runMode) == 0 { + fmt.Println("Usage:") + flag.PrintDefaults() + os.Exit(1) +} + + // Echo instance e := router.New() @@ -14,19 +29,34 @@ func main() { e.Use(middleware.Logger()) e.Use(middleware.Recover()) - // Routes for basic k8s operations + + + // Routes for basic k8s operations and api calls to info endpoints e.GET("/", handler.RootHandler) e.GET("/openapi/v2", handler.OpenApiHandler) e.GET("/api/v1", handler.ApiResourceList) e.GET("/api", handler.ApiHandler) e.GET("/apis", handler.ApiGroupList) - e.GET("/apis/apps/v1/namespaces/:namespace/:workload", handler.PodsHandler) - e.GET("/apis/apps/v1/namespaces/:namespace/:workload/:app", handler.ResourceHandler) e.GET("/apis/:service/:version", handler.ServiceHandler) - e.GET("/api/v1/namespaces/:namespace/:resource", handler.PodsHandler) - e.GET("/apis/extensions/v1beta1/namespaces/:namespace/:resource", handler.PodsHandler) - e.GET("/api/v1/:service", handler.PodsHandler) - e.POST("/api*", handler.PostHandler) + e.GET("/apis/apps/v1/namespaces/:namespace/:workload/:app", handler.ResourceHandler) + // Routes for Typical API Mode + if runMode == "api" { + e.GET("/apis/apps/v1/namespaces/:namespace/:workload", handler.PodsHandler) + e.GET("/api/v1/namespaces/:namespace/:resource", handler.PodsHandler) + e.GET("/apis/extensions/v1beta1/namespaces/:namespace/:resource", handler.PodsHandler) + e.GET("/api/v1/:service", handler.PodsHandler) + e.POST("/api*", handler.PostHandler) + + } + // Routes for Active Defense Mode + if runMode == "ad" { + e.GET("/apis/apps/v1/namespaces/:namespace/:workload", handler.AdGetHandler) + e.GET("/api/v1/namespaces/:namespace/:resource", handler.AdGetHandler) + e.GET("/apis/extensions/v1beta1/namespaces/:namespace/:resource", handler.AdGetHandler) + e.GET("/api/v1/:service", handler.AdGetHandler) + e.POST("/api*", handler.AdPostHandler) + } + diff --git a/readme.md b/readme.md index 2f53c06..a215c49 100644 --- a/readme.md +++ b/readme.md @@ -6,7 +6,7 @@ [![Docker Image CI](https://github.com/Zeerg/helix-honeypot/actions/workflows/docker-image.yml/badge.svg)](https://github.com/Zeerg/helix-honeypot/actions/workflows/docker-image.yml) # Introduction -Helix is a honeypot that fakes the K8s API server. All events are logged to stdout +Helix is a honeypot that serves two primary purposes. When running in K8s mode it listens and responds as a typical K8s api server(most endpoints). When running in active defense mode the api responses become massive and are meant to disrupt typical internet scanners. # Local Testing Clone this repo From 938a69661372a50c8d7e71d064336d88eb7fe492 Mon Sep 17 00:00:00 2001 From: Tom Date: Wed, 1 Sep 2021 22:29:21 -0500 Subject: [PATCH 5/8] readme updates --- readme.md | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/readme.md b/readme.md index a215c49..dd9ca38 100644 --- a/readme.md +++ b/readme.md @@ -6,7 +6,14 @@ [![Docker Image CI](https://github.com/Zeerg/helix-honeypot/actions/workflows/docker-image.yml/badge.svg)](https://github.com/Zeerg/helix-honeypot/actions/workflows/docker-image.yml) # Introduction -Helix is a honeypot that serves two primary purposes. When running in K8s mode it listens and responds as a typical K8s api server(most endpoints). When running in active defense mode the api responses become massive and are meant to disrupt typical internet scanners. +Helix is a honeypot that serves two primary purposes. When running in K8s mode it listens and responds as a typical K8s api server(most endpoints). When running in active defense mode the api responses become massive and are meant to disrupt typical internet scanners. + +# Usage +``` +Usage: + -mode string + The run mode for the honeypot [api, ad] (default "api") +``` # Local Testing Clone this repo From bc32b5fa1bc20a02746977f5fcb5bc41c2f011ad Mon Sep 17 00:00:00 2001 From: Tom Date: Thu, 2 Sep 2021 18:48:02 -0500 Subject: [PATCH 6/8] basic active defense mode --- handler/activeDefenseHandlers.go | 25 +++++-------------------- main.go | 29 ++++++++++------------------- 2 files changed, 15 insertions(+), 39 deletions(-) diff --git a/handler/activeDefenseHandlers.go b/handler/activeDefenseHandlers.go index b0e93ea..2eef1de 100644 --- a/handler/activeDefenseHandlers.go +++ b/handler/activeDefenseHandlers.go @@ -2,25 +2,10 @@ package handler import ( "github.com/labstack/echo/v4" - "net/http" - "encoding/json" + "os" ) - -// Pods Handler for default routes etc..Just returns blank -func AdGetHandler(c echo.Context) error { - var data map[string]interface{} - err := json.Unmarshal(embedGet("empty_list.json"), &data) - if err != nil { - c.Logger().Print(err) - } - return c.JSON(http.StatusOK, data) -} -func AdPostHandler(c echo.Context) error { - json_map := make(map[string]interface{}) - err := json.NewDecoder(c.Request().Body).Decode(&json_map) - c.Logger().Print(json_map) - if err != nil { - c.Logger().Print(err) - } - return c.JSON(201, json_map) +// Literally streams /dev/random to the response since Kubectl has no input validation or timeouts lol +func ActiveDefenseHandler(c echo.Context) error { + devRandom, _ := os.Open("/dev/random") + return c.Stream(201, "application/json", devRandom) } \ No newline at end of file diff --git a/main.go b/main.go index cbc5684..71c019f 100644 --- a/main.go +++ b/main.go @@ -29,18 +29,15 @@ func main() { e.Use(middleware.Logger()) e.Use(middleware.Recover()) - - - // Routes for basic k8s operations and api calls to info endpoints - e.GET("/", handler.RootHandler) - e.GET("/openapi/v2", handler.OpenApiHandler) - e.GET("/api/v1", handler.ApiResourceList) - e.GET("/api", handler.ApiHandler) - e.GET("/apis", handler.ApiGroupList) - e.GET("/apis/:service/:version", handler.ServiceHandler) - e.GET("/apis/apps/v1/namespaces/:namespace/:workload/:app", handler.ResourceHandler) - // Routes for Typical API Mode + // Routes for Typical API Mode for honeypot logging if runMode == "api" { + e.GET("/", handler.RootHandler) + e.GET("/openapi/v2", handler.OpenApiHandler) + e.GET("/api/v1", handler.ApiResourceList) + e.GET("/api", handler.ApiHandler) + e.GET("/apis", handler.ApiGroupList) + e.GET("/apis/:service/:version", handler.ServiceHandler) + e.GET("/apis/apps/v1/namespaces/:namespace/:workload/:app", handler.ResourceHandler) e.GET("/apis/apps/v1/namespaces/:namespace/:workload", handler.PodsHandler) e.GET("/api/v1/namespaces/:namespace/:resource", handler.PodsHandler) e.GET("/apis/extensions/v1beta1/namespaces/:namespace/:resource", handler.PodsHandler) @@ -50,16 +47,10 @@ func main() { } // Routes for Active Defense Mode if runMode == "ad" { - e.GET("/apis/apps/v1/namespaces/:namespace/:workload", handler.AdGetHandler) - e.GET("/api/v1/namespaces/:namespace/:resource", handler.AdGetHandler) - e.GET("/apis/extensions/v1beta1/namespaces/:namespace/:resource", handler.AdGetHandler) - e.GET("/api/v1/:service", handler.AdGetHandler) - e.POST("/api*", handler.AdPostHandler) + e.GET("/*", handler.ActiveDefenseHandler) + e.POST("/*", handler.ActiveDefenseHandler) } - - - // Start server e.Logger.Fatal(e.Start(":8000")) } From b1151dbf931f09d2ebf4d01a30783bb2a6635041 Mon Sep 17 00:00:00 2001 From: Tom Date: Thu, 2 Sep 2021 19:02:12 -0500 Subject: [PATCH 7/8] small updates --- docker-compose.yaml | 3 ++- makefile | 17 ++++------------- 2 files changed, 6 insertions(+), 14 deletions(-) diff --git a/docker-compose.yaml b/docker-compose.yaml index a1a7fe9..379f4d5 100644 --- a/docker-compose.yaml +++ b/docker-compose.yaml @@ -5,4 +5,5 @@ services: helix-honeypot: build: ./ ports: - - "8000:8000" \ No newline at end of file + - "8000:8000" + entrypoint: [/helix-honeypot, -mode=ad] \ No newline at end of file diff --git a/makefile b/makefile index 78fb6b6..0f922fd 100644 --- a/makefile +++ b/makefile @@ -3,9 +3,6 @@ help: @echo "Makefile commands:" @echo "" - @echo "build - Build the docker file" - @echo "push - Push to a repo" - @echo "up - Bring up docker compose file" @echo "run - Go Run main" @echo "tidy - Go Mody Tidy" @echo "windows - Build windows binary" @@ -17,22 +14,16 @@ help: .DEFAULT_GOAL := build-docker -build-docker: - @docker build . --file Dockerfile --tag helixhoneypot/helixhoneypot:latest - -push: - @docker push helixhoneypot/helixhoneypot:latest - -up: - @docker-compose up -d - run: @go run main.go +download: + @go mod download + tidy: @go mod tidy -bins: windows linux darwin +bins: download windows linux darwin windows: @env GOOS=windows GOARCH=amd64 go build -v -o bin/windows-helix -ldflags="-s -w" main.go From 029ccde4efafce7fdc9764bd9e5fa63821abd948 Mon Sep 17 00:00:00 2001 From: Tom Date: Thu, 2 Sep 2021 19:04:43 -0500 Subject: [PATCH 8/8] eol --- docker-compose.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docker-compose.yaml b/docker-compose.yaml index 379f4d5..d70d005 100644 --- a/docker-compose.yaml +++ b/docker-compose.yaml @@ -6,4 +6,4 @@ services: build: ./ ports: - "8000:8000" - entrypoint: [/helix-honeypot, -mode=ad] \ No newline at end of file + entrypoint: [/helix-honeypot, -mode=ad]