Skip to content

Commit

Permalink
Merge pull request #350 from BishopFox/registry
Browse files Browse the repository at this point in the history
Add windows registry operations
  • Loading branch information
moloch-- authored Mar 16, 2021
2 parents abac706 + 3921a19 commit a9639b0
Show file tree
Hide file tree
Showing 12 changed files with 713 additions and 19 deletions.
68 changes: 68 additions & 0 deletions client/command/bind-commands.go
Original file line number Diff line number Diff line change
Expand Up @@ -1423,4 +1423,72 @@ func BindCommands(app *grumble.App, rpc rpcpb.SliverRPCClient) {
},
HelpGroup: consts.GenericHelpGroup,
})

registryCmd := &grumble.Command{
Name: consts.RegistryStr,
Help: "Windows registry operations",
LongHelp: help.GetHelpFor(consts.RegistryStr),
Run: func(ctx *grumble.Context) error {
return nil
},
HelpGroup: consts.SliverWinHelpGroup,
}

registryCmd.AddCommand(&grumble.Command{
Name: consts.RegistryReadStr,
Help: "Read values from the Windows registry",
LongHelp: help.GetHelpFor(consts.RegistryReadStr),
Run: func(ctx *grumble.Context) error {
fmt.Println()
registryReadCmd(ctx, rpc)
fmt.Println()
return nil
},
AllowArgs: true,
Flags: func(f *grumble.Flags) {
f.Int("t", "timeout", defaultTimeout, "command timeout in seconds")
f.String("H", "hive", "HKCU", "egistry hive")
f.String("o", "hostname", "", "remote host to read values from")
},
HelpGroup: consts.SliverWinHelpGroup,
})
registryCmd.AddCommand(&grumble.Command{
Name: consts.RegistryWriteStr,
Help: "Write values to the Windows registry",
LongHelp: help.GetHelpFor(consts.RegistryWriteStr),
AllowArgs: true,
Run: func(ctx *grumble.Context) error {
fmt.Println()
registryWriteCmd(ctx, rpc)
fmt.Println()
return nil
},
Flags: func(f *grumble.Flags) {
f.Int("t", "timeout", defaultTimeout, "command timeout in seconds")
f.String("H", "hive", "HKCU", "registry hive")
f.String("o", "hostname", "", "remote host to write values to")
f.String("T", "type", "string", "type of the value to write (string, dword, qword, binary). If binary, you must provide a path to a file with --path")
f.String("p", "path", "", "path to the binary file to write")
},
HelpGroup: consts.SliverWinHelpGroup,
})
registryCmd.AddCommand(&grumble.Command{
Name: consts.RegistryCreateKeyStr,
Help: "Create a registry key",
LongHelp: help.GetHelpFor(consts.RegistryCreateKeyStr),
AllowArgs: true,
Run: func(ctx *grumble.Context) error {
fmt.Println()
regCreateKeyCmd(ctx, rpc)
fmt.Println()
return nil
},
Flags: func(f *grumble.Flags) {
f.Int("t", "timeout", defaultTimeout, "command timeout in seconds")
f.String("H", "hive", "HKCU", "registry hive")
f.String("o", "hostname", "", "remote host to write values to")
},
})
app.AddCommand(registryCmd)

}
257 changes: 257 additions & 0 deletions client/command/registry.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,257 @@
package command

import (
"context"
"encoding/hex"
"fmt"
"io/ioutil"
"strconv"
"strings"

"github.com/bishopfox/sliver/protobuf/rpcpb"
"github.com/bishopfox/sliver/protobuf/sliverpb"
"github.com/desertbit/grumble"
)

var validHives = []string{
"HKCU",
"HKLM",
"HKCC",
"HKPD",
"HKU",
"HKCR",
}

var validTypes = []string{
"binary",
"dword",
"qword",
"string",
}

func checkHive(hive string) error {
for _, h := range validHives {
if h == hive {
return nil
}
}
return fmt.Errorf("invalid hive %s", hive)
}

func getType(t string) (sliverpb.RegistryType, error) {
var res sliverpb.RegistryType
switch t {
case "binary":
res = sliverpb.RegistryType_BINARY
case "dword":
res = sliverpb.RegistryType_DWORD
case "qword":
res = sliverpb.RegistryType_QWORD
case "string":
res = sliverpb.RegistryType_STRING
default:
return res, fmt.Errorf("invalid type %s", t)
}
return res, nil
}

// registry read --hostname aa.bc.local --hive HKCU "software\google\chrome\blbeacon\version"
func registryReadCmd(ctx *grumble.Context, rpc rpcpb.SliverRPCClient) {
session := ActiveSession.Get()
if session == nil {
return
}

if session.OS != "windows" {
fmt.Printf(Warn + "Error: command not supported on this operating system.")
return
}

hostname := ctx.Flags.String("hostname")
hive := ctx.Flags.String("hive")
if err := checkHive(hive); err != nil {
fmt.Printf(Warn+"Error: %v", err)
return
}

if len(ctx.Args) != 1 {
fmt.Printf(Warn + "you must provide a path")
return
}
regPath := ctx.Args[0]
if strings.Contains(regPath, "/") {
regPath = strings.ReplaceAll(regPath, "/", "\\")
}
slashIndex := strings.LastIndex(regPath, "\\")
key := regPath[slashIndex+1:]
regPath = regPath[:slashIndex]
regRead, err := rpc.RegistryRead(context.Background(), &sliverpb.RegistryReadReq{
Hive: hive,
Path: regPath,
Key: key,
Hostname: hostname,
Request: ActiveSession.Request(ctx),
})

if err != nil {
fmt.Printf(Warn+"Error: %v", err)
return
}

if regRead.Response != nil && regRead.Response.Err != "" {
fmt.Printf(Warn+"Error: %s", regRead.Response.Err)
return
}
fmt.Println(regRead.Value)
}

// registry write --hive HKCU --type dword "software\google\chrome\blbeacon\hello" 32
func registryWriteCmd(ctx *grumble.Context, rpc rpcpb.SliverRPCClient) {
var (
dwordValue uint32
qwordValue uint64
stringValue string
binaryValue []byte
)
session := ActiveSession.Get()
if session == nil {
return
}

if session.OS != "windows" {
fmt.Printf(Warn + "Error: command not supported on this operating system.")
return
}
binPath := ctx.Flags.String("path")
hostname := ctx.Flags.String("hostname")
flagType := ctx.Flags.String("type")
valType, err := getType(flagType)
if err != nil {
fmt.Printf(Warn+"Error: %v", err)
return
}
hive := ctx.Flags.String("hive")
if err := checkHive(hive); err != nil {
fmt.Printf(Warn+"Error: %v", err)
return
}

if len(ctx.Args) != 2 {
fmt.Printf(Warn + "you must provide a path and a value to write")
return
}
regPath := ctx.Args[0]
if strings.Contains(regPath, "/") {
regPath = strings.ReplaceAll(regPath, "/", "\\")
}
slashIndex := strings.LastIndex(regPath, "\\")
key := regPath[slashIndex+1:]
regPath = regPath[:slashIndex]
value := ctx.Args[1]
switch valType {
case sliverpb.RegistryType_BINARY:
var (
v []byte
err error
)
if binPath == "" {
v, err = hex.DecodeString(value)
if err != nil {
fmt.Printf(Warn+"Error: %v", err)
return
}
} else {
v, err = ioutil.ReadFile(binPath)
if err != nil {
fmt.Printf(Warn+"Error: %v", err)
return
}
}
binaryValue = v
case sliverpb.RegistryType_DWORD:
v, err := strconv.ParseUint(value, 10, 32)
if err != nil {
fmt.Printf(Warn+"Error: %v", err)
return
}
dwordValue = uint32(v)
case sliverpb.RegistryType_QWORD:
v, err := strconv.ParseUint(value, 10, 64)
if err != nil {
fmt.Printf(Warn+"Error: %v", err)
return
}
qwordValue = v
case sliverpb.RegistryType_STRING:
stringValue = value
default:
fmt.Printf(Warn + "Invalid type")
return
}
regWrite, err := rpc.RegistryWrite(context.Background(), &sliverpb.RegistryWriteReq{
Request: ActiveSession.Request(ctx),
Hostname: hostname,
Hive: hive,
Path: regPath,
Type: valType,
Key: key,
StringValue: stringValue,
DWordValue: dwordValue,
QWordValue: qwordValue,
ByteValue: binaryValue,
})

if err != nil {
fmt.Printf(Warn+"Error: %v", err)
return
}
if regWrite.Response != nil && regWrite.Response.Err != "" {
fmt.Printf(Warn+"Error: %v", regWrite.Response.Err)
return
}
fmt.Printf(Info + "Value written to registry\n")
}

func regCreateKeyCmd(ctx *grumble.Context, rpc rpcpb.SliverRPCClient) {
session := ActiveSession.Get()
if session == nil {
return
}

hostname := ctx.Flags.String("hostname")
hive := ctx.Flags.String("hive")
if err := checkHive(hive); err != nil {
fmt.Printf(Warn+"Error: %v", err)
return
}

if len(ctx.Args) != 1 {
fmt.Printf(Warn + "you must provide a path")
return
}
regPath := ctx.Args[0]
if strings.Contains(regPath, "/") {
regPath = strings.ReplaceAll(regPath, "/", "\\")
}
slashIndex := strings.LastIndex(regPath, "\\")
key := regPath[slashIndex+1:]
regPath = regPath[:slashIndex]
createKeyResp, err := rpc.RegistryCreateKey(context.Background(), &sliverpb.RegistryCreateKeyReq{
Hive: hive,
Path: regPath,
Key: key,
Hostname: hostname,
Request: ActiveSession.Request(ctx),
})

if err != nil {
fmt.Printf(Warn+"Error: %v", err)
return
}

if createKeyResp.Response != nil && createKeyResp.Response.Err != "" {
fmt.Printf(Warn+"Error: %s", createKeyResp.Response.Err)
return
}
fmt.Printf(Info+"Key created at %s\\%s", regPath, key)
}
18 changes: 12 additions & 6 deletions client/constants/constants.go
Original file line number Diff line number Diff line change
Expand Up @@ -142,12 +142,18 @@ const (
AddWebContentStr = "add-content"
WebContentTypeStr = "content-type"

ScreenshotStr = "screenshot"
PsExecStr = "psexec"
BackdoorStr = "backdoor"
MakeTokenStr = "make-token"
GetEnvStr = "getenv"
SetEnvStr = "setenv"
ScreenshotStr = "screenshot"
PsExecStr = "psexec"
BackdoorStr = "backdoor"
MakeTokenStr = "make-token"
GetEnvStr = "getenv"
SetEnvStr = "setenv"
RegistryStr = "registry"
RegistryReadStr = "read"
RegistryWriteStr = "write"
RegistryListSubStr = "list-subkeys"
RegistryListValuesStr = "list-values"
RegistryCreateKeyStr = "create"

LicensesStr = "licenses"
)
Expand Down
Loading

0 comments on commit a9639b0

Please sign in to comment.