Skip to content

Commit 8810449

Browse files
authored
Merge branch 'main' into fix-minor-issues
2 parents 5836d44 + 8eb7b81 commit 8810449

File tree

11 files changed

+1655
-631
lines changed

11 files changed

+1655
-631
lines changed

blobs.go

Lines changed: 26 additions & 85 deletions
Original file line numberDiff line numberDiff line change
@@ -3,21 +3,31 @@ package shuffle
33
func GetPublicDetections() []DetectionResponse {
44
return []DetectionResponse{
55
DetectionResponse{
6-
Title: "Sigma SIEM Detections",
6+
Title: "Sigma SIEM Detections",
77
DetectionName: "Sigma",
88
Category: "SIEM",
99
DetectionInfo: []DetectionFileInfo{},
1010
FolderDisabled: false,
1111
IsConnectorActive: false,
12-
DownloadRepo: "https://github.com/satti-hari-krishna-reddy/shuffle_sigma",
12+
DownloadRepo: "https://github.com/shuffle/security-rules",
1313
},
1414
DetectionResponse{
15-
Title: "Sublime Email Detection",
15+
Title: "Sublime Email Detection",
1616
DetectionName: "Sublime",
1717
Category: "Email",
1818
DetectionInfo: []DetectionFileInfo{},
1919
FolderDisabled: false,
2020
IsConnectorActive: false,
21+
DownloadRepo: "https://github.com/shuffle/security-rules",
22+
},
23+
DetectionResponse{
24+
Title: "File Detection",
25+
DetectionName: "Yara",
26+
Category: "Files",
27+
DetectionInfo: []DetectionFileInfo{},
28+
FolderDisabled: false,
29+
IsConnectorActive: false,
30+
DownloadRepo: "https://github.com/shuffle/security-rules",
2131
},
2232
}
2333
}
@@ -302,29 +312,8 @@ func GetUsecaseData() string {
302312
"blogpost": "https://medium.com/shuffle-automation/introducing-shuffle-an-open-source-soar-platform-part-1-58a529de7d12",
303313
"reference_image": "/images/detectionframework.png",
304314
"items": {}
305-
},
306-
{
307-
"type": "cases",
308-
"last": "cases",
309-
"name": "2-way Ticket synchronization",
310-
"priority": 20,
311-
"items": {}
312-
},
313-
{
314-
"name": "ChatOps",
315-
"priority": 70,
316-
"type": "communication",
317-
"last": "cases",
318-
"items": {}
319-
},
320-
{
321-
"name": "Threat Intel received",
322-
"priority": 50,
323-
"type": "intel",
324-
"last": "cases",
325-
"items": {}
326-
}
327-
]
315+
}
316+
]
328317
},
329318
{
330319
"name": "2. Enrich",
@@ -441,79 +430,31 @@ func GetUsecaseData() string {
441430
"color": "#4885ed",
442431
"list": [
443432
{
444-
"name": "Eradicate malware",
445-
"priority": 90,
446-
"type": "intel",
447-
"last": "edr",
448-
"items": {}
449-
},
450-
{
451-
"name": "Quarantine host(s)",
452-
"priority": 90,
433+
"name": "Isolate Host",
434+
"old_name": "Quarantine host(s)",
435+
"priority": 80,
453436
"type": "edr",
454437
"items": {}
455438
},
456439
{
457-
"name": "Update Outdated Software",
458-
"priority": 70,
459-
"type": "assets",
460-
"items": {}
461-
},
462-
{
463-
"name": "Block IPs, URLs, Domains and Hashes",
464-
"priority": 90,
440+
"name": "Block an IP",
441+
"old_name": "Block IPs, URLs, Domains and Hashes",
442+
"priority": 75,
465443
"type": "network",
466444
"items": {}
467445
},
468446
{
469-
"name": "Trigger scans",
470-
"priority": 50,
471-
"type": "assets",
472-
"items": {}
473-
},
474-
{
475-
"name": "Update indicators (FW, EDR, SIEM...)",
476-
"priority": 50,
477-
"type": "intel",
478-
"last": "siem",
479-
"items": {}
480-
},
481-
{
482-
"name": "Autoblock activity when threat intel is received",
447+
"name": "Kill a process",
483448
"priority": 50,
484-
"type": "intel",
485-
"last": "iam",
486-
"items": {}
487-
},
488-
{
489-
"name": "Lock/Delete/Reset account",
490-
"priority": 50,
491-
"type": "iam",
492-
"items": {}
493-
},
494-
{
495-
"name": "Lock vault",
496-
"priority": 50,
497-
"type": "iam",
449+
"type": "edr",
498450
"items": {}
499451
},
500452
{
501-
"name": "Increase authentication",
502-
"priority": 50,
453+
"name": "Lock account",
454+
"old_name": "Lock/Delete/Reset account",
455+
"priority": 70,
503456
"type": "iam",
504457
"items": {}
505-
},
506-
{
507-
"name": "Get policies from assets",
508-
"priority": 50,
509-
"type": "assets",
510-
"items": {}
511-
},
512-
{
513-
"name": "Run ansible scripts",
514-
"type": "assets",
515-
"priority": 50,
516-
"items": {}
517458
}
518459
]
519460
},

codegen.go

Lines changed: 132 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,14 +16,17 @@ import (
1616
"sort"
1717
"strconv"
1818
"strings"
19+
"net/http"
1920

2021
"cloud.google.com/go/storage"
2122
"github.com/frikky/kin-openapi/openapi3"
23+
docker "github.com/docker/docker/client"
2224

2325
//"github.com/satori/go.uuid"
2426
"gopkg.in/yaml.v2"
2527
)
2628

29+
var downloadedImages = []string{}
2730
var pythonAllowed = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_"
2831
var pythonReplacements = map[string]string{
2932
"[": "",
@@ -3771,3 +3774,132 @@ func RemoveJsonValues(input []byte, depth int64) ([]byte, string, error) {
37713774

37723775
return input, keyToken, nil
37733776
}
3777+
3778+
func DownloadDockerImageBackend(topClient *http.Client, imageName string) error {
3779+
// Check environment SHUFFLE_AUTO_IMAGE_DOWNLOAD
3780+
if os.Getenv("SHUFFLE_AUTO_IMAGE_DOWNLOAD") == "false" {
3781+
log.Printf("[DEBUG] SHUFFLE_AUTO_IMAGE_DOWNLOAD is false. Not downloading image %s", imageName)
3782+
return nil
3783+
}
3784+
3785+
if ArrayContains(downloadedImages, imageName) && project.Environment == "worker" {
3786+
log.Printf("[DEBUG] Image %s already downloaded - not re-downloading. This only applies to workers.", imageName)
3787+
return nil
3788+
}
3789+
3790+
baseUrl := os.Getenv("BASE_URL")
3791+
log.Printf("[DEBUG] Trying to download image %s from backend %s as it doesn't exist. All images: %#v", imageName, baseUrl, downloadedImages)
3792+
3793+
if !ArrayContains(downloadedImages, imageName) {
3794+
downloadedImages = append(downloadedImages, imageName)
3795+
}
3796+
3797+
data := fmt.Sprintf(`{"name": "%s"}`, imageName)
3798+
dockerImgUrl := fmt.Sprintf("%s/api/v1/get_docker_image", baseUrl)
3799+
3800+
req, err := http.NewRequest(
3801+
"POST",
3802+
dockerImgUrl,
3803+
bytes.NewBuffer([]byte(data)),
3804+
)
3805+
3806+
// Specific to the worker
3807+
authorization := os.Getenv("AUTHORIZATION")
3808+
if len(authorization) > 0 {
3809+
req.Header.Add("Authorization", fmt.Sprintf("Bearer %s", authorization))
3810+
} else {
3811+
// Specific to Orborus auth (org + auth) -> environment auth
3812+
authorization = os.Getenv("AUTH")
3813+
if len(authorization) > 0 {
3814+
log.Printf("[DEBUG] Found Orborus environment auth - adding to header.")
3815+
req.Header.Add("Authorization", fmt.Sprintf("Bearer %s", authorization))
3816+
3817+
org := os.Getenv("ORG")
3818+
if len(org) > 0 {
3819+
req.Header.Add("Org-Id", org)
3820+
}
3821+
3822+
} else {
3823+
log.Printf("[WARNING] No auth found - running backend download without it.")
3824+
}
3825+
}
3826+
3827+
newresp, err := topClient.Do(req)
3828+
if err != nil {
3829+
log.Printf("[ERROR] Failed download request for %s: %s", imageName, err)
3830+
return err
3831+
}
3832+
3833+
defer newresp.Body.Close()
3834+
if newresp.StatusCode != 200 {
3835+
log.Printf("[ERROR] Docker download for image %s (backend) StatusCode (1): %d", imageName, newresp.StatusCode)
3836+
return errors.New(fmt.Sprintf("Failed to get image - status code %d", newresp.StatusCode))
3837+
}
3838+
3839+
newImageName := strings.Replace(imageName, "/", "_", -1)
3840+
newFileName := newImageName + ".tar"
3841+
3842+
tar, err := os.Create(newFileName)
3843+
if err != nil {
3844+
log.Printf("[WARNING] Failed creating file: %s", err)
3845+
return err
3846+
}
3847+
3848+
defer tar.Close()
3849+
_, err = io.Copy(tar, newresp.Body)
3850+
if err != nil {
3851+
log.Printf("[WARNING] Failed response body copying: %s", err)
3852+
return err
3853+
}
3854+
tar.Seek(0, 0)
3855+
3856+
dockercli, err := docker.NewEnvClient()
3857+
if err != nil {
3858+
log.Printf("[ERROR] Unable to create docker client (3): %s", err)
3859+
return err
3860+
}
3861+
3862+
defer dockercli.Close()
3863+
3864+
imageLoadResponse, err := dockercli.ImageLoad(context.Background(), tar, true)
3865+
if err != nil {
3866+
log.Printf("[ERROR] Error loading images: %s", err)
3867+
return err
3868+
}
3869+
3870+
defer imageLoadResponse.Body.Close()
3871+
body, err := ioutil.ReadAll(imageLoadResponse.Body)
3872+
if err != nil {
3873+
log.Printf("[ERROR] Error reading: %s", err)
3874+
return err
3875+
}
3876+
3877+
if strings.Contains(string(body), "no such file") {
3878+
return errors.New(string(body))
3879+
}
3880+
3881+
os.Remove(newFileName)
3882+
3883+
if strings.Contains(strings.ToLower(string(body)), "error") {
3884+
log.Printf("[ERROR] Error loading image %s: %s", imageName, string(body))
3885+
return errors.New(string(body))
3886+
}
3887+
3888+
baseTag := strings.Split(imageName, ":")
3889+
if len(baseTag) > 1 {
3890+
tag := baseTag[1]
3891+
log.Printf("[DEBUG] Creating tag copies of downloaded containers from tag %s", tag)
3892+
3893+
// Remapping
3894+
ctx := context.Background()
3895+
dockercli.ImageTag(ctx, imageName, fmt.Sprintf("frikky/shuffle:%s", tag))
3896+
dockercli.ImageTag(ctx, imageName, fmt.Sprintf("registry.hub.docker.com/frikky/shuffle:%s", tag))
3897+
3898+
downloadedImages = append(downloadedImages, fmt.Sprintf("frikky/shuffle:%s", tag))
3899+
downloadedImages = append(downloadedImages, fmt.Sprintf("registry.hub.docker.com/frikky/shuffle:%s", tag))
3900+
3901+
}
3902+
3903+
log.Printf("[INFO] Successfully loaded image %s: %s", imageName, string(body))
3904+
return nil
3905+
}

0 commit comments

Comments
 (0)