Skip to content

Commit

Permalink
completed and tested windows + linux agents
Browse files Browse the repository at this point in the history
  • Loading branch information
pygrum committed Oct 6, 2023
1 parent 7bc18f4 commit 9bc328d
Show file tree
Hide file tree
Showing 39 changed files with 1,490 additions and 129 deletions.
9 changes: 0 additions & 9 deletions Dockerfile

This file was deleted.

11 changes: 7 additions & 4 deletions Makefile
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
.PHONY: build run
.PHONY: build build-agent build-gen
build:
docker build -t siphon .
go build cmd/siphon/siphon.go

run:
docker run --rm -it siphon
build-agent:
go build cmd/agent/siphon_agent.go

build-gen:
go build cmd/generator/siphon_gen.go
30 changes: 19 additions & 11 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,20 +10,17 @@ A database of basic sample information is built up as often as an un-indexed sam
is found by querying threat intelligence APIs. You can view the most recent samples,
sorted by time, and download them from their source.

## Installation
## Support

You can either download Siphon from the [releases](https://github.com/pygrum/siphon/releases/latest)
page, or run the application in a Docker container
Siphon is designed with only Unix host support in mind, however, it is possible to set it up on Windows
using Git Bash, WSL or similar applications.

### Using docker
#### Dependencies
- Docker
- Make
## Installation

1. Clone the repository: `git clone https://github.com/pygrum/siphon`
2. Enter the cloned repository and run `make build run`
You can download Siphon source code from the [releases](https://github.com/pygrum/siphon/releases/latest) page, or clone it from this URL.
Then, after entering the containing folder, run `bash scripts/install.sh`.

## Supported Integrations
### Supported Integrations

| Name | Setup instructions |
|---------------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
Expand All @@ -42,4 +39,15 @@ sources:
- name: MalwareBazaar
apikey: <your-api-key>
endpoint: https://mb-api.abuse.ch/api/v1/
```
```
### Changelog
#### v2.0.0
Siphon has introduced honeypot integration! Agents can now be configured and used on decoy hosts to log
information about and cache samples that are used by attackers in real time. These agents provide the same
interface as other integrations - with the ability to query and download recent samples.
See the [docs](https://github.com/pygrum/siphon/blob/main/docs/DOCS.md) for how to build and configure
agents.
40 changes: 40 additions & 0 deletions cmd/agent/siphon_agent.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
package main

import (
"github.com/pygrum/siphon/internal/agent"
"github.com/pygrum/siphon/internal/logger"
"github.com/spf13/cobra"
"github.com/spf13/viper"
)

var (
AgentID string
Interface string
Port string
ClientCertData string // Base64 Encoded certificate data
cfgFile string

rootCmd = &cobra.Command{
Use: "siphon_agent",
Short: "A Honeypot-Resident Sample Curator",
Long: ``,
Run: func(cmd *cobra.Command, args []string) {
viper.SetConfigFile(cfgFile)
if err := viper.ReadInConfig(); err != nil {
logger.Fatalf("reading configuration file failed: %v", err)
}
agent.Initialize(AgentID, Interface, Port, ClientCertData)
},
}
)

func init() {
rootCmd.PersistentFlags().StringVar(&cfgFile, "config", "", "agent configuration file")
_ = cobra.MarkFlagRequired(rootCmd.PersistentFlags(), "config")
}

func main() {
if err := rootCmd.Execute(); err != nil {
logger.Fatal(err)
}
}
74 changes: 74 additions & 0 deletions cmd/generator/generator/generator.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
package generator

import (
"crypto/rand"
"encoding/base64"
"fmt"
"github.com/pygrum/siphon/internal/db"
"github.com/pygrum/siphon/internal/logger"
"github.com/spf13/viper"
"math/big"
"net"
"os"
)

const (
AgentIDLength = 16
AgentIDPrefix = "AA"
)

var charSet = []byte("0123456789ABCDEF")

func RandID() string {
ret := make([]byte, AgentIDLength-len(AgentIDPrefix))
for i := 0; i < AgentIDLength-len(AgentIDPrefix); i++ {
num, _ := rand.Int(rand.Reader, big.NewInt(int64(len(charSet))))
ret[i] = charSet[num.Int64()]
}
return AgentIDPrefix + string(ret)
}

func IsAgentID(s string) bool {
return len(s) == AgentIDLength && s[:2] == "AA"
}

func Generate() error {
name := viper.GetString("name")
goos := viper.GetString("os")
arch := viper.GetString("arch")
iFace := viper.GetString("host")
port := viper.GetString("port")
outFile := viper.GetString("outfile")
siphonCert := viper.GetString("cert_file")

certData, err := os.ReadFile(siphonCert)
if err != nil {
logger.Fatalf("could not read siphon certificate from %s: %v", siphonCert, err)
}
agentID := RandID()
if len(name) == 0 {
name = agentID
}
mainPath := viper.GetString("src_path")

builder := NewBuilder("go", goos, arch)
builder.AddSrcPath(mainPath)
builder.SetFlags(
Flag{"main.AgentID", agentID},
Flag{"main.Interface", iFace},
Flag{"main.Port", port},
// Add certificate data base64 encoded to agent, so it is added to its rootCAs
Flag{"main.ClientCertData", base64.StdEncoding.EncodeToString(certData)},
)
builder.SetOutFile(outFile)
// Exits if unsuccessful
builder.Build()

conn := db.Initialize()
agent := &db.Agent{
AgentID: agentID,
Name: name,
Endpoint: fmt.Sprintf("https://%s/api", net.JoinHostPort(iFace, port)),
}
return conn.Add(agent)
}
78 changes: 78 additions & 0 deletions cmd/generator/generator/wrapper.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
package generator

import (
"bytes"
"fmt"
"github.com/pygrum/siphon/internal/logger"
"os"
"os/exec"
"strings"
)

type Builder struct {
CC string
GOOS string
GOARCH string
SrcPaths []string
outFile string
flags []Flag
}

type Flag struct {
Name string
Value string
}

const (
outFileOption = "-o"
flagsOption = "-ldflags"
flagPrefix = "-X"
)

func NewBuilder(cc, goos, goarch string) *Builder {
return &Builder{
CC: cc,
GOOS: goos,
GOARCH: goarch,
}
}

func (b *Builder) AddSrcPath(path string) {
b.SrcPaths = append(b.SrcPaths, path)
}

func (b *Builder) SetFlags(flags ...Flag) {
b.flags = flags
}

func (b *Builder) SetOutFile(name string) {
b.outFile = name
}

func (b *Builder) Build() {
var buildCmd []string
buildCmd = append(buildCmd, "build")
buildCmd = append(buildCmd, outFileOption)
buildCmd = append(buildCmd, b.outFile)
buildCmd = append(buildCmd, flagsOption)
var flags []string
for _, f := range b.flags {
flags = append(flags, flagPrefix)
formatString := "'%s=%s'"
flags = append(flags, fmt.Sprintf(formatString, f.Name, f.Value))
}
buildCmd = append(buildCmd, strings.Join(flags, " "))
for _, s := range b.SrcPaths {
buildCmd = append(buildCmd, s)
}
fmt.Println(b.CC, strings.Join(buildCmd, " "))
var cerr bytes.Buffer
cmd := exec.Command(b.CC, buildCmd...)
// Set arch and os environment vars
cmd.Env = os.Environ()
cmd.Env = append(cmd.Env, fmt.Sprintf("GOOS=%s", b.GOOS), fmt.Sprintf("GOARCH=%s", b.GOARCH)) // go-sqlite3 requires cgo
cmd.Stderr = &cerr
if err := cmd.Run(); err != nil {
logger.Fatalf("%v: %s", err, cerr.String())
}
}
47 changes: 47 additions & 0 deletions cmd/generator/siphon_gen.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
package main

import (
"fmt"
"github.com/pygrum/siphon/cmd/generator/generator"
"github.com/pygrum/siphon/internal/logger"
"github.com/pygrum/siphon/internal/version"
"github.com/spf13/cobra"
"github.com/spf13/viper"
)

func init() {
fmt.Printf("{_/¬ SIPHON GENERATOR %s ¬\\_}\n\n}", version.VersionString())
}

var (
cfgFile string

rootCmd = &cobra.Command{
Use: "generator",
Short: "A utility for Siphon agent generation",
Long: ``,
Run: func(cmd *cobra.Command, args []string) {
viper.SetConfigFile(cfgFile)
if err := viper.ReadInConfig(); err != nil {
logger.Fatalf("reading configuration file failed: %v", err)
}
if err := generator.Generate(); err != nil {
logger.Fatal(err)
}
logger.Notifyf("agent has successfully been built. For installation instructions, see the docs: %s",
"https://github.com/pygrum/siphon/blob/main/docs/DOCS.md",
)
},
}
)

func init() {
rootCmd.PersistentFlags().StringVar(&cfgFile, "config", "", "generator configuration file - see https://github.com/pygrum/siphon/blob/main/docs/DOCS.md for help")
_ = cobra.MarkFlagRequired(rootCmd.PersistentFlags(), "config")
}

func main() {
if err := rootCmd.Execute(); err != nil {
logger.Fatal(err)
}
}
24 changes: 8 additions & 16 deletions cmd/root.go → cmd/siphon/siphon.go
Original file line number Diff line number Diff line change
@@ -1,24 +1,19 @@
package cmd
package main

import (
"errors"
"fmt"
"github.com/pygrum/siphon/internal/console"
"github.com/pygrum/siphon/internal/db"
"github.com/pygrum/siphon/internal/logger"
"github.com/pygrum/siphon/internal/version"
"github.com/spf13/cobra"
"github.com/spf13/viper"
"os"
"path/filepath"
"strings"
)

const (
VersionMajor = "1"
VersionMinor = "0"
VersionPatch = "0"
)

var (
cfgFile string

Expand All @@ -33,7 +28,7 @@ var (
fmt.Println(strings.ReplaceAll(
title(),
"{VER}",
versionString()))
version.VersionString()))
console.Start()
},
}
Expand All @@ -56,7 +51,6 @@ func initCfg() {
if !errors.Is(err, os.ErrExist) {
cobra.CheckErr(err)
}
logger.Infof("creating new configuration file at %s", filepath.Join(cfgDir, ".siphon.yaml"))
if _, err := os.Stat(filepath.Join(cfgDir, ".siphon.yaml")); os.IsNotExist(err) {
err = os.WriteFile(filepath.Join(cfgDir, ".siphon.yaml"), cfgBoilerplate(), 0666)
cobra.CheckErr(err)
Expand All @@ -68,7 +62,7 @@ func initCfg() {
}

if err := viper.ReadInConfig(); err != nil {
logger.Errorf("reading configuration file ($HOME/.siphon.yaml) failed: %v", err)
logger.Errorf("reading configuration file failed: %v", err)
}
db.Initialize()
}
Expand All @@ -88,12 +82,10 @@ func title() string {
`
}

func Execute() error {
return rootCmd.Execute()
}

func versionString() string {
return "v" + strings.Join([]string{VersionMajor, VersionMinor, VersionPatch}, ".")
func main() {
if err := rootCmd.Execute(); err != nil {
logger.Fatal(err)
}
}

func cfgBoilerplate() []byte {
Expand Down
9 changes: 9 additions & 0 deletions configs/siphon.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
# Example configuration file for Siphon

refreshrate: 5 # Refresh sample list every 5 minutes
cert_file: "/path/to/cert/file.crt"
key_file: "/path/to/key/file.crt"
sources:
- name: "malwarebazaar"
endpoint:
apikey:
Loading

0 comments on commit 9bc328d

Please sign in to comment.