Skip to content

Commit 8d942c8

Browse files
committed
Importing to Github
1 parent fc02bc5 commit 8d942c8

File tree

93 files changed

+5932
-2
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

93 files changed

+5932
-2
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
gitbook/_book

README.md

Lines changed: 20 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,24 @@
22

33
![SPLAT](images/splat-logo.png)
44

5-
## Material
5+
## Getting Started
6+
7+
Clone this repository
8+
9+
```
10+
git clone https://github.com/appsecco/using-docker-kubernetes-for-automating-appsec-and-osint-workflows
11+
```
12+
13+
Install `gitbook-cli` for serving documentation locally
14+
15+
```
16+
npm install -g gitbook-cli
17+
```
18+
19+
Start `gitbook` server locally
20+
21+
```
22+
cd using-docker-kubernetes-for-automating-appsec-and-osint-workflows/gitbook
23+
gitbook serve
24+
```
625

7-
_We will update this repository on 2nd of March 2019_

apps/adapter/README.md

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
# SPLAT Adapter
2+
3+
## Build
4+
5+
```
6+
go get -u github.com/nats-io/go-nats
7+
go get -u github.com/minio/minio-go
8+
```
9+
10+
```
11+
go build
12+
```
13+
14+
## Configuration
15+
16+
> Enabled through environment variables
17+
18+
| Environment Variable | Purpose |
19+
| -------------------------- | --------------------------------------------------------------- |
20+
| SPLAT_TOOL_NAME | |
21+
| SPLAT_NATS_URL | |
22+
| SPLAT_NATS_CONSUMER_TOPIC | |
23+
| SPLAT_EXEC_PATTERN | Shell exec with bash -c |
24+
| SPLAT_EXEC_TIMEOUT | Timeout in seconds |
25+
| SPLAT_USE_OUTPUT_FILE_PATH |
26+
| SPLAT_MINIO_ENDPOINT | |
27+
| SPLAT_MINIO_ACCESS_KEY | |
28+
| SPLAT_MINIO_SECRET_KEY | |
29+
| SPLAT_MINIO_FILE_PATTERN | Example: "scans/{{SCAN_ID}}/{{OUTPUT_EVENT}}/data.json |
30+
| SPLAT_MINIO_EVENT_NAME | Name |
31+
| SPLAT_MINIO_CAPTURE_STDOUT | Yes to send stdout to minio. Empty to send output file to Minio |
32+
33+
34+
## Command Placeholders
35+
36+
These variables can be used to construct the tool command to execute
37+
38+
`{{TARGET}}` is replaced with input string
39+
`{{OUTPUT_FILE_PATH}}` is replaced with this program's auto generated temporary file. The content of this file will be sent to minio
40+
41+
Example command line:
42+
43+
```
44+
nmap -sS -sV {{TARGET}} -oX {{OUTPUT_FILE_PATH}}
45+
```

apps/adapter/main.go

Lines changed: 227 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,227 @@
1+
package main
2+
3+
import (
4+
"bytes"
5+
"encoding/json"
6+
"io/ioutil"
7+
"log"
8+
"os"
9+
"os/exec"
10+
"path/filepath"
11+
"runtime"
12+
"strconv"
13+
"strings"
14+
"time"
15+
16+
minio "github.com/minio/minio-go"
17+
nats "github.com/nats-io/go-nats"
18+
)
19+
20+
type PubSubEvent struct {
21+
ScanID string
22+
EventType string
23+
EventValue string
24+
}
25+
26+
func initLogging() {
27+
// TBD: Should logger be configured?
28+
}
29+
30+
func getConfigValue(key string) string {
31+
return os.Getenv(key)
32+
}
33+
34+
func getOutputFilePath() (string, error) {
35+
file, err := ioutil.TempFile("", "execTool")
36+
37+
if err != nil {
38+
log.Print("Failed to create temporary file: ", err.Error())
39+
return "", err
40+
}
41+
42+
file.Close()
43+
fp, err := filepath.Abs(file.Name())
44+
45+
if err != nil {
46+
log.Print("Failed to temporary file path: ", err.Error())
47+
return "", err
48+
}
49+
50+
return fp, nil
51+
}
52+
53+
func replaceStrPlaceholders(str string, event *PubSubEvent, outputFilePath string) string {
54+
str = strings.Replace(str, "{{SCAN_ID}}", event.ScanID, -1)
55+
str = strings.Replace(str, "{{OUTPUT_EVENT}}", getConfigValue("SPLAT_MINIO_EVENT_NAME"), -1)
56+
str = strings.Replace(str, "{{TARGET}}", event.EventValue, -1)
57+
str = strings.Replace(str, "{{OUTPUT_FILE_PATH}}", outputFilePath, -1)
58+
str = strings.Replace(str, "{{TIMESTAMP}}", strconv.FormatInt(time.Now().UnixNano(), 10), -1)
59+
60+
return str
61+
}
62+
63+
func getExecTimeout() int {
64+
timeout := getConfigValue("SPLAT_EXEC_TIMEOUT")
65+
66+
if timeout == "" {
67+
timeout = "60"
68+
}
69+
70+
t, err := strconv.Atoi(timeout)
71+
if err != nil {
72+
return 60
73+
}
74+
75+
return t
76+
}
77+
78+
func printUploadStatus(n int64, err error) {
79+
if err != nil {
80+
log.Print("Failed to upload to minio: ", err.Error())
81+
} else {
82+
log.Printf("Successfully uploaded: size %d", n)
83+
}
84+
}
85+
86+
func minioDeployOutput(event *PubSubEvent, stdOut bytes.Buffer, outputFilePath string) {
87+
endpoint := getConfigValue("SPLAT_MINIO_ENDPOINT")
88+
accessKeyID := getConfigValue("SPLAT_MINIO_ACCESS_KEY")
89+
secretAccessKey := getConfigValue("SPLAT_MINIO_SECRET_KEY")
90+
useSSL := false
91+
92+
log.Printf("Deploying STDOUT:%d bytes OutputFile:%s", stdOut.Len(), outputFilePath)
93+
94+
client, err := minio.New(endpoint, accessKeyID, secretAccessKey, useSSL)
95+
if err != nil {
96+
log.Print("Failed to connect to Minio endpoint")
97+
return
98+
}
99+
100+
bucketName := getConfigValue("MINIO_OUTPUT_BUCKET")
101+
location := getConfigValue("SPLAT_MINIO_FILE_PATTERN")
102+
103+
// location = strings.Replace(location, "{{SCAN_ID}}", event.ScanID, -1)
104+
// location = strings.Replace(location, "{{OUTPUT_EVENT}}", eventName, -1)
105+
location = replaceStrPlaceholders(location, event, getConfigValue("SPLAT_USE_OUTPUT_FILE_PATH"))
106+
107+
log.Print("Writing to Minio: Bucket: ", bucketName, " Location: ", location)
108+
109+
contentType := "application/json"
110+
if len(getConfigValue("SPLAT_MINIO_CAPTURE_STDOUT")) > 0 {
111+
log.Print("Sending stdout to Minio")
112+
n, err := client.PutObject(bucketName, location, strings.NewReader(stdOut.String()), -1, minio.PutObjectOptions{ContentType: contentType})
113+
printUploadStatus(n, err)
114+
} else {
115+
log.Print("Sending output file to Minio")
116+
n, err := client.FPutObject(bucketName, location, outputFilePath, minio.PutObjectOptions{ContentType: contentType})
117+
printUploadStatus(n, err)
118+
}
119+
}
120+
121+
func deployOutput(event *PubSubEvent, stdout bytes.Buffer, outputFilePath string) {
122+
minioDeployOutput(event, stdout, outputFilePath)
123+
}
124+
125+
/*
126+
SPLAT_EXEC_PATTERN="nmap -sT -p 443,80,8080 {{TARGET}} -oX {{OUTPUT_FILE_PATH}}"
127+
*/
128+
129+
func execToolAndGetOutput(event *PubSubEvent) {
130+
log.Print("Executing external tool on PubSub event")
131+
132+
var err error
133+
execPattern := getConfigValue("SPLAT_EXEC_PATTERN")
134+
outputFilePath := getConfigValue("SPLAT_USE_OUTPUT_FILE_PATH")
135+
136+
if len(outputFilePath) == 0 {
137+
outputFilePath, err = getOutputFilePath()
138+
if err != nil {
139+
log.Print("Failed to generated output file path: ", err.Error())
140+
return
141+
}
142+
}
143+
144+
// TODO: Shell escape this string
145+
targetStr := event.EventValue
146+
147+
execPattern = strings.Replace(execPattern, "{{TARGET}}", targetStr, -1)
148+
execPattern = strings.Replace(execPattern, "{{OUTPUT_FILE_PATH}}", outputFilePath, -1)
149+
150+
log.Print("Running exec pattern: ", execPattern)
151+
152+
// cmdArray := strings.Split(execPattern, " ")
153+
// cmd := exec.Command(cmdArray[0], cmdArray[1:]...)
154+
155+
// We need this to be able to pipe shell commands
156+
cmd := exec.Command("sh", "-c", execPattern)
157+
158+
var stdOut bytes.Buffer
159+
cmd.Stdout = &stdOut
160+
161+
err = cmd.Start()
162+
163+
done := make(chan error)
164+
go func() { done <- cmd.Wait() }()
165+
166+
timeout := time.After(time.Duration(getExecTimeout()) * time.Second)
167+
select {
168+
case <-timeout:
169+
cmd.Process.Kill()
170+
log.Print("Command execution timed out!")
171+
case err := <-done:
172+
if err != nil {
173+
log.Print("Non-zero exit code from command: ", err.Error())
174+
} else {
175+
log.Print("Command execution finished successfully")
176+
177+
log.Print("STDOUT: ")
178+
log.Print(stdOut.String())
179+
deployOutput(event, stdOut, outputFilePath)
180+
}
181+
}
182+
}
183+
184+
func handleNatsEvent(m *nats.Msg) {
185+
log.Print("Received a message: ", string(m.Data))
186+
187+
var event PubSubEvent
188+
err := json.Unmarshal(m.Data, &event)
189+
190+
if err != nil {
191+
log.Print("Error JSON decoding message: ", err.Error())
192+
return
193+
}
194+
195+
execToolAndGetOutput(&event)
196+
}
197+
198+
func startConsumer() {
199+
log.Print("Starting consumer loop")
200+
nc, err := nats.Connect(getConfigValue("SPLAT_NATS_URL"))
201+
202+
if err != nil {
203+
log.Fatal("Failed to connect NATS: ", err.Error())
204+
return
205+
}
206+
207+
queueGroupName := getConfigValue("SPLAT_QUEUE_GROUP_NAME")
208+
if len(queueGroupName) > 0 {
209+
log.Printf("Using queue subscription with group: %s", queueGroupName)
210+
nc.QueueSubscribe(getConfigValue("SPLAT_NATS_CONSUMER_TOPIC"), queueGroupName, func(m *nats.Msg) {
211+
handleNatsEvent(m)
212+
})
213+
} else {
214+
log.Print("Using topic subscription")
215+
nc.Subscribe(getConfigValue("SPLAT_NATS_CONSUMER_TOPIC"), func(m *nats.Msg) {
216+
handleNatsEvent(m)
217+
})
218+
}
219+
220+
nc.Flush()
221+
runtime.Goexit() // Blocking
222+
}
223+
224+
func main() {
225+
initLogging()
226+
startConsumer()
227+
}

apps/dnsrecon/Dockerfile

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
FROM python:2.7-alpine
2+
LABEL MAINTAINER="Appsecco"
3+
4+
RUN apk update && apk add git \
5+
&& git clone https://github.com/darkoperator/dnsrecon.git \
6+
&& apk add --update --no-cache g++ gcc libxslt-dev
7+
8+
WORKDIR /dnsrecon
9+
10+
RUN pip install -r requirements.txt
11+
12+
ENTRYPOINT [ "python", "/dnsrecon/dnsrecon.py" ]

apps/fn-crtsh/README.md

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
# Setup
2+
3+
Deploy function
4+
5+
```
6+
kubeless function deploy splat-crtsh-scanner -f app.js -d package.json --runtime nodejs8 --handler app.handler
7+
```
8+
9+
Create NATS trigger
10+
11+
```
12+
kubeless trigger nats create crtsh-input-trigger --trigger-topic splat-input-domain --function-selector created-by=kubeless,function=splat-crtsh-scanner
13+
```
14+
15+
```
16+
kubeless trigger nats delete crtsh-input-trigger
17+
```

0 commit comments

Comments
 (0)