Skip to content

Commit f9958de

Browse files
authored
Embed default config (#183)
* embed default config * bedder udp payload truncating
1 parent 90db741 commit f9958de

9 files changed

Lines changed: 61 additions & 56 deletions

File tree

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ _testmain.go
3030
# Artifacts
3131
glutton.log*
3232
payloads/
33+
samples/
3334

3435
# PoCs
3536
poc/

app/server.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ func main() {
3535
fmt.Printf("%s %s\n\n", VERSION, BUILDDATE)
3636

3737
pflag.StringP("interface", "i", "eth0", "Bind to this interface")
38-
pflag.IntP("ssh", "s", 0, "Override SSH port")
38+
pflag.IntP("ssh", "s", 22, "Override SSH port")
3939
pflag.StringP("logpath", "l", "/dev/null", "Log file path")
4040
pflag.StringP("confpath", "c", "config/", "Configuration file path")
4141
pflag.BoolP("debug", "d", false, "Enable debug mode")

connection/connection.go

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package connection
22

33
import (
4+
"context"
45
"errors"
56
"fmt"
67
"net"
@@ -55,10 +56,25 @@ type ConnTable struct {
5556
mtx sync.RWMutex
5657
}
5758

58-
func New() *ConnTable {
59+
func New(ctx context.Context) *ConnTable {
5960
ct := &ConnTable{
6061
table: make(map[CKey]Metadata, 1024),
6162
}
63+
// every 5 minutes using a ticker, flush the table
64+
65+
go func() {
66+
ticker := time.NewTicker(5 * time.Minute)
67+
defer ticker.Stop()
68+
for {
69+
select {
70+
case <-ctx.Done():
71+
return
72+
case <-ticker.C:
73+
ct.FlushOlderThan(5 * time.Minute)
74+
}
75+
}
76+
}()
77+
6278
return ct
6379
}
6480

connection/connection_test.go

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package connection
22

33
import (
4+
"context"
45
"net"
56
"testing"
67
"time"
@@ -32,12 +33,12 @@ func TestNewConnKeyFromNetConn(t *testing.T) {
3233
}
3334

3435
func TestNewConnTable(t *testing.T) {
35-
table := New()
36+
table := New(context.Background())
3637
require.NotNil(t, table)
3738
}
3839

3940
func TestRegister(t *testing.T) {
40-
table := New()
41+
table := New(context.Background())
4142
targetPort := 4321
4243
m1, err := table.Register("127.0.0.1", "1234", uint16(targetPort), &rules.Rule{})
4344
require.NoError(t, err)
@@ -57,7 +58,7 @@ func TestRegisterConn(t *testing.T) {
5758
require.NoError(t, err)
5859
require.NotNil(t, conn)
5960
defer conn.Close()
60-
table := New()
61+
table := New(context.Background())
6162
md, err := table.RegisterConn(conn, &rules.Rule{Target: "tcp"})
6263
require.NoError(t, err)
6364
require.NotNil(t, md)
@@ -67,7 +68,7 @@ func TestRegisterConn(t *testing.T) {
6768
}
6869

6970
func TestFlushOlderThan(t *testing.T) {
70-
table := New()
71+
table := New(context.Background())
7172
targetPort := 4321
7273
md, err := table.Register("127.0.0.1", "1234", uint16(targetPort), &rules.Rule{})
7374
require.NoError(t, err)

glutton.go

Lines changed: 10 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -43,43 +43,37 @@ type Glutton struct {
4343
//go:embed config/rules.yaml
4444
var defaultRules []byte
4545

46+
//go:embed config/config.yaml
47+
var defaultConfig []byte
48+
4649
func (g *Glutton) initConfig() error {
4750
viper.SetConfigName("config")
4851
viper.AddConfigPath(viper.GetString("confpath"))
4952
if _, err := os.Stat(viper.GetString("confpath")); !os.IsNotExist(err) {
50-
if err := viper.ReadInConfig(); err != nil {
51-
return err
52-
}
53+
g.Logger.Info("Using configuration file", slog.String("path", viper.GetString("confpath")), slog.String("reporter", "glutton"))
54+
return viper.ReadInConfig()
5355
}
54-
// If no config is found, use the defaults
55-
viper.SetDefault("ports.tcp", 5000)
56-
viper.SetDefault("ports.udp", 5001)
57-
viper.SetDefault("ports.ssh", 22)
58-
viper.SetDefault("max_tcp_payload", 4096)
59-
viper.SetDefault("conn_timeout", 45)
60-
viper.SetDefault("rules_path", "rules/rules.yaml")
61-
viper.SetDefault("interface", "eth0") // Default interface name
62-
63-
g.Logger.Debug("configuration set successfully", slog.String("reporter", "glutton"))
64-
return nil
56+
57+
g.Logger.Info("No configuration file found, using default configuration", slog.String("reporter", "glutton"))
58+
return viper.ReadConfig(bytes.NewBuffer(defaultConfig))
6559
}
6660

6761
// New creates a new Glutton instance
6862
func New(ctx context.Context) (*Glutton, error) {
6963
g := &Glutton{
7064
tcpProtocolHandlers: make(map[string]protocols.TCPHandlerFunc),
7165
udpProtocolHandlers: make(map[string]protocols.UDPHandlerFunc),
72-
connTable: connection.New(),
7366
}
7467
g.ctx, g.cancel = context.WithCancel(ctx)
7568

69+
g.connTable = connection.New(ctx)
7670
if err := g.makeID(); err != nil {
7771
return nil, err
7872
}
7973
g.Logger = producer.NewLogger(g.id.String())
8074

8175
// Loading the configuration
82-
g.Logger.Info("Loading configurations from: config/config.yaml", slog.String("reporter", "glutton"))
76+
g.Logger.Info("Loading configurations", slog.String("reporter", "glutton"))
8377
if err := g.initConfig(); err != nil {
8478
return nil, err
8579
}

protocols/helpers/helpers.go

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15,13 +15,13 @@ func FirstOrEmpty[T any](s []T) T {
1515
return t
1616
}
1717

18-
func StorePayload(data []byte) (string, error) {
18+
func Store(data []byte, folder string) (string, error) {
1919
sum := sha256.Sum256(data)
20-
if err := os.MkdirAll("payloads", os.ModePerm); err != nil {
20+
if err := os.MkdirAll(folder, os.ModePerm); err != nil {
2121
return "", err
2222
}
2323
sha256Hash := hex.EncodeToString(sum[:])
24-
path := filepath.Join("payloads", sha256Hash)
24+
path := filepath.Join(folder, sha256Hash)
2525
if _, err := os.Stat(path); err == nil {
2626
// file already exists
2727
return "", nil

protocols/tcp/tcp.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,7 @@ func HandleTCP(ctx context.Context, conn net.Conn, md connection.Metadata, logge
6767

6868
defer func() {
6969
if msgLength > 0 {
70-
payloadHash, err := helpers.StorePayload(data)
70+
payloadHash, err := helpers.Store(data, "payloads")
7171
if err != nil {
7272
logger.Error("Failed to store payload", slog.String("handler", "tcp"), producer.ErrAttr(err))
7373
}

protocols/tcp/telnet.go

Lines changed: 20 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -4,16 +4,12 @@ import (
44
"bufio"
55
"context"
66
"crypto/rand"
7-
"crypto/sha256"
8-
"encoding/hex"
97
"errors"
108
"io"
119
"log/slog"
1210
"math/big"
1311
"net"
1412
"net/http"
15-
"os"
16-
"path/filepath"
1713
"regexp"
1814
"strings"
1915
"time"
@@ -95,46 +91,38 @@ func (s *telnetServer) read(conn net.Conn) (string, error) {
9591
func (s *telnetServer) getSample(cmd string, logger interfaces.Logger) error {
9692
url := cmd[strings.Index(cmd, "http"):]
9793
url = strings.Split(url, " ")[0]
94+
url = strings.TrimSpace(url)
9895
logger.Debug("Fetching sample", slog.String("url", url), slog.String("handler", "telnet"))
9996
resp, err := s.client.Get(url)
10097
if err != nil {
10198
return err
10299
}
103100
if resp.StatusCode != 200 {
104-
return errors.New("getSample read http: error: Non 200 status code on getSample")
101+
return errors.New("failed to fetch sample: " + resp.Status)
105102
}
106103
defer resp.Body.Close()
107104
if resp.ContentLength <= 0 {
108-
return errors.New("getSample read http: error: Empty response body")
105+
return errors.New("content length is 0")
109106
}
110-
bodyBuffer, err := io.ReadAll(resp.Body)
107+
108+
data, err := io.ReadAll(resp.Body)
111109
if err != nil {
112110
return err
113111
}
114-
sum := sha256.Sum256(bodyBuffer)
115-
// Ignoring errors for if the folder already exists
116-
if err = os.MkdirAll("samples", os.ModePerm); err != nil {
117-
return err
118-
}
119-
sha256Hash := hex.EncodeToString(sum[:])
120-
path := filepath.Join("samples", sha256Hash)
121-
if _, err = os.Stat(path); err == nil {
122-
logger.Debug("getSample already known", slog.String("sha", sha256Hash), slog.String("handler", "telnet"))
123-
return nil
124-
}
125-
out, err := os.Create(path)
126-
if err != nil {
127-
return err
112+
113+
if len(data) == 0 {
114+
return errors.New("empty response body")
128115
}
129-
defer out.Close()
130-
_, err = out.Write(bodyBuffer)
116+
117+
sha256Hash, err := helpers.Store(data, "samples")
131118
if err != nil {
132119
return err
133120
}
121+
134122
logger.Info(
135-
"new sample fetched from telnet",
123+
"New sample fetched",
136124
slog.String("handler", "telnet"),
137-
slog.String("sha256", sha256Hash),
125+
slog.String("sample_hash", sha256Hash),
138126
slog.String("source", url),
139127
)
140128
return nil
@@ -197,7 +185,12 @@ func HandleTelnet(ctx context.Context, conn net.Conn, md connection.Metadata, lo
197185
}
198186
for _, cmd := range strings.Split(msg, ";") {
199187
if strings.Contains(strings.Trim(cmd, " "), "wget http") {
200-
go s.getSample(strings.Trim(cmd, " "), logger)
188+
go func() {
189+
err := s.getSample(strings.Trim(cmd, " "), logger)
190+
if err != nil {
191+
logger.Error("Failed to get sample", slog.String("handler", "telnet"), producer.ErrAttr(err))
192+
}
193+
}()
201194
}
202195
if strings.TrimRight(cmd, "") == " rm /dev/.t" {
203196
continue
@@ -226,7 +219,7 @@ func HandleTelnet(ctx context.Context, conn net.Conn, md connection.Metadata, lo
226219
}
227220
} else {
228221
// /bin/busybox YDKBI
229-
re := regexp.MustCompile(`\/bin\/busybox (?P<applet>[A-Z]+)`)
222+
re := regexp.MustCompile(`\/bin\/busybox (?P<applet>[A-Za-z]+)`)
230223
match := re.FindStringSubmatch(cmd)
231224
if len(match) > 1 {
232225
if err := s.write(conn, match[1]+": applet not found\r\n"); err != nil {

protocols/udp/udp.go

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13,11 +13,11 @@ import (
1313
)
1414

1515
func HandleUDP(ctx context.Context, srcAddr, dstAddr *net.UDPAddr, data []byte, md connection.Metadata, log interfaces.Logger, h interfaces.Honeypot) error {
16-
log.Info(fmt.Sprintf("UDP payload:\n%s", hex.Dump(data[:len(data)%1024])))
17-
if _, err := helpers.StorePayload(data[:len(data)%1024]); err != nil {
16+
log.Info(fmt.Sprintf("UDP payload:\n%s", hex.Dump(data[:min(len(data), 1024)])))
17+
if _, err := helpers.Store(data[:min(len(data), 1024)], "payloads"); err != nil {
1818
log.Error("failed to store UDP payload", producer.ErrAttr(err))
1919
}
20-
if err := h.ProduceUDP("udp", srcAddr, dstAddr, md, data[:len(data)%1024], nil); err != nil {
20+
if err := h.ProduceUDP("udp", srcAddr, dstAddr, md, data[:min(len(data), 1024)], nil); err != nil {
2121
log.Error("failed to produce UDP payload", producer.ErrAttr(err))
2222
}
2323
return nil

0 commit comments

Comments
 (0)