Skip to content

Commit

Permalink
Merge pull request #451 from BishopFox/loot
Browse files Browse the repository at this point in the history
Loot
  • Loading branch information
moloch-- authored Jul 1, 2021
2 parents 3ab6061 + c47b024 commit f6f68dc
Show file tree
Hide file tree
Showing 13 changed files with 733 additions and 486 deletions.
47 changes: 36 additions & 11 deletions client/command/bind-commands.go
Original file line number Diff line number Diff line change
Expand Up @@ -368,6 +368,7 @@ func BindCommands(app *grumble.App, rpc rpcpb.SliverRPCClient) {
Flags: func(f *grumble.Flags) {
f.Bool("T", "token", false, "execute command with current token (windows only)")
f.Bool("s", "silent", false, "don't print the command output")
f.Bool("X", "loot", false, "save output as loot")

f.Int("t", "timeout", defaultTimeout, "command timeout in seconds")
},
Expand Down Expand Up @@ -712,6 +713,8 @@ func BindCommands(app *grumble.App, rpc rpcpb.SliverRPCClient) {
HelpGroup: consts.SliverHelpGroup,
})

// [ Session Commands ] ---------------------------------------------

app.AddCommand(&grumble.Command{
Name: consts.PsStr,
Help: "List remote processes",
Expand Down Expand Up @@ -915,6 +918,7 @@ func BindCommands(app *grumble.App, rpc rpcpb.SliverRPCClient) {
Flags: func(f *grumble.Flags) {
f.Int("t", "timeout", defaultTimeout, "command timeout in seconds")
f.Bool("c", "colorize-output", false, "colorize output")
f.Bool("X", "loot", false, "save output as loot")
},
Args: func(a *grumble.Args) {
a.String("path", "path to the file to print")
Expand All @@ -934,6 +938,8 @@ func BindCommands(app *grumble.App, rpc rpcpb.SliverRPCClient) {
LongHelp: help.GetHelpFor([]string{consts.DownloadStr}),
Flags: func(f *grumble.Flags) {
f.Int("t", "timeout", defaultTimeout, "command timeout in seconds")

f.Bool("X", "loot", false, "save output as loot")
},
Args: func(a *grumble.Args) {
a.String("remote-path", "path to the file or directory to download")
Expand Down Expand Up @@ -1102,21 +1108,23 @@ func BindCommands(app *grumble.App, rpc rpcpb.SliverRPCClient) {
a.String("filepath", "path the assembly file")
a.StringList("arguments", "arguments to pass to the assembly entrypoint", grumble.Default([]string{}))
},
Run: func(ctx *grumble.Context) error {
fmt.Println()
executeAssembly(ctx, rpc)
fmt.Println()
return nil
},
Flags: func(f *grumble.Flags) {
f.String("p", "process", "notepad.exe", "hosting process to inject into")
f.String("m", "method", "", "Optional method (a method is required for a .NET DLL)")
f.String("c", "class", "", "Optional class name (required for .NET DLL)")
f.String("d", "app-domain", "", "AppDomain name to create for .NET assembly. Generated randomly if not set.")
f.String("a", "arch", "x84", "Assembly target architecture: x86, x64, x84 (x86+x64)")
f.Bool("s", "save", false, "save output to file")
f.Bool("X", "loot", false, "save output as loot")

f.Int("t", "timeout", defaultTimeout, "command timeout in seconds")
},
Run: func(ctx *grumble.Context) error {
fmt.Println()
executeAssembly(ctx, rpc)
fmt.Println()
return nil
},
HelpGroup: consts.SliverWinHelpGroup,
})

Expand Down Expand Up @@ -1332,15 +1340,17 @@ func BindCommands(app *grumble.App, rpc rpcpb.SliverRPCClient) {
Name: consts.ScreenshotStr,
Help: "Take a screenshot",
LongHelp: help.GetHelpFor([]string{consts.ScreenshotStr}),
Flags: func(f *grumble.Flags) {
f.Bool("X", "loot", false, "save output as loot")

f.Int("t", "timeout", defaultTimeout, "command timeout in seconds")
},
Run: func(ctx *grumble.Context) error {
fmt.Println()
screenshot(ctx, rpc)
fmt.Println()
return nil
},
Flags: func(f *grumble.Flags) {
f.Int("t", "timeout", defaultTimeout, "command timeout in seconds")
},
HelpGroup: consts.SliverHelpGroup,
})

Expand Down Expand Up @@ -1459,7 +1469,7 @@ func BindCommands(app *grumble.App, rpc rpcpb.SliverRPCClient) {

app.AddCommand(&grumble.Command{
Name: consts.SetStr,
Help: "Set agent option",
Help: "Set an implant/session option",
LongHelp: help.GetHelpFor([]string{consts.SetStr}),
Flags: func(f *grumble.Flags) {
f.String("n", "name", "", "agent name to change to")
Expand All @@ -1483,7 +1493,7 @@ func BindCommands(app *grumble.App, rpc rpcpb.SliverRPCClient) {
f.Int("t", "timeout", defaultTimeout, "command timeout in seconds")
},
Args: func(a *grumble.Args) {
a.String("name", "environment varialbe to fetch", grumble.Default(""))
a.String("name", "environment variable to fetch", grumble.Default(""))
},
Run: func(ctx *grumble.Context) error {
fmt.Println()
Expand Down Expand Up @@ -1936,6 +1946,21 @@ func BindCommands(app *grumble.App, rpc rpcpb.SliverRPCClient) {
},
HelpGroup: consts.GenericHelpGroup,
})
lootCmd.AddCommand(&grumble.Command{
Name: consts.RenameStr,
Help: "Re-name a piece of existing loot",
LongHelp: help.GetHelpFor([]string{consts.LootStr, consts.RenameStr}),
Flags: func(f *grumble.Flags) {
f.Int("t", "timeout", defaultTimeout, "command timeout in seconds")
},
Run: func(ctx *grumble.Context) error {
fmt.Println()
lootRename(ctx, rpc)
fmt.Println()
return nil
},
HelpGroup: consts.GenericHelpGroup,
})
lootCmd.AddCommand(&grumble.Command{
Name: consts.LootFetchStr,
Help: "Fetch a piece of loot from the server's loot store",
Expand Down
10 changes: 10 additions & 0 deletions client/command/execute.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ package command
import (
"context"
"fmt"
"strings"

"github.com/bishopfox/sliver/protobuf/rpcpb"
"github.com/bishopfox/sliver/protobuf/sliverpb"
Expand Down Expand Up @@ -62,6 +63,15 @@ func execute(ctx *grumble.Context, rpc rpcpb.SliverRPCClient) {
}
} else {
fmt.Printf(Info+"Output:\n%s\n", exec.Result)
if ctx.Flags.Bool("loot") && 0 < len(exec.Result) {
name := fmt.Sprintf("[exec] %s %s", cmdPath, strings.Join(args, " "))
err = AddLootFile(rpc, name, "console.txt", []byte(exec.Result), false)
if err != nil {
fmt.Printf(Warn+"Failed to save output as loot: %s\n", err)
} else {
fmt.Printf(clearln + Info + "Output saved as loot\n")
}
}
}
}
}
17 changes: 17 additions & 0 deletions client/command/filesystem.go
Original file line number Diff line number Diff line change
Expand Up @@ -193,6 +193,14 @@ func cat(ctx *grumble.Context, rpc rpcpb.SliverRPCClient) {
} else {
fmt.Println(string(download.Data))
}
if ctx.Flags.Bool("loot") && 0 < len(download.Data) {
err = AddLootFile(rpc, fmt.Sprintf("[cat] %s", filepath.Base(filePath)), filePath, download.Data, false)
if err != nil {
fmt.Printf(Warn+"Failed to save output as loot: %s", err)
} else {
fmt.Printf(clearln + Info + "Output saved as loot\n")
}
}
}

func colorize(f *sliverpb.Download) error {
Expand Down Expand Up @@ -288,6 +296,15 @@ func download(ctx *grumble.Context, rpc rpcpb.SliverRPCClient) {
} else {
fmt.Printf(Info+"Wrote %d bytes to %s\n", n, dstFile.Name())
}

if ctx.Flags.Bool("loot") && 0 < len(download.Data) {
err = AddLootFile(rpc, fmt.Sprintf("[download] %s", filepath.Base(remotePath)), remotePath, download.Data, false)
if err != nil {
fmt.Printf(Warn+"Failed to save output as loot: %s", err)
} else {
fmt.Printf(Info + "Output saved as loot\n")
}
}
}

func upload(ctx *grumble.Context, rpc rpcpb.SliverRPCClient) {
Expand Down
95 changes: 92 additions & 3 deletions client/command/loot.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,74 @@ import (
var (
ErrInvalidFileType = errors.New("invalid file type")
ErrInvalidLootType = errors.New("invalid loot type")
ErrNoLootFileData = errors.New("no loot file data")
)

// --- Loot Helpers for other commands ---

// AddLootFile - Add a file as loot
func AddLootFile(rpc rpcpb.SliverRPCClient, name string, fileName string, data []byte, isCredential bool) error {
if len(data) < 1 {
return ErrNoLootFileData
}
var lootType clientpb.LootType
if isCredential {
lootType = clientpb.LootType_LOOT_CREDENTIAL
} else {
lootType = clientpb.LootType_LOOT_FILE
}
var lootFileType clientpb.FileType
if isText(data) || strings.HasSuffix(fileName, ".txt") {
lootFileType = clientpb.FileType_TEXT
} else {
lootFileType = clientpb.FileType_BINARY
}
loot := &clientpb.Loot{
Name: name,
Type: lootType,
FileType: lootFileType,
File: &commonpb.File{
Name: path.Base(fileName),
Data: data,
},
}
if lootType == clientpb.LootType_LOOT_CREDENTIAL {
loot.CredentialType = clientpb.CredentialType_FILE
}
_, err := rpc.LootAdd(context.Background(), loot)
return err
}

// AddLootUserPassword - Add user/password as loot
func AddLootUserPassword(rpc rpcpb.SliverRPCClient, name string, user string, password string) error {
loot := &clientpb.Loot{
Name: name,
Type: clientpb.LootType_LOOT_CREDENTIAL,
CredentialType: clientpb.CredentialType_USER_PASSWORD,
Credential: &clientpb.Credential{
User: user,
Password: password,
},
}
_, err := rpc.LootAdd(context.Background(), loot)
return err
}

// AddLootAPIKey - Add a api key as loot
func AddLootAPIKey(rpc rpcpb.SliverRPCClient, name string, apiKey string) error {
loot := &clientpb.Loot{
Name: name,
Type: clientpb.LootType_LOOT_CREDENTIAL,
CredentialType: clientpb.CredentialType_API_KEY,
Credential: &clientpb.Credential{
APIKey: apiKey,
},
}
_, err := rpc.LootAdd(context.Background(), loot)
return err
}

// --- Loot Command ---
func lootRoot(ctx *grumble.Context, rpc rpcpb.SliverRPCClient) {
filter := ctx.Flags.String("filter")
var allLoot *clientpb.AllLoot
Expand Down Expand Up @@ -214,6 +280,28 @@ func lootAddRemote(ctx *grumble.Context, rpc rpcpb.SliverRPCClient) {
fmt.Printf(Info+"Successfully added loot to server (%s)\n", loot.LootID)
}

func lootRename(ctx *grumble.Context, rpc rpcpb.SliverRPCClient) {
loot, err := selectLoot(ctx, rpc)
if err != nil {
fmt.Printf(Warn+"%s\n", err)
return
}
oldName := loot.Name
newName := ""
prompt := &survey.Input{Message: "Enter new name: "}
survey.AskOne(prompt, &newName)

loot, err = rpc.LootUpdate(context.Background(), &clientpb.Loot{
LootID: loot.LootID,
Name: newName,
})
if err != nil {
fmt.Printf(Warn+"%s\n", err)
return
}
fmt.Printf(Info+"Renamed %s -> %s\n", oldName, loot.Name)
}

func lootRm(ctx *grumble.Context, rpc rpcpb.SliverRPCClient) {
loot, err := selectLoot(ctx, rpc)
if err != nil {
Expand All @@ -226,7 +314,8 @@ func lootRm(ctx *grumble.Context, rpc rpcpb.SliverRPCClient) {
fmt.Printf(Warn+"%s\n", err)
return
}
fmt.Printf(Info + "Removed loot from server\n")
fmt.Println()
fmt.Printf(clearln + Info + "Removed loot from server\n")
}

func lootFetch(ctx *grumble.Context, rpc rpcpb.SliverRPCClient) {
Expand Down Expand Up @@ -316,8 +405,8 @@ func displayLootFile(loot *clientpb.Loot) {
if loot.File.Name != "" {
fmt.Printf("%sFile Name:%s %s\n\n", bold, normal, loot.File.Name)
}
if loot.File.Data != nil {
if isText(loot.File.Data) {
if loot.File.Data != nil && 0 < len(loot.File.Data) {
if loot.FileType == clientpb.FileType_TEXT || isText(loot.File.Data) {
fmt.Printf(string(loot.File.Data))
} else {
fmt.Printf("<%d bytes of binary data>\n", len(loot.File.Data))
Expand Down
9 changes: 9 additions & 0 deletions client/command/screenshot.go
Original file line number Diff line number Diff line change
Expand Up @@ -63,4 +63,13 @@ func screenshot(ctx *grumble.Context, rpc rpcpb.SliverRPCClient) {
return
}
fmt.Printf(bold+"Screenshot written to %s\n", tmpFile.Name())

if ctx.Flags.Bool("loot") && 0 < len(screenshot.Data) {
err = AddLootFile(rpc, fmt.Sprintf("[screenshot] %s", timestamp), tmpFileName, screenshot.Data, false)
if err != nil {
fmt.Printf(Warn+"Failed to save output as loot: %s\n", err)
} else {
fmt.Printf(clearln + Info + "Output saved as loot\n")
}
}
}
10 changes: 10 additions & 0 deletions client/command/tasks.go
Original file line number Diff line number Diff line change
Expand Up @@ -273,6 +273,16 @@ func executeAssembly(ctx *grumble.Context, rpc rpcpb.SliverRPCClient) {
outFilePath.Write(executeAssembly.GetOutput())
fmt.Printf(Info+"Output saved to %s\n", outFilePath.Name())
}

if ctx.Flags.Bool("loot") && 0 < len(executeAssembly.GetOutput()) {
name := fmt.Sprintf("[execute-assembly] %s", filepath.Base(filePath))
err = AddLootFile(rpc, name, "console.txt", executeAssembly.GetOutput(), false)
if err != nil {
fmt.Printf(Warn+"Failed to save output as loot: %s\n", err)
} else {
fmt.Printf(clearln + Info + "Output saved as loot\n")
}
}
}

func sideload(ctx *grumble.Context, rpc rpcpb.SliverRPCClient) {
Expand Down
2 changes: 2 additions & 0 deletions client/constants/constants.go
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,8 @@ const (
LootFetchStr = "fetch"
LootCredsStr = "creds"

RenameStr = "rename"

ImplantBuildsStr = "implants"
ListCanariesStr = "canaries"

Expand Down
Loading

0 comments on commit f6f68dc

Please sign in to comment.