mirror of
https://github.com/BishopFox/sliver.git
synced 2026-11-10 09:51:30 -10:00
Compare commits
13
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
c7844f57b3 | ||
|
|
23eef3d15c | ||
|
|
22b2704259 | ||
|
|
856fbb5974 | ||
|
|
6cbfe64f61 | ||
|
|
573ec4d800 | ||
|
|
11f93ab5b2 | ||
|
|
48a061d59e | ||
|
|
6262266cac | ||
|
|
37524596bb | ||
|
|
91108619f5 | ||
|
|
7972fce3cc | ||
|
|
30c569259d |
No files matched your search
+1
-1
@@ -1,4 +1,4 @@
|
||||
FROM golang:1.18.2
|
||||
FROM golang:1.18.3
|
||||
|
||||
#
|
||||
# IMPORTANT: This Dockerfile is used for testing, I do not recommend deploying
|
||||
|
||||
@@ -21,7 +21,9 @@ package assets
|
||||
import (
|
||||
"encoding/json"
|
||||
"io/ioutil"
|
||||
"log"
|
||||
"os"
|
||||
"os/exec"
|
||||
"path/filepath"
|
||||
)
|
||||
|
||||
@@ -30,8 +32,10 @@ const (
|
||||
)
|
||||
|
||||
var (
|
||||
// DefaultArmoryPublicKey - The default public key for the armory
|
||||
DefaultArmoryPublicKey string
|
||||
DefaultArmoryRepoURL string
|
||||
// DefaultArmoryRepoURL - The default repo url for the armory
|
||||
DefaultArmoryRepoURL string
|
||||
|
||||
defaultArmoryConfig = &ArmoryConfig{
|
||||
PublicKey: DefaultArmoryPublicKey,
|
||||
@@ -39,9 +43,12 @@ var (
|
||||
}
|
||||
)
|
||||
|
||||
// ArmoryConfig - The armory config file
|
||||
type ArmoryConfig struct {
|
||||
PublicKey string `json:"public_key"`
|
||||
RepoURL string `json:"repo_url"`
|
||||
PublicKey string `json:"public_key"`
|
||||
RepoURL string `json:"repo_url"`
|
||||
Authorization string `json:"authorization"`
|
||||
AuthorizationCmd string `json:"authorization_cmd"`
|
||||
}
|
||||
|
||||
// GetArmoriesConfig - The parsed armory config file
|
||||
@@ -59,5 +66,22 @@ func GetArmoriesConfig() []*ArmoryConfig {
|
||||
if err != nil {
|
||||
return []*ArmoryConfig{defaultArmoryConfig}
|
||||
}
|
||||
for _, armoryConfig := range armoryConfigs {
|
||||
if armoryConfig.AuthorizationCmd != "" {
|
||||
armoryConfig.Authorization = executeAuthorizationCmd(armoryConfig)
|
||||
}
|
||||
}
|
||||
return append(armoryConfigs, defaultArmoryConfig)
|
||||
}
|
||||
|
||||
func executeAuthorizationCmd(armoryConfig *ArmoryConfig) string {
|
||||
if armoryConfig.AuthorizationCmd == "" {
|
||||
return ""
|
||||
}
|
||||
out, err := exec.Command(armoryConfig.AuthorizationCmd).CombinedOutput()
|
||||
if err != nil {
|
||||
log.Printf("Failed to execute authorization_cmd '%s': %v", armoryConfig.AuthorizationCmd, err)
|
||||
return ""
|
||||
}
|
||||
return string(out)
|
||||
}
|
||||
@@ -38,12 +38,15 @@ import (
|
||||
"golang.org/x/term"
|
||||
)
|
||||
|
||||
// ArmoryIndex - Index JSON containing alias/extension/bundle information
|
||||
type ArmoryIndex struct {
|
||||
Aliases []*ArmoryPackage `json:"aliases"`
|
||||
Extensions []*ArmoryPackage `json:"extensions"`
|
||||
Bundles []*ArmoryBundle `json:"bundles"`
|
||||
ArmoryConfig *assets.ArmoryConfig `json:"-"`
|
||||
Aliases []*ArmoryPackage `json:"aliases"`
|
||||
Extensions []*ArmoryPackage `json:"extensions"`
|
||||
Bundles []*ArmoryBundle `json:"bundles"`
|
||||
}
|
||||
|
||||
// ArmoryPackage - JSON metadata for alias or extension
|
||||
type ArmoryPackage struct {
|
||||
Name string `json:"name"`
|
||||
CommandName string `json:"command_name"`
|
||||
@@ -53,12 +56,15 @@ type ArmoryPackage struct {
|
||||
IsAlias bool `json:"-"`
|
||||
}
|
||||
|
||||
// AmoryBundle - A list of packages
|
||||
type ArmoryBundle struct {
|
||||
Name string `json:"name"`
|
||||
Packages []string `json:"packages"`
|
||||
}
|
||||
|
||||
// ArmoryHTTPConfig - Configuration for armory HTTP client
|
||||
type ArmoryHTTPConfig struct {
|
||||
ArmoryConfig *assets.ArmoryConfig
|
||||
IgnoreCache bool
|
||||
ProxyURL *url.URL
|
||||
Timeout time.Duration
|
||||
@@ -66,20 +72,22 @@ type ArmoryHTTPConfig struct {
|
||||
}
|
||||
|
||||
type indexCacheEntry struct {
|
||||
RepoURL string
|
||||
Fetched time.Time
|
||||
Index ArmoryIndex
|
||||
LastErr error
|
||||
ArmoryConfig *assets.ArmoryConfig
|
||||
RepoURL string
|
||||
Fetched time.Time
|
||||
Index ArmoryIndex
|
||||
LastErr error
|
||||
}
|
||||
|
||||
type pkgCacheEntry struct {
|
||||
RepoURL string
|
||||
Fetched time.Time
|
||||
Pkg ArmoryPackage
|
||||
Sig minisign.Signature
|
||||
Alias *alias.AliasManifest
|
||||
Extension *extensions.ExtensionManifest
|
||||
LastErr error
|
||||
ArmoryConfig *assets.ArmoryConfig
|
||||
RepoURL string
|
||||
Fetched time.Time
|
||||
Pkg ArmoryPackage
|
||||
Sig minisign.Signature
|
||||
Alias *alias.AliasManifest
|
||||
Extension *extensions.ExtensionManifest
|
||||
LastErr error
|
||||
}
|
||||
|
||||
var (
|
||||
@@ -395,7 +403,10 @@ func fetchIndex(armoryConfig *assets.ArmoryConfig, clientConfig ArmoryHTTPConfig
|
||||
}
|
||||
}
|
||||
|
||||
armoryResult := &indexCacheEntry{RepoURL: armoryConfig.RepoURL}
|
||||
armoryResult := &indexCacheEntry{
|
||||
ArmoryConfig: armoryConfig,
|
||||
RepoURL: armoryConfig.RepoURL,
|
||||
}
|
||||
defer func() {
|
||||
armoryResult.Fetched = time.Now()
|
||||
indexCache.Store(armoryConfig.PublicKey, *armoryResult)
|
||||
@@ -431,18 +442,18 @@ func fetchPackageSignatures(indexes []ArmoryIndex, clientConfig ArmoryHTTPConfig
|
||||
for _, armoryPkg := range index.Extensions {
|
||||
wg.Add(1)
|
||||
armoryPkg.IsAlias = false
|
||||
go fetchPackageSignature(wg, armoryPkg, clientConfig)
|
||||
go fetchPackageSignature(wg, index.ArmoryConfig, armoryPkg, clientConfig)
|
||||
}
|
||||
for _, armoryPkg := range index.Aliases {
|
||||
wg.Add(1)
|
||||
armoryPkg.IsAlias = true
|
||||
go fetchPackageSignature(wg, armoryPkg, clientConfig)
|
||||
go fetchPackageSignature(wg, index.ArmoryConfig, armoryPkg, clientConfig)
|
||||
}
|
||||
}
|
||||
wg.Wait()
|
||||
}
|
||||
|
||||
func fetchPackageSignature(wg *sync.WaitGroup, armoryPkg *ArmoryPackage, clientConfig ArmoryHTTPConfig) {
|
||||
func fetchPackageSignature(wg *sync.WaitGroup, armoryConfig *assets.ArmoryConfig, armoryPkg *ArmoryPackage, clientConfig ArmoryHTTPConfig) {
|
||||
defer wg.Done()
|
||||
cacheEntry, ok := pkgCache.Load(armoryPkg.CommandName)
|
||||
if ok {
|
||||
@@ -452,7 +463,10 @@ func fetchPackageSignature(wg *sync.WaitGroup, armoryPkg *ArmoryPackage, clientC
|
||||
}
|
||||
}
|
||||
|
||||
pkgCacheEntry := &pkgCacheEntry{RepoURL: armoryPkg.RepoURL}
|
||||
pkgCacheEntry := &pkgCacheEntry{
|
||||
ArmoryConfig: armoryConfig,
|
||||
RepoURL: armoryPkg.RepoURL,
|
||||
}
|
||||
defer func() {
|
||||
pkgCacheEntry.Fetched = time.Now()
|
||||
pkgCache.Store(armoryPkg.CommandName, *pkgCacheEntry)
|
||||
@@ -472,7 +486,7 @@ func fetchPackageSignature(wg *sync.WaitGroup, armoryPkg *ArmoryPackage, clientC
|
||||
if pkgParser, ok := pkgParsers[repoURL.Hostname()]; ok {
|
||||
sig, _, err = pkgParser(armoryPkg, true, clientConfig)
|
||||
} else {
|
||||
sig, _, err = DefaultArmoryPkgParser(armoryPkg, true, clientConfig)
|
||||
sig, _, err = DefaultArmoryPkgParser(armoryConfig, armoryPkg, true, clientConfig)
|
||||
}
|
||||
if err != nil {
|
||||
pkgCacheEntry.LastErr = fmt.Errorf("failed to parse pkg manifest: %s", err)
|
||||
|
||||
@@ -35,6 +35,7 @@ import (
|
||||
)
|
||||
|
||||
var (
|
||||
// ErrPackageNotFound - The package was not found
|
||||
ErrPackageNotFound = errors.New("package not found")
|
||||
)
|
||||
|
||||
@@ -144,7 +145,7 @@ func installAliasPackageByName(name string, clientConfig ArmoryHTTPConfig, con *
|
||||
if pkgParser, ok := pkgParsers[repoURL.Hostname()]; ok {
|
||||
sig, tarGz, err = pkgParser(&entry.Pkg, false, clientConfig)
|
||||
} else {
|
||||
sig, tarGz, err = DefaultArmoryPkgParser(&entry.Pkg, false, clientConfig)
|
||||
sig, tarGz, err = DefaultArmoryPkgParser(entry.ArmoryConfig, &entry.Pkg, false, clientConfig)
|
||||
}
|
||||
if err != nil {
|
||||
return err
|
||||
@@ -262,7 +263,7 @@ func installExtensionPackageByName(name string, clientConfig ArmoryHTTPConfig, c
|
||||
if pkgParser, ok := pkgParsers[repoURL.Hostname()]; ok {
|
||||
sig, tarGz, err = pkgParser(&entry.Pkg, false, clientConfig)
|
||||
} else {
|
||||
sig, tarGz, err = DefaultArmoryPkgParser(&entry.Pkg, false, clientConfig)
|
||||
sig, tarGz, err = DefaultArmoryPkgParser(entry.ArmoryConfig, &entry.Pkg, false, clientConfig)
|
||||
}
|
||||
if err != nil {
|
||||
return err
|
||||
|
||||
@@ -58,13 +58,13 @@ const (
|
||||
)
|
||||
|
||||
type armoryIndexResponse struct {
|
||||
Minisig string `json:"minisig"` // Minisig
|
||||
ArmoryIndex string `json:"armory_index"` // Base64 String
|
||||
Minisig string `json:"minisig"` // Minisig (Base64)
|
||||
ArmoryIndex string `json:"armory_index"` // Index JSON (Base64)
|
||||
}
|
||||
|
||||
type armoryPkgResponse struct {
|
||||
Minisig string `json:"minisig"` // Minisig
|
||||
TarGzURL string `json:"tar_gz_url"`
|
||||
Minisig string `json:"minisig"` // Minisig (Base64)
|
||||
TarGzURL string `json:"tar_gz_url"` // Raw tar.gz url
|
||||
}
|
||||
|
||||
//
|
||||
@@ -80,7 +80,19 @@ func DefaultArmoryIndexParser(armoryConfig *assets.ArmoryConfig, clientConfig Ar
|
||||
}
|
||||
|
||||
client := httpClient(clientConfig)
|
||||
resp, err := client.Get(armoryConfig.RepoURL)
|
||||
repoURL, err := url.Parse(armoryConfig.RepoURL)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
req := &http.Request{
|
||||
Method: http.MethodGet,
|
||||
URL: repoURL,
|
||||
Header: map[string][]string{},
|
||||
}
|
||||
if armoryConfig.Authorization != "" {
|
||||
req.Header.Set("Authorization", armoryConfig.Authorization)
|
||||
}
|
||||
resp, err := client.Do(req)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -92,20 +104,28 @@ func DefaultArmoryIndexParser(armoryConfig *assets.ArmoryConfig, clientConfig Ar
|
||||
if resp.StatusCode != http.StatusOK {
|
||||
return nil, errors.New("api returned non-200 status code")
|
||||
}
|
||||
index := &armoryIndexResponse{}
|
||||
err = json.Unmarshal(body, index)
|
||||
|
||||
indexResp := &armoryIndexResponse{}
|
||||
err = json.Unmarshal(body, indexResp)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
armoryIndexData, err := base64.StdEncoding.DecodeString(indexResp.ArmoryIndex)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
armoryIndexSigData, err := base64.StdEncoding.DecodeString(indexResp.Minisig)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Verify index is signed by trusted key
|
||||
valid := minisign.Verify(publicKey, []byte(index.ArmoryIndex), []byte(index.ArmoryIndex))
|
||||
valid := minisign.Verify(publicKey, armoryIndexData, armoryIndexSigData)
|
||||
if !valid {
|
||||
return nil, errors.New("invalid signature")
|
||||
return nil, errors.New("index has invalid signature")
|
||||
}
|
||||
|
||||
armoryIndex := &ArmoryIndex{}
|
||||
armoryIndexData, err := base64.StdEncoding.DecodeString(index.ArmoryIndex)
|
||||
armoryIndex := &ArmoryIndex{ArmoryConfig: armoryConfig}
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -117,7 +137,7 @@ func DefaultArmoryIndexParser(armoryConfig *assets.ArmoryConfig, clientConfig Ar
|
||||
}
|
||||
|
||||
// DefaultArmoryPkgParser - Parse the armory package manifest directly from the url
|
||||
func DefaultArmoryPkgParser(armoryPkg *ArmoryPackage, sigOnly bool, clientConfig ArmoryHTTPConfig) (*minisign.Signature, []byte, error) {
|
||||
func DefaultArmoryPkgParser(armoryConfig *assets.ArmoryConfig, armoryPkg *ArmoryPackage, sigOnly bool, clientConfig ArmoryHTTPConfig) (*minisign.Signature, []byte, error) {
|
||||
var publicKey minisign.PublicKey
|
||||
err := publicKey.UnmarshalText([]byte(armoryPkg.PublicKey))
|
||||
if err != nil {
|
||||
@@ -125,7 +145,19 @@ func DefaultArmoryPkgParser(armoryPkg *ArmoryPackage, sigOnly bool, clientConfig
|
||||
}
|
||||
|
||||
client := httpClient(clientConfig)
|
||||
resp, err := client.Get(armoryPkg.RepoURL)
|
||||
repoURL, err := url.Parse(armoryConfig.RepoURL)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
req := &http.Request{
|
||||
Method: http.MethodGet,
|
||||
URL: repoURL,
|
||||
Header: map[string][]string{},
|
||||
}
|
||||
if armoryConfig.Authorization != "" {
|
||||
req.Header.Set("Authorization", armoryConfig.Authorization)
|
||||
}
|
||||
resp, err := client.Do(req)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
@@ -19,17 +19,20 @@ package filesystem
|
||||
*/
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/hex"
|
||||
"fmt"
|
||||
"os"
|
||||
"path/filepath"
|
||||
|
||||
"github.com/alecthomas/chroma/formatters"
|
||||
"github.com/alecthomas/chroma/lexers"
|
||||
"github.com/alecthomas/chroma/styles"
|
||||
"github.com/bishopfox/sliver/client/command/loot"
|
||||
"github.com/bishopfox/sliver/client/console"
|
||||
"github.com/bishopfox/sliver/protobuf/clientpb"
|
||||
"github.com/bishopfox/sliver/protobuf/sliverpb"
|
||||
"github.com/bishopfox/sliver/util/encoders"
|
||||
"google.golang.org/protobuf/proto"
|
||||
|
||||
"github.com/desertbit/grumble"
|
||||
)
|
||||
@@ -47,19 +50,55 @@ func CatCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
|
||||
return
|
||||
}
|
||||
|
||||
ctrl := make(chan bool)
|
||||
con.SpinUntil(fmt.Sprintf("Downloading %s ...", filePath), ctrl)
|
||||
download, err := con.Rpc.Download(context.Background(), &sliverpb.DownloadReq{
|
||||
Request: con.ActiveTarget.Request(ctx),
|
||||
Path: filePath,
|
||||
})
|
||||
ctrl <- true
|
||||
<-ctrl
|
||||
if err != nil {
|
||||
con.PrintErrorf("%s\n", err)
|
||||
return
|
||||
}
|
||||
if download.Response != nil && download.Response.Async {
|
||||
con.AddBeaconCallback(download.Response.TaskID, func(task *clientpb.BeaconTask) {
|
||||
err = proto.Unmarshal(task.Response, download)
|
||||
if err != nil {
|
||||
con.PrintErrorf("Failed to decode response %s\n", err)
|
||||
return
|
||||
}
|
||||
PrintCat(download, ctx, con)
|
||||
})
|
||||
con.PrintAsyncResponse(download.Response)
|
||||
} else {
|
||||
PrintCat(download, ctx, con)
|
||||
}
|
||||
}
|
||||
|
||||
// PrintCat - Print the download to stdout
|
||||
func PrintCat(download *sliverpb.Download, ctx *grumble.Context, con *console.SliverConsoleClient) {
|
||||
var (
|
||||
lootDownload bool = true
|
||||
err error
|
||||
)
|
||||
saveLoot := ctx.Flags.Bool("loot")
|
||||
lootName := ctx.Flags.String("name")
|
||||
userLootType := ctx.Flags.String("type")
|
||||
userLootFileType := ctx.Flags.String("file-type")
|
||||
var lootDownload bool = true
|
||||
|
||||
download, err := PerformDownload(filePath, filepath.Base(filePath), "console", ctx, con)
|
||||
|
||||
if err != nil {
|
||||
con.PrintErrorf("%s\n", err)
|
||||
if download.Response != nil && download.Response.Err != "" {
|
||||
con.PrintErrorf("%s\n", download.Response.Err)
|
||||
return
|
||||
}
|
||||
|
||||
if download.Encoder == "gzip" {
|
||||
download.Data, err = new(encoders.Gzip).Decode(download.Data)
|
||||
if err != nil {
|
||||
con.PrintErrorf("Decoding failed %s", err)
|
||||
}
|
||||
}
|
||||
|
||||
if saveLoot {
|
||||
lootType, err := loot.ValidateLootType(userLootType)
|
||||
if err != nil {
|
||||
@@ -75,14 +114,6 @@ func CatCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
|
||||
con.Printf("\n")
|
||||
}
|
||||
}
|
||||
|
||||
PrintCat(download, ctx, con)
|
||||
}
|
||||
|
||||
// PrintCat - Print the download to stdout
|
||||
func PrintCat(download *sliverpb.Download, ctx *grumble.Context, con *console.SliverConsoleClient) {
|
||||
var err error
|
||||
|
||||
if ctx.Flags.Bool("colorize-output") {
|
||||
if err = colorize(download); err != nil {
|
||||
con.Println(string(download.Data))
|
||||
|
||||
@@ -26,20 +26,26 @@ import (
|
||||
"path/filepath"
|
||||
"strings"
|
||||
|
||||
"github.com/AlecAivazis/survey/v2"
|
||||
"github.com/bishopfox/sliver/client/command/loot"
|
||||
"github.com/bishopfox/sliver/client/console"
|
||||
"github.com/bishopfox/sliver/protobuf/clientpb"
|
||||
"github.com/bishopfox/sliver/protobuf/sliverpb"
|
||||
"github.com/bishopfox/sliver/util/encoders"
|
||||
"google.golang.org/protobuf/proto"
|
||||
"gopkg.in/AlecAivazis/survey.v1"
|
||||
|
||||
"github.com/desertbit/grumble"
|
||||
)
|
||||
|
||||
func PerformDownload(remotePath string, fileName string, destination string, ctx *grumble.Context, con *console.SliverConsoleClient) (*sliverpb.Download, error) {
|
||||
func DownloadCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
|
||||
session, beacon := con.ActiveTarget.GetInteractive()
|
||||
if session == nil && beacon == nil {
|
||||
return
|
||||
}
|
||||
remotePath := ctx.Args.String("remote-path")
|
||||
|
||||
ctrl := make(chan bool)
|
||||
con.SpinUntil(fmt.Sprintf("%s -> %s", fileName, destination), ctrl)
|
||||
con.SpinUntil(fmt.Sprintf("Downloading %s ...", remotePath), ctrl)
|
||||
download, err := con.Rpc.Download(context.Background(), &sliverpb.DownloadReq{
|
||||
Request: con.ActiveTarget.Request(ctx),
|
||||
Path: remotePath,
|
||||
@@ -47,68 +53,61 @@ func PerformDownload(remotePath string, fileName string, destination string, ctx
|
||||
ctrl <- true
|
||||
<-ctrl
|
||||
if err != nil {
|
||||
return nil, err
|
||||
con.PrintErrorf("%s\n", err)
|
||||
return
|
||||
}
|
||||
if download.Response != nil && download.Response.Async {
|
||||
con.AddBeaconCallback(download.Response.TaskID, func(task *clientpb.BeaconTask) {
|
||||
err = proto.Unmarshal(task.Response, download)
|
||||
if err != nil {
|
||||
con.PrintErrorf("Failed to decode response %s\n", err)
|
||||
return
|
||||
}
|
||||
HandleDownloadResponse(download, ctx, con)
|
||||
})
|
||||
con.PrintAsyncResponse(download.Response)
|
||||
} else {
|
||||
HandleDownloadResponse(download, ctx, con)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func HandleDownloadResponse(download *sliverpb.Download, ctx *grumble.Context, con *console.SliverConsoleClient) {
|
||||
var err error
|
||||
if download.Response != nil && download.Response.Err != "" {
|
||||
return download, fmt.Errorf("%s\n", download.Response.Err)
|
||||
con.PrintErrorf("%s\n", download.Response.Err)
|
||||
return
|
||||
}
|
||||
|
||||
if download.Encoder == "gzip" {
|
||||
download.Data, err = new(encoders.Gzip).Decode(download.Data)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("Decoding failed %s", err)
|
||||
con.PrintErrorf("Decoding failed %s", err)
|
||||
}
|
||||
}
|
||||
|
||||
return download, nil
|
||||
}
|
||||
|
||||
// DownloadCmd - Download a file from the remote system
|
||||
func DownloadCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
|
||||
session, beacon := con.ActiveTarget.GetInteractive()
|
||||
if session == nil && beacon == nil {
|
||||
return
|
||||
}
|
||||
|
||||
remotePath := ctx.Args.String("remote-path")
|
||||
localPath := ctx.Args.String("local-path")
|
||||
saveLoot := ctx.Flags.Bool("loot")
|
||||
|
||||
src := remotePath
|
||||
fileName := filepath.Base(src)
|
||||
var dst string
|
||||
var err error
|
||||
var lootType clientpb.LootType
|
||||
var fileType clientpb.FileType
|
||||
var lootName string = ""
|
||||
|
||||
if ctx.Flags.Bool("loot") {
|
||||
// The destination is the loot store.
|
||||
dst = "loot"
|
||||
lootName = ctx.Flags.String("name")
|
||||
|
||||
lootType, err = loot.ValidateLootType(ctx.Flags.String("type"))
|
||||
if saveLoot {
|
||||
lootName := ctx.Flags.String("name")
|
||||
lootType, err := loot.ValidateLootType(ctx.Flags.String("type"))
|
||||
if err != nil {
|
||||
con.PrintErrorf("%s\n", err)
|
||||
return
|
||||
}
|
||||
// Determine file type after the download is complete
|
||||
// Hand off to the loot package to take care of looting
|
||||
fileType := loot.ValidateLootFileType(ctx.Flags.String("file-type"), download.Data)
|
||||
loot.LootDownload(download, lootName, lootType, fileType, ctx, con)
|
||||
} else {
|
||||
// If this download is not being looted, make sure the local path exists
|
||||
dst, err = filepath.Abs(localPath)
|
||||
fileName := filepath.Base(remotePath)
|
||||
dst, err := filepath.Abs(localPath)
|
||||
if err != nil {
|
||||
con.PrintErrorf("%s\n", err)
|
||||
return
|
||||
}
|
||||
|
||||
fi, err := os.Stat(dst)
|
||||
if err != nil && !os.IsNotExist(err) {
|
||||
con.PrintErrorf("%s\n", err)
|
||||
@@ -117,74 +116,32 @@ func DownloadCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
|
||||
if err == nil && fi.IsDir() {
|
||||
dst = path.Join(dst, fileName)
|
||||
}
|
||||
}
|
||||
|
||||
download, err := PerformDownload(src, fileName, dst, ctx, con)
|
||||
if err != nil {
|
||||
con.PrintErrorf("%s\n", err)
|
||||
return
|
||||
}
|
||||
// Add an extension to a directory download if one is not provided.
|
||||
if download.IsDir && (!strings.HasSuffix(dst, ".tgz") || !strings.HasSuffix(dst, ".tar.gz")) {
|
||||
dst += ".tar.gz"
|
||||
}
|
||||
|
||||
if dst == "loot" {
|
||||
// Hand off to the loot package to take care of looting
|
||||
fileType = loot.ValidateLootFileType(ctx.Flags.String("file-type"), download.Data)
|
||||
loot.LootDownload(download, lootName, lootType, fileType, ctx, con)
|
||||
} else {
|
||||
PrintDownload(download, ctx, con)
|
||||
}
|
||||
}
|
||||
if _, err := os.Stat(dst); err == nil {
|
||||
overwrite := false
|
||||
prompt := &survey.Confirm{Message: "Overwrite local file?"}
|
||||
survey.AskOne(prompt, &overwrite, nil)
|
||||
if !overwrite {
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
// PrintDownload - Print the download response, and save file to disk
|
||||
func PrintDownload(download *sliverpb.Download, ctx *grumble.Context, con *console.SliverConsoleClient) {
|
||||
if download.Response != nil && download.Response.Err != "" {
|
||||
con.PrintErrorf("%s\n", download.Response.Err)
|
||||
return
|
||||
}
|
||||
|
||||
remotePath := ctx.Args.String("remote-path")
|
||||
localPath := ctx.Args.String("local-path")
|
||||
|
||||
src := remotePath
|
||||
fileName := filepath.Base(src)
|
||||
dst, err := filepath.Abs(localPath)
|
||||
if err != nil {
|
||||
con.PrintErrorf("%s\n", err)
|
||||
return
|
||||
}
|
||||
|
||||
fi, err := os.Stat(dst)
|
||||
if err != nil && !os.IsNotExist(err) {
|
||||
con.PrintErrorf("%s\n", err)
|
||||
return
|
||||
}
|
||||
if err == nil && fi.IsDir() {
|
||||
dst = path.Join(dst, fileName)
|
||||
}
|
||||
|
||||
// Add an extension to a directory download if one is not provided.
|
||||
if download.IsDir && (!strings.HasSuffix(dst, ".tgz") || !strings.HasSuffix(dst, ".tar.gz")) {
|
||||
dst += ".tar.gz"
|
||||
}
|
||||
|
||||
if _, err := os.Stat(dst); err == nil {
|
||||
overwrite := false
|
||||
prompt := &survey.Confirm{Message: "Overwrite local file?"}
|
||||
survey.AskOne(prompt, &overwrite, nil)
|
||||
if !overwrite {
|
||||
dstFile, err := os.Create(dst)
|
||||
if err != nil {
|
||||
con.PrintErrorf("Failed to open local file %s: %s\n", dst, err)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
dstFile, err := os.Create(dst)
|
||||
if err != nil {
|
||||
con.PrintErrorf("Failed to open local file %s: %s\n", dst, err)
|
||||
return
|
||||
}
|
||||
defer dstFile.Close()
|
||||
n, err := dstFile.Write(download.Data)
|
||||
if err != nil {
|
||||
con.PrintErrorf("Failed to write data %v\n", err)
|
||||
} else {
|
||||
con.PrintInfof("Wrote %d bytes to %s\n", n, dstFile.Name())
|
||||
defer dstFile.Close()
|
||||
n, err := dstFile.Write(download.Data)
|
||||
if err != nil {
|
||||
con.PrintErrorf("Failed to write data %v\n", err)
|
||||
} else {
|
||||
con.PrintInfof("Wrote %d bytes to %s\n", n, dstFile.Name())
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -89,7 +89,7 @@ func StageListenerCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
|
||||
}
|
||||
|
||||
if aesEncrypt {
|
||||
stage2 = util.Encrypt(stage2, []byte(aesEncryptKey), []byte(aesEncryptIv))
|
||||
stage2 = util.PreludeEncrypt(stage2, []byte(aesEncryptKey), []byte(aesEncryptIv))
|
||||
}
|
||||
|
||||
switch stagingURL.Scheme {
|
||||
|
||||
@@ -26,7 +26,6 @@ import (
|
||||
"io/ioutil"
|
||||
"log"
|
||||
insecureRand "math/rand"
|
||||
"path"
|
||||
"path/filepath"
|
||||
"strconv"
|
||||
"strings"
|
||||
@@ -109,7 +108,7 @@ func Start(rpc rpcpb.SliverRPCClient, bindCmds BindCmds, extraCmds BindCmds, isS
|
||||
App: grumble.New(&grumble.Config{
|
||||
Name: "Sliver",
|
||||
Description: "Sliver Client",
|
||||
HistoryFile: path.Join(assets.GetRootAppDir(), "history"),
|
||||
HistoryFile: filepath.Join(assets.GetRootAppDir(), "history"),
|
||||
PromptColor: color.New(),
|
||||
HelpHeadlineColor: color.New(),
|
||||
HelpHeadlineUnderline: true,
|
||||
|
||||
@@ -74,7 +74,7 @@ func (a *OperatorImplantBridge) register() {
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
encrypted := util.Encrypt(data, []byte(a.Config.AESKey), nil)
|
||||
encrypted := util.PreludeEncrypt(data, []byte(a.Config.AESKey), nil)
|
||||
dataBuff := append([]byte(fmt.Sprintf("%x", encrypted)), "\n"...)
|
||||
(*a.Conn).Write(dataBuff)
|
||||
}
|
||||
@@ -84,7 +84,7 @@ func (a *OperatorImplantBridge) ReceiveLoop() {
|
||||
go func() {
|
||||
for {
|
||||
data := <-a.send
|
||||
encrypted := util.Encrypt(data, []byte(a.Config.AESKey), nil)
|
||||
encrypted := util.PreludeEncrypt(data, []byte(a.Config.AESKey), nil)
|
||||
dataBuff := append([]byte(fmt.Sprintf("%x", encrypted)), "\n"...)
|
||||
(*a.Conn).Write(dataBuff)
|
||||
time.Sleep(time.Duration(a.PBeacon.Sleep))
|
||||
@@ -105,7 +105,7 @@ func (a *OperatorImplantBridge) handleMessage(message string) {
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
if err := json.Unmarshal(util.Decrypt(decoded, []byte(a.Config.AESKey)), &tempBeacon); err == nil {
|
||||
if err := json.Unmarshal(util.PreludeDecrypt(decoded, []byte(a.Config.AESKey)), &tempBeacon); err == nil {
|
||||
a.PBeacon.Links = a.PBeacon.Links[:0]
|
||||
a.runLinks(&tempBeacon)
|
||||
}
|
||||
|
||||
+1
-1
@@ -20,7 +20,7 @@ set -e
|
||||
|
||||
# Creates the static go asset archives
|
||||
|
||||
GO_VER="1.18.2"
|
||||
GO_VER="1.18.3"
|
||||
GARBLE_VER="1.18.0"
|
||||
|
||||
GO_ARCH_1="amd64"
|
||||
|
||||
@@ -325,11 +325,12 @@ func downloadHandler(data []byte, resp RPCResponse) {
|
||||
gzipData := bytes.NewBuffer([]byte{})
|
||||
gzipWrite(gzipData, rawData)
|
||||
download = &sliverpb.Download{
|
||||
Path: target,
|
||||
Data: gzipData.Bytes(),
|
||||
Encoder: "gzip",
|
||||
Exists: true,
|
||||
IsDir: isDir,
|
||||
Path: target,
|
||||
Data: gzipData.Bytes(),
|
||||
Encoder: "gzip",
|
||||
Exists: true,
|
||||
IsDir: isDir,
|
||||
Response: &commonpb.Response{},
|
||||
}
|
||||
} else {
|
||||
download = &sliverpb.Download{Path: target, Exists: false}
|
||||
|
||||
@@ -141,9 +141,17 @@ func CreateNetTUN(localAddresses, dnsServers []netip.Addr, mtu int) (tun.Device,
|
||||
}
|
||||
if dev.hasV4 {
|
||||
dev.stack.AddRoute(tcpip.Route{Destination: header.IPv4EmptySubnet, NIC: 1})
|
||||
tcpipErr = dev.stack.SetForwardingDefaultAndAllNICs(header.IPv4ProtocolNumber, true)
|
||||
if tcpipErr != nil {
|
||||
return nil, nil, fmt.Errorf("SetForwarding(): %v", tcpipErr)
|
||||
}
|
||||
}
|
||||
if dev.hasV6 {
|
||||
dev.stack.AddRoute(tcpip.Route{Destination: header.IPv6EmptySubnet, NIC: 1})
|
||||
tcpipErr = dev.stack.SetForwardingDefaultAndAllNICs(header.IPv6ProtocolNumber, true)
|
||||
if tcpipErr != nil {
|
||||
return nil, nil, fmt.Errorf("SetForwarding(): %v", tcpipErr)
|
||||
}
|
||||
}
|
||||
|
||||
dev.events <- tun.EventUp
|
||||
|
||||
@@ -26,8 +26,8 @@ import (
|
||||
"io"
|
||||
)
|
||||
|
||||
//Encrypt the results
|
||||
func Encrypt(data []byte, key []byte, iv []byte) []byte {
|
||||
// PreludeEncrypt the results
|
||||
func PreludeEncrypt(data []byte, key []byte, iv []byte) []byte {
|
||||
plainText, err := pad(data, aes.BlockSize)
|
||||
if err != nil {
|
||||
return make([]byte, 0)
|
||||
@@ -47,8 +47,8 @@ func Encrypt(data []byte, key []byte, iv []byte) []byte {
|
||||
return cipherText
|
||||
}
|
||||
|
||||
//Decrypt a command
|
||||
func Decrypt(data []byte, key []byte) []byte {
|
||||
// PreludeDecrypt a command
|
||||
func PreludeDecrypt(data []byte, key []byte) []byte {
|
||||
block, err := aes.NewCipher(key)
|
||||
if err != nil {
|
||||
return nil
|
||||
|
||||
Reference in new issue
Block a user