Skip to content

Commit

Permalink
Adding multi port listening option + adding readme details
Browse files Browse the repository at this point in the history
  • Loading branch information
binchick.in committed May 3, 2023
1 parent d5297e5 commit 57bf16b
Show file tree
Hide file tree
Showing 5 changed files with 148 additions and 122 deletions.
13 changes: 11 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,18 @@ A scalable HTTP Honey Pot for Fun and Mischief.

Broken into 2 primary parts (the collector and the consumer), you can deploy Honey across VMs of any shape and any size.

## The setup is simple

![HTTP Honey Pot Image](docs/img/http_honey_pot.png)

* Collectors capture requests, serialize them, and toss them on to a pubsub queue.
* Consumers grab tasks, parse them, format them and insert them into a MySQL table for analysis


## The setup is simple

1. Clone this repo
2. `go build .`
3. Config a GCP service account with pub/sub publisher permissions and download the json key.

```
GCP_CREDS=$(cat service-account-cred.json) ./honey-collector --ports "8080"
```
84 changes: 41 additions & 43 deletions honey/client.go
Original file line number Diff line number Diff line change
@@ -1,60 +1,58 @@
package honey

import (
"fmt"
"context"
"os"
"context"
"fmt"
"os"

"cloud.google.com/go/pubsub"
"google.golang.org/api/option"
"cloud.google.com/go/pubsub"
"google.golang.org/api/option"
)

var ctx = context.Background()


type hostMetaData map[string]string

type HoneyClient struct {
client *pubsub.Client
topic *pubsub.Topic
hostMetaData hostMetaData
client *pubsub.Client
topic *pubsub.Topic
hostMetaData hostMetaData
}

func (h *HoneyClient) Publish(data []byte) {
msg := pubsub.Message{
Data: data,
Attributes: h.hostMetaData,
}
r := h.topic.Publish(ctx, &msg) // Leave this unassigned for now. We might want to handle this later though.
s, err := r.Get(ctx)
if err != nil {
panic(err)
}
fmt.Println(s) // Remove this line
msg := pubsub.Message{
Data: data,
Attributes: h.hostMetaData,
}
r := h.topic.Publish(ctx, &msg) // Leave this unassigned for now. We might want to handle this later though.
s, err := r.Get(ctx)
if err != nil {
panic(err)
}
fmt.Println(s) // Remove this line
}


func NewHoneyClientFromEnv() HoneyClient {
creds, projectid := checkEnvForCreds()
pubSubClient, pubSubClientErr := pubsub.NewClient(
ctx,
projectid,
option.WithCredentialsJSON(creds),
)
if pubSubClientErr != nil {
panic(pubSubClientErr)
}

hostname, hostnameErr := os.Hostname()
if hostnameErr != nil {
panic(hostnameErr)
}

return HoneyClient{
client: pubSubClient,
topic: pubSubClient.Topic("honey"), // TODO: Put topic string in environment
hostMetaData: hostMetaData{
"hostname": hostname,
},
}
}
creds, projectid := checkEnvForCreds()
pubSubClient, pubSubClientErr := pubsub.NewClient(
ctx,
projectid,
option.WithCredentialsJSON(creds),
)
if pubSubClientErr != nil {
panic(pubSubClientErr)
}

hostname, hostnameErr := os.Hostname()
if hostnameErr != nil {
panic(hostnameErr)
}

return HoneyClient{
client: pubSubClient,
topic: pubSubClient.Topic("honey"), // TODO: Put topic string in environment
hostMetaData: hostMetaData{
"hostname": hostname,
},
}
}
68 changes: 34 additions & 34 deletions honey/models.go
Original file line number Diff line number Diff line change
@@ -1,47 +1,47 @@
package honey

import (
"encoding/json"
"net/http"
"strings"
"time"
"encoding/json"
"net/http"
"strings"
"time"
)

type LoggedRequest struct {
Host string `json:"host"`
Method string `json:"method"`
Path string `json:"path"`
RemoteAddress string `json:"remote_address"`
UserAgent string `json:"user_agent"`
QueryParams map[string]string `json:"query_params"`
Headers map[string]string `json:"headers"`
Body string `json:"body"`
Time uint64 `json:"time"`
Host string `json:"host"`
Method string `json:"method"`
Path string `json:"path"`
RemoteAddress string `json:"remote_address"`
UserAgent string `json:"user_agent"`
QueryParams map[string]string `json:"query_params"`
Headers map[string]string `json:"headers"`
Body string `json:"body"`
Time uint64 `json:"time"`
}

func (lr *LoggedRequest) ToJson() string {
j, err := json.Marshal(lr)
if err != nil {
panic(err)
}
return string(j)
j, err := json.Marshal(lr)
if err != nil {
panic(err)
}
return string(j)
}

func NewLoggedRequest(r http.Request) LoggedRequest {
var decodedBody string
if r.Method == http.MethodPost {
decodedBody = decodeRequestBody(r.Body)
}
remoteHost := strings.Split(r.RemoteAddr, ":")
return LoggedRequest{
Host: r.Host,
Method: r.Method,
Path: r.URL.Path,
RemoteAddress: remoteHost[0],
UserAgent: r.UserAgent(),
QueryParams: processMapOfSlices(r.URL.Query()),
Headers: processMapOfSlices(r.Header),
Body: decodedBody,
Time: uint64(time.Now().Unix()),
}
var decodedBody string
if r.Method == http.MethodPost {
decodedBody = decodeRequestBody(r.Body)
}
remoteHost := strings.Split(r.RemoteAddr, ":")
return LoggedRequest{
Host: r.Host,
Method: r.Method,
Path: r.URL.Path,
RemoteAddress: remoteHost[0],
UserAgent: r.UserAgent(),
QueryParams: processMapOfSlices(r.URL.Query()),
Headers: processMapOfSlices(r.Header),
Body: decodedBody,
Time: uint64(time.Now().Unix()),
}
}
63 changes: 35 additions & 28 deletions honey/utils.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,50 +4,57 @@ import (
"encoding/json"
"errors"
"io"
"log"
"io/ioutil"
"log"
"os"
"strings"
)

const GOOGLECLOUD_PLATFORM_CREDS = "GCP_CREDS"

var (
ErrCredsNotFound = errors.New("could not find JSON creds in environment")
ErrCredsNotFound = errors.New("could not find JSON creds in environment")
)

/*
Check the environment for GCP_CREDS and then parse and return
*/
func checkEnvForCreds() (creds []byte, projectId string) {
var structuredCreds map[string]string
val, present := os.LookupEnv(GOOGLECLOUD_PLATFORM_CREDS)
if !present {
panic(ErrCredsNotFound)
}
creds = []byte(val)
jErr := json.Unmarshal(creds, &structuredCreds)
if jErr != nil {
panic(jErr)
}
projectId = structuredCreds["project_id"] // Handle missing key
return
var structuredCreds map[string]string
val, present := os.LookupEnv(GOOGLECLOUD_PLATFORM_CREDS)
if !present {
panic(ErrCredsNotFound)
}
creds = []byte(val)
jErr := json.Unmarshal(creds, &structuredCreds)
if jErr != nil {
panic(jErr)
}
projectId = structuredCreds["project_id"] // Handle missing key
return
}


func processMapOfSlices(x map[string][]string) map[string]string {
r := make(map[string]string)
for k, v := range x {
r[k] = v[0]
}
return r
r := make(map[string]string)
for k, v := range x {
r[k] = v[0]
}
return r
}


func decodeRequestBody(b io.ReadCloser) string {
rawBody, err := ioutil.ReadAll(b)
if err != nil {
log.Print(err)
return "ERROR PARSING BODY"
}
return string(rawBody)
}
rawBody, err := ioutil.ReadAll(b)
if err != nil {
log.Print(err)
return "ERROR PARSING BODY"
}
return string(rawBody)
}

func PreparePorts(x string) (a []string) {
ports := strings.Split(x, ",")
for _, i := range ports {
a = append(a, strings.TrimSpace(i))
}
return
}
42 changes: 27 additions & 15 deletions main.go
Original file line number Diff line number Diff line change
@@ -1,27 +1,39 @@
package main

import (
"fmt"
"net/http"
"flag"
"fmt"
"net/http"
"sync"

"honey-collector/honey"
"honey-collector/honey"
)

var honeyClient honey.HoneyClient
var (
honeyClient honey.HoneyClient
ports string
)

func ReqHandler(resp http.ResponseWriter, req *http.Request) {
lr := honey.NewLoggedRequest(*req)
honeyClient.Publish([]byte(lr.ToJson()))
fmt.Fprintf(resp, "\\( ^ o ^)/")
lr := honey.NewLoggedRequest(*req)
honeyClient.Publish([]byte(lr.ToJson()))
fmt.Fprintf(resp, "\\( ^ o ^)/")
}

func main() {
defaultPort := 80
honeyClient = honey.NewHoneyClientFromEnv()
fmt.Printf("Starting honey pot on port: %d\n", defaultPort)
http.HandleFunc("/", ReqHandler)
serverStartErr := http.ListenAndServe(fmt.Sprintf(":%d", defaultPort), nil)
if serverStartErr != nil {
panic(serverStartErr)
}
flag.StringVar(&ports, "ports", "", "Wrap your port list in double quotes")
flag.Parse()

var wg sync.WaitGroup
preppedPorts := honey.PreparePorts(ports)
honeyClient = honey.NewHoneyClientFromEnv()
http.HandleFunc("/", ReqHandler)

for _, p := range preppedPorts {
wg.Add(1)
addr := fmt.Sprintf(":%s", p)
fmt.Printf("Starting honey pot on port: %s\n", p)
go http.ListenAndServe(addr, nil)
}
wg.Wait()
}

0 comments on commit 57bf16b

Please sign in to comment.