mirror of
https://github.com/BishopFox/sliver.git
synced 2026-11-08 01:38:17 -10:00
Compare commits
27
Commits
go-sqlite2
...
v1.5.12
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
aacf2c16ac | ||
|
|
c345731a6b | ||
|
|
c495377f4b | ||
|
|
cd5717db2a | ||
|
|
1f00eec899 | ||
|
|
ef87aa91cc | ||
|
|
faab1edaaf | ||
|
|
6dab042c8c | ||
|
|
b116ac97c5 | ||
|
|
d9fe00d1ef | ||
|
|
630f215bed | ||
|
|
f42ba31753 | ||
|
|
72065cd39e | ||
|
|
0c1a0fd7bf | ||
|
|
c12cbc77a7 | ||
|
|
f79e0d1845 | ||
|
|
b4b1a5bf74 | ||
|
|
c0431bf9db | ||
|
|
54ce7ef341 | ||
|
|
bbff000f5d | ||
|
|
009cae470e | ||
|
|
696d2980ff | ||
|
|
f2065ca72a | ||
|
|
5a9c4c9ddb | ||
|
|
6ff1edb962 | ||
|
|
11a4ae0741 | ||
|
|
c8eec91232 |
No files matched your search
@@ -7,17 +7,17 @@ on:
|
||||
branches:
|
||||
- master
|
||||
types:
|
||||
- opened
|
||||
- reopened
|
||||
- synchronize
|
||||
- ready_for_review
|
||||
- opened
|
||||
- reopened
|
||||
- synchronize
|
||||
- ready_for_review
|
||||
|
||||
jobs:
|
||||
|
||||
linux-windows-build:
|
||||
name: Linux & Windows Build
|
||||
runs-on: ubuntu-latest
|
||||
timeout-minutes: 45
|
||||
timeout-minutes: 90
|
||||
steps:
|
||||
|
||||
- name: Go 1.18
|
||||
@@ -52,7 +52,7 @@ jobs:
|
||||
macos-build:
|
||||
name: MacOS Build
|
||||
runs-on: macos-latest
|
||||
timeout-minutes: 45
|
||||
timeout-minutes: 90
|
||||
steps:
|
||||
|
||||
- name: Go 1.18
|
||||
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
FROM golang:1.18
|
||||
FROM golang:1.18.1
|
||||
|
||||
#
|
||||
# IMPORTANT: This Dockerfile is used for testing, I do not recommend deploying
|
||||
|
||||
@@ -21,6 +21,7 @@ package beacons
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"regexp"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
@@ -71,27 +72,36 @@ func BeaconsCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
|
||||
con.PrintInfof("Killed %s (%s)\n", beacon.Name, beacon.ID)
|
||||
}
|
||||
}
|
||||
filter := ctx.Flags.String("filter")
|
||||
var filterRegex *regexp.Regexp
|
||||
if ctx.Flags.String("filter-re") != "" {
|
||||
var err error
|
||||
filterRegex, err = regexp.Compile(ctx.Flags.String("filter-re"))
|
||||
if err != nil {
|
||||
con.PrintErrorf("%s\n", err)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
beacons, err := con.Rpc.GetBeacons(context.Background(), &commonpb.Empty{})
|
||||
if err != nil {
|
||||
con.PrintErrorf("%s\n", err)
|
||||
return
|
||||
}
|
||||
|
||||
PrintBeacons(beacons.Beacons, con)
|
||||
PrintBeacons(beacons.Beacons, filter, filterRegex, con)
|
||||
}
|
||||
|
||||
// PrintBeacons - Display a list of beacons
|
||||
func PrintBeacons(beacons []*clientpb.Beacon, con *console.SliverConsoleClient) {
|
||||
func PrintBeacons(beacons []*clientpb.Beacon, filter string, filterRegex *regexp.Regexp, con *console.SliverConsoleClient) {
|
||||
if len(beacons) == 0 {
|
||||
con.PrintInfof("No beacons 🙁\n")
|
||||
return
|
||||
}
|
||||
tw := renderBeacons(beacons, con)
|
||||
tw := renderBeacons(beacons, filter, filterRegex, con)
|
||||
con.Printf("%s\n", tw.Render())
|
||||
}
|
||||
|
||||
func renderBeacons(beacons []*clientpb.Beacon, con *console.SliverConsoleClient) table.Writer {
|
||||
func renderBeacons(beacons []*clientpb.Beacon, filter string, filterRegex *regexp.Regexp, con *console.SliverConsoleClient) table.Writer {
|
||||
width, _, err := term.GetSize(0)
|
||||
if err != nil {
|
||||
width = 999
|
||||
@@ -140,8 +150,11 @@ func renderBeacons(beacons []*clientpb.Beacon, con *console.SliverConsoleClient)
|
||||
eta := time.Until(nextCheckin)
|
||||
next = fmt.Sprintf("%s%s%s", console.Bold+console.Green, eta, console.Normal)
|
||||
}
|
||||
|
||||
// We need a slice of strings so we can apply filters
|
||||
var rowEntries []string
|
||||
if con.Settings.SmallTermWidth < width {
|
||||
tw.AppendRow(table.Row{
|
||||
rowEntries = []string{
|
||||
fmt.Sprintf(color+"%s"+console.Normal, strings.Split(beacon.ID, "-")[0]),
|
||||
fmt.Sprintf(color+"%s"+console.Normal, beacon.Name),
|
||||
fmt.Sprintf(color+"%d/%d"+console.Normal, beacon.TasksCountCompleted, beacon.TasksCount),
|
||||
@@ -152,9 +165,9 @@ func renderBeacons(beacons []*clientpb.Beacon, con *console.SliverConsoleClient)
|
||||
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))),
|
||||
next,
|
||||
})
|
||||
}
|
||||
} else {
|
||||
tw.AppendRow(table.Row{
|
||||
rowEntries = []string{
|
||||
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),
|
||||
@@ -162,7 +175,31 @@ func renderBeacons(beacons []*clientpb.Beacon, con *console.SliverConsoleClient)
|
||||
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))),
|
||||
next,
|
||||
})
|
||||
}
|
||||
}
|
||||
// Build the row struct
|
||||
row := table.Row{}
|
||||
for _, entry := range rowEntries {
|
||||
row = append(row, entry)
|
||||
}
|
||||
// Apply filters if any
|
||||
if filter == "" && filterRegex == nil {
|
||||
tw.AppendRow(row)
|
||||
} else {
|
||||
for _, rowEntry := range rowEntries {
|
||||
if filter != "" {
|
||||
if strings.Contains(rowEntry, filter) {
|
||||
tw.AppendRow(row)
|
||||
break
|
||||
}
|
||||
}
|
||||
if filterRegex != nil {
|
||||
if filterRegex.MatchString(rowEntry) {
|
||||
tw.AppendRow(row)
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return tw
|
||||
|
||||
@@ -45,7 +45,7 @@ func BeaconsWatchCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
|
||||
if err != nil {
|
||||
panic(err) // If we return we may leak the waiting goroutine, so we panic instead
|
||||
}
|
||||
tw := renderBeacons(beacons.Beacons, con)
|
||||
tw := renderBeacons(beacons.Beacons, "", nil, con)
|
||||
lines := strings.Split(tw.Render(), "\n")
|
||||
for _, line := range lines {
|
||||
con.Printf(console.Clearln+"\r%s\n", line)
|
||||
|
||||
@@ -399,6 +399,7 @@ func BindCommands(con *console.SliverConsoleClient) {
|
||||
f.Bool("c", "no-canaries", false, "disable dns canary detection")
|
||||
f.String("L", "lhost", "", "interface to bind server to")
|
||||
f.Int("l", "lport", generate.DefaultDNSLPort, "udp listen port")
|
||||
f.Bool("D", "disable-otp", false, "disable otp authentication")
|
||||
|
||||
f.Int("t", "timeout", defaultTimeout, "command timeout in seconds")
|
||||
f.Bool("p", "persistent", false, "make persistent across restarts")
|
||||
@@ -558,7 +559,10 @@ 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.Bool("F", "force", false, "force session action without waiting for results")
|
||||
|
||||
f.String("f", "filter", "", "filter sessions by substring")
|
||||
f.String("e", "filter-re", "", "filter sessions by regular expression")
|
||||
|
||||
f.Int("t", "timeout", defaultTimeout, "command timeout in seconds")
|
||||
},
|
||||
@@ -575,7 +579,8 @@ 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.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 {
|
||||
@@ -615,7 +620,7 @@ func BindCommands(con *console.SliverConsoleClient) {
|
||||
return nil
|
||||
},
|
||||
Flags: func(f *grumble.Flags) {
|
||||
f.Bool("f", "force", false, "Force kill, does not clean up")
|
||||
f.Bool("F", "force", false, "Force kill, does not clean up")
|
||||
|
||||
f.Int("t", "timeout", defaultTimeout, "command timeout in seconds")
|
||||
},
|
||||
@@ -1250,6 +1255,7 @@ func BindCommands(con *console.SliverConsoleClient) {
|
||||
|
||||
f.Bool("R", "run-at-load", false, "run the implant entrypoint from DllMain/Constructor (shared library only)")
|
||||
|
||||
f.String("Z", "strategy", "", "specify a connection strategy (r = random, rd = random domain, s = sequential)")
|
||||
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")
|
||||
@@ -1306,6 +1312,7 @@ func BindCommands(con *console.SliverConsoleClient) {
|
||||
|
||||
f.Bool("R", "run-at-load", false, "run the implant entrypoint from DllMain/Constructor (shared library only)")
|
||||
|
||||
f.String("Z", "strategy", "", "specify a connection strategy (r = random, rd = random domain, s = sequential)")
|
||||
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")
|
||||
@@ -1455,6 +1462,7 @@ func BindCommands(con *console.SliverConsoleClient) {
|
||||
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.String("Z", "strategy", "", "specify a connection strategy (r = random, rd = random domain, s = sequential)")
|
||||
|
||||
f.Int("j", "reconnect", generate.DefaultReconnect, "attempt to reconnect every n second(s)")
|
||||
f.Int("P", "poll-timeout", generate.DefaultPollTimeout, "long poll request timeout")
|
||||
@@ -1511,6 +1519,7 @@ func BindCommands(con *console.SliverConsoleClient) {
|
||||
f.String("n", "dns", "", "dns connection strings")
|
||||
f.String("p", "named-pipe", "", "named-pipe connection strings")
|
||||
f.String("i", "tcp-pivot", "", "tcp-pivot connection strings")
|
||||
f.String("Z", "strategy", "", "specify a connection strategy (r = random, rd = random domain, s = sequential)")
|
||||
|
||||
f.Int("X", "key-exchange", generate.DefaultWGKeyExPort, "wg key-exchange port")
|
||||
f.Int("T", "tcp-comms", generate.DefaultWGNPort, "wg c2 comms port")
|
||||
@@ -1677,7 +1686,7 @@ func BindCommands(con *console.SliverConsoleClient) {
|
||||
LongHelp: help.GetHelpFor([]string{consts.RmStr}),
|
||||
Flags: func(f *grumble.Flags) {
|
||||
f.Bool("r", "recursive", false, "recursively remove files")
|
||||
f.Bool("f", "force", false, "ignore safety and forcefully remove files")
|
||||
f.Bool("F", "force", false, "ignore safety and forcefully remove files")
|
||||
|
||||
f.Int("t", "timeout", defaultTimeout, "command timeout in seconds")
|
||||
},
|
||||
@@ -1913,7 +1922,7 @@ func BindCommands(con *console.SliverConsoleClient) {
|
||||
a.Uint("pid", "pid")
|
||||
},
|
||||
Flags: func(f *grumble.Flags) {
|
||||
f.Bool("f", "force", false, "disregard safety and kill the PID")
|
||||
f.Bool("F", "force", false, "disregard safety and kill the PID")
|
||||
|
||||
f.Int("t", "timeout", defaultTimeout, "command timeout in seconds")
|
||||
},
|
||||
@@ -2163,8 +2172,11 @@ func BindCommands(con *console.SliverConsoleClient) {
|
||||
Flags: func(f *grumble.Flags) {
|
||||
f.String("k", "kill", "", "kill a beacon")
|
||||
f.Bool("K", "kill-all", false, "kill all beacons")
|
||||
f.Bool("F", "force", false, "force killing of the beacon")
|
||||
f.String("f", "filter", "", "filter beacons by substring")
|
||||
f.String("e", "filter-re", "", "filter beacons by regular expression")
|
||||
|
||||
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 {
|
||||
|
||||
@@ -305,6 +305,13 @@ func parseCompileFlags(ctx *grumble.Context, con *console.SliverConsoleClient) *
|
||||
con.PrintInfof("Generated unique ip for wg peer tun interface: %s\n", tunIP.String())
|
||||
}
|
||||
|
||||
// TODO: Use generics or something to check in a slice
|
||||
connectionStrategy := ctx.Flags.String("strategy")
|
||||
if connectionStrategy != "" && connectionStrategy != "s" && connectionStrategy != "r" && connectionStrategy != "rd" {
|
||||
con.PrintErrorf("Invalid connection strategy: %s\n", connectionStrategy)
|
||||
return nil
|
||||
}
|
||||
|
||||
config := &clientpb.ImplantConfig{
|
||||
GOOS: targetOS,
|
||||
GOARCH: targetArch,
|
||||
@@ -319,6 +326,7 @@ func parseCompileFlags(ctx *grumble.Context, con *console.SliverConsoleClient) *
|
||||
WGKeyExchangePort: uint32(ctx.Flags.Int("key-exchange")),
|
||||
WGTcpCommsPort: uint32(ctx.Flags.Int("tcp-comms")),
|
||||
|
||||
ConnectionStrategy: connectionStrategy,
|
||||
ReconnectInterval: int64(reconnectInterval) * int64(time.Second),
|
||||
PollTimeout: int64(pollTimeout) * int64(time.Second),
|
||||
MaxConnectionErrors: uint32(maxConnectionErrors),
|
||||
|
||||
@@ -31,9 +31,9 @@ import (
|
||||
func DNSListenerCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
|
||||
|
||||
domains := strings.Split(ctx.Flags.String("domains"), ",")
|
||||
for _, domain := range domains {
|
||||
for index, domain := range domains {
|
||||
if !strings.HasSuffix(domain, ".") {
|
||||
domain += "."
|
||||
domains[index] += "."
|
||||
}
|
||||
}
|
||||
|
||||
@@ -47,6 +47,7 @@ func DNSListenerCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
|
||||
Port: uint32(lport),
|
||||
Canaries: !ctx.Flags.Bool("no-canaries"),
|
||||
Persistent: ctx.Flags.Bool("persistent"),
|
||||
EnforceOTP: !ctx.Flags.Bool("disable-otp"),
|
||||
})
|
||||
con.Println()
|
||||
if err != nil {
|
||||
|
||||
@@ -21,6 +21,7 @@ package sessions
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"regexp"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
@@ -97,12 +98,23 @@ func SessionsCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
|
||||
con.PrintErrorf("Invalid session name or session number: %s\n", interact)
|
||||
}
|
||||
} else {
|
||||
filter := ctx.Flags.String("filter")
|
||||
var filterRegex *regexp.Regexp
|
||||
if ctx.Flags.String("filter-re") != "" {
|
||||
var err error
|
||||
filterRegex, err = regexp.Compile(ctx.Flags.String("filter-re"))
|
||||
if err != nil {
|
||||
con.PrintErrorf("%s\n", err)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
sessionsMap := map[string]*clientpb.Session{}
|
||||
for _, session := range sessions.GetSessions() {
|
||||
sessionsMap[session.ID] = session
|
||||
}
|
||||
if 0 < len(sessionsMap) {
|
||||
PrintSessions(sessionsMap, con)
|
||||
PrintSessions(sessionsMap, filter, filterRegex, con)
|
||||
} else {
|
||||
con.PrintInfof("No sessions 🙁\n")
|
||||
}
|
||||
@@ -110,7 +122,7 @@ func SessionsCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
|
||||
}
|
||||
|
||||
// PrintSessions - Print the current sessions
|
||||
func PrintSessions(sessions map[string]*clientpb.Session, con *console.SliverConsoleClient) {
|
||||
func PrintSessions(sessions map[string]*clientpb.Session, filter string, filterRegex *regexp.Regexp, con *console.SliverConsoleClient) {
|
||||
width, _, err := term.GetSize(0)
|
||||
if err != nil {
|
||||
width = 999
|
||||
@@ -128,7 +140,7 @@ func PrintSessions(sessions map[string]*clientpb.Session, con *console.SliverCon
|
||||
"Hostname",
|
||||
"Username",
|
||||
"Operating System",
|
||||
"Last Check-in",
|
||||
"Last Message",
|
||||
"Health",
|
||||
})
|
||||
} else {
|
||||
@@ -164,8 +176,9 @@ func PrintSessions(sessions map[string]*clientpb.Session, con *console.SliverCon
|
||||
}
|
||||
username := strings.TrimPrefix(session.Username, session.Hostname+"\\") // For non-AD Windows users
|
||||
|
||||
var rowEntries []string
|
||||
if con.Settings.SmallTermWidth < width {
|
||||
tw.AppendRow(table.Row{
|
||||
rowEntries = []string{
|
||||
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),
|
||||
@@ -175,9 +188,9 @@ func PrintSessions(sessions map[string]*clientpb.Session, con *console.SliverCon
|
||||
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{
|
||||
rowEntries = []string{
|
||||
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),
|
||||
@@ -185,7 +198,31 @@ func PrintSessions(sessions map[string]*clientpb.Session, con *console.SliverCon
|
||||
fmt.Sprintf(color+"%s"+console.Normal, username),
|
||||
fmt.Sprintf(color+"%s/%s"+console.Normal, session.OS, session.Arch),
|
||||
burned + SessionHealth,
|
||||
})
|
||||
}
|
||||
}
|
||||
// Build the row struct
|
||||
row := table.Row{}
|
||||
for _, entry := range rowEntries {
|
||||
row = append(row, entry)
|
||||
}
|
||||
// Apply filters if any
|
||||
if filter == "" && filterRegex == nil {
|
||||
tw.AppendRow(row)
|
||||
} else {
|
||||
for _, rowEntry := range rowEntries {
|
||||
if filter != "" {
|
||||
if strings.Contains(rowEntry, filter) {
|
||||
tw.AppendRow(row)
|
||||
break
|
||||
}
|
||||
}
|
||||
if filterRegex != nil {
|
||||
if filterRegex.MatchString(rowEntry) {
|
||||
tw.AppendRow(row)
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+1
-1
@@ -232,7 +232,7 @@ GEM
|
||||
jekyll-seo-tag (~> 2.1)
|
||||
minitest (5.15.0)
|
||||
multipart-post (2.1.1)
|
||||
nokogiri (1.13.3)
|
||||
nokogiri (1.13.4)
|
||||
mini_portile2 (~> 2.8.0)
|
||||
racc (~> 1.4)
|
||||
octokit (4.22.0)
|
||||
|
||||
+22
-6
@@ -20,7 +20,7 @@ set -e
|
||||
|
||||
# Creates the static go asset archives
|
||||
|
||||
GO_VER="1.18"
|
||||
GO_VER="1.18.1"
|
||||
GARBLE_VER="1.18.0"
|
||||
|
||||
GO_ARCH_1="amd64"
|
||||
@@ -102,9 +102,9 @@ cp -vv darwin-go.zip $OUTPUT_DIR/darwin/$GO_ARCH_2/go.zip
|
||||
rm -rf ./go
|
||||
rm -f darwin-go.zip go$GO_VER.darwin-$GO_ARCH_2.tar.gz
|
||||
|
||||
# --- Linux ---
|
||||
curl --output go$GO_VER.linux-amd64.tar.gz https://dl.google.com/go/go$GO_VER.linux-$GO_ARCH_1.tar.gz
|
||||
tar xvf go$GO_VER.linux-amd64.tar.gz
|
||||
# --- Linux (amd64) ---
|
||||
curl --output go$GO_VER.linux-$GO_ARCH_1.tar.gz https://dl.google.com/go/go$GO_VER.linux-$GO_ARCH_1.tar.gz
|
||||
tar xvf go$GO_VER.linux-$GO_ARCH_1.tar.gz
|
||||
cd go
|
||||
rm -rf $BLOAT_FILES
|
||||
rm -rf ./src
|
||||
@@ -118,6 +118,22 @@ cp -vv linux-go.zip $OUTPUT_DIR/linux/$GO_ARCH_1/go.zip
|
||||
rm -rf ./go
|
||||
rm -f linux-go.zip go$GO_VER.linux-$GO_ARCH_1.tar.gz
|
||||
|
||||
# --- Linux (arm64) ---
|
||||
curl --output go$GO_VER.linux-$GO_ARCH_2.tar.gz https://dl.google.com/go/go$GO_VER.linux-$GO_ARCH_2.tar.gz
|
||||
tar xvf go$GO_VER.linux-$GO_ARCH_2.tar.gz
|
||||
cd go
|
||||
rm -rf $BLOAT_FILES
|
||||
rm -rf ./src
|
||||
rm -f ./pkg/tool/linux_$GO_ARCH_2/doc
|
||||
rm -f ./pkg/tool/linux_$GO_ARCH_2/tour
|
||||
rm -f ./pkg/tool/linux_$GO_ARCH_2/test2json
|
||||
cd ..
|
||||
zip -r linux-go.zip ./go
|
||||
mkdir -p $OUTPUT_DIR/linux/$GO_ARCH_2
|
||||
cp -vv linux-go.zip $OUTPUT_DIR/linux/$GO_ARCH_2/go.zip
|
||||
rm -rf ./go
|
||||
rm -f linux-go.zip go$GO_VER.linux-$GO_ARCH_2.tar.gz
|
||||
|
||||
# --- Windows ---
|
||||
curl --output go$GO_VER.windows-amd64.zip https://dl.google.com/go/go$GO_VER.windows-$GO_ARCH_1.zip
|
||||
unzip go$GO_VER.windows-amd64.zip
|
||||
@@ -140,8 +156,8 @@ echo "-----------------------------------------------------------------"
|
||||
|
||||
echo "curl -L --fail --output $OUTPUT_DIR/linux/$GO_ARCH_1/garble https://github.com/moloch--/garble/releases/download/v$GARBLE_VER/garble_linux"
|
||||
curl -L --fail --output $OUTPUT_DIR/linux/$GO_ARCH_1/garble https://github.com/moloch--/garble/releases/download/v$GARBLE_VER/garble_linux
|
||||
file $OUTPUT_DIR/linux/$GO_ARCH_1/garble
|
||||
|
||||
echo "curl -L --fail --output $OUTPUT_DIR/linux/$GO_ARCH_2/garble https://github.com/moloch--/garble/releases/download/v$GARBLE_VER/garble_linux"
|
||||
curl -L --fail --output $OUTPUT_DIR/linux/$GO_ARCH_2/garble https://github.com/moloch--/garble/releases/download/v$GARBLE_VER/garble_linux
|
||||
echo "curl -L --fail --output $OUTPUT_DIR/windows/$GO_ARCH_1/garble.exe https://github.com/moloch--/garble/releases/download/v$GARBLE_VER/garble_windows.exe"
|
||||
curl -L --fail --output $OUTPUT_DIR/windows/$GO_ARCH_1/garble.exe https://github.com/moloch--/garble/releases/download/v$GARBLE_VER/garble_windows.exe
|
||||
echo "curl -L --fail --output $OUTPUT_DIR/darwin/$GO_ARCH_1/garble https://github.com/moloch--/garble/releases/download/v$GARBLE_VER/garble_macos-$GO_ARCH_1"
|
||||
|
||||
@@ -10,6 +10,15 @@ import (
|
||||
"time"
|
||||
)
|
||||
|
||||
const (
|
||||
FLAGS_ERROR_UI_FILTER_FOR_ERRORS uint32 = 0x01
|
||||
FLAGS_ERROR_UI_FLAGS_CHANGE_OPTIONS uint32 = 0x02
|
||||
FLAGS_ERROR_UI_FLAGS_GENERATE_DATA uint32 = 0x04
|
||||
INTERNET_ERROR_BASE uint32 = 12000
|
||||
ERROR_INTERNET_INCORRECT_PASSWORD uint32 = INTERNET_ERROR_BASE + 14
|
||||
ERROR_INTERNET_FORCE_RETRY uint32 = INTERNET_ERROR_BASE + 32
|
||||
)
|
||||
|
||||
// Client is a struct containing relevant metadata to make HTTP
|
||||
// requests.
|
||||
type Client struct {
|
||||
@@ -18,7 +27,8 @@ type Client struct {
|
||||
TLSClientConfig struct {
|
||||
InsecureSkipVerify bool
|
||||
}
|
||||
CookieJar *Jar
|
||||
CookieJar *Jar
|
||||
AskProxyCreds bool
|
||||
}
|
||||
|
||||
// NewClient will return a pointer to a new Client instance that
|
||||
@@ -147,6 +157,21 @@ func (c *Client) Do(request *http.Request) (*http.Response, error) {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if c.AskProxyCreds {
|
||||
if resp.StatusCode == 407 {
|
||||
err := promptUserPassword(reqHandle)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err = sendRequest(reqHandle, req); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if resp, err = buildResponse(reqHandle, req); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
c.CookieJar.cookies = resp.Cookies()
|
||||
|
||||
return &http.Response{
|
||||
@@ -162,6 +187,17 @@ func (c *Client) Do(request *http.Request) (*http.Response, error) {
|
||||
}, nil
|
||||
}
|
||||
|
||||
func promptUserPassword(reqHandle uintptr) error {
|
||||
var lppvData []byte
|
||||
dwError := ERROR_INTERNET_INCORRECT_PASSWORD
|
||||
dwFlags := FLAGS_ERROR_UI_FILTER_FOR_ERRORS | FLAGS_ERROR_UI_FLAGS_CHANGE_OPTIONS | FLAGS_ERROR_UI_FLAGS_GENERATE_DATA
|
||||
_, err := InternetErrorDlg(GetDesktopWindow(), reqHandle, dwError, dwFlags, &lppvData)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Jar - CookieJar implementation that ignores domains/origins
|
||||
type Jar struct {
|
||||
lk sync.Mutex
|
||||
|
||||
@@ -0,0 +1,16 @@
|
||||
package wininet
|
||||
|
||||
import (
|
||||
"golang.org/x/sys/windows"
|
||||
)
|
||||
|
||||
var (
|
||||
libuser32 = windows.NewLazySystemDLL("User32")
|
||||
)
|
||||
|
||||
func GetDesktopWindow() uintptr {
|
||||
|
||||
ret, _, _ := libuser32.NewProc("GetDesktopWindow").Call()
|
||||
|
||||
return ret
|
||||
}
|
||||
@@ -413,3 +413,34 @@ func InternetSetOptionW(
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// InternetErrorDlg is from wininet.h
|
||||
func InternetErrorDlg(
|
||||
hWnd uintptr,
|
||||
hRequest uintptr,
|
||||
dwError uint32,
|
||||
dwFlags uint32,
|
||||
lppvData *[]byte,
|
||||
) (uintptr, error) {
|
||||
var buf []byte
|
||||
var proc string = "InternetErrorDlg"
|
||||
var success uintptr
|
||||
|
||||
buf = make([]byte, 1024) //arbitrary size (safe?)
|
||||
|
||||
success, _, _ = wininet.NewProc(proc).Call(
|
||||
uintptr(hWnd),
|
||||
hRequest,
|
||||
uintptr(dwError),
|
||||
uintptr(dwFlags),
|
||||
uintptr(unsafe.Pointer(&buf[0])),
|
||||
)
|
||||
// we expect 12032 if user hits okay, otherwise we return the response code as an error
|
||||
if uint32(success) != ERROR_INTERNET_FORCE_RETRY {
|
||||
return success, fmt.Errorf("%s: %s", proc, success)
|
||||
}
|
||||
|
||||
*lppvData = buf
|
||||
|
||||
return success, nil
|
||||
}
|
||||
@@ -58,5 +58,6 @@ func WininetDriver(origin string, secure bool, opts *HTTPOptions) (HTTPDriver, e
|
||||
return nil, err
|
||||
}
|
||||
wininetClient.TLSClientConfig.InsecureSkipVerify = true
|
||||
wininetClient.AskProxyCreds = opts.AskProxyCreds
|
||||
return wininetClient, nil
|
||||
}
|
||||
@@ -74,6 +74,7 @@ type HTTPOptions struct {
|
||||
ProxyConfig string
|
||||
ProxyUsername string
|
||||
ProxyPassword string
|
||||
AskProxyCreds bool
|
||||
}
|
||||
|
||||
// ParseHTTPOptions - Parse c2 specific configuration options
|
||||
@@ -112,6 +113,7 @@ func ParseHTTPOptions(c2URI *url.URL) *HTTPOptions {
|
||||
ProxyConfig: c2URI.Query().Get("proxy"),
|
||||
ProxyUsername: c2URI.Query().Get("proxy-username"),
|
||||
ProxyPassword: c2URI.Query().Get("proxy-password"),
|
||||
AskProxyCreds: c2URI.Query().Get("ask-proxy-creds") == "true",
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
// Code generated by protoc-gen-go. DO NOT EDIT.
|
||||
// versions:
|
||||
// protoc-gen-go v1.26.0
|
||||
// protoc v3.20.0
|
||||
// protoc v3.19.4
|
||||
// source: clientpb/client.proto
|
||||
|
||||
package clientpb
|
||||
@@ -2606,6 +2606,7 @@ type DNSListenerReq struct {
|
||||
Host string `protobuf:"bytes,3,opt,name=Host,proto3" json:"Host,omitempty"`
|
||||
Port uint32 `protobuf:"varint,4,opt,name=Port,proto3" json:"Port,omitempty"`
|
||||
Persistent bool `protobuf:"varint,5,opt,name=Persistent,proto3" json:"Persistent,omitempty"`
|
||||
EnforceOTP bool `protobuf:"varint,6,opt,name=EnforceOTP,proto3" json:"EnforceOTP,omitempty"`
|
||||
}
|
||||
|
||||
func (x *DNSListenerReq) Reset() {
|
||||
@@ -2675,6 +2676,13 @@ func (x *DNSListenerReq) GetPersistent() bool {
|
||||
return false
|
||||
}
|
||||
|
||||
func (x *DNSListenerReq) GetEnforceOTP() bool {
|
||||
if x != nil {
|
||||
return x.EnforceOTP
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
type DNSListener struct {
|
||||
state protoimpl.MessageState
|
||||
sizeCache protoimpl.SizeCache
|
||||
@@ -5850,7 +5858,7 @@ var file_clientpb_client_proto_rawDesc = []byte{
|
||||
0x08, 0x52, 0x0a, 0x50, 0x65, 0x72, 0x73, 0x69, 0x73, 0x74, 0x65, 0x6e, 0x74, 0x22, 0x22, 0x0a,
|
||||
0x0a, 0x57, 0x47, 0x4c, 0x69, 0x73, 0x74, 0x65, 0x6e, 0x65, 0x72, 0x12, 0x14, 0x0a, 0x05, 0x4a,
|
||||
0x6f, 0x62, 0x49, 0x44, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x05, 0x4a, 0x6f, 0x62, 0x49,
|
||||
0x44, 0x22, 0x8e, 0x01, 0x0a, 0x0e, 0x44, 0x4e, 0x53, 0x4c, 0x69, 0x73, 0x74, 0x65, 0x6e, 0x65,
|
||||
0x44, 0x22, 0xae, 0x01, 0x0a, 0x0e, 0x44, 0x4e, 0x53, 0x4c, 0x69, 0x73, 0x74, 0x65, 0x6e, 0x65,
|
||||
0x72, 0x52, 0x65, 0x71, 0x12, 0x18, 0x0a, 0x07, 0x44, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x73, 0x18,
|
||||
0x01, 0x20, 0x03, 0x28, 0x09, 0x52, 0x07, 0x44, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x73, 0x12, 0x1a,
|
||||
0x0a, 0x08, 0x43, 0x61, 0x6e, 0x61, 0x72, 0x69, 0x65, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x08,
|
||||
@@ -5859,7 +5867,9 @@ var file_clientpb_client_proto_rawDesc = []byte{
|
||||
0x0a, 0x04, 0x50, 0x6f, 0x72, 0x74, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x04, 0x50, 0x6f,
|
||||
0x72, 0x74, 0x12, 0x1e, 0x0a, 0x0a, 0x50, 0x65, 0x72, 0x73, 0x69, 0x73, 0x74, 0x65, 0x6e, 0x74,
|
||||
0x18, 0x05, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0a, 0x50, 0x65, 0x72, 0x73, 0x69, 0x73, 0x74, 0x65,
|
||||
0x6e, 0x74, 0x22, 0x23, 0x0a, 0x0b, 0x44, 0x4e, 0x53, 0x4c, 0x69, 0x73, 0x74, 0x65, 0x6e, 0x65,
|
||||
0x6e, 0x74, 0x12, 0x1e, 0x0a, 0x0a, 0x45, 0x6e, 0x66, 0x6f, 0x72, 0x63, 0x65, 0x4f, 0x54, 0x50,
|
||||
0x18, 0x06, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0a, 0x45, 0x6e, 0x66, 0x6f, 0x72, 0x63, 0x65, 0x4f,
|
||||
0x54, 0x50, 0x22, 0x23, 0x0a, 0x0b, 0x44, 0x4e, 0x53, 0x4c, 0x69, 0x73, 0x74, 0x65, 0x6e, 0x65,
|
||||
0x72, 0x12, 0x14, 0x0a, 0x05, 0x4a, 0x6f, 0x62, 0x49, 0x44, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0d,
|
||||
0x52, 0x05, 0x4a, 0x6f, 0x62, 0x49, 0x44, 0x22, 0xcf, 0x02, 0x0a, 0x0f, 0x48, 0x54, 0x54, 0x50,
|
||||
0x4c, 0x69, 0x73, 0x74, 0x65, 0x6e, 0x65, 0x72, 0x52, 0x65, 0x71, 0x12, 0x16, 0x0a, 0x06, 0x44,
|
||||
|
||||
@@ -282,6 +282,7 @@ message DNSListenerReq {
|
||||
string Host = 3;
|
||||
uint32 Port = 4;
|
||||
bool Persistent = 5;
|
||||
bool EnforceOTP = 6;
|
||||
}
|
||||
|
||||
message DNSListener {
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
// Code generated by protoc-gen-go. DO NOT EDIT.
|
||||
// versions:
|
||||
// protoc-gen-go v1.26.0
|
||||
// protoc v3.20.0
|
||||
// protoc v3.19.4
|
||||
// source: commonpb/common.proto
|
||||
|
||||
package commonpb
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
// Code generated by protoc-gen-go. DO NOT EDIT.
|
||||
// versions:
|
||||
// protoc-gen-go v1.26.0
|
||||
// protoc v3.20.0
|
||||
// protoc v3.19.4
|
||||
// source: dnspb/dns.proto
|
||||
|
||||
package dnspb
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
// Code generated by protoc-gen-go. DO NOT EDIT.
|
||||
// versions:
|
||||
// protoc-gen-go v1.26.0
|
||||
// protoc v3.20.0
|
||||
// protoc v3.19.4
|
||||
// source: rpcpb/services.proto
|
||||
|
||||
package rpcpb
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
// Code generated by protoc-gen-go. DO NOT EDIT.
|
||||
// versions:
|
||||
// protoc-gen-go v1.26.0
|
||||
// protoc v3.20.0
|
||||
// protoc v3.19.4
|
||||
// source: sliverpb/sliver.proto
|
||||
|
||||
package sliverpb
|
||||
|
||||
@@ -0,0 +1,10 @@
|
||||
//go:build server
|
||||
|
||||
package assets
|
||||
|
||||
import "embed"
|
||||
|
||||
var (
|
||||
//go:embed fs/sliver.asc fs/*.txt fs/*.zip fs/linux/arm64/*
|
||||
assetsFs embed.FS
|
||||
)
|
||||
+43
-51
@@ -37,33 +37,29 @@ package c2
|
||||
import (
|
||||
"bytes"
|
||||
secureRand "crypto/rand"
|
||||
"encoding/base64"
|
||||
"encoding/binary"
|
||||
"errors"
|
||||
"fmt"
|
||||
"hash/crc32"
|
||||
"sort"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
"unicode"
|
||||
|
||||
consts "github.com/bishopfox/sliver/client/constants"
|
||||
"github.com/bishopfox/sliver/protobuf/dnspb"
|
||||
"github.com/bishopfox/sliver/protobuf/sliverpb"
|
||||
"github.com/bishopfox/sliver/server/core"
|
||||
"github.com/bishopfox/sliver/server/cryptography"
|
||||
"github.com/bishopfox/sliver/server/db"
|
||||
"github.com/bishopfox/sliver/server/generate"
|
||||
sliverHandlers "github.com/bishopfox/sliver/server/handlers"
|
||||
"github.com/bishopfox/sliver/util/encoders"
|
||||
"google.golang.org/protobuf/proto"
|
||||
|
||||
"encoding/base64"
|
||||
"encoding/binary"
|
||||
|
||||
"fmt"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
consts "github.com/bishopfox/sliver/client/constants"
|
||||
"github.com/bishopfox/sliver/server/core"
|
||||
"github.com/bishopfox/sliver/server/log"
|
||||
|
||||
"github.com/bishopfox/sliver/util/encoders"
|
||||
"github.com/miekg/dns"
|
||||
"google.golang.org/protobuf/proto"
|
||||
)
|
||||
|
||||
const (
|
||||
@@ -82,15 +78,15 @@ var (
|
||||
)
|
||||
|
||||
// StartDNSListener - Start a DNS listener
|
||||
func StartDNSListener(bindIface string, lport uint16, domains []string, canaries bool) *SliverDNSServer {
|
||||
func StartDNSListener(bindIface string, lport uint16, domains []string, canaries bool, enforceOTP bool) *SliverDNSServer {
|
||||
// StartPivotListener()
|
||||
server := &SliverDNSServer{
|
||||
server: &dns.Server{Addr: fmt.Sprintf("%s:%d", bindIface, lport), Net: "udp"},
|
||||
sessions: &sync.Map{}, // DNS Session ID -> DNSSession
|
||||
messages: &sync.Map{}, // In progress message streams
|
||||
totpToSessionID: &sync.Map{}, // Atomic TOTP -> DNS Session ID
|
||||
TTL: 0,
|
||||
MaxTXTLength: defaultMaxTXTLength,
|
||||
server: &dns.Server{Addr: fmt.Sprintf("%s:%d", bindIface, lport), Net: "udp"},
|
||||
sessions: &sync.Map{}, // DNS Session ID -> DNSSession
|
||||
messages: &sync.Map{}, // In progress message streams
|
||||
TTL: 0,
|
||||
MaxTXTLength: defaultMaxTXTLength,
|
||||
EnforceOTP: enforceOTP,
|
||||
}
|
||||
dnsLog.Infof("Starting DNS listener for %v (canaries: %v) ...", domains, canaries)
|
||||
dns.HandleFunc(".", func(writer dns.ResponseWriter, req *dns.Msg) {
|
||||
@@ -310,12 +306,12 @@ func (p *PendingEnvelope) Insert(dnsMsg *dnspb.DNSMessage) bool {
|
||||
|
||||
// SliverDNSServer - DNS server implementation
|
||||
type SliverDNSServer struct {
|
||||
server *dns.Server
|
||||
sessions *sync.Map
|
||||
messages *sync.Map
|
||||
totpToSessionID *sync.Map
|
||||
TTL uint32
|
||||
MaxTXTLength int
|
||||
server *dns.Server
|
||||
sessions *sync.Map
|
||||
messages *sync.Map
|
||||
TTL uint32
|
||||
MaxTXTLength int
|
||||
EnforceOTP bool
|
||||
}
|
||||
|
||||
// Shutdown - Shutdown the DNS server
|
||||
@@ -465,33 +461,29 @@ func (s *SliverDNSServer) refusedErrorResp(req *dns.Msg) *dns.Msg {
|
||||
func (s *SliverDNSServer) handleTOTP(domain string, msg *dnspb.DNSMessage, req *dns.Msg) *dns.Msg {
|
||||
dnsLog.Debugf("[dns] totp request: %v", msg)
|
||||
totpCode := fmt.Sprintf("%08d", msg.ID)
|
||||
valid, err := cryptography.ValidateTOTP(totpCode)
|
||||
if err != nil || !valid {
|
||||
dnsLog.Warnf("totp request invalid (%v)", err)
|
||||
return s.nameErrorResp(req)
|
||||
if s.EnforceOTP {
|
||||
valid, err := cryptography.ValidateTOTP(totpCode)
|
||||
if err != nil || !valid {
|
||||
dnsLog.Warnf("totp request invalid (%v)", err)
|
||||
return s.nameErrorResp(req)
|
||||
}
|
||||
dnsLog.Debugf("[dns] totp request valid")
|
||||
} else {
|
||||
dnsLog.Warn("[dns] totp validation is disabled")
|
||||
}
|
||||
dnsLog.Debugf("[dns] totp request valid")
|
||||
|
||||
// Queries must be deterministic, so create or load the dns session id
|
||||
// we'll likely get multiple queries for the same domain
|
||||
actualID, loaded := s.totpToSessionID.LoadOrStore(totpCode, dnsSessionID())
|
||||
dnsSessionID := actualID.(uint32)
|
||||
dnsSessionID := dnsSessionID()
|
||||
dnsLog.Debugf("[dns] Assigned new dns session id = %d", dnsSessionID&sessionIDBitMask)
|
||||
if !loaded {
|
||||
s.sessions.Store(dnsSessionID&sessionIDBitMask, &DNSSession{
|
||||
ID: dnsSessionID & sessionIDBitMask,
|
||||
outgoingMsgIDs: []uint32{},
|
||||
outgoingBuffers: map[uint32][]byte{},
|
||||
outgoingMutex: &sync.RWMutex{},
|
||||
incomingEnvelopes: map[uint32]*PendingEnvelope{},
|
||||
incomingMutex: &sync.Mutex{},
|
||||
msgCount: uint32(0),
|
||||
})
|
||||
go func() {
|
||||
time.Sleep(90 * time.Second) // Best effort to remove totp code after expiration
|
||||
s.totpToSessionID.Delete(totpCode)
|
||||
}()
|
||||
}
|
||||
s.sessions.Store(dnsSessionID&sessionIDBitMask, &DNSSession{
|
||||
ID: dnsSessionID & sessionIDBitMask,
|
||||
outgoingMsgIDs: []uint32{},
|
||||
outgoingBuffers: map[uint32][]byte{},
|
||||
outgoingMutex: &sync.RWMutex{},
|
||||
incomingEnvelopes: map[uint32]*PendingEnvelope{},
|
||||
incomingMutex: &sync.Mutex{},
|
||||
msgCount: uint32(0),
|
||||
})
|
||||
|
||||
resp := new(dns.Msg)
|
||||
resp.SetReply(req)
|
||||
resp.Authoritative = true
|
||||
|
||||
@@ -140,7 +140,7 @@ func reassemble(t *testing.T, parent string, size int, encoder encoders.Encoder)
|
||||
}
|
||||
|
||||
func TestIsC2Domain(t *testing.T) {
|
||||
listener := StartDNSListener("", uint16(9999), c2Domains, false)
|
||||
listener := StartDNSListener("", uint16(9999), c2Domains, false, true)
|
||||
isC2, domain := listener.isC2SubDomain(c2Domains, "asdf.1.example.com.")
|
||||
if !isC2 {
|
||||
t.Fatal("IsC2Domain expected true, got false")
|
||||
@@ -163,7 +163,7 @@ func TestIsC2Domain(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestDetermineLikelyEncoders(t *testing.T) {
|
||||
listener := StartDNSListener("", uint16(9999), c2Domains, false)
|
||||
listener := StartDNSListener("", uint16(9999), c2Domains, false, true)
|
||||
sample := randomDataRandomSize(2048)
|
||||
b58Sample := string(encoders.Base58{}.Encode(sample))
|
||||
likelyEncoders := listener.determineLikelyEncoders(b58Sample)
|
||||
|
||||
+3
-3
@@ -146,8 +146,8 @@ func StartWGListenerJob(listenPort uint16, nListenPort uint16, keyExchangeListen
|
||||
}
|
||||
|
||||
// StartDNSListenerJob - Start a DNS listener as a job
|
||||
func StartDNSListenerJob(bindIface string, lport uint16, domains []string, canaries bool) (*core.Job, error) {
|
||||
server := StartDNSListener(bindIface, lport, domains, canaries)
|
||||
func StartDNSListenerJob(bindIface string, lport uint16, domains []string, canaries bool, enforceOTP bool) (*core.Job, error) {
|
||||
server := StartDNSListener(bindIface, lport, domains, canaries, enforceOTP)
|
||||
description := fmt.Sprintf("%s (canaries %v)", strings.Join(domains, " "), canaries)
|
||||
job := &core.Job{
|
||||
ID: core.NextJobID(),
|
||||
@@ -362,7 +362,7 @@ func StartPersistentJobs(cfg *configs.ServerConfig) error {
|
||||
}
|
||||
|
||||
for _, j := range cfg.Jobs.DNS {
|
||||
job, err := StartDNSListenerJob(j.Host, j.Port, j.Domains, j.Canaries)
|
||||
job, err := StartDNSListenerJob(j.Host, j.Port, j.Domains, j.Canaries, j.EnforceOTP)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -23,7 +23,6 @@ import (
|
||||
"path"
|
||||
|
||||
"github.com/bishopfox/sliver/server/log"
|
||||
|
||||
"golang.org/x/crypto/acme/autocert"
|
||||
)
|
||||
|
||||
|
||||
@@ -1,10 +1,5 @@
|
||||
package certs
|
||||
|
||||
import (
|
||||
"crypto/rand"
|
||||
"crypto/rsa"
|
||||
)
|
||||
|
||||
/*
|
||||
Sliver Implant Framework
|
||||
Copyright (C) 2019 Bishop Fox
|
||||
@@ -23,6 +18,11 @@ import (
|
||||
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import (
|
||||
"crypto/rand"
|
||||
"crypto/rsa"
|
||||
)
|
||||
|
||||
const (
|
||||
// HTTPSCA - Directory containing operator certificates
|
||||
HTTPSCA = "https"
|
||||
|
||||
@@ -1,5 +1,23 @@
|
||||
package certs
|
||||
|
||||
/*
|
||||
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 (
|
||||
"encoding/hex"
|
||||
"errors"
|
||||
|
||||
@@ -34,7 +34,6 @@ import (
|
||||
"github.com/bishopfox/sliver/server/console"
|
||||
"github.com/bishopfox/sliver/server/cryptography"
|
||||
"github.com/bishopfox/sliver/server/daemon"
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
|
||||
@@ -35,7 +35,7 @@ import (
|
||||
|
||||
const (
|
||||
httpC2ConfigFileName = "http-c2.json"
|
||||
chromeBaseVer = 92
|
||||
chromeBaseVer = 97
|
||||
)
|
||||
|
||||
// HTTPC2Config - Parent config file struct for implant/server
|
||||
|
||||
@@ -93,11 +93,12 @@ type WGJobConfig struct {
|
||||
|
||||
// DNSJobConfig - Persistent DNS job config
|
||||
type DNSJobConfig struct {
|
||||
Domains []string `json:"domains"`
|
||||
Canaries bool `json:"canaries"`
|
||||
Host string `json:"host"`
|
||||
Port uint16 `json:"port"`
|
||||
JobID string `json:"job_id"`
|
||||
Domains []string `json:"domains"`
|
||||
Canaries bool `json:"canaries"`
|
||||
Host string `json:"host"`
|
||||
Port uint16 `json:"port"`
|
||||
JobID string `json:"job_id"`
|
||||
EnforceOTP bool `json:"enforce_otp"`
|
||||
}
|
||||
|
||||
// HTTPJobConfig - Persistent HTTP job config
|
||||
|
||||
@@ -150,6 +150,7 @@ func ImplantConfigFromProtobuf(pbConfig *clientpb.ImplantConfig) (string, *model
|
||||
cfg.Debug = pbConfig.Debug
|
||||
cfg.Evasion = pbConfig.Evasion
|
||||
cfg.ObfuscateSymbols = pbConfig.ObfuscateSymbols
|
||||
cfg.ConnectionStrategy = pbConfig.ConnectionStrategy
|
||||
|
||||
cfg.WGImplantPrivKey = pbConfig.WGImplantPrivKey
|
||||
cfg.WGServerPubKey = pbConfig.WGServerPubKey
|
||||
@@ -267,6 +268,7 @@ func SliverShellcode(name string, config *models.ImplantConfig) (string, error)
|
||||
GOROOT: gogo.GetGoRootDir(appDir),
|
||||
GOPROXY: getGoProxy(),
|
||||
HTTPPROXY: getGoHttpProxy(),
|
||||
HTTPSPROXY: getGoHttpsProxy(),
|
||||
|
||||
Obfuscation: config.ObfuscateSymbols,
|
||||
GOGARBLE: goPrivate(config),
|
||||
@@ -340,6 +342,7 @@ func SliverSharedLibrary(name string, config *models.ImplantConfig) (string, err
|
||||
GOROOT: gogo.GetGoRootDir(appDir),
|
||||
GOPROXY: getGoProxy(),
|
||||
HTTPPROXY: getGoHttpProxy(),
|
||||
HTTPSPROXY: getGoHttpsProxy(),
|
||||
|
||||
Obfuscation: config.ObfuscateSymbols,
|
||||
GOGARBLE: goPrivate(config),
|
||||
@@ -349,7 +352,7 @@ func SliverSharedLibrary(name string, config *models.ImplantConfig) (string, err
|
||||
return "", err
|
||||
}
|
||||
|
||||
dest := path.Join(goConfig.ProjectDir, "bin", path.Base(name))
|
||||
dest := filepath.Join(goConfig.ProjectDir, "bin", filepath.Base(name))
|
||||
if goConfig.GOOS == WINDOWS {
|
||||
dest += ".dll"
|
||||
}
|
||||
@@ -365,6 +368,10 @@ func SliverSharedLibrary(name string, config *models.ImplantConfig) (string, err
|
||||
if !config.Debug && goConfig.GOOS == WINDOWS {
|
||||
ldflags[0] += " -H=windowsgui"
|
||||
}
|
||||
// Statically link Linux .so files to avoid glibc hell
|
||||
if goConfig.GOOS == LINUX && goConfig.CC != "" && goConfig.CGO == "1" {
|
||||
ldflags[0] += " -linkmode external -extldflags \"-static\""
|
||||
}
|
||||
// Keep those for potential later use
|
||||
gcflags := ""
|
||||
asmflags := ""
|
||||
@@ -374,7 +381,7 @@ func SliverSharedLibrary(name string, config *models.ImplantConfig) (string, err
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
config.FileName = path.Base(dest)
|
||||
config.FileName = filepath.Base(dest)
|
||||
|
||||
err = ImplantBuildSave(name, config, dest)
|
||||
if err != nil {
|
||||
@@ -401,6 +408,7 @@ func SliverExecutable(name string, config *models.ImplantConfig) (string, error)
|
||||
GOMODCACHE: gogo.GetGoModCache(appDir),
|
||||
GOPROXY: getGoProxy(),
|
||||
HTTPPROXY: getGoHttpProxy(),
|
||||
HTTPSPROXY: getGoHttpsProxy(),
|
||||
|
||||
Obfuscation: config.ObfuscateSymbols,
|
||||
GOGARBLE: goPrivate(config),
|
||||
@@ -669,14 +677,18 @@ func getCrossCompilersFromEnv(targetGoos string, targetGoarch string) (string, s
|
||||
|
||||
// Get Defaults
|
||||
if targetGoarch == "amd64" {
|
||||
cc = os.Getenv(SliverCC64EnvVar)
|
||||
if os.Getenv(fmt.Sprintf(SliverPlatformCC64EnvVar, TARGET_GOOS)) != "" {
|
||||
cc = os.Getenv(fmt.Sprintf(SliverPlatformCC64EnvVar, TARGET_GOOS))
|
||||
}
|
||||
cxx = os.Getenv(SliverCXX64EnvVar)
|
||||
if cc == "" {
|
||||
cc = os.Getenv(SliverCC64EnvVar)
|
||||
}
|
||||
if os.Getenv(fmt.Sprintf(SliverPlatformCXX64EnvVar, TARGET_GOOS)) != "" {
|
||||
cc = os.Getenv(fmt.Sprintf(SliverPlatformCXX64EnvVar, TARGET_GOOS))
|
||||
}
|
||||
if cxx == "" {
|
||||
cxx = os.Getenv(SliverCXX64EnvVar)
|
||||
}
|
||||
}
|
||||
if targetGoarch == "386" {
|
||||
cc = os.Getenv(SliverCC32EnvVar)
|
||||
@@ -713,11 +725,9 @@ func findCrossCompilers(targetGoos string, targetGoarch string) (string, string)
|
||||
// Check to see if CC and CXX exist
|
||||
if _, err := os.Stat(cc); os.IsNotExist(err) {
|
||||
buildLog.Warnf("CC path '%s' does not exist", cc)
|
||||
cc = "" // Path does not exist
|
||||
}
|
||||
if _, err := os.Stat(cxx); os.IsNotExist(err) {
|
||||
buildLog.Warnf("CXX path '%s' does not exist", cxx)
|
||||
cxx = "" // Path does not exist
|
||||
}
|
||||
buildLog.Debugf(" CC = '%s'", cc)
|
||||
buildLog.Debugf("CXX = '%s'", cxx)
|
||||
@@ -872,6 +882,16 @@ func getGoHttpProxy() string {
|
||||
return ""
|
||||
}
|
||||
|
||||
func getGoHttpsProxy() string {
|
||||
value, present := os.LookupEnv("HTTPS_PROXY")
|
||||
if present {
|
||||
buildLog.Debugf("Using HTTPS_PROXY from env: %s", value)
|
||||
return value
|
||||
}
|
||||
buildLog.Debugf("No HTTPS_PROXY found")
|
||||
return ""
|
||||
}
|
||||
|
||||
const (
|
||||
// GoPrivate - The default Go private arg to garble when obfuscation is enabled.
|
||||
// Wireguard dependencies prevent the use of wildcard github.com/* and golang.org/*.
|
||||
|
||||
@@ -78,6 +78,12 @@ func getDonut(data []byte, config *donut.DonutConfig) (shellcode []byte, err err
|
||||
return
|
||||
}
|
||||
shellcode = res.Bytes()
|
||||
stackCheckPrologue := []byte{
|
||||
// Check stack is 8 byte but not 16 byte aligned or else errors in LoadLibrary
|
||||
0x48, 0x83, 0xE4, 0xF0, // and rsp,0xfffffffffffffff0
|
||||
0x48, 0x83, 0xC4, 0x08, // add rsp,0x8
|
||||
}
|
||||
shellcode = append(stackCheckPrologue, shellcode...)
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
+7
-1
@@ -56,6 +56,7 @@ type GoConfig struct {
|
||||
CC string
|
||||
CXX string
|
||||
HTTPPROXY string
|
||||
HTTPSPROXY string
|
||||
|
||||
Obfuscation bool
|
||||
GOGARBLE string
|
||||
@@ -117,6 +118,7 @@ func GarbleCmd(config GoConfig, cwd string, command []string) ([]byte, error) {
|
||||
fmt.Sprintf("GOPROXY=%s", config.GOPROXY),
|
||||
fmt.Sprintf("GARBLE_MAX_LITERAL_SIZE=%s", garbleMaxLiteralSize()),
|
||||
fmt.Sprintf("HTTP_PROXY=%s", config.HTTPPROXY),
|
||||
fmt.Sprintf("HTTPS_PROXY=%s", config.HTTPSPROXY),
|
||||
fmt.Sprintf("PATH=%s:%s", filepath.Join(config.GOROOT, "bin"), os.Getenv("PATH")),
|
||||
fmt.Sprintf("GOGARBLE=%s", config.GOGARBLE),
|
||||
}
|
||||
@@ -124,7 +126,10 @@ func GarbleCmd(config GoConfig, cwd string, command []string) ([]byte, error) {
|
||||
var stderr bytes.Buffer
|
||||
cmd.Stdout = &stdout
|
||||
cmd.Stderr = &stderr
|
||||
|
||||
gogoLog.Debugf("--- env ---\n")
|
||||
for _, envVar := range cmd.Env {
|
||||
gogoLog.Debugf("%s\n", envVar)
|
||||
}
|
||||
gogoLog.Infof("garble cmd: '%v'", cmd)
|
||||
err := cmd.Run()
|
||||
if err != nil {
|
||||
@@ -155,6 +160,7 @@ func GoCmd(config GoConfig, cwd string, command []string) ([]byte, error) {
|
||||
fmt.Sprintf("GOMODCACHE=%s", config.GOMODCACHE),
|
||||
fmt.Sprintf("GOPROXY=%s", config.GOPROXY),
|
||||
fmt.Sprintf("HTTP_PROXY=%s", config.HTTPPROXY),
|
||||
fmt.Sprintf("HTTPS_PROXY=%s", config.HTTPSPROXY),
|
||||
fmt.Sprintf("PATH=%s:%s", filepath.Join(config.GOROOT, "bin"), os.Getenv("PATH")),
|
||||
}
|
||||
var stdout bytes.Buffer
|
||||
|
||||
@@ -159,17 +159,18 @@ func (rpc *Server) StartDNSListener(ctx context.Context, req *clientpb.DNSListen
|
||||
listenPort = uint16(req.Port)
|
||||
}
|
||||
|
||||
job, err := c2.StartDNSListenerJob(req.Host, listenPort, req.Domains, req.Canaries)
|
||||
job, err := c2.StartDNSListenerJob(req.Host, listenPort, req.Domains, req.Canaries, req.EnforceOTP)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if req.Persistent {
|
||||
cfg := &configs.DNSJobConfig{
|
||||
Domains: req.Domains,
|
||||
Host: req.Host,
|
||||
Port: listenPort,
|
||||
Canaries: req.Canaries,
|
||||
Domains: req.Domains,
|
||||
Host: req.Host,
|
||||
Port: listenPort,
|
||||
Canaries: req.Canaries,
|
||||
EnforceOTP: req.EnforceOTP,
|
||||
}
|
||||
configs.GetServerConfig().AddDNSJob(cfg)
|
||||
job.PersistentID = cfg.JobID
|
||||
|
||||
Reference in new issue
Block a user