Compare commits

...
Author SHA1 Message Date
moloch-- ce27108c1a Added support for aliases in beacon mode 2022-01-23 14:33:02 -06:00
moloch-- 235fb87842 Skip list ext check in beacon mode 2022-01-23 14:02:50 -06:00
moloch-- a0d71f4fe8 fix output 2022-01-23 13:18:02 -06:00
moloch-- 0502f82967 cleanup 2022-01-23 13:07:32 -06:00
moloch-- 2553772ec0 exts execute in beacon mode but no output 2022-01-23 11:58:58 -06:00
moloch-- 406a10d639 initial refactor to support async ext 2022-01-23 10:01:47 -06:00
moloch-- 92b2d2464c initial refactor to support async ext 2022-01-23 10:01:44 -06:00
moloch-- ead0a5ea1e Use golang.org/x/term 2022-01-22 11:44:39 -06:00
moloch-- d0ec264454 hide armory urls on small terminals 2022-01-22 10:23:14 -06:00
moloch-- 9c7e47c95e added armory github.com parser 2022-01-22 08:57:20 -06:00
Joe 4c5a099d5c Merge pull request #569 from BishopFox/fix/alias
Fix/alias
2022-01-22 08:02:49 -06:00
Joe 99e6765896 Merge pull request #568 from BishopFox/fix/namedpipes
fix named pipe pivots
2022-01-21 20:02:30 -06:00
Joe d1dbd3dcb7 Merge pull request #566 from bluec0re/patch-1
Fix broken implants rm command
2022-01-21 09:14:01 -06:00
BlueC0re 8b81de5129 Fix broken implants rm command
ImplantConfig.Name is empty and the config name is instead stored in the map key.
2022-01-21 15:30:05 +01:00
24 changed files with 1226 additions and 997 deletions

No files matched your search

+93 -20
View File
@@ -32,9 +32,11 @@ import (
"github.com/bishopfox/sliver/client/command/help"
"github.com/bishopfox/sliver/client/console"
consts "github.com/bishopfox/sliver/client/constants"
"github.com/bishopfox/sliver/protobuf/clientpb"
"github.com/bishopfox/sliver/protobuf/sliverpb"
"github.com/bishopfox/sliver/util"
"github.com/desertbit/grumble"
"google.golang.org/protobuf/proto"
)
const (
@@ -64,12 +66,14 @@ type loadedAlias struct {
Command *grumble.Command
}
// AliasFile - An OS/Arch specific file
type AliasFile struct {
OS string `json:"os"`
Arch string `json:"arch"`
Path string `json:"path"`
}
// AliasManifest - The manifest for an alias, contains metadata
type AliasManifest struct {
Name string `json:"name"`
Version string `json:"version"`
@@ -230,17 +234,27 @@ func ParseAliasManifest(data []byte) (*AliasManifest, error) {
}
func runAliasCommand(ctx *grumble.Context, con *console.SliverConsoleClient) {
session := con.ActiveTarget.GetSessionInteractive()
if session == nil {
session, beacon := con.ActiveTarget.GetInteractive()
if session == nil && beacon == nil {
return
}
var goos string
var goarch string
if session != nil {
goos = session.OS
goarch = session.Arch
} else {
goos = beacon.OS
goarch = beacon.Arch
}
loadedAlias, ok := loadedAliases[ctx.Command.Name]
if !ok {
con.PrintErrorf("No alias found for `%s` command\n", ctx.Command.Name)
return
}
aliasManifest := loadedAlias.Manifest
binPath, err := aliasManifest.getFileForTarget(ctx.Command.Name, session.GetOS(), session.GetArch())
binPath, err := aliasManifest.getFileForTarget(ctx.Command.Name, goos, goarch)
if err != nil {
con.PrintErrorf("Fail to find alias file: %s\n", err)
return
@@ -255,14 +269,14 @@ func runAliasCommand(ctx *grumble.Context, con *console.SliverConsoleClient) {
entryPoint := aliasManifest.Entrypoint
processName := ctx.Flags.String("process")
if processName == "" {
processName, err = aliasManifest.getDefaultProcess(session.GetOS())
processName, err = aliasManifest.getDefaultProcess(goos)
if err != nil {
con.PrintErrorf("%s\n", err)
return
}
}
isDLL := false
if filepath.Ext(binPath) == ".dll" {
if strings.ToLower(filepath.Ext(binPath)) == ".dll" {
isDLL = true
}
binData, err := ioutil.ReadFile(binPath)
@@ -272,14 +286,17 @@ func runAliasCommand(ctx *grumble.Context, con *console.SliverConsoleClient) {
}
var outFilePath *os.File
if ctx.Flags.Bool("save") {
outFile := path.Base(fmt.Sprintf("%s_%s*.log", ctx.Command.Name, session.GetHostname()))
outFile := filepath.Base(fmt.Sprintf("%s_%s*.log", filepath.Base(ctx.Command.Name), filepath.Base(session.GetHostname())))
outFilePath, err = ioutil.TempFile("", outFile)
if err != nil {
con.PrintErrorf("%s\n", err)
return
}
}
if aliasManifest.IsAssembly {
// Execute Assembly
ctrl := make(chan bool)
msg := fmt.Sprintf("Executing %s %s ...", ctx.Command.Name, extArgs)
con.SpinUntil(msg, ctrl)
@@ -300,12 +317,24 @@ func runAliasCommand(ctx *grumble.Context, con *console.SliverConsoleClient) {
con.PrintErrorf("%s\n", err)
return
}
con.PrintInfof("Output:\n%s", string(executeAssemblyResp.GetOutput()))
if outFilePath != nil {
outFilePath.Write(executeAssemblyResp.GetOutput())
con.PrintInfof("Output saved to %s\n", outFilePath.Name())
if executeAssemblyResp.Response != nil && executeAssemblyResp.Response.Async {
con.AddBeaconCallback(executeAssemblyResp.Response.TaskID, func(task *clientpb.BeaconTask) {
err = proto.Unmarshal(task.Response, executeAssemblyResp)
if err != nil {
con.PrintErrorf("Failed to decode call ext response %s\n", err)
return
}
PrintAssemblyOutput(ctx.Command.Name, executeAssemblyResp, outFilePath, con)
})
con.PrintAsyncResponse(executeAssemblyResp.Response)
} else {
PrintAssemblyOutput(ctx.Command.Name, executeAssemblyResp, outFilePath, con)
}
} else if aliasManifest.IsReflective {
// Spawn DLL
ctrl := make(chan bool)
msg := fmt.Sprintf("Executing %s %s ...", ctx.Command.Name, extArgs)
con.SpinUntil(msg, ctrl)
@@ -319,18 +348,28 @@ func runAliasCommand(ctx *grumble.Context, con *console.SliverConsoleClient) {
})
ctrl <- true
<-ctrl
if err != nil {
con.PrintErrorf("%s\n", err)
return
}
con.PrintInfof("Output:\n%s", spawnDllResp.GetResult())
if outFilePath != nil {
outFilePath.Write([]byte(spawnDllResp.GetResult()))
con.PrintInfof("Output saved to %s\n", outFilePath.Name())
if spawnDllResp.Response != nil && spawnDllResp.Response.Async {
con.AddBeaconCallback(spawnDllResp.Response.TaskID, func(task *clientpb.BeaconTask) {
err = proto.Unmarshal(task.Response, spawnDllResp)
if err != nil {
con.PrintErrorf("Failed to decode call ext response %s\n", err)
return
}
PrintSpawnDLLOutput(ctx.Command.Name, spawnDllResp, outFilePath, con)
})
con.PrintAsyncResponse(spawnDllResp.Response)
} else {
PrintSpawnDLLOutput(ctx.Command.Name, spawnDllResp, outFilePath, con)
}
} else {
// Sideload
ctrl := make(chan bool)
msg := fmt.Sprintf("Executing %s %s ...", ctx.Command.Name, extArgs)
con.SpinUntil(msg, ctrl)
@@ -345,20 +384,54 @@ func runAliasCommand(ctx *grumble.Context, con *console.SliverConsoleClient) {
})
ctrl <- true
<-ctrl
if err != nil {
con.PrintErrorf("%s\n", err)
return
}
con.PrintInfof("Output:\n%s", sideloadResp.GetResult())
if outFilePath != nil {
outFilePath.Write([]byte(sideloadResp.GetResult()))
con.PrintInfof("Output saved to %s\n", outFilePath.Name())
if sideloadResp.Response != nil && sideloadResp.Response.Async {
con.AddBeaconCallback(sideloadResp.Response.TaskID, func(task *clientpb.BeaconTask) {
err = proto.Unmarshal(task.Response, sideloadResp)
if err != nil {
con.PrintErrorf("Failed to decode call ext response %s\n", err)
return
}
PrintSideloadOutput(ctx.Command.Name, sideloadResp, outFilePath, con)
})
con.PrintAsyncResponse(sideloadResp.Response)
} else {
PrintSideloadOutput(ctx.Command.Name, sideloadResp, outFilePath, con)
}
}
}
// PrintSpawnDLLOutput - Prints the output of a spawn dll command
func PrintSpawnDLLOutput(cmdName string, spawnDllResp *sliverpb.SpawnDll, outFilePath *os.File, con *console.SliverConsoleClient) {
con.PrintInfof("%s output:\n%s", cmdName, spawnDllResp.GetResult())
if outFilePath != nil {
outFilePath.Write([]byte(spawnDllResp.GetResult()))
con.PrintInfof("Output saved to %s\n", outFilePath.Name())
}
}
// PrintSideloadOutput - Prints the output of a sideload command
func PrintSideloadOutput(cmdName string, sideloadResp *sliverpb.Sideload, outFilePath *os.File, con *console.SliverConsoleClient) {
con.PrintInfof("%s output:\n%s", cmdName, sideloadResp.GetResult())
if outFilePath != nil {
outFilePath.Write([]byte(sideloadResp.GetResult()))
con.PrintInfof("Output saved to %s\n", outFilePath.Name())
}
}
// PrintAssemblyOutput - Prints the output of an execute-assembly command
func PrintAssemblyOutput(cmdName string, execAsmResp *sliverpb.ExecuteAssembly, outFilePath *os.File, con *console.SliverConsoleClient) {
con.PrintInfof("%s output:\n%s", cmdName, string(execAsmResp.GetOutput()))
if outFilePath != nil {
outFilePath.Write(execAsmResp.GetOutput())
con.PrintInfof("Output saved to %s\n", outFilePath.Name())
}
}
func cmdExists(name string, app *grumble.App) bool {
for _, c := range app.Commands().All() {
if name == c.Name {
+51 -22
View File
@@ -35,6 +35,7 @@ import (
"github.com/bishopfox/sliver/server/cryptography/minisign"
"github.com/desertbit/grumble"
"github.com/jedib0t/go-pretty/v6/table"
"golang.org/x/term"
)
type ArmoryIndex struct {
@@ -213,6 +214,38 @@ func AliasExtensionOrBundleCompleter(prefix string, args []string, con *console.
// PrintArmoryPackages - Prints the armory packages
func PrintArmoryPackages(aliases []*alias.AliasManifest, exts []*extensions.ExtensionManifest, con *console.SliverConsoleClient) {
width, _, err := term.GetSize(0)
if err != nil {
width = 999
}
tw := table.NewWriter()
tw.SetStyle(settings.GetTableStyle(con))
tw.SetTitle(console.Bold + "Packages" + console.Normal)
minWidth := 150
if minWidth < width {
tw.AppendHeader(table.Row{
"Command Name",
"Version",
"Type",
"Help",
"URL",
})
} else {
tw.AppendHeader(table.Row{
"Command Name",
"Version",
"Type",
"Help",
})
}
// Columns start at 1 for some dumb reason
tw.SortBy([]table.SortBy{
{Number: 1, Mode: table.Asc},
})
type pkgInfo struct {
CommandName string
Version string
@@ -240,34 +273,30 @@ func PrintArmoryPackages(aliases []*alias.AliasManifest, exts []*extensions.Exte
})
}
tw := table.NewWriter()
tw.SetStyle(settings.GetTableStyle(con))
tw.SetTitle(console.Bold + "Packages" + console.Normal)
tw.AppendHeader(table.Row{
"Command Name",
"Version",
"Type",
"Help",
"URL",
})
tw.SortBy([]table.SortBy{
{Name: "Command Name", Mode: table.Asc},
})
rows := []table.Row{}
for _, pkg := range entries {
color := console.Normal
if extensions.CmdExists(pkg.CommandName, con.App) {
color = console.Green
}
tw.AppendRow(table.Row{
fmt.Sprintf(color+"%s"+console.Normal, pkg.CommandName),
fmt.Sprintf(color+"%s"+console.Normal, pkg.Version),
fmt.Sprintf(color+"%s"+console.Normal, pkg.Type),
fmt.Sprintf(color+"%s"+console.Normal, pkg.Help),
fmt.Sprintf(color+"%s"+console.Normal, pkg.URL),
})
if minWidth < width {
rows = append(rows, table.Row{
fmt.Sprintf(color+"%s"+console.Normal, pkg.CommandName),
fmt.Sprintf(color+"%s"+console.Normal, pkg.Version),
fmt.Sprintf(color+"%s"+console.Normal, pkg.Type),
fmt.Sprintf(color+"%s"+console.Normal, pkg.Help),
fmt.Sprintf(color+"%s"+console.Normal, pkg.URL),
})
} else {
rows = append(rows, table.Row{
fmt.Sprintf(color+"%s"+console.Normal, pkg.CommandName),
fmt.Sprintf(color+"%s"+console.Normal, pkg.Version),
fmt.Sprintf(color+"%s"+console.Normal, pkg.Type),
fmt.Sprintf(color+"%s"+console.Normal, pkg.Help),
})
}
}
tw.AppendRows(rows)
con.Printf("%s\n", tw.Render())
}
+97
View File
@@ -28,6 +28,8 @@ import (
"net"
"net/http"
"net/url"
"path"
"strings"
"github.com/bishopfox/sliver/client/assets"
"github.com/bishopfox/sliver/server/cryptography/minisign"
@@ -45,6 +47,7 @@ var (
}
pkgParsers = map[string]ArmoryPackageParser{
"api.github.com": GithubAPIArmoryPackageParser,
"github.com": GithubArmoryPackageParser,
}
)
@@ -339,6 +342,100 @@ func GithubAPIArmoryPackageParser(armoryPkg *ArmoryPackage, sigOnly bool, client
return sig, tarGz, err
}
//
// GitHub Parsers
//
// GithubArmoryPackageParser - Uses github.com instead of api.github.com to download packages
func GithubArmoryPackageParser(armoryPkg *ArmoryPackage, sigOnly bool, clientConfig ArmoryHTTPConfig) (*minisign.Signature, []byte, error) {
latestTag, err := githubLatestTagParser(armoryPkg, clientConfig)
if err != nil {
return nil, nil, err
}
client := httpClient(clientConfig)
sigURL, err := url.Parse(armoryPkg.RepoURL)
if err != nil {
return nil, nil, fmt.Errorf("failed to parse armory pkg url '%s': %s", armoryPkg.RepoURL, err)
}
sigURL.Path = path.Join(sigURL.Path, "releases", "download", latestTag, fmt.Sprintf("%s.minisig", armoryPkg.CommandName))
sigResp, err := client.Get(sigURL.String())
if err != nil {
return nil, nil, err
}
defer sigResp.Body.Close()
if sigResp.StatusCode != http.StatusOK {
return nil, nil, fmt.Errorf("failed to get signature for armory pkg '%s': %s", armoryPkg.RepoURL, sigResp.Status)
}
var body []byte
body, err = ioutil.ReadAll(sigResp.Body)
if err != nil {
return nil, nil, fmt.Errorf("failed to read resp body '%s': %s", armoryPkg.RepoURL, err)
}
sig, err := parsePkgMinsig(body)
if err != nil {
return nil, nil, fmt.Errorf("failed to parse pkg sig '%s': %s", armoryPkg.RepoURL, err)
}
var tarGz []byte
if !sigOnly {
tarGzURL, err := url.Parse(armoryPkg.RepoURL)
if err != nil {
return nil, nil, fmt.Errorf("failed to parse armory pkg url '%s': %s", armoryPkg.RepoURL, err)
}
tarGzURL.Path = path.Join(tarGzURL.Path, "releases", "download", latestTag, fmt.Sprintf("%s.tar.gz", armoryPkg.CommandName))
tarGzResp, err := client.Get(tarGzURL.String())
if err != nil {
return nil, nil, err
}
defer tarGzResp.Body.Close()
if tarGzResp.StatusCode != http.StatusOK {
return nil, nil, fmt.Errorf("failed to get tar.gz for armory pkg '%s': %s", armoryPkg.RepoURL, tarGzResp.Status)
}
tarGz, err = ioutil.ReadAll(tarGzResp.Body)
if err != nil {
return nil, nil, fmt.Errorf("failed to read tar.gz body '%s': %s", armoryPkg.RepoURL, err)
}
}
return sig, tarGz, nil
}
// We need to intercept the 302 redirect to determine the latest version tag
func githubLatestTagParser(armoryPkg *ArmoryPackage, clientConfig ArmoryHTTPConfig) (string, error) {
client := httpClient(clientConfig)
client.CheckRedirect = func(req *http.Request, via []*http.Request) error {
return http.ErrUseLastResponse
}
latestURL, err := url.Parse(armoryPkg.RepoURL)
if err != nil {
return "", fmt.Errorf("failed to parse armory pkg url '%s': %s", armoryPkg.RepoURL, err)
}
latestURL.Path = path.Join(latestURL.Path, "releases", "latest")
latestRedirect, err := client.Get(latestURL.String())
if err != nil {
return "", fmt.Errorf("http get failed armory pkg url '%s': %s", armoryPkg.RepoURL, err)
}
if latestRedirect.StatusCode != http.StatusFound {
return "", fmt.Errorf("unexpected response status (wanted 302) '%s': %s", armoryPkg.RepoURL, latestRedirect.Status)
}
if latestRedirect.Header.Get("Location") == "" {
return "", fmt.Errorf("no location header in response '%s'", armoryPkg.RepoURL)
}
latestLocationURL, err := url.Parse(latestRedirect.Header.Get("Location"))
if err != nil {
return "", fmt.Errorf("failed to parse location header '%s'->'%s': %s",
armoryPkg.RepoURL, latestRedirect.Header.Get("Location"), err)
}
pathSegments := strings.Split(latestLocationURL.Path, "/")
for index, segment := range pathSegments {
if segment == "tag" && index+1 < len(pathSegments) {
return pathSegments[index+1], nil
}
}
return "", errors.New("tag not found in location header")
}
func parsePkgMinsig(data []byte) (*minisign.Signature, error) {
var sig minisign.Signature
err := sig.UnmarshalText(data)
+64 -59
View File
@@ -38,11 +38,13 @@ import (
"github.com/bishopfox/sliver/protobuf/sliverpb"
"github.com/bishopfox/sliver/util"
"github.com/desertbit/grumble"
"google.golang.org/protobuf/proto"
)
const (
defaultTimeout = 60
// ManifestFileName - Extension manifest file name
ManifestFileName = "extension.json"
)
@@ -113,7 +115,7 @@ func ExtensionLoadCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
con.PrintInfof("Added %s command: %s\n", extCmd.CommandName, extCmd.Help)
}
// ParseExtensions - Parse extension files
// LoadExtensionManifest - Parse extension files
func LoadExtensionManifest(manifestPath string) (*ExtensionManifest, error) {
data, err := ioutil.ReadFile(manifestPath)
if err != nil {
@@ -178,11 +180,11 @@ func ExtensionRegisterCommand(extCmd *ExtensionManifest, con *console.SliverCons
return nil
},
Flags: func(f *grumble.Flags) {
f.Bool("s", "save", false, "Save output to disk")
// f.Bool("s", "save", false, "Save output to disk")
f.Int("t", "timeout", defaultTimeout, "command timeout in seconds")
},
Args: func(a *grumble.Args) {
if len(extCmd.Arguments) > 0 {
if 0 < len(extCmd.Arguments) {
// BOF specific
for _, arg := range extCmd.Arguments {
var (
@@ -212,27 +214,26 @@ func ExtensionRegisterCommand(extCmd *ExtensionManifest, con *console.SliverCons
con.App.AddCommand(extensionCmd)
}
func loadExtension(ctx *grumble.Context, session *clientpb.Session, con *console.SliverConsoleClient, ext *ExtensionManifest) error {
func loadExtension(goos string, goarch string, checkCache bool, ext *ExtensionManifest, ctx *grumble.Context, con *console.SliverConsoleClient) error {
var extensionList []string
binPath, err := ext.getFileForTarget(ctx.Command.Name, session.OS, session.Arch)
binPath, err := ext.getFileForTarget(ctx.Command.Name, goos, goarch)
if err != nil {
return err
}
// Try to find the extension in the loaded extensions
if len(session.Extensions) == 0 {
if checkCache {
extList, err := con.Rpc.ListExtensions(context.Background(), &sliverpb.ListExtensionsReq{
Request: con.ActiveTarget.Request(ctx),
})
if err != nil {
con.PrintErrorf("%s\n", err.Error())
con.PrintErrorf("List extensions error: %s\n", err.Error())
return err
}
if extList.Response != nil && extList.Response.Err != "" {
return errors.New(extList.Response.Err)
}
extensionList = extList.Names
} else {
extensionList = session.Extensions
}
depLoaded := false
for _, extName := range extensionList {
@@ -248,7 +249,7 @@ func loadExtension(ctx *grumble.Context, session *clientpb.Session, con *console
// BOFs are not loaded by the DLL loader, but we make sure the loader itself is loaded
// Auto load the coff loader if we have it
if !depLoaded {
if errLoad := loadDep(session, con, ctx, ext.DependsOn); errLoad != nil {
if errLoad := loadDep(goos, goarch, ext.DependsOn, ctx, con); errLoad != nil {
return errLoad
}
}
@@ -258,31 +259,17 @@ func loadExtension(ctx *grumble.Context, session *clientpb.Session, con *console
if err != nil {
return err
}
if errRegister := registerExtension(con, ext, binData, session, ctx); errRegister != nil {
if errRegister := registerExtension(goos, ext, binData, ctx, con); errRegister != nil {
return errRegister
}
// Update session info
if filepath.Ext(binPath) != ".o" {
// Don't update session for BOFs, we don't cache them
// on the implant side (yet)
// update the Session info
_, err = con.Rpc.UpdateSession(context.Background(), &clientpb.UpdateSession{
Extensions: extensionList,
SessionID: session.ID,
})
if err != nil {
con.PrintErrorf("%s\n", err.Error())
return err
}
}
return nil
}
func registerExtension(con *console.SliverConsoleClient, ext *ExtensionManifest, binData []byte, session *clientpb.Session, ctx *grumble.Context) error {
func registerExtension(goos string, ext *ExtensionManifest, binData []byte, ctx *grumble.Context, con *console.SliverConsoleClient) error {
registerResp, err := con.Rpc.RegisterExtension(context.Background(), &sliverpb.RegisterExtensionReq{
Name: ext.CommandName,
Data: binData,
OS: session.OS,
OS: goos,
Init: ext.Init,
Request: con.ActiveTarget.Request(ctx),
})
@@ -295,10 +282,10 @@ func registerExtension(con *console.SliverConsoleClient, ext *ExtensionManifest,
return nil
}
func loadDep(session *clientpb.Session, con *console.SliverConsoleClient, ctx *grumble.Context, depName string) error {
depExt, f := loadedExtensions[depName]
if f {
depBinPath, err := depExt.getFileForTarget(depExt.CommandName, session.OS, session.Arch)
func loadDep(goos string, goarch string, depName string, ctx *grumble.Context, con *console.SliverConsoleClient) error {
depExt, ok := loadedExtensions[depName]
if ok {
depBinPath, err := depExt.getFileForTarget(depExt.CommandName, goos, goarch)
if err != nil {
return err
}
@@ -306,23 +293,31 @@ func loadDep(session *clientpb.Session, con *console.SliverConsoleClient, ctx *g
if err != nil {
return err
}
return registerExtension(con, depExt, depBinData, session, ctx)
return registerExtension(goos, depExt, depBinData, ctx, con)
}
return fmt.Errorf("missing dependency %s", depName)
}
func runExtensionCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
var (
callExtension *sliverpb.CallExtension
err error
extensionArgs []byte
extName string
entryPoint string
)
session := con.ActiveTarget.GetSessionInteractive()
if session == nil {
session, beacon := con.ActiveTarget.GetInteractive()
if session == nil && beacon == nil {
return
}
var goos string
var goarch string
if session != nil {
goos = session.OS
goarch = session.Arch
} else {
goos = beacon.OS
goarch = beacon.Arch
}
ext, ok := loadedExtensions[ctx.Command.Name]
if !ok {
@@ -330,23 +325,15 @@ func runExtensionCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
return
}
if err = loadExtension(ctx, session, con, ext); err != nil {
checkCache := session != nil
if err = loadExtension(goos, goarch, checkCache, ext, ctx, con); err != nil {
con.PrintErrorf("Could not load extension: %s\n", err)
return
}
var outFilePath *os.File
if ctx.Flags.Bool("save") {
outFile := path.Base(fmt.Sprintf("%s_%s*.log", ctx.Command.Name, session.GetHostname()))
outFilePath, err = ioutil.TempFile("", outFile)
if err != nil {
con.PrintErrorf("%s\n", err)
return
}
}
binPath, err := ext.getFileForTarget(ctx.Command.Name, session.OS, session.Arch)
binPath, err := ext.getFileForTarget(ctx.Command.Name, goos, goarch)
if err != nil {
con.PrintErrorf("%s\n", err)
con.PrintErrorf("Failed to read extension file: %s\n", err)
return
}
@@ -361,7 +348,7 @@ func runExtensionCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
// Beacon Object File -- requires a COFF loader
extensionArgs, err = getBOFArgs(ctx, binPath, ext)
if err != nil {
con.PrintErrorf("Error: %s\n", err)
con.PrintErrorf("BOF args error: %s\n", err)
return
}
extName = ext.DependsOn
@@ -373,10 +360,11 @@ func runExtensionCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
extName = ext.CommandName
entryPoint = ext.Entrypoint
}
ctrl := make(chan bool)
msg := fmt.Sprintf("Executing %s ...", ctx.Command.Name)
con.SpinUntil(msg, ctrl)
callExtension, err = con.Rpc.CallExtension(context.Background(), &sliverpb.CallExtensionReq{
callExtResp, err := con.Rpc.CallExtension(context.Background(), &sliverpb.CallExtensionReq{
Name: extName,
Export: entryPoint,
Args: extensionArgs,
@@ -385,22 +373,39 @@ func runExtensionCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
ctrl <- true
<-ctrl
if err != nil {
con.PrintErrorf("%s\n", err.Error())
con.PrintErrorf("Call extension error: %s\n", err.Error())
return
}
if callExtResp.Response != nil && callExtResp.Response.Async {
con.AddBeaconCallback(callExtResp.Response.TaskID, func(task *clientpb.BeaconTask) {
err = proto.Unmarshal(task.Response, callExtResp)
if err != nil {
con.PrintErrorf("Failed to decode call ext response %s\n", err)
return
}
PrintExtOutput(extName, ext.CommandName, callExtResp, con)
})
con.PrintAsyncResponse(callExtResp.Response)
} else {
PrintExtOutput(extName, ext.CommandName, callExtResp, con)
}
}
// PrintExtOutput - Print the ext execution output
func PrintExtOutput(extName string, commandName string, callExtension *sliverpb.CallExtension, con *console.SliverConsoleClient) {
if extName == commandName {
con.PrintInfof("Successfully executed %s\n", extName)
} else {
con.PrintInfof("Successfully executed %s (%s)\n", commandName, extName)
}
if 0 < len(string(callExtension.Output)) {
con.PrintInfof("Got output:\n%s\n", callExtension.Output)
}
if callExtension.Response != nil && callExtension.Response.Err != "" {
con.PrintErrorf("%s\n", callExtension.Response.Err)
return
}
con.PrintInfof("Successfully executed %s\n", extName)
if len(callExtension.Output) > 0 {
con.PrintInfof("Got output:\n%s", string(callExtension.Output))
if outFilePath != nil {
outFilePath.Write(callExtension.Output)
con.PrintInfof("Output saved to %s\n", outFilePath.Name())
}
con.Println()
}
}
func getBOFArgs(ctx *grumble.Context, binPath string, ext *ExtensionManifest) ([]byte, error) {
+2 -2
View File
@@ -157,8 +157,8 @@ func ImplantBuildByName(name string, con *console.SliverConsoleClient) *clientpb
if err != nil {
return nil
}
for _, build := range builds.Configs {
if build.Name == name {
for sliverName, build := range builds.Configs {
if sliverName == name {
return build
}
}
+1 -1
View File
@@ -64,6 +64,7 @@ require (
github.com/moloch--/memmod v0.0.0-20211120144554-8b37cc654945
github.com/shirou/gopsutil/v3 v3.21.10
github.com/things-go/go-socks5 v0.0.3-0.20210722055343-24af464efe43
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1
modernc.org/sqlite v1.14.3
)
@@ -107,7 +108,6 @@ require (
github.com/thedevsaddam/gojsonq/v2 v2.5.2 // indirect
golang.org/x/mod v0.3.0 // indirect
golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d // indirect
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1 // indirect
golang.org/x/time v0.0.0-20210220033141-f8bda1e9f3ba // indirect
golang.org/x/tools v0.1.0 // indirect
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 // indirect
+11 -7
View File
@@ -37,15 +37,15 @@ const (
)
type WindowsExtension struct {
id string
data []byte
module *memmod.Module
arch string
init string
onFinish func([]byte)
serverStore bool
id string
data []byte
module *memmod.Module
arch string
init string
onFinish func([]byte)
}
// NewWindowsExtension - Load a new windows extension
func NewWindowsExtension(data []byte, id string, arch string, init string) *WindowsExtension {
return &WindowsExtension{
id: id,
@@ -55,14 +55,17 @@ func NewWindowsExtension(data []byte, id string, arch string, init string) *Wind
}
}
// GetID - Get the extension ID
func (w *WindowsExtension) GetID() string {
return w.id
}
// GetArch - Get the extension architecture
func (w *WindowsExtension) GetArch() string {
return w.arch
}
// Load - Load the extension into memory
func (w *WindowsExtension) Load() error {
var err error
if len(w.data) == 0 {
@@ -86,6 +89,7 @@ func (w *WindowsExtension) Load() error {
return nil
}
// Call - Call an extension export
func (w *WindowsExtension) Call(export string, arguments []byte, onFinish func([]byte)) error {
var (
argumentsPtr uintptr
+4 -10
View File
@@ -602,20 +602,17 @@ func getPrivsHandler(data []byte, resp RPCResponse) {
func registerExtensionHandler(data []byte, resp RPCResponse) {
registerReq := &sliverpb.RegisterExtensionReq{}
err := proto.Unmarshal(data, registerReq)
if err != nil {
return
}
ext := extension.NewWindowsExtension(registerReq.Data, registerReq.Name, registerReq.OS, registerReq.Init)
extension.Add(ext)
err = ext.Load()
registerResp := &sliverpb.RegisterExtension{
Response: &commonpb.Response{},
}
registerResp := &sliverpb.RegisterExtension{Response: &commonpb.Response{}}
if err != nil {
registerResp.Response.Err = err.Error()
} else {
extension.Add(ext)
}
data, err = proto.Marshal(registerResp)
resp(data, err)
@@ -623,15 +620,12 @@ func registerExtensionHandler(data []byte, resp RPCResponse) {
func callExtensionHandler(data []byte, resp RPCResponse) {
callReq := &sliverpb.CallExtensionReq{}
err := proto.Unmarshal(data, callReq)
if err != nil {
return
}
callResp := &sliverpb.CallExtension{
Response: &commonpb.Response{},
}
callResp := &sliverpb.CallExtension{Response: &commonpb.Response{}}
gotOutput := false
err = extension.Run(callReq.Name, callReq.Export, callReq.Args, func(out []byte) {
gotOutput = true
File diff suppressed because it is too large. Load diff
+5 -1
View File
@@ -215,6 +215,8 @@ message Mkdir {
message DownloadReq {
string Path = 1;
int64 Start = 2;
int64 Stop = 3;
commonpb.Request Request = 9;
}
@@ -223,7 +225,9 @@ message Download {
string Path = 1;
string Encoder = 2;
bool Exists = 3;
bytes Data = 4;
int64 Start = 4;
int64 Stop = 5;
bytes Data = 6;
commonpb.Response Response = 9;
}
+2 -2
View File
@@ -293,7 +293,7 @@ func ListBeacons() ([]*models.Beacon, error) {
return beacons, err
}
// PendingBeaconTasksByBeaconID - Select a Beacon by ID
// PendingBeaconTasksByBeaconID - Select a Beacon by ID, ordered by creation time
func PendingBeaconTasksByBeaconID(beaconID string) ([]*models.BeaconTask, error) {
tasks := []*models.BeaconTask{}
err := Session().Where(
@@ -301,7 +301,7 @@ func PendingBeaconTasksByBeaconID(beaconID string) ([]*models.BeaconTask, error)
BeaconID: uuid.FromStringOrNil(beaconID),
State: models.PENDING,
},
).Find(&tasks).Error
).Order("created_at").Find(&tasks).Error
return tasks, err
}
+2
View File
@@ -123,6 +123,8 @@ func beaconTasksHandler(implantConn *core.ImplantConnection, data []byte) *slive
}
beaconHandlerLog.Infof("Beacon %s requested pending task(s)", beaconTasks.ID)
// Pending tasks are ordered by their creation time.
pendingTasks, err := db.PendingBeaconTasksByBeaconID(beaconTasks.ID)
if err != nil && !errors.Is(err, gorm.ErrRecordNotFound) {
beaconHandlerLog.Errorf("Beacon task database error: %s", err)
+4 -4
View File
@@ -187,11 +187,11 @@ func (rpc *Server) SaveImplantProfile(ctx context.Context, profile *clientpb.Imp
}
core.EventBroker.Publish(core.Event{
EventType: consts.ProfileEvent,
Data: []byte(fmt.Sprintf("%s", profile.Name)),
Data: []byte(profile.Name),
})
return profile, nil
}
return nil, errors.New("Invalid profile name")
return nil, errors.New("invalid profile name")
}
// DeleteImplantProfile - Delete an implant profile
@@ -204,7 +204,7 @@ func (rpc *Server) DeleteImplantProfile(ctx context.Context, req *clientpb.Delet
if err == nil {
core.EventBroker.Publish(core.Event{
EventType: consts.ProfileEvent,
Data: []byte(fmt.Sprintf("%s", profile.Name)),
Data: []byte(profile.Name),
})
}
return &commonpb.Empty{}, err
@@ -224,7 +224,7 @@ func (rpc *Server) DeleteImplantBuild(ctx context.Context, req *clientpb.DeleteR
if err == nil {
core.EventBroker.Publish(core.Event{
EventType: consts.BuildEvent,
Data: []byte(fmt.Sprintf("%s", build.Name)),
Data: []byte(build.Name),
})
}
return &commonpb.Empty{}, err
+3 -3
View File
@@ -100,9 +100,9 @@ func (rpc *Server) HijackDLL(ctx context.Context, req *clientpb.DllHijackReq) (*
}
if p.Config.Format != clientpb.OutputFormat_SHARED_LIB {
return nil, status.Error(codes.InvalidArgument, fmt.Sprintf(
return nil, status.Error(codes.InvalidArgument,
"please select a profile targeting a shared library format",
))
)
}
name, config := generate.ImplantConfigFromProtobuf(p.Config)
@@ -145,7 +145,7 @@ func (rpc *Server) HijackDLL(ctx context.Context, req *clientpb.DllHijackReq) (*
Path: req.TargetLocation,
Request: &commonpb.Request{
SessionID: session.ID,
Timeout: int64(defaultTimeout),
Timeout: int64(minTimeout),
},
})
+3 -4
View File
@@ -24,12 +24,11 @@ import (
"github.com/bishopfox/sliver/protobuf/clientpb"
"github.com/bishopfox/sliver/protobuf/commonpb"
"github.com/bishopfox/sliver/server/db"
"github.com/bishopfox/sliver/server/log"
)
var (
hostsRPCLog = log.NamedLogger("rpc", "hosts")
)
// var (
// hostsRPCLog = log.NamedLogger("rpc", "hosts")
// )
// Hosts - List all hosts
func (rpc *Server) Hosts(ctx context.Context, _ *commonpb.Empty) (*clientpb.AllHosts, error) {
+2 -2
View File
@@ -43,7 +43,7 @@ const (
var (
// ErrInvalidPort - Invalid TCP port number
ErrInvalidPort = errors.New("Invalid listener port")
ErrInvalidPort = errors.New("invalid listener port")
)
// GetJobs - List jobs
@@ -78,7 +78,7 @@ func (rpc *Server) KillJob(ctx context.Context, kill *clientpb.KillJobReq) (*cli
}
} else {
killJob.Success = false
err = errors.New("Invalid Job ID")
err = errors.New("invalid Job ID")
}
return killJob, err
}
+3 -4
View File
@@ -25,13 +25,12 @@ import (
"github.com/bishopfox/sliver/protobuf/clientpb"
"github.com/bishopfox/sliver/protobuf/commonpb"
"github.com/bishopfox/sliver/server/core"
"github.com/bishopfox/sliver/server/log"
"github.com/bishopfox/sliver/server/loot"
)
var (
lootRPCLog = log.NamedLogger("rpc", "loot")
)
// var (
// lootRPCLog = log.NamedLogger("rpc", "loot")
// )
// LootAdd - Add loot
func (rpc *Server) LootAdd(ctx context.Context, lootReq *clientpb.Loot) (*clientpb.Loot, error) {
+2 -1
View File
@@ -20,6 +20,7 @@ package rpc
import (
"context"
"errors"
"fmt"
"math/rand"
"path"
@@ -170,7 +171,7 @@ func (rpc *Server) MsfStage(ctx context.Context, req *clientpb.MsfStagerReq) (*c
payload = "meterpreter/reverse_https"
uri = generateCallbackURI()
default:
return MSFStage, fmt.Errorf("Protocol not supported")
return MSFStage, errors.New("protocol not supported")
}
// We only support windows at the moment
+1 -1
View File
@@ -86,7 +86,7 @@ func (rpc *Server) GetSystem(ctx context.Context, req *clientpb.GetSystemReq) (*
if err != nil {
return nil, err
}
shellcode, err = ioutil.ReadFile(shellcodePath)
shellcode, _ = ioutil.ReadFile(shellcodePath)
}
data, err := proto.Marshal(&sliverpb.InvokeGetSystemReq{
Data: shellcode,
+2 -9
View File
@@ -134,15 +134,8 @@ func (s *Server) CreateSocks(ctx context.Context, req *sliverpb.Socks) (*sliverp
// CloseSocks - Client requests we close a Socks
func (s *Server) CloseSocks(ctx context.Context, req *sliverpb.Socks) (*commonpb.Empty, error) {
err := core.SocksTunnels.Close(req.TunnelID)
if _, ok := toImplantCacheSocks[req.TunnelID]; ok {
delete(toImplantCacheSocks, req.TunnelID)
}
if _, ok := fromImplantCacheSocks[req.TunnelID]; ok {
delete(fromImplantCacheSocks, req.TunnelID)
}
delete(toImplantCacheSocks, req.TunnelID)
delete(fromImplantCacheSocks, req.TunnelID)
if err != nil {
return nil, err
}
+42 -43
View File
@@ -24,7 +24,6 @@ import (
"encoding/binary"
"fmt"
"io/ioutil"
"os"
"path"
"strings"
@@ -78,7 +77,7 @@ func (rpc *Server) Migrate(ctx context.Context, req *clientpb.MigrateReq) (*sliv
if err != nil {
return nil, err
}
shellcode, err = ioutil.ReadFile(shellcodePath)
shellcode, _ = ioutil.ReadFile(shellcodePath)
}
reqData, err := proto.Marshal(&sliverpb.InvokeMigrateReq{
Request: req.Request,
@@ -332,49 +331,49 @@ func getOrdinal(index uint32, rawData []byte, fpe *pe.File, funcArrayFoa uint32)
return funcOffset
}
func getExportOffsetFromFile(filepath string, exportName string) (funcOffset uint32, err error) {
rawData, err := ioutil.ReadFile(filepath)
if err != nil {
return 0, err
}
handle, err := os.Open(filepath)
if err != nil {
return 0, err
}
defer handle.Close()
fpe, _ := pe.NewFile(handle)
var exportDirectoryRVA uint32
switch (fpe.OptionalHeader).(type) {
case *pe.OptionalHeader32:
exportDirectoryRVA = fpe.OptionalHeader.(*pe.OptionalHeader32).DataDirectory[pe.IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress
case *pe.OptionalHeader64:
exportDirectoryRVA = fpe.OptionalHeader.(*pe.OptionalHeader64).DataDirectory[pe.IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress
}
var offset = rvaToFoa(exportDirectoryRVA, fpe)
exportDir := ExportDirectory{}
buff := &bytes.Buffer{}
buff.Write(rawData[offset:])
err = binary.Read(buff, binary.LittleEndian, &exportDir)
if err != nil {
return 0, err
}
current := exportDir.AddressOfNames
nameArrayFOA := rvaToFoa(exportDir.AddressOfNames, fpe)
ordinalArrayFOA := rvaToFoa(exportDir.AddressOfNameOrdinals, fpe)
funcArrayFoa := rvaToFoa(exportDir.AddressOfFunctions, fpe)
// func getExportOffsetFromFile(filepath string, exportName string) (funcOffset uint32, err error) {
// rawData, err := ioutil.ReadFile(filepath)
// if err != nil {
// return 0, err
// }
// handle, err := os.Open(filepath)
// if err != nil {
// return 0, err
// }
// defer handle.Close()
// fpe, _ := pe.NewFile(handle)
// var exportDirectoryRVA uint32
// switch (fpe.OptionalHeader).(type) {
// case *pe.OptionalHeader32:
// exportDirectoryRVA = fpe.OptionalHeader.(*pe.OptionalHeader32).DataDirectory[pe.IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress
// case *pe.OptionalHeader64:
// exportDirectoryRVA = fpe.OptionalHeader.(*pe.OptionalHeader64).DataDirectory[pe.IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress
// }
// var offset = rvaToFoa(exportDirectoryRVA, fpe)
// exportDir := ExportDirectory{}
// buff := &bytes.Buffer{}
// buff.Write(rawData[offset:])
// err = binary.Read(buff, binary.LittleEndian, &exportDir)
// if err != nil {
// return 0, err
// }
// current := exportDir.AddressOfNames
// nameArrayFOA := rvaToFoa(exportDir.AddressOfNames, fpe)
// ordinalArrayFOA := rvaToFoa(exportDir.AddressOfNameOrdinals, fpe)
// funcArrayFoa := rvaToFoa(exportDir.AddressOfFunctions, fpe)
for i := uint32(0); i < exportDir.NumberOfNames; i++ {
index := nameArrayFOA + i*8
name := getFuncName(index, rawData, fpe)
if strings.Contains(name, exportName) {
ordIndex := ordinalArrayFOA + i*2
funcOffset = getOrdinal(ordIndex, rawData, fpe, funcArrayFoa)
}
current += uint32(binary.Size(i))
}
// for i := uint32(0); i < exportDir.NumberOfNames; i++ {
// index := nameArrayFOA + i*8
// name := getFuncName(index, rawData, fpe)
// if strings.Contains(name, exportName) {
// ordIndex := ordinalArrayFOA + i*2
// funcOffset = getOrdinal(ordIndex, rawData, fpe, funcArrayFoa)
// }
// current += uint32(binary.Size(i))
// }
return
}
// return
// }
func getExportOffsetFromMemory(rawData []byte, exportName string) (funcOffset uint32, err error) {
peReader := bytes.NewReader(rawData)
+4 -11
View File
@@ -63,15 +63,8 @@ func (s *Server) CreateTunnel(ctx context.Context, req *sliverpb.Tunnel) (*slive
// CloseTunnel - Client requests we close a tunnel
func (s *Server) CloseTunnel(ctx context.Context, req *sliverpb.Tunnel) (*commonpb.Empty, error) {
err := core.Tunnels.Close(req.TunnelID)
if _, ok := toImplantCache[req.TunnelID]; ok {
delete(toImplantCache, req.TunnelID)
}
if _, ok := fromImplantCache[req.TunnelID]; ok {
delete(fromImplantCache, req.TunnelID)
}
delete(toImplantCache, req.TunnelID)
delete(fromImplantCache, req.TunnelID)
if err != nil {
return nil, err
}
@@ -107,7 +100,7 @@ func (s *Server) TunnelData(stream rpcpb.SliverRPC_TunnelDataServer) error {
go func() {
sendCache, _ := toImplantCache[tunnel.ID]
sendCache := toImplantCache[tunnel.ID]
for tunnelData := range tunnel.FromImplant {
tunnelLog.Debugf("Tunnel %d: From implant %d byte(s), seq: %d ack: %d",
@@ -170,7 +163,7 @@ func (s *Server) TunnelData(stream rpcpb.SliverRPC_TunnelDataServer) error {
go func() {
session := core.Sessions.Get(tunnel.SessionID)
sendCache, _ := toImplantCache[tunnel.ID]
sendCache := toImplantCache[tunnel.ID]
for data := range tunnel.ToImplant {
tunnelLog.Debugf("Tunnel %d: To implant %d byte(s), seq: %d", tunnel.ID, len(data), tunnel.ToImplantSequence)
tunnelData := sliverpb.TunnelData{
+4 -5
View File
@@ -20,7 +20,6 @@ package rpc
import (
"context"
"fmt"
"mime"
"path/filepath"
@@ -83,7 +82,7 @@ func (rpc *Server) WebsiteRemove(ctx context.Context, req *clientpb.Website) (*c
core.EventBroker.Publish(core.Event{
EventType: consts.WebsiteEvent,
Data: []byte(fmt.Sprintf("%s", req.Name)),
Data: []byte(req.Name),
})
return &commonpb.Empty{}, nil
@@ -122,7 +121,7 @@ func (rpc *Server) WebsiteAddContent(ctx context.Context, req *clientpb.WebsiteA
core.EventBroker.Publish(core.Event{
EventType: consts.WebsiteEvent,
Data: []byte(fmt.Sprintf("%s", req.Name)),
Data: []byte(req.Name),
})
return website.MapContent(req.Name, false)
@@ -149,7 +148,7 @@ func (rpc *Server) WebsiteUpdateContent(ctx context.Context, req *clientpb.Websi
core.EventBroker.Publish(core.Event{
EventType: consts.WebsiteEvent,
Data: []byte(fmt.Sprintf("%s", req.Name)),
Data: []byte(req.Name),
})
return website.MapContent(req.Name, false)
@@ -167,7 +166,7 @@ func (rpc *Server) WebsiteRemoveContent(ctx context.Context, req *clientpb.Websi
core.EventBroker.Publish(core.Event{
EventType: consts.WebsiteEvent,
Data: []byte(fmt.Sprintf("%s", req.Name)),
Data: []byte(req.Name),
})
return website.MapContent(req.Name, false)
+5 -4
View File
@@ -44,7 +44,7 @@ var (
)
const (
defaultTimeout = time.Duration(30 * time.Second)
minTimeout = time.Duration(30 * time.Second)
)
// Server - gRPC server
@@ -132,12 +132,13 @@ func (rpc *Server) GenericHandler(req GenericRequest, resp GenericResponse) erro
if err != nil {
return err
}
return rpc.getError(resp.(GenericResponse))
return rpc.getError(resp)
}
// asyncGenericHandler - Generic handler for async request/response's for beacon tasks
func (rpc *Server) asyncGenericHandler(req GenericRequest, resp GenericResponse) error {
rpcLog.Debugf("Async Generic Handler: %#v", req)
// VERY VERBOSE
// rpcLog.Debugf("Async Generic Handler: %#v", req)
request := req.GetRequest()
if request == nil {
return ErrMissingRequestField
@@ -202,7 +203,7 @@ func (rpc *Server) getClientCommonName(ctx context.Context) string {
func (rpc *Server) getTimeout(req GenericRequest) time.Duration {
timeout := req.GetRequest().Timeout
if time.Duration(timeout) < time.Second {
return defaultTimeout
return minTimeout
}
return time.Duration(timeout)
}