Skip to content

Commit 117e253

Browse files
Merge pull request #5 from MexHigh/main
Fix: custom_download_url is not being used for BOFs
2 parents 1690a91 + 10eab65 commit 117e253

1 file changed

Lines changed: 99 additions & 78 deletions

File tree

Payload_Type/forge/forge/agentfunctions/forge_download.go

Lines changed: 99 additions & 78 deletions
Original file line numberDiff line numberDiff line change
@@ -7,17 +7,18 @@ import (
77
"encoding/json"
88
"errors"
99
"fmt"
10-
agentstructs "github.com/MythicMeta/MythicContainer/agent_structs"
11-
"github.com/MythicMeta/MythicContainer/logging"
12-
"github.com/MythicMeta/MythicContainer/mythicrpc"
13-
"github.com/MythicMeta/MythicContainer/rabbitmq"
1410
"io"
1511
"net/http"
1612
"os"
1713
"path/filepath"
1814
"slices"
1915
"strings"
2016
"time"
17+
18+
agentstructs "github.com/MythicMeta/MythicContainer/agent_structs"
19+
"github.com/MythicMeta/MythicContainer/logging"
20+
"github.com/MythicMeta/MythicContainer/mythicrpc"
21+
"github.com/MythicMeta/MythicContainer/rabbitmq"
2122
)
2223

2324
var assemblyVersions = []string{
@@ -514,6 +515,7 @@ func createAssemblyCommand(commandSource collectionSourceCommandData, collection
514515
}
515516
return newCommand
516517
}
518+
517519
func downloadBofFile(commandSource collectionSourceCommandData, collectionSourceData collectionSource, taskData *agentstructs.PTTaskMessageAllData) error {
518520
if len(commandSource.customBofFileIDs) > 0 {
519521
extractPath := filepath.Join(".", PayloadTypeName, "collections", collectionSourceData.Name, commandSource.CommandName) + string(os.PathSeparator)
@@ -568,95 +570,114 @@ func downloadBofFile(commandSource collectionSourceCommandData, collectionSource
568570
}
569571
return nil
570572
}
571-
urlPieces := strings.Split(commandSource.RepoURL, "/")
572-
repo := strings.Join(urlPieces[3:], "/")
573-
url := fmt.Sprintf("https://api.github.com/repos/%s/releases/latest", repo)
574-
if commandSource.CustomVersion != "" {
575-
url = fmt.Sprintf("https://api.github.com/repos/%s/releases/tags/%s", repo, commandSource.CustomVersion)
573+
574+
downloadPath := filepath.Join(".", PayloadTypeName, "collections", collectionSourceData.Name, commandSource.CommandName+".tar.gz")
575+
extractPath := filepath.Join(".", PayloadTypeName, "collections", collectionSourceData.Name, commandSource.CommandName) + string(os.PathSeparator)
576+
577+
err := os.MkdirAll(extractPath, os.ModePerm)
578+
if err != nil {
579+
return err
576580
}
577-
req, err := http.NewRequest("GET", url, nil)
581+
downloadFile, err := os.Create(downloadPath)
578582
if err != nil {
579-
logging.LogError(err, "failed to make get request for bof")
580583
return err
581584
}
582-
// Add required headers
583-
req.Header.Add("Accept", "application/vnd.github.v3.text-match+json")
584-
req.Header.Add("Accept", "application/vnd.github.moondragon+json")
585+
defer downloadFile.Close()
586+
if taskData != nil {
587+
mythicrpc.SendMythicRPCResponseCreate(mythicrpc.MythicRPCResponseCreateMessage{
588+
TaskID: taskData.Task.ID,
589+
Response: []byte(fmt.Sprintf("[*] Downloading %s...\n", commandSource.Name+".tar.gz")),
590+
})
591+
}
592+
593+
tarGzURL := ""
594+
if commandSource.CustomDownloadURL != "" {
595+
logging.LogInfo("Custom download URL was supplied")
596+
tarGzURL = commandSource.CustomDownloadURL
597+
} else {
598+
logging.LogInfo("Using default download procedure, assuming GitHub")
599+
// calculate GitHub asset download URL
600+
urlPieces := strings.Split(commandSource.RepoURL, "/")
601+
repo := strings.Join(urlPieces[3:], "/")
602+
url := fmt.Sprintf("https://api.github.com/repos/%s/releases/latest", repo)
603+
if commandSource.CustomVersion != "" {
604+
url = fmt.Sprintf("https://api.github.com/repos/%s/releases/tags/%s", repo, commandSource.CustomVersion)
605+
}
606+
req, err := http.NewRequest("GET", url, nil)
607+
if err != nil {
608+
logging.LogError(err, "failed to make get request for bof")
609+
return err
610+
}
611+
// Add required headers
612+
req.Header.Add("Accept", "application/vnd.github.v3.text-match+json")
613+
req.Header.Add("Accept", "application/vnd.github.moondragon+json")
614+
if taskData != nil {
615+
if _, ok := taskData.Secrets["GITHUB_TOKEN"]; ok {
616+
req.Header.Add("Authorization", "Bearer "+taskData.Secrets["GITHUB_TOKEN"].(string))
617+
}
618+
}
619+
body, err := rateLimitLoopFetchURL(req)
620+
if err != nil {
621+
return err
622+
}
623+
result := make(map[string]interface{})
624+
err = json.Unmarshal(body, &result)
625+
if err != nil {
626+
logging.LogError(err, "failed to unmarshal response body")
627+
return err
628+
}
629+
if len(result["assets"].([]interface{})) == 0 {
630+
return errors.New("no assets found in GitHub release")
631+
}
632+
found := false
633+
for _, asset := range result["assets"].([]interface{}) {
634+
if asset.(map[string]interface{})["name"].(string) == commandSource.CommandName+".tar.gz" {
635+
tarGzURL = asset.(map[string]interface{})["url"].(string)
636+
found = true
637+
}
638+
}
639+
if !found {
640+
return errors.New("unable to find command name in assets")
641+
}
642+
}
643+
644+
if tarGzURL == "" {
645+
return errors.New("no download URL present")
646+
}
647+
648+
downloadReq, err := http.NewRequest("GET", tarGzURL, nil)
649+
if err != nil {
650+
logging.LogError(err, "failed to make new request for bof in released assets")
651+
return err
652+
}
653+
downloadReq.Header.Add("Accept", "application/octet-stream")
585654
if taskData != nil {
586655
if _, ok := taskData.Secrets["GITHUB_TOKEN"]; ok {
587-
req.Header.Add("Authorization", "Bearer "+taskData.Secrets["GITHUB_TOKEN"].(string))
656+
downloadReq.Header.Add("Authorization", "Bearer "+taskData.Secrets["GITHUB_TOKEN"].(string))
588657
}
589658
}
590-
body, err := rateLimitLoopFetchURL(req)
659+
downloadFileBody, err := rateLimitLoopFetchURL(downloadReq)
591660
if err != nil {
661+
os.Remove(downloadPath)
592662
return err
593663
}
594-
result := make(map[string]interface{})
595-
err = json.Unmarshal(body, &result)
664+
_, err = downloadFile.Write(downloadFileBody)
596665
if err != nil {
597-
logging.LogError(err, "failed to unmarshal response body")
666+
os.Remove(downloadPath)
598667
return err
599668
}
600-
for _, asset := range result["assets"].([]interface{}) {
601-
if asset.(map[string]interface{})["name"].(string) == commandSource.CommandName+".tar.gz" {
602-
downloadURL := asset.(map[string]interface{})["url"].(string)
603-
downloadPath := filepath.Join(".", PayloadTypeName, "collections", collectionSourceData.Name, commandSource.CommandName+".tar.gz")
604-
extractPath := filepath.Join(".", PayloadTypeName, "collections", collectionSourceData.Name, commandSource.CommandName) + string(os.PathSeparator)
605-
err = os.MkdirAll(extractPath, os.ModePerm)
606-
if err != nil {
607-
return err
608-
}
609-
downloadFile, err := os.Create(downloadPath)
610-
if err != nil {
611-
return err
612-
}
613-
if taskData != nil {
614-
mythicrpc.SendMythicRPCResponseCreate(mythicrpc.MythicRPCResponseCreateMessage{
615-
TaskID: taskData.Task.ID,
616-
Response: []byte(fmt.Sprintf("[*] Downloading %s...\n", commandSource.Name+".tar.gz")),
617-
})
618-
}
619-
620-
downloadReq, err := http.NewRequest("GET", downloadURL, nil)
621-
if err != nil {
622-
downloadFile.Close()
623-
logging.LogError(err, "failed to make new request for bof in released assets")
624-
return err
625-
}
626-
downloadReq.Header.Add("Accept", "application/octet-stream")
627-
if taskData != nil {
628-
if _, ok := taskData.Secrets["GITHUB_TOKEN"]; ok {
629-
downloadReq.Header.Add("Authorization", "Bearer "+taskData.Secrets["GITHUB_TOKEN"].(string))
630-
}
631-
}
632-
downloadFileBody, err := rateLimitLoopFetchURL(downloadReq)
633-
if err != nil {
634-
downloadFile.Close()
635-
os.Remove(downloadPath)
636-
return err
637-
}
638-
_, err = downloadFile.Write(downloadFileBody)
639-
if err != nil {
640-
downloadFile.Close()
641-
os.Remove(downloadPath)
642-
return err
643-
}
644-
if taskData != nil {
645-
mythicrpc.SendMythicRPCResponseCreate(mythicrpc.MythicRPCResponseCreateMessage{
646-
TaskID: taskData.Task.ID,
647-
Response: []byte(fmt.Sprintf("[+] Finished Downloading %s\n", commandSource.Name+".tar.gz")),
648-
})
649-
}
650-
downloadFile.Seek(0, 0)
651-
err = ExtractTarGz(downloadFile, extractPath)
652-
if err != nil {
653-
return err
654-
}
655-
return nil
656-
}
657-
//logging.LogInfo("asset data", "asset", asset.(map[string]interface{}))
669+
if taskData != nil {
670+
mythicrpc.SendMythicRPCResponseCreate(mythicrpc.MythicRPCResponseCreateMessage{
671+
TaskID: taskData.Task.ID,
672+
Response: []byte(fmt.Sprintf("[+] Finished Downloading %s\n", commandSource.Name+".tar.gz")),
673+
})
658674
}
659-
return errors.New("failed to find file in latest assets")
675+
downloadFile.Seek(0, 0)
676+
err = ExtractTarGz(downloadFile, extractPath)
677+
if err != nil {
678+
return err
679+
}
680+
return nil
660681
}
661682

662683
type bofCommandDefinitionFiles struct {

0 commit comments

Comments
 (0)