Compare commits

...
357 Commits
Author SHA1 Message Date
rkervella 6553084d4e lib-inject wip 2021-12-15 15:55:29 -08:00
rkervella 21fa8c71d8 Use extended std lib for memfd 2021-12-15 08:28:17 -08:00
moloch-- a37749bf50 Fix byte type 2021-12-02 21:32:40 -06:00
rkervella 0c7c7b54d3 Fix #544 2021-11-30 10:18:09 +01:00
rkervella 832ac585f7 Merge branch 'cert-issue' into stage 2021-11-30 10:09:59 +01:00
Joe 14492dfbcb Merge pull request #550 from usiegl00/stage
Expand tilde in generate file path
2021-11-29 20:10:24 -06:00
usiegl00 1e283e54a9 Expand tilde in generate file path 2021-11-30 09:59:05 +09:00
Ronan Kervella f679e99403 Merge pull request #549 from usiegl00/stage
Add CmdLine to Windows process list.
2021-11-29 12:09:11 +01:00
usiegl00 aab7143708 Add CmdLine to Windows process list 2021-11-29 19:19:14 +09:00
Joe 886ab348f4 Merge pull request #548 from cmprmsd/patch-1
Add Bitdefender Process Names
2021-11-28 15:07:49 -06:00
cmprmsd 8211f8f0e4 Add Bitdefender Process Names
Feel free to remove the source that I added to find out about "Bitdefender redline update"
2021-11-28 11:46:47 +01:00
rkervella 483654d58f Fix error check during client cert generation 2021-11-26 12:52:34 +01:00
rkervella b87a7034a9 Only log in when in debug mode 2021-11-22 09:55:56 +01:00
moloch-- edc6d21c23 Fixed dns beacon reconnect problems 2021-11-20 16:23:44 -06:00
moloch-- 31ca964e6c Fixes to beacon key life cycle 2021-11-20 15:36:31 -06:00
moloch-- 735ae74f1d Fix state revert bug 2021-11-20 14:54:12 -06:00
moloch-- 49679538eb Made beacon registration eventable 2021-11-20 14:27:31 -06:00
moloch-- 000ca54a15 nil resp check 2021-11-20 11:29:16 -06:00
moloch-- eb615f3add Fixed poll truncation/race issue #540 2021-11-20 11:23:37 -06:00
moloch-- acb0f857b3 Force generation of secure password 2021-11-20 09:54:23 -06:00
moloch-- 610d8b18c9 Force generation of secure password 2021-11-20 09:51:12 -06:00
moloch-- edf126c149 Warn user about socks proxy creds 2021-11-20 09:48:33 -06:00
moloch-- 1794d0cebd Renable socks user/pw 2021-11-20 09:45:07 -06:00
moloch-- e66d563f65 Fix nil RemoteAddr deref 2021-11-20 09:38:51 -06:00
moloch-- 8dd2b5d7ce Update socks api usage 2021-11-20 09:00:41 -06:00
moloch-- 10246681ba Switched deps to fork of memmod and go-socks5 2021-11-20 08:47:24 -06:00
moloch-- ed19017941 Update table 2021-11-20 08:37:46 -06:00
moloch-- c0116cc9d5 Tweaks to socks ux 2021-11-20 08:22:20 -06:00
moloch-- a890812a0a Fix logging levels 2021-11-19 20:43:30 -06:00
moloch-- b1922bce73 Fix log import 2021-11-19 20:15:39 -06:00
moloch-- 47aaeb0225 Merge socks 2021-11-19 19:44:56 -06:00
moloch-- 61c844db44 Rebase 2021-11-19 19:41:23 -06:00
moloch-- 35bbc61a9a Stage socks branch 2021-11-19 19:39:57 -06:00
moloch-- 6453f477f4 Fix fmt import 2021-11-19 19:39:57 -06:00
moloch-- b0709a364a Tweaked dns c2 2021-11-19 19:39:55 -06:00
moloch-- 2e65e1842f Moving to per-c2 opts 2021-11-19 19:39:45 -06:00
moloch-- c068664854 Wire dns c2 to beacon interface 2021-11-19 19:39:45 -06:00
moloch-- e9debcc2a4 Increase default workers 2021-11-19 19:39:45 -06:00
moloch-- 7ae2d0a481 DNS C2 mvp 2021-11-19 19:39:44 -06:00
moloch-- b62e3354e0 Wired send loop 2021-11-19 19:39:44 -06:00
moloch-- e55afa7efe Outlined the rest of server-side dns c2 2021-11-19 19:39:44 -06:00
moloch-- 65dc11a40e Wired dns recv to core 2021-11-19 19:39:44 -06:00
moloch-- 2620673f50 More/larger tests 2021-11-19 19:39:44 -06:00
moloch-- e22d3ac58e Re-assemble unit tests 2021-11-19 19:39:44 -06:00
moloch-- 604c3480cf Updated garble 2021-11-19 19:39:44 -06:00
rkervella ca8544a169 No need for CGO for shellcodes anymore 2021-11-19 19:39:44 -06:00
rkervella e1713bd418 Add missing Request field 2021-11-19 19:39:44 -06:00
rkervella 0649a2680b Switch upstream memmod to up to date version 2021-11-19 19:39:44 -06:00
rkervella 280f5c6be7 Fix flag name 2021-11-19 19:39:44 -06:00
rkervella 77ddfd8013 Add error handling 2021-11-19 19:39:44 -06:00
rkervella 48d2eed385 Replace protobuf annotations with unique strings 2021-11-19 19:39:44 -06:00
moloch-- 36d531fa86 Entrypoint -> StartW 2021-11-19 19:39:44 -06:00
moloch-- ab2ab45edc Improved worker/queue pattern 2021-11-19 19:39:44 -06:00
moloch-- 2b2c1bdc13 splitBuffer tests for max parent 2021-11-19 19:39:44 -06:00
moloch-- 983b5476bd splitBuffer tests for b32 and b58 2021-11-19 19:39:43 -06:00
moloch-- cbd95a2003 tests and fixes for splitBuffer 2021-11-19 19:39:43 -06:00
moloch-- a3b1693a41 dnsclient unit tests 2021-11-19 19:39:43 -06:00
moloch-- 434ca2fee9 Improved unit tests 2021-11-19 19:39:43 -06:00
moloch-- 92ef847a59 wip on server-side send/recv impl 2021-11-19 19:39:43 -06:00
moloch-- 800c584397 Added variable encoding, wip 2021-11-19 19:39:43 -06:00
moloch-- b2a2dac63b Initial fingerprint impl working 2021-11-19 19:39:43 -06:00
moloch-- 954616b5a3 outlined fingerprint scheme 2021-11-19 19:39:43 -06:00
moloch-- 2cd4264101 Abstracted resolver impl 2021-11-19 19:39:43 -06:00
moloch-- b8d78c56e9 Platform specific find resolvers 2021-11-19 19:39:43 -06:00
moloch-- c5262aa807 Platform specific find resolvers 2021-11-19 19:39:43 -06:00
moloch-- 17dba3543d wip on dns c2 updates 2021-11-19 19:39:43 -06:00
moloch-- 7b0a83027e Modified base58 alphabet 2021-11-19 19:39:43 -06:00
moloch-- f46f7a36ff Updated b58 unit tests 2021-11-19 19:39:43 -06:00
moloch-- a369c46952 Base62 -> Base58 2021-11-19 19:39:43 -06:00
moloch-- 907ef9ca2f Updated lics 2021-11-19 19:39:43 -06:00
moloch-- 4df5c78b7e Obfuscate more of the pkgs, limited pkg obfuscation is currently broken 2021-11-19 19:39:43 -06:00
moloch-- 3765e016b4 Updated garble 2021-11-19 19:39:42 -06:00
moloch-- 6fa06e8d74 Updated garble 2021-11-19 19:39:42 -06:00
moloch-- c3841efcef Fix dns imports 2021-11-19 19:39:42 -06:00
moloch-- 508e9ab9d9 dns wip 2021-11-19 19:39:42 -06:00
moloch-- 433482031c added pb 2021-11-19 19:39:42 -06:00
moloch-- a4a94eca98 some initial refactoring 2021-11-19 19:39:42 -06:00
moloch-- ecea6049a8 check n bytes 2021-11-19 19:39:42 -06:00
moloch-- 1767c34f47 Go v1.17.2 2021-11-19 19:39:42 -06:00
moloch-- 6fd1e4802b Cleanup tunnel read() 2021-11-19 19:39:42 -06:00
moloch-- f745d9524e Remove server core import 2021-11-19 19:39:42 -06:00
rkervella a8464d5b0c Fix DLL hijack protobuf 2021-11-19 19:39:40 -06:00
rkervella cc7a56e07b Close connection once payload has been sent. 2021-11-19 19:38:32 -06:00
Chris Smith cdbf93d64b Enable hyphen in operator names 2021-11-19 19:38:32 -06:00
rkervella fdd319f6f3 Handle 32 bits PE for sideload/spawndll. Fix crash on unhandled OptionalHeader type 2021-11-19 19:38:32 -06:00
dependabot[bot] 22f840acbd Bump nokogiri from 1.11.7 to 1.12.5 in /docs
Bumps [nokogiri](https://github.com/sparklemotion/nokogiri) from 1.11.7 to 1.12.5.
- [Release notes](https://github.com/sparklemotion/nokogiri/releases)
- [Changelog](https://github.com/sparklemotion/nokogiri/blob/main/CHANGELOG.md)
- [Commits](https://github.com/sparklemotion/nokogiri/compare/v1.11.7...v1.12.5)

---
updated-dependencies:
- dependency-name: nokogiri
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <[email protected]>
2021-11-19 19:38:32 -06:00
moloch-- 9d200bb2aa mvp of open session 2021-11-19 19:38:32 -06:00
moloch-- 17b6cf7a5e OpenSession wip 2021-11-19 19:38:30 -06:00
moloch-- 22efd18301 Modified connection pattern to support runtime values 2021-11-19 19:38:14 -06:00
rkervella 4d45883c72 Fix Sprintf statement 2021-11-19 19:36:56 -06:00
rkervella b98bf6ef53 Fix short flag conflict 2021-11-19 19:36:56 -06:00
rkervella 65ea935750 Add missing flag, rename short flag 2021-11-19 19:36:56 -06:00
rkervella 9865ee2396 Update COFF Loader version 2021-11-19 19:36:56 -06:00
rkervella ca7cf74387 Remove double build constraints 2021-11-19 19:36:56 -06:00
rkervella 9eb6fda037 Rework uintptr cast to avoid size limitation 2021-11-19 19:36:56 -06:00
rkervella 1a5eb1c118 Fix flags types and help string 2021-11-19 19:36:56 -06:00
rkervella f43d01b4b0 Add kill support for beacons 2021-11-19 19:36:54 -06:00
moloch-- 96fe3c7db8 Regenerate pb 2021-11-19 19:36:23 -06:00
Raf 8188ba689d client/command/filesystem/ls: Fix an off-by-one error that prevented the ls command from operating against the root of the drive. 2021-11-19 19:36:00 -06:00
rkervella 4517684728 Refactor to use GetInteractive() 2021-11-19 19:35:08 -06:00
rkervella ab1b72f410 Cleaning up Windows kill handler 2021-11-19 19:35:08 -06:00
rkervella fd83024e4b Add autocomplete for use 2021-11-19 19:35:08 -06:00
rkervella 18ee8e5133 Switch beacons command to the Generic help group 2021-11-19 19:35:07 -06:00
rkervella 5a96962611 Switch beacons command to the proper help group 2021-11-19 19:35:07 -06:00
rkervella 85b592b2b9 Add helpgroup for beacons 2021-11-19 19:35:07 -06:00
moloch-- 91a569f389 Implemented beacon priv cmds 2021-11-19 19:35:07 -06:00
moloch-- b646ca835c Implemented beacon registry cmds 2021-11-19 19:35:07 -06:00
moloch-- 26993f797c Implemented beacon screenshot 2021-11-19 19:35:07 -06:00
moloch-- ec743b2e85 Implemented beacon proc cmds 2021-11-19 19:35:07 -06:00
moloch-- 0ac43c69d6 Implemented task fetch for netstat 2021-11-19 19:35:07 -06:00
moloch-- a2f8bac4b1 Ported netstat to beacon/table writer 2021-11-19 19:35:07 -06:00
moloch-- 2c9643b404 Added support for GOPROXY env var and server config 2021-11-19 19:35:07 -06:00
moloch-- 1239b5fd87 Added multiplayer -p flag 2021-11-19 19:35:07 -06:00
moloch-- d904a74d14 Added new flags to http/https listeners 2021-11-19 19:35:07 -06:00
moloch-- 60aaeebe0b Added --all to ifconfig 2021-11-19 19:35:07 -06:00
moloch-- 000ecb51eb Added beacon prune command 2021-11-19 19:35:07 -06:00
moloch-- fbddd67930 Added beacon watch command 2021-11-19 19:35:07 -06:00
moloch-- 10f7b000b4 implemented ifconfig 2021-11-19 19:35:07 -06:00
moloch-- 2f3ebbfcd5 Task fetch for ssh, and env tasks 2021-11-19 19:35:06 -06:00
moloch-- b54d97b497 Implemented task fetch for exec pkg 2021-11-19 19:35:06 -06:00
moloch-- eedfb272a5 Implemented more task fetch renderers 2021-11-19 19:35:06 -06:00
moloch-- 47857e903c Added command to fetch old task results 2021-11-19 19:35:06 -06:00
moloch-- 0da314d925 Updated ssh to work with beacon 2021-11-19 19:35:06 -06:00
moloch-- c132b14272 Updated spawndll client cmd 2021-11-19 19:35:06 -06:00
moloch-- f6b7e07653 Updated server-side rpc's for execute-assembly, sideload, spawndll 2021-11-19 19:35:06 -06:00
moloch-- 60cbf09520 Ported msf/msf-remote to support beacon 2021-11-19 19:35:04 -06:00
moloch-- 0090e8dfd8 Added beacon support to execute-shellcode 2021-11-19 19:34:11 -06:00
moloch-- 099753fa74 Added beacon support to execute-assembly 2021-11-19 19:34:11 -06:00
moloch-- 6685bf486e Only paginate on 2x terminal sized tables 2021-11-19 19:34:11 -06:00
moloch-- 6d5a288626 UX improvements 2021-11-19 19:34:11 -06:00
rkervella 3bf157b29d Refactor 2021-11-19 19:34:11 -06:00
rkervella 146be0e814 Revert "Refactoring"
This reverts commit de7fd664cd.
2021-11-19 19:34:11 -06:00
rkervella 065fc3ffa6 Revert "Escape string before JSON parsing"
This reverts commit 1549b894fa.
2021-11-19 19:34:11 -06:00
rkervella d3da84731f Refactoring 2021-11-19 19:34:11 -06:00
rkervella b451d90a33 Escape string before JSON parsing 2021-11-19 19:34:11 -06:00
rkervella c01ace4a67 Add PID to bof result 2021-11-19 19:34:10 -06:00
rkervella e8d22af3bc Check for nil pointer 2021-11-19 19:34:10 -06:00
rkervella 50f83c958b Removed comment 2021-11-19 19:34:10 -06:00
rkervella 6ac9a16aa7 Remove commented code 2021-11-19 19:34:10 -06:00
rkervella caad9de26c Initial BOF support for Prelude Operator 2021-11-19 19:34:10 -06:00
rkervella 70805d04f7 Remove logging 2021-11-19 19:34:10 -06:00
moloch-- a3b98716a7 Stage socks branch 2021-11-19 19:28:52 -06:00
moloch-- 24f6a9d8ab Fix fmt import 2021-11-19 17:26:52 -06:00
moloch-- d6b5571c7e Tweaked dns c2 2021-11-19 17:02:34 -06:00
moloch-- c0b08cbd42 Moving to per-c2 opts 2021-11-19 15:09:06 -06:00
moloch-- d567a21f8c Wire dns c2 to beacon interface 2021-11-19 13:28:13 -06:00
moloch-- 105d80cdb7 Increase default workers 2021-11-19 09:33:59 -06:00
moloch-- d1627c9030 DNS C2 mvp 2021-11-18 20:10:55 -06:00
moloch-- 661732012d Wired send loop 2021-11-18 12:43:51 -06:00
moloch-- f55f248fbc Outlined the rest of server-side dns c2 2021-11-18 11:24:50 -06:00
moloch-- 6817c5a117 Wired dns recv to core 2021-11-18 08:56:17 -06:00
moloch-- 6b31d6985a More/larger tests 2021-11-17 19:47:42 -06:00
moloch-- 47357c346a Re-assemble unit tests 2021-11-17 19:38:28 -06:00
moloch-- 970ff6b80b Updated garble 2021-11-17 14:48:01 -06:00
moloch-- 126dc44c44 Merge branch 'stage' into v1.5.0_dns2 2021-11-17 13:53:00 -06:00
moloch-- 4abc395485 Entrypoint -> StartW 2021-11-16 08:52:18 -06:00
rkervella 0f5284fb2d No need for CGO for shellcodes anymore 2021-11-15 14:21:32 +01:00
moloch-- 0f4dc27498 Improved worker/queue pattern 2021-11-14 15:16:39 -06:00
moloch-- 7ea5039e9a splitBuffer tests for max parent 2021-11-14 13:25:58 -06:00
moloch-- b1e4a016d4 splitBuffer tests for b32 and b58 2021-11-14 13:19:18 -06:00
moloch-- 785810ebea tests and fixes for splitBuffer 2021-11-14 10:44:52 -06:00
moloch-- 5779f337d0 dnsclient unit tests 2021-11-14 09:10:28 -06:00
moloch-- ab93f0d1c6 Improved unit tests 2021-11-13 13:40:15 -06:00
moloch-- d4cc59d1e6 wip on server-side send/recv impl 2021-11-09 18:43:55 -06:00
rkervella 03d1f92441 Merge branch 'v1.5.0_beacon' into stage 2021-11-09 11:23:24 +01:00
rkervella 77ddf234bd Add missing Request field 2021-11-09 11:22:02 +01:00
rkervella a53bc17665 Switch upstream memmod to up to date version 2021-11-08 10:09:14 +01:00
moloch-- 1682f58801 Added variable encoding, wip 2021-11-06 19:16:06 -05:00
moloch-- 3d4e76990c Initial fingerprint impl working 2021-11-06 13:14:46 -05:00
moloch-- d97fb249a8 outlined fingerprint scheme 2021-11-05 17:46:29 -05:00
rkervella e8714dbdec Fix flag name 2021-11-03 11:48:59 +01:00
rkervella f69a4f8b92 Add error handling 2021-11-03 10:34:04 +01:00
moloch-- c2925a8a57 Abstracted resolver impl 2021-11-02 19:46:14 -05:00
moloch-- 6484b0c5a6 Platform specific find resolvers 2021-11-01 10:59:37 -05:00
moloch-- 338b8bb5b2 Platform specific find resolvers 2021-11-01 10:55:12 -05:00
moloch-- 15ca3871dd wip on dns c2 updates 2021-10-31 15:50:13 -05:00
moloch-- f11a1333bb Modified base58 alphabet 2021-10-31 10:40:27 -05:00
moloch-- 4a2c9cb50e Updated b58 unit tests 2021-10-31 10:36:28 -05:00
moloch-- c8928b4864 Base62 -> Base58 2021-10-31 10:35:34 -05:00
moloch-- 13ecb9782b Updated lics 2021-10-30 15:33:23 -05:00
moloch-- 05ce79e986 Obfuscate more of the pkgs, limited pkg obfuscation is currently broken 2021-10-30 15:26:31 -05:00
moloch-- a3c7d057f6 Updated garble 2021-10-30 13:00:16 -05:00
moloch-- b3277d0f4c Updated garble 2021-10-30 12:51:09 -05:00
moloch-- 1f0e9d6995 Fix dns imports 2021-10-30 12:16:57 -05:00
moloch-- 478f677f55 dns wip 2021-10-30 11:30:22 -05:00
moloch-- 7463298de1 added pb 2021-10-30 09:45:19 -05:00
moloch-- 7306d439e1 some initial refactoring 2021-10-30 08:22:59 -05:00
rkervella 66d6e8043a Merge branch 'dont-merge-that' into stage 2021-10-29 19:00:40 +02:00
rkervella 11505d8f94 Replace protobuf annotations with unique strings 2021-10-29 19:00:13 +02:00
moloch-- 452d7b7fce check n bytes 2021-10-27 16:43:18 -05:00
moloch-- 606c5ac948 Go v1.17.2 2021-10-22 08:31:58 -05:00
moloch-- 8ee4f786b4 Cleanup tunnel read() 2021-10-21 08:46:15 -05:00
moloch-- 79a96368d0 Remove server core import 2021-10-21 08:44:00 -05:00
moloch-- 8176068bb5 Merge latest v1.5 2021-10-21 08:31:03 -05:00
moloch-- ff8de9922e Merge master 2021-10-21 08:29:05 -05:00
Ronan Kervella 13cbf53851 Merge pull request #527 from BishopFox/dll-hijack-fix
DLL Hijack update
2021-10-21 15:17:37 +02:00
rkervella 56f339c8a3 Fix Sprintf statement 2021-10-21 15:13:29 +02:00
rkervella e31fd56730 Fix DLL hijack protobuf 2021-10-21 14:45:55 +02:00
Ronan Kervella 9af5d9126f Merge pull request #525 from BishopFox/fix-stager-close-conn
Close TCP connection on TCP stager
2021-10-12 12:49:09 +02:00
rkervella d9499c26a1 Close connection once payload has been sent. 2021-10-12 12:21:49 +02:00
Ronan Kervella 5bd101bc47 Merge pull request #524 from BishopFox/bugfix/fix-operator-usernames
Enable hyphen in operator names
2021-10-12 10:57:30 +02:00
Chris Smith 0e1d21bb28 Enable hyphen in operator names 2021-10-12 05:20:15 +00:00
Ronan Kervella 1f5a950752 Merge pull request #523 from BishopFox/fix-spawndll-crash
Handle 32 bits PE for sideload/spawndll. Fix crash on unhandled OptionalHeader type
2021-10-11 11:43:10 +02:00
rkervella 3a1ff3fa52 Handle 32 bits PE for sideload/spawndll. Fix crash on unhandled OptionalHeader type 2021-10-11 09:43:47 +02:00
moloch-- 9db930b10f mvp of open session 2021-10-09 17:49:03 -05:00
a3sroot 2fa6bc2e59 Defective socks 2021-10-05 11:57:29 +08:00
moloch-- 2e3f92ed22 OpenSession wip 2021-10-04 17:35:51 -05:00
rkervella c552a2fd9f Fix short flag conflict 2021-10-01 12:11:27 +02:00
rkervella e729576a6d Add missing flag, rename short flag 2021-10-01 12:05:32 +02:00
moloch-- c9f04b0a1c Modified connection pattern to support runtime values 2021-09-28 13:02:18 -10:00
rkervella a439c39d64 Update COFF Loader version 2021-09-28 10:44:58 +02:00
rkervella 0471a219c4 Remove double build constraints 2021-09-28 10:35:00 +02:00
rkervella 6631727242 Rework uintptr cast to avoid size limitation 2021-09-28 10:34:10 +02:00
rkervella c21171d739 Fix flags types and help string 2021-09-28 10:19:23 +02:00
Ronan Kervella 98aa4ed58c Merge pull request #518 from BishopFox/dependabot/bundler/docs/nokogiri-1.12.5
Bump nokogiri from 1.11.7 to 1.12.5 in /docs
2021-09-28 10:16:18 +02:00
rkervella 4ad1f1a561 Add kill support for beacons 2021-09-28 10:15:51 +02:00
dependabot[bot] d0a38bb792 Bump nokogiri from 1.11.7 to 1.12.5 in /docs
Bumps [nokogiri](https://github.com/sparklemotion/nokogiri) from 1.11.7 to 1.12.5.
- [Release notes](https://github.com/sparklemotion/nokogiri/releases)
- [Changelog](https://github.com/sparklemotion/nokogiri/blob/main/CHANGELOG.md)
- [Commits](https://github.com/sparklemotion/nokogiri/compare/v1.11.7...v1.12.5)

---
updated-dependencies:
- dependency-name: nokogiri
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <[email protected]>
2021-09-28 05:59:37 +00:00
rkervella ee8603b30c Merge branches 'v1.5.0_beacon' and 'stage' of bishopfox.github.com:BishopFox/sliver into stage 2021-09-27 18:19:38 +02:00
rkervella 11ea01819f Refactor to use GetInteractive() 2021-09-27 11:05:30 +02:00
rkervella da39a82b83 Cleaning up Windows kill handler 2021-09-27 10:58:48 +02:00
rkervella 3ce730a469 Add autocomplete for use 2021-09-27 10:50:58 +02:00
rkervella f52ee8c28f Switch beacons command to the Generic help group 2021-09-27 10:37:08 +02:00
rkervella 150511df9b Switch beacons command to the proper help group 2021-09-27 10:36:20 +02:00
rkervella 3e8c3fc02e Add helpgroup for beacons 2021-09-27 10:32:09 +02:00
moloch-- 019d0d40f6 Regenerate pb 2021-09-26 19:47:54 -07:00
moloch-- 268aa95169 Merged v1.5.0_beacon 2021-09-26 19:47:23 -07:00
moloch-- 7775880277 Implemented beacon priv cmds 2021-09-26 19:31:05 -07:00
moloch-- ba541ffd43 Implemented beacon registry cmds 2021-09-26 18:44:59 -07:00
moloch-- a60cc86c9a Implemented beacon screenshot 2021-09-26 18:12:32 -07:00
moloch-- 0099e06cc6 Implemented beacon proc cmds 2021-09-26 17:41:18 -07:00
moloch-- b0fdec2700 Implemented task fetch for netstat 2021-09-26 15:43:28 -07:00
moloch-- 8419cf7442 Ported netstat to beacon/table writer 2021-09-26 15:38:24 -07:00
moloch-- d470543f98 Added support for GOPROXY env var and server config 2021-09-26 10:59:46 -05:00
moloch-- 84d41f063b Added multiplayer -p flag 2021-09-25 22:47:15 -05:00
moloch-- c876f34cd0 Added new flags to http/https listeners 2021-09-25 19:42:53 -05:00
moloch-- 7ba3f87afb Added --all to ifconfig 2021-09-25 17:57:26 -05:00
moloch-- 008f9c6fde Added beacon prune command 2021-09-25 17:16:21 -05:00
moloch-- 80e6c2a24e Added beacon watch command 2021-09-25 16:15:08 -05:00
moloch-- 69842674d2 implemented ifconfig 2021-09-25 15:34:23 -05:00
moloch-- b2f9ccfab6 Task fetch for ssh, and env tasks 2021-09-25 14:34:53 -05:00
moloch-- 358b6ab20d Implemented task fetch for exec pkg 2021-09-25 13:34:52 -05:00
moloch-- 268db3ce00 Implemented more task fetch renderers 2021-09-25 12:10:24 -05:00
moloch-- 03dfb2f5d9 Added command to fetch old task results 2021-09-25 10:07:29 -05:00
moloch-- d4e809d889 Updated ssh to work with beacon 2021-09-25 08:44:38 -05:00
moloch-- 6f6fd8f0f5 Updated spawndll client cmd 2021-09-25 08:21:45 -05:00
moloch-- f5e374293c Updated server-side rpc's for execute-assembly, sideload, spawndll 2021-09-25 07:56:36 -05:00
moloch-- 8f12e35124 Ported msf/msf-remote to support beacon 2021-09-25 07:06:27 -05:00
moloch-- b27809d9ba Added beacon support to execute-shellcode 2021-09-24 22:52:13 -05:00
moloch-- 377d56bda3 Added beacon support to execute-assembly 2021-09-24 22:35:46 -05:00
moloch-- 4bcb0cb61f Only paginate on 2x terminal sized tables 2021-09-24 20:46:17 -05:00
moloch-- 9d6870e792 UX improvements 2021-09-24 19:34:44 -05:00
moloch-- 93b1e3a7b4 Fix use context switch 2021-09-23 20:37:06 -05:00
moloch-- 90f799a6f2 UX improvements 2021-09-23 19:23:13 -05:00
moloch-- 251423bc28 Improved beacon ux 2021-09-23 15:38:57 -05:00
moloch-- 03957f4d01 Fix next/last checkin for beacons 2021-09-23 13:50:31 -05:00
moloch-- a7d07e372a Bug fixes to http(s) beacons 2021-09-23 08:42:55 -05:00
moloch-- 364b0d6f57 Added http close() 2021-09-22 14:42:58 -05:00
moloch-- 52ef179988 Improved comments 2021-09-22 07:52:55 -05:00
moloch-- 79a50d24fe Go v1.17.1 2021-09-21 09:19:50 -05:00
moloch-- 4e23091147 Send hash of public key instead of public key 2021-09-20 19:02:19 -05:00
moloch-- 98e7f7abf8 New key exchange working 2021-09-20 18:32:54 -05:00
moloch-- 92e833a481 Fixes/refactor to mtls 2021-09-20 17:30:53 -05:00
moloch-- b442f95a7b Major refactor of core crypto 2021-09-20 16:33:36 -05:00
moloch-- da8d5b8a0c wip on pivots 2021-09-19 20:41:46 -05:00
moloch-- 3151b559a6 Added chacha20poly1305 to cryptography 2021-09-17 16:36:33 -05:00
moloch-- b02489a5d3 Fixes/updates operators status command 2021-09-14 19:13:42 -05:00
moloch-- eb57802c28 More strict auth checks in middleware 2021-09-14 16:45:31 -05:00
Joe 767644ddc3 Merge pull request #510 from RafBishopFox/stage
A small fix for ls
2021-09-13 17:15:29 -05:00
Raf 185913c6eb client/command/filesystem/ls: Fix an off-by-one error that prevented the ls command from operating against the root of the drive. 2021-09-13 15:22:29 -04:00
moloch-- e3093bee6e Implemented a real kick-operator cmd 2021-09-11 23:18:24 -05:00
moloch-- f6014393be Added per-operator call credentials 2021-09-11 22:39:32 -05:00
moloch-- 90de40f1ee gofmt 2021-09-11 19:57:15 -05:00
a3sroot 43548ad4b2 Merged pr #509 2021-09-11 19:54:29 -05:00
moloch-- 09358666a1 Fix null http session bug and nil ptr in sessions cmd 2021-09-11 19:14:27 -05:00
moloch-- 213ad330c5 Fixed variable shadowing issue when executing multiple tasks 2021-09-11 15:19:25 -05:00
moloch-- f7d7bdc677 Implemented async versions of all fs commands 2021-09-11 13:23:29 -05:00
moloch-- c292ac4b28 The ls command works round trip 2021-09-11 10:43:59 -05:00
moloch-- f576c138c9 Added task counts and pb descriptions 2021-09-11 09:16:47 -05:00
moloch-- 216054e90c Implemented task rpc's 2021-09-10 18:48:30 -05:00
moloch-- 62e311fb6f Beacons can return results 2021-09-10 16:25:31 -05:00
moloch-- 90de32b6f2 Added additional settings 2021-09-10 13:27:13 -05:00
rkervella cc2a5bb622 Refactor 2021-09-10 17:27:59 +02:00
moloch-- b8b20711fe Implemented async task creation 2021-09-10 09:37:38 -05:00
rkervella 3d7889183a Revert "Refactoring"
This reverts commit de7fd664cd.
2021-09-10 16:17:49 +02:00
rkervella d2297f9423 Revert "Escape string before JSON parsing"
This reverts commit 1549b894fa.
2021-09-10 16:13:47 +02:00
rkervella de7fd664cd Refactoring 2021-09-10 15:25:05 +02:00
moloch-- f87582462d Re-implemented UseCmd args 2021-09-10 07:58:28 -05:00
rkervella 1549b894fa Escape string before JSON parsing 2021-09-10 13:39:59 +02:00
rkervella 32119e09dc Add PID to bof result 2021-09-10 12:31:26 +02:00
rkervella 4dd5319987 Check for nil pointer 2021-09-10 11:06:46 +02:00
rkervella 860452c418 Removed comment 2021-09-10 10:51:55 +02:00
moloch-- 87fba59c57 Implemented client settings and customizable tables 2021-09-09 18:22:32 -05:00
moloch-- ab58a67df4 converted beacons cmd to table writer 2021-09-09 17:42:57 -05:00
moloch-- 424db7bdca Added command/settings and porting tables to use lib 2021-09-09 16:29:28 -05:00
moloch-- cec1451dec Do not export active session 2021-09-09 11:19:33 -05:00
rkervella 4d64866a15 Remove commented code 2021-09-09 10:19:27 +02:00
rkervella 1d859f99c8 Initial BOF support for Prelude Operator 2021-09-08 13:55:31 +02:00
moloch-- e79e3daf7d Updated use cmd 2021-09-07 18:11:52 -05:00
moloch-- 1a632f48ff Initial refactor of client code to support beacons and sessions 2021-09-07 17:43:35 -05:00
moloch-- 83adb36bbd Beacon rm tweaks 2021-09-06 20:43:06 -05:00
moloch-- 686452a65e Implemented rm beacon cmd 2021-09-06 20:36:08 -05:00
moloch-- e436e9ca89 Outlined beacon tasks 2021-09-06 19:49:05 -05:00
moloch-- db29281233 Implemented beacons cmd 2021-09-06 19:01:16 -05:00
moloch-- 65cea9eeb2 Wired handler to db 2021-09-06 17:47:46 -05:00
moloch-- 06a44f980b Basic beacon compiles 2021-09-06 15:06:08 -05:00
moloch-- 952f22583e Improvements to handling of poll timeout value 2021-09-06 11:14:43 -05:00
moloch-- 5429c8d45a Fix http client desync issue 2021-09-06 10:06:19 -05:00
moloch-- 9e8bfb62d7 Improvements to time handling, configurable client poll timeout 2021-09-06 09:55:47 -05:00
moloch-- 45ef2a27a9 Merged burned/health columns 2021-09-05 16:16:12 -05:00
moloch-- 93a1492a05 Fix time, moved more to int64 2021-09-05 14:05:40 -05:00
moloch-- b554b49b42 All time fields are int64 2021-09-05 12:25:10 -05:00
moloch-- e7d8495cb0 Server compiles 2021-09-05 11:16:50 -05:00
moloch-- 2ebb2734bf Merge stage, wip on server-side beacon support 2021-09-05 09:52:32 -05:00
rkervella c3f5f2bf85 Remove logging 2021-09-05 10:53:37 +02:00
rkervella 515b927791 Set default AES key 2021-09-05 09:56:17 +02:00
rkervella 35489e974f Rename operator to prelude-operator 2021-09-05 09:47:02 +02:00
rkervella e2cf688044 Merge branch 'prelude-operator' into stage 2021-09-05 09:45:55 +02:00
moloch-- 79772297bc wip on deticated beacon mode 2021-09-04 19:00:11 -05:00
moloch-- 7d4de43559 wip on deticated beacon mode 2021-09-04 17:39:08 -05:00
moloch-- 7df290386e wip on deticated beacon mode 2021-09-04 16:50:14 -05:00
moloch-- fc5673b33e Added fallback host uuid method 2021-09-04 14:10:07 -05:00
moloch-- 31a53a4cba Fix named pipe / unit tests 2021-09-04 12:59:26 -05:00
moloch-- 8967bcf35d Remove duplicate GetSpecialHandlers() 2021-09-04 12:27:34 -05:00
moloch-- 6d4b28731e Refactoring implant transports, and handlers 2021-09-04 12:11:16 -05:00
moloch-- 235201f701 Refactoring implant transports 2021-09-04 09:34:45 -05:00
rkervella d1135d1d68 Add Prelude's Operator support 2021-09-04 12:31:34 +02:00
moloch-- a998a571f9 Various fixes to http c2 transport 2021-09-03 20:49:50 -05:00
moloch-- ce3cee731c Improved c2 unit tests 2021-09-03 17:55:20 -05:00
moloch-- 9e924efcb2 Fix unit tests for matcher funcs 2021-09-03 17:43:40 -05:00
moloch-- 23309233a8 Merged stage 2021-09-03 17:18:53 -05:00
moloch-- e107382d07 Improvements to http server 2021-09-03 10:02:01 -05:00
moloch-- 9ea9d1add8 Fixes to the http router and path generation 2021-09-02 09:20:50 -05:00
moloch-- bc5a622944 Improved unit tests 2021-09-02 08:14:09 -05:00
moloch-- c24a37edcd Renamed implant generation code 2021-09-01 20:56:23 -05:00
moloch-- 536171e8ac Fix paths for sliver .c and .h 2021-09-01 16:39:21 -05:00
moloch-- 4d17f0ed66 Moved pty to build constraints in shell pkg 2021-09-01 16:23:37 -05:00
moloch-- 1e5bf9a39c Fix version build constraints 2021-09-01 16:06:07 -05:00
moloch-- 18cb8d142d Fix version pkg 2021-09-01 15:56:54 -05:00
moloch-- b3467e0512 Fix shell pkg 2021-09-01 15:38:17 -05:00
moloch-- 8a1845baf8 Major refactor to implant render code 2021-09-01 14:50:52 -05:00
moloch-- 00a2faf137 Code cleanup, added max req length 2021-09-01 09:14:32 -05:00
moloch-- 6fb3835e14 Merged stage, fix unit tests 2021-08-31 08:38:02 -05:00
moloch-- f3144eb919 wip on server-side updates 2021-08-31 07:17:32 -05:00
moloch-- 83c5fad8eb Go mod vendor 2021-08-28 18:27:37 -05:00
moloch-- bfe2013eb5 Merged otp 2021-08-28 18:19:31 -05:00
moloch-- 0923de192c Updated with other branches 2021-08-28 18:17:32 -05:00
moloch-- c41e9dead0 Session connects 2021-08-28 17:58:32 -05:00
moloch-- e989ba581b Basic outline of http/otp working 2021-08-28 14:02:26 -05:00
moloch-- 7f9657f32d WIP on otp 2021-08-27 15:26:33 -05:00
moloch-- 8cc3f1984a Updated garble 2021-08-26 17:31:01 -05:00
rkervella d337d4f13c Merge branch 'master' into stage 2021-08-23 09:42:24 +02:00
rkervella 75dd1b1a26 Add missing imports 2021-08-20 16:33:19 +02:00
rkervella 359746120a Add execute redirection to remote file 2021-08-20 16:13:59 +02:00
rkervella b08728765d Add missing import 2021-08-20 12:59:45 +02:00
rkervella cbfae11876 Reflect changes to windows executeTokenHandler 2021-08-20 12:34:25 +02:00
rkervella b7a814f0c5 Rework execute stdout/stderr handling 2021-08-20 11:58:22 +02:00
rkervella 572e717634 Move DLL hijack to client protobuf side 2021-08-20 11:23:06 +02:00
763 changed files with 49200 additions and 22243 deletions

No files matched your search

+1
View File
@@ -1,5 +1,6 @@
/.vscode/*
/.devcontainer
/.idea
/Dockerfile.*
/*.sdk.tar.xz
+2 -1
View File
@@ -24,9 +24,10 @@ Contributing to Sliver
* _Never_ use homegrown or non-peer reviewed encryption or random number generation algorithms.
* Whenever possible, use the following algorithms/encryption modes:
- AES-GCM-256
- RSA-OAEP-2048 / RSA-OAEP-4096
- SHA2-256 / HMAC-SHA2-256 or higher (e.g. SHA2-384)
- Curves P521, P384, P256
- Curve25519, XSalsa20, and Poly1305 (Nacl)
- ChaCha20Poly1305
* _Never_ use the following in a security context, and _avoid_ use even in a non-security context:
- MD5
- SHA1
+1 -1
View File
@@ -1,4 +1,4 @@
FROM golang:1.17
FROM golang:1.17.2
#
# IMPORTANT: This Dockerfile is used for testing, I do not recommend deploying
+2 -1
View File
@@ -123,6 +123,7 @@ pb:
protoc -I protobuf/ protobuf/commonpb/common.proto --go_out=paths=source_relative:protobuf/
protoc -I protobuf/ protobuf/sliverpb/sliver.proto --go_out=paths=source_relative:protobuf/
protoc -I protobuf/ protobuf/clientpb/client.proto --go_out=paths=source_relative:protobuf/
protoc -I protobuf/ protobuf/dnspb/dns.proto --go_out=paths=source_relative:protobuf/
protoc -I protobuf/ protobuf/rpcpb/services.proto --go_out=paths=source_relative:protobuf/ --go-grpc_out=protobuf/ --go-grpc_opt=paths=source_relative
.PHONY: clean-all
@@ -136,4 +137,4 @@ clean-all: clean
.PHONY: clean
clean:
rm -f sliver-client_arm64 sliver-server_arm64
rm -f sliver-client sliver-server *.exe
rm -f sliver-client sliver-server sliver-*.exe
+4 -1
View File
@@ -20,9 +20,11 @@ The server and client support MacOS, Windows, and Linux. Implants are supported
* Local and remote process injection
* Windows process migration
* Windows user token manipulation
* Anti-anti-anti-forensics
* Anti-fingerprinting features
* Let's Encrypt integration
* In-memory .NET assembly execution
* COFF/BOF in-memory loader
* Much more!
### Getting Started
@@ -43,3 +45,4 @@ See the [wiki](https://github.com/BishopFox/sliver/wiki/Compile-From-Source).
### License - GPLv3
Sliver is licensed under [GPLv3](https://www.gnu.org/licenses/gpl-3.0.en.html), some sub-components may have separate licenses. See their respective subdirectories in this project for details.
+4
View File
@@ -26,6 +26,7 @@ import (
"os"
"os/user"
"path"
"path/filepath"
"strings"
ver "github.com/bishopfox/sliver/client/version"
@@ -101,6 +102,9 @@ func Setup(force bool, echo bool) {
}
saveAssetVersion(appDir)
}
if _, err := os.Stat(filepath.Join(appDir, settingsFileName)); os.IsNotExist(err) {
SaveSettings(nil)
}
}
func setupCoffLoaderExt(appDir string) error {
+1
View File
@@ -40,6 +40,7 @@ type ClientConfig struct {
Operator string `json:"operator"` // This value is actually ignored for the most part (cert CN is used instead)
LHost string `json:"lhost"`
LPort int `json:"lport"`
Token string `json:"token"`
CACertificate string `json:"ca_certificate"`
PrivateKey string `json:"private_key"`
Certificate string `json:"certificate"`
+73
View File
@@ -0,0 +1,73 @@
package assets
/*
Sliver Implant Framework
Copyright (C) 2021 Bishop Fox
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
import (
"encoding/json"
"io/ioutil"
"path/filepath"
)
const (
settingsFileName = "tui-settings.json"
)
// ClientSettings - Client JSON config
type ClientSettings struct {
TableStyle string `json:"tables"`
AutoAdult bool `json:"autoadult"`
BeaconAutoResults bool `json:"beacon_autoresults"`
}
// LoadSettings - Load the client settings from disk
func LoadSettings() (*ClientSettings, error) {
rootDir, _ := filepath.Abs(GetRootAppDir())
data, err := ioutil.ReadFile(filepath.Join(rootDir, settingsFileName))
if err != nil {
return defaultSettings(), err
}
settings := defaultSettings()
err = json.Unmarshal(data, settings)
if err != nil {
return defaultSettings(), err
}
return settings, nil
}
func defaultSettings() *ClientSettings {
return &ClientSettings{
TableStyle: "SliverDefault",
AutoAdult: false,
BeaconAutoResults: true,
}
}
// SaveSettings - Save the current settings to disk
func SaveSettings(settings *ClientSettings) error {
rootDir, _ := filepath.Abs(GetRootAppDir())
if settings == nil {
settings = defaultSettings()
}
data, err := json.MarshalIndent(settings, "", " ")
if err != nil {
return err
}
err = ioutil.WriteFile(filepath.Join(rootDir, settingsFileName), data, 0600)
return err
}
+2 -2
View File
@@ -29,7 +29,7 @@ import (
// BackdoorCmd - Command to inject implant code into an existing binary
func BackdoorCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
session := con.ActiveSession.GetInteractive()
session := con.ActiveTarget.GetSessionInteractive()
if session == nil {
return
}
@@ -48,7 +48,7 @@ func BackdoorCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
backdoor, err := con.Rpc.Backdoor(context.Background(), &sliverpb.BackdoorReq{
FilePath: remoteFilePath,
ProfileName: profileName,
Request: con.ActiveSession.Request(ctx),
Request: con.ActiveTarget.Request(ctx),
})
ctrl <- true
<-ctrl
+4
View File
@@ -0,0 +1,4 @@
Beacons
========
This package implements the beacons command, which can be used to list and interact with beacons.
+169
View File
@@ -0,0 +1,169 @@
package beacons
/*
Sliver Implant Framework
Copyright (C) 2021 Bishop Fox
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
import (
"context"
"fmt"
"strings"
"time"
"github.com/bishopfox/sliver/client/command/kill"
"github.com/bishopfox/sliver/client/command/settings"
"github.com/bishopfox/sliver/client/console"
"github.com/bishopfox/sliver/protobuf/clientpb"
"github.com/bishopfox/sliver/protobuf/commonpb"
"github.com/desertbit/grumble"
"github.com/jedib0t/go-pretty/v6/table"
"golang.org/x/crypto/ssh/terminal"
)
// BeaconsCmd - Display/interact with beacons
func BeaconsCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
killFlag := ctx.Flags.String("kill")
killAll := ctx.Flags.Bool("kill-all")
// Handle kill
if killFlag != "" {
beacon, err := GetBeacon(con, killFlag)
if err != nil {
con.PrintErrorf("%s\n", err)
return
}
err = kill.KillBeacon(beacon, false, con)
if err != nil {
con.PrintErrorf("%s\n", err)
return
}
con.Println()
con.PrintInfof("Killed %s (%s)\n", beacon.Name, beacon.ID)
}
if killAll {
beacons, err := GetBeacons(con)
if err != nil {
con.PrintErrorf("%s\n", err)
return
}
for _, beacon := range beacons.Beacons {
err = kill.KillBeacon(beacon, true, con)
if err != nil {
con.PrintErrorf("%s\n", err)
return
}
con.Println()
con.PrintInfof("Killed %s (%s)\n", beacon.Name, beacon.ID)
}
}
beacons, err := con.Rpc.GetBeacons(context.Background(), &commonpb.Empty{})
if err != nil {
con.PrintErrorf("%s\n", err)
return
}
PrintBeacons(beacons.Beacons, con)
}
// PrintBeacons - Display a list of beacons
func PrintBeacons(beacons []*clientpb.Beacon, con *console.SliverConsoleClient) {
if len(beacons) == 0 {
con.PrintInfof("No beacons 🙁\n")
return
}
tw := renderBeacons(beacons, con)
con.Printf("%s\n", tw.Render())
}
func renderBeacons(beacons []*clientpb.Beacon, con *console.SliverConsoleClient) table.Writer {
width, _, err := terminal.GetSize(0)
if err != nil {
width = 999
}
tw := table.NewWriter()
tw.SetStyle(settings.GetTableStyle(con))
if 182 < width {
tw.AppendHeader(table.Row{
"ID",
"Name",
"Tasks",
"Transport",
"Remote Address",
"Hostname",
"Username",
"Operating System",
"Last Check-in",
"Next Check-in",
})
} else {
tw.AppendHeader(table.Row{
"ID",
"Name",
"Transport",
"Username",
"Operating System",
"Last Check-in",
"Next Check-in",
})
}
for _, beacon := range beacons {
color := console.Normal
activeBeacon := con.ActiveTarget.GetBeacon()
if activeBeacon != nil && activeBeacon.ID == beacon.ID {
color = console.Green
}
nextCheckin := time.Unix(beacon.NextCheckin, 0)
var next string
if time.Unix(beacon.NextCheckin, 0).Before(time.Now()) {
past := time.Now().Sub(nextCheckin)
next = fmt.Sprintf("%s-%s%s", console.Bold+console.Red, past, console.Normal)
} else {
eta := nextCheckin.Sub(time.Now())
next = fmt.Sprintf("%s%s%s", console.Bold+console.Green, eta, console.Normal)
}
if 182 < width {
tw.AppendRow(table.Row{
fmt.Sprintf(color+"%s"+console.Normal, strings.Split(beacon.ID, "-")[0]),
fmt.Sprintf(color+"%s"+console.Normal, beacon.Name),
fmt.Sprintf(color+"%d/%d"+console.Normal, beacon.TasksCountCompleted, beacon.TasksCount),
fmt.Sprintf(color+"%s"+console.Normal, beacon.Transport),
fmt.Sprintf(color+"%s"+console.Normal, beacon.RemoteAddress),
fmt.Sprintf(color+"%s"+console.Normal, beacon.Hostname),
fmt.Sprintf(color+"%s"+console.Normal, beacon.Username),
fmt.Sprintf(color+"%s/%s"+console.Normal, beacon.OS, beacon.Arch),
fmt.Sprintf(color+"%s ago"+console.Normal, time.Now().Sub(time.Unix(beacon.LastCheckin, 0))),
next,
})
} else {
tw.AppendRow(table.Row{
fmt.Sprintf(color+"%s"+console.Normal, strings.Split(beacon.ID, "-")[0]),
fmt.Sprintf(color+"%s"+console.Normal, beacon.Name),
fmt.Sprintf(color+"%s"+console.Normal, beacon.Transport),
fmt.Sprintf(color+"%s"+console.Normal, beacon.Username),
fmt.Sprintf(color+"%s/%s"+console.Normal, beacon.OS, beacon.Arch),
fmt.Sprintf(color+"%s ago"+console.Normal, time.Now().Sub(time.Unix(beacon.LastCheckin, 0))),
next,
})
}
}
return tw
}
+128
View File
@@ -0,0 +1,128 @@
package beacons
/*
Sliver Implant Framework
Copyright (C) 2021 Bishop Fox
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
import (
"bytes"
"context"
"errors"
"fmt"
"sort"
"strings"
"text/tabwriter"
"github.com/AlecAivazis/survey/v2"
"github.com/bishopfox/sliver/client/console"
"github.com/bishopfox/sliver/protobuf/clientpb"
"github.com/bishopfox/sliver/protobuf/commonpb"
)
var (
// ErrNoBeacons - No sessions available
ErrNoBeacons = errors.New("no beacons")
// ErrNoSelection - No selection made
ErrNoSelection = errors.New("no selection")
// ErrBeaconNotFound
ErrBeaconNotFound = errors.New("no beacon found for this ID")
)
// SelectBeacon - Interactive menu for the user to select an session, optionally only display live sessions
func SelectBeacon(con *console.SliverConsoleClient) (*clientpb.Beacon, error) {
beacons, err := con.Rpc.GetBeacons(context.Background(), &commonpb.Empty{})
if err != nil {
return nil, err
}
if len(beacons.Beacons) == 0 {
return nil, ErrNoBeacons
}
beaconsMap := map[string]*clientpb.Beacon{}
for _, beacon := range beacons.Beacons {
beaconsMap[beacon.ID] = beacon
}
keys := []string{}
for beaconID := range beaconsMap {
keys = append(keys, beaconID)
}
sort.Strings(keys)
outputBuf := bytes.NewBufferString("")
table := tabwriter.NewWriter(outputBuf, 0, 2, 2, ' ', 0)
// Column Headers
for _, key := range keys {
beacon := beaconsMap[key]
fmt.Fprintf(table, "%s\t%s\t%s\t%s\t%s\t%s\n",
beacon.ID,
beacon.Name,
beacon.RemoteAddress,
beacon.Hostname,
beacon.Username,
fmt.Sprintf("%s/%s", beacon.OS, beacon.Arch),
)
}
table.Flush()
options := strings.Split(outputBuf.String(), "\n")
options = options[:len(options)-1] // Remove the last empty option
prompt := &survey.Select{
Message: "Select a beacon:",
Options: options,
}
selected := ""
survey.AskOne(prompt, &selected)
if selected == "" {
return nil, ErrNoSelection
}
// Go from the selected option -> index -> session
for index, option := range options {
if option == selected {
return beaconsMap[keys[index]], nil
}
}
return nil, ErrNoSelection
}
func GetBeacon(con *console.SliverConsoleClient, beaconID string) (*clientpb.Beacon, error) {
beacons, err := con.Rpc.GetBeacons(context.Background(), &commonpb.Empty{})
if err != nil {
return nil, err
}
if len(beacons.Beacons) == 0 {
return nil, ErrNoBeacons
}
for _, beacon := range beacons.Beacons {
if beacon.ID == beaconID {
return beacon, nil
}
}
return nil, ErrBeaconNotFound
}
func GetBeacons(con *console.SliverConsoleClient) (*clientpb.Beacons, error) {
beacons, err := con.Rpc.GetBeacons(context.Background(), &commonpb.Empty{})
if err != nil {
return nil, err
}
if len(beacons.Beacons) == 0 {
return nil, ErrNoBeacons
}
return beacons, nil
}
+85
View File
@@ -0,0 +1,85 @@
package beacons
/*
Sliver Implant Framework
Copyright (C) 2021 Bishop Fox
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
import (
"context"
"time"
"github.com/AlecAivazis/survey/v2"
"github.com/bishopfox/sliver/client/console"
"github.com/bishopfox/sliver/protobuf/clientpb"
"github.com/bishopfox/sliver/protobuf/commonpb"
"github.com/desertbit/grumble"
)
// BeaconsPruneCmd - Prune stale beacons automatically
func BeaconsPruneCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
pruneDuration, err := time.ParseDuration(ctx.Flags.String("duration"))
if err != nil {
con.PrintErrorf("%s\n", err)
return
}
con.PrintInfof("Pruning beacons that missed their last checking by %s or more...\n\n", pruneDuration)
beacons, err := con.Rpc.GetBeacons(context.Background(), &commonpb.Empty{})
if err != nil {
con.PrintErrorf("%s\n", err)
return
}
pruneBeacons := []*clientpb.Beacon{}
for _, beacon := range beacons.Beacons {
nextCheckin := time.Unix(beacon.NextCheckin, 0)
if time.Now().Before(nextCheckin) {
continue
}
delta := time.Now().Sub(nextCheckin)
if pruneDuration <= delta {
pruneBeacons = append(pruneBeacons, beacon)
}
}
if len(pruneBeacons) == 0 {
con.PrintInfof("No beacons to prune.\n")
return
}
con.PrintWarnf("The following beacons and their tasks will be removed:\n")
for index, beacon := range pruneBeacons {
beacon, err := con.Rpc.GetBeacon(context.Background(), &clientpb.Beacon{ID: beacon.ID})
if err != nil {
con.PrintErrorf("%s\n", err)
continue
}
con.Printf("\t%d. %s (%s)\n", (index + 1), beacon.Name, beacon.ID)
}
con.Println()
confirm := false
prompt := &survey.Confirm{Message: "Prune these beacons?"}
survey.AskOne(prompt, &confirm)
if !confirm {
return
}
errCount := 0
for _, beacon := range pruneBeacons {
_, err := con.Rpc.RmBeacon(context.Background(), &clientpb.Beacon{ID: beacon.ID})
if err != nil {
con.PrintErrorf("%s\n", err)
errCount++
}
}
con.PrintInfof("Pruned %d beacon(s)\n", len(pruneBeacons)-errCount)
}
+41
View File
@@ -0,0 +1,41 @@
package beacons
/*
Sliver Implant Framework
Copyright (C) 2021 Bishop Fox
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
import (
"context"
"github.com/bishopfox/sliver/client/console"
"github.com/desertbit/grumble"
)
// BeaconsRmCmd - Display/interact with beacons
func BeaconsRmCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
beacon, err := SelectBeacon(con)
if err != nil {
con.PrintErrorf("%s\n", err)
return
}
_, err = con.Rpc.RmBeacon(context.Background(), beacon)
if err != nil {
con.PrintErrorf("%s\n", err)
return
}
con.PrintInfof("Beacon removed (%s)\n", beacon.ID)
}
+67
View File
@@ -0,0 +1,67 @@
package beacons
/*
Sliver Implant Framework
Copyright (C) 2021 Bishop Fox
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
import (
"context"
"fmt"
"strings"
"time"
"github.com/bishopfox/sliver/client/console"
"github.com/bishopfox/sliver/protobuf/commonpb"
"github.com/desertbit/grumble"
)
// BeaconsWatchCmd - Watch your beacons in real-ish time
func BeaconsWatchCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
done := waitForInput()
defer func() {
con.Printf(console.UpN+console.Clearln+"\r", 1)
con.Printf(console.UpN+console.Clearln+"\r", 1)
}()
for {
select {
case <-done:
return
case <-time.After(time.Second):
beacons, err := con.Rpc.GetBeacons(context.Background(), &commonpb.Empty{})
if err != nil {
panic(err) // If we return we may leak the waiting goroutine, so we panic instead
}
tw := renderBeacons(beacons.Beacons, con)
lines := strings.Split(tw.Render(), "\n")
for _, line := range lines {
con.Printf(console.Clearln+"\r%s\n", line)
}
con.Printf("\nPress enter to stop.\n")
con.Printf(console.UpN+"\r", len(lines)+2)
}
}
}
func waitForInput() <-chan bool {
done := make(chan bool)
go func() {
defer close(done)
fmt.Scanf("\n")
done <- true
}()
return done
}
+463 -35
View File
@@ -36,8 +36,11 @@ package command
import (
"os"
"github.com/bishopfox/sliver/client/command/socks"
"github.com/bishopfox/sliver/client/assets"
"github.com/bishopfox/sliver/client/command/backdoor"
"github.com/bishopfox/sliver/client/command/beacons"
"github.com/bishopfox/sliver/client/command/dllhijack"
"github.com/bishopfox/sliver/client/command/environment"
"github.com/bishopfox/sliver/client/command/exec"
@@ -48,6 +51,7 @@ import (
"github.com/bishopfox/sliver/client/command/hosts"
"github.com/bishopfox/sliver/client/command/info"
"github.com/bishopfox/sliver/client/command/jobs"
"github.com/bishopfox/sliver/client/command/kill"
"github.com/bishopfox/sliver/client/command/loot"
"github.com/bishopfox/sliver/client/command/macros"
"github.com/bishopfox/sliver/client/command/monitor"
@@ -55,14 +59,18 @@ import (
"github.com/bishopfox/sliver/client/command/operators"
"github.com/bishopfox/sliver/client/command/pivots"
"github.com/bishopfox/sliver/client/command/portfwd"
operator "github.com/bishopfox/sliver/client/command/prelude-operator"
"github.com/bishopfox/sliver/client/command/privilege"
"github.com/bishopfox/sliver/client/command/processes"
"github.com/bishopfox/sliver/client/command/reaction"
"github.com/bishopfox/sliver/client/command/registry"
"github.com/bishopfox/sliver/client/command/screenshot"
"github.com/bishopfox/sliver/client/command/sessions"
"github.com/bishopfox/sliver/client/command/settings"
"github.com/bishopfox/sliver/client/command/shell"
"github.com/bishopfox/sliver/client/command/tasks"
"github.com/bishopfox/sliver/client/command/update"
"github.com/bishopfox/sliver/client/command/use"
"github.com/bishopfox/sliver/client/command/websites"
"github.com/bishopfox/sliver/client/command/wireguard"
"github.com/bishopfox/sliver/client/console"
@@ -184,8 +192,9 @@ func BindCommands(con *console.SliverConsoleClient) {
f.Int("l", "lport", generate.DefaultWGLPort, "udp listen port")
f.Int("n", "nport", generate.DefaultWGNPort, "virtual tun interface listen port")
f.Int("x", "key-port", generate.DefaultWGKeyExPort, "virtual tun interface key exchange port")
f.Int("t", "timeout", defaultTimeout, "command timeout in seconds")
f.Bool("p", "persistent", false, "make persistent across restarts")
f.Int("t", "timeout", defaultTimeout, "command timeout in seconds")
},
Run: func(ctx *grumble.Context) error {
con.Println()
@@ -227,6 +236,9 @@ func BindCommands(con *console.SliverConsoleClient) {
f.String("w", "website", "", "website name (see websites cmd)")
f.String("L", "lhost", "", "interface to bind server to")
f.Int("l", "lport", generate.DefaultHTTPLPort, "tcp listen port")
f.Bool("D", "disable-otp", false, "disable otp authentication")
f.String("T", "long-poll-timeout", "1m30s", "server-side long poll timeout")
f.String("J", "long-poll-jitter", "30s", "server-side long poll jitter")
f.Int("t", "timeout", defaultTimeout, "command timeout in seconds")
f.Bool("p", "persistent", false, "make persistent across restarts")
@@ -249,10 +261,12 @@ func BindCommands(con *console.SliverConsoleClient) {
f.String("w", "website", "", "website name (see websites cmd)")
f.String("L", "lhost", "", "interface to bind server to")
f.Int("l", "lport", generate.DefaultHTTPSLPort, "tcp listen port")
f.Bool("D", "disable-otp", false, "disable otp authentication")
f.String("T", "long-poll-timeout", "1m30s", "server-side long poll timeout")
f.String("J", "long-poll-jitter", "30s", "server-side long poll jitter")
f.String("c", "cert", "", "PEM encoded certificate file")
f.String("k", "key", "", "PEM encoded private key file")
f.Bool("e", "lets-encrypt", false, "attempt to provision a let's encrypt certificate")
f.Int("t", "timeout", defaultTimeout, "command timeout in seconds")
@@ -290,9 +304,9 @@ func BindCommands(con *console.SliverConsoleClient) {
// [ Operators ] --------------------------------------------------------------
con.App.AddCommand(&grumble.Command{
Name: consts.PlayersStr,
Name: consts.OperatorsStr,
Help: "Manage operators",
LongHelp: help.GetHelpFor([]string{consts.PlayersStr}),
LongHelp: help.GetHelpFor([]string{consts.OperatorsStr}),
Flags: func(f *grumble.Flags) {
f.Int("t", "timeout", defaultTimeout, "command timeout in seconds")
},
@@ -381,32 +395,13 @@ func BindCommands(con *console.SliverConsoleClient) {
HelpGroup: consts.GenericHelpGroup,
})
con.App.AddCommand(&grumble.Command{
Name: consts.UseStr,
Help: "Switch the active session",
LongHelp: help.GetHelpFor([]string{consts.UseStr}),
Flags: func(f *grumble.Flags) {
f.Int("t", "timeout", defaultTimeout, "command timeout in seconds")
},
Args: func(a *grumble.Args) {
a.String("session", "session ID or name", grumble.Default(""))
},
Run: func(ctx *grumble.Context) error {
con.Println()
sessions.UseCmd(ctx, con)
con.Println()
return nil
},
HelpGroup: consts.GenericHelpGroup,
})
con.App.AddCommand(&grumble.Command{
Name: consts.KillStr,
Help: "Kill a session",
LongHelp: help.GetHelpFor([]string{consts.KillStr}),
Run: func(ctx *grumble.Context) error {
con.Println()
sessions.KillCmd(ctx, con)
kill.KillCmd(ctx, con)
con.Println()
return nil
},
@@ -418,6 +413,200 @@ func BindCommands(con *console.SliverConsoleClient) {
HelpGroup: consts.SliverHelpGroup,
})
openSessionCmd := &grumble.Command{
Name: consts.InteractiveStr,
Help: "Task a beacon to open an interactive session (Beacon only)",
LongHelp: help.GetHelpFor([]string{consts.InteractiveStr}),
Flags: func(f *grumble.Flags) {
f.String("m", "mtls", "", "mtls connection strings")
f.String("g", "wg", "", "wg connection strings")
f.String("b", "http", "", "http(s) connection strings")
f.String("n", "dns", "", "dns connection strings")
f.String("p", "named-pipe", "", "named-pipe connection strings")
f.String("i", "tcp-pivot", "", "tcp-pivot connection strings")
f.String("d", "delay", "0s", "delay opening the session (after checkin) for a given period of time")
f.Int("t", "timeout", defaultTimeout, "command timeout in seconds")
},
Run: func(ctx *grumble.Context) error {
con.Println()
sessions.InteractiveCmd(ctx, con)
con.Println()
return nil
},
HelpGroup: consts.SliverHelpGroup,
}
con.App.AddCommand(openSessionCmd)
// [ Tasks ] --------------------------------------------------------------
tasksCmd := &grumble.Command{
Name: consts.TasksStr,
Help: "Beacon task management",
LongHelp: help.GetHelpFor([]string{consts.TasksStr}),
Flags: func(f *grumble.Flags) {
f.Bool("O", "overflow", false, "overflow terminal width (display truncated rows)")
f.Int("S", "skip-pages", 0, "skip the first n page(s)")
f.String("f", "filter", "", "filter based on task type (case-insensitive prefix matching)")
f.Int("t", "timeout", defaultTimeout, "command timeout in seconds")
},
Run: func(ctx *grumble.Context) error {
con.Println()
tasks.TasksCmd(ctx, con)
con.Println()
return nil
},
HelpGroup: consts.GenericHelpGroup,
}
tasksCmd.AddCommand(&grumble.Command{
Name: consts.FetchStr,
Help: "Fetch the details of a beacon task",
LongHelp: help.GetHelpFor([]string{consts.TasksStr, consts.FetchStr}),
Flags: func(f *grumble.Flags) {
f.Bool("O", "overflow", false, "overflow terminal width (display truncated rows)")
f.Int("S", "skip-pages", 0, "skip the first n page(s)")
f.String("f", "filter", "", "filter based on task type (case-insensitive prefix matching)")
f.Int("t", "timeout", defaultTimeout, "command timeout in seconds")
},
Args: func(a *grumble.Args) {
a.String("id", "beacon task ID", grumble.Default(""))
},
Run: func(ctx *grumble.Context) error {
con.Println()
tasks.TasksFetchCmd(ctx, con)
con.Println()
return nil
},
HelpGroup: consts.GenericHelpGroup,
})
con.App.AddCommand(tasksCmd)
// [ Use ] --------------------------------------------------------------
useCmd := &grumble.Command{
Name: consts.UseStr,
Help: "Switch the active session or beacon",
LongHelp: help.GetHelpFor([]string{consts.UseStr}),
Flags: func(f *grumble.Flags) {
f.Int("t", "timeout", defaultTimeout, "command timeout in seconds")
},
Args: func(a *grumble.Args) {
a.String("id", "beacon or session ID", grumble.Default(""))
},
Run: func(ctx *grumble.Context) error {
con.Println()
use.UseCmd(ctx, con)
con.Println()
return nil
},
Completer: func(prefix string, args []string) []string {
return use.Completer(con, prefix, args)
},
HelpGroup: consts.GenericHelpGroup,
}
useCmd.AddCommand(&grumble.Command{
Name: consts.SessionsStr,
Help: "Switch the active session",
LongHelp: help.GetHelpFor([]string{consts.UseStr, consts.SessionsStr}),
Flags: func(f *grumble.Flags) {
f.Int("t", "timeout", defaultTimeout, "command timeout in seconds")
},
Args: func(a *grumble.Args) {
},
Run: func(ctx *grumble.Context) error {
con.Println()
use.UseSessionCmd(ctx, con)
con.Println()
return nil
},
HelpGroup: consts.GenericHelpGroup,
})
useCmd.AddCommand(&grumble.Command{
Name: consts.BeaconsStr,
Help: "Switch the active beacon",
LongHelp: help.GetHelpFor([]string{consts.UseStr, consts.BeaconsStr}),
Flags: func(f *grumble.Flags) {
f.Int("t", "timeout", defaultTimeout, "command timeout in seconds")
},
Args: func(a *grumble.Args) {
},
Run: func(ctx *grumble.Context) error {
con.Println()
use.UseBeaconCmd(ctx, con)
con.Println()
return nil
},
HelpGroup: consts.GenericHelpGroup,
})
con.App.AddCommand(useCmd)
// [ Settings ] --------------------------------------------------------------
settingsCmd := &grumble.Command{
Name: consts.SettingsStr,
Help: "Manage client settings",
LongHelp: help.GetHelpFor([]string{consts.SettingsStr}),
Run: func(ctx *grumble.Context) error {
con.Println()
settings.SettingsCmd(ctx, con)
con.Println()
return nil
},
HelpGroup: consts.GenericHelpGroup,
}
settingsCmd.AddCommand(&grumble.Command{
Name: consts.SaveStr,
Help: "Save the current settings to disk",
LongHelp: help.GetHelpFor([]string{consts.SettingsStr, consts.SaveStr}),
Run: func(ctx *grumble.Context) error {
con.Println()
settings.SettingsSaveCmd(ctx, con)
con.Println()
return nil
},
HelpGroup: consts.GenericHelpGroup,
})
settingsCmd.AddCommand(&grumble.Command{
Name: consts.TablesStr,
Help: "Modify tables setting (style)",
LongHelp: help.GetHelpFor([]string{consts.SettingsStr, consts.TablesStr}),
Run: func(ctx *grumble.Context) error {
con.Println()
settings.SettingsTablesCmd(ctx, con)
con.Println()
return nil
},
HelpGroup: consts.GenericHelpGroup,
})
settingsCmd.AddCommand(&grumble.Command{
Name: "beacon-autoresults",
Help: "Automatically display beacon task results when completed",
LongHelp: help.GetHelpFor([]string{consts.SettingsStr, "beacon-autoresults"}),
Run: func(ctx *grumble.Context) error {
con.Println()
settings.SettingsBeaconsAutoResultCmd(ctx, con)
con.Println()
return nil
},
HelpGroup: consts.GenericHelpGroup,
})
settingsCmd.AddCommand(&grumble.Command{
Name: "autoadult",
Help: "Automatically accept OPSEC warnings",
LongHelp: help.GetHelpFor([]string{consts.SettingsStr, "autoadult"}),
Run: func(ctx *grumble.Context) error {
con.Println()
settings.SettingsAutoAdultCmd(ctx, con)
con.Println()
return nil
},
HelpGroup: consts.GenericHelpGroup,
})
con.App.AddCommand(settingsCmd)
// [ Info ] --------------------------------------------------------------
con.App.AddCommand(&grumble.Command{
@@ -548,8 +737,11 @@ func BindCommands(con *console.SliverConsoleClient) {
LongHelp: help.GetHelpFor([]string{consts.ExecuteStr}),
Flags: func(f *grumble.Flags) {
f.Bool("T", "token", false, "execute command with current token (windows only)")
f.Bool("s", "silent", false, "don't print the command output")
f.Bool("o", "output", false, "capture command output")
f.Bool("X", "loot", false, "save output as loot")
f.Bool("S", "ignore-stderr", false, "don't print STDERR output")
f.String("O", "stdout", "", "remote path to redirect STDOUT to")
f.String("E", "stderr", "", "remote path to redirect STDERR to")
f.Int("t", "timeout", defaultTimeout, "command timeout in seconds")
},
@@ -789,13 +981,13 @@ func BindCommands(con *console.SliverConsoleClient) {
f.String("N", "name", "", "agent name")
f.Bool("d", "debug", false, "enable debug features")
f.Bool("e", "evasion", false, "enable evasion features")
f.Bool("b", "skip-symbols", false, "skip symbol obfuscation")
f.Bool("l", "skip-symbols", false, "skip symbol obfuscation")
f.String("c", "canary", "", "canary domain(s)")
f.String("m", "mtls", "", "mtls connection strings")
f.String("g", "wg", "", "wg connection strings")
f.String("H", "http", "", "http(s) connection strings")
f.String("b", "http", "", "http(s) connection strings")
f.String("n", "dns", "", "dns connection strings")
f.String("p", "named-pipe", "", "named-pipe connection strings")
f.String("i", "tcp-pivot", "", "tcp-pivot connection strings")
@@ -804,7 +996,7 @@ func BindCommands(con *console.SliverConsoleClient) {
f.Int("T", "tcp-comms", generate.DefaultWGNPort, "wg c2 comms port")
f.Int("j", "reconnect", generate.DefaultReconnect, "attempt to reconnect every n second(s)")
f.Int("P", "poll", generate.DefaultPoll, "attempt to poll every n second(s)")
f.Int("P", "poll-timeout", generate.DefaultPollTimeout, "long poll request timeout")
f.Int("k", "max-errors", generate.DefaultMaxErrors, "max number of connection errors")
f.String("w", "limit-datetime", "", "limit execution to before datetime")
@@ -814,7 +1006,6 @@ func BindCommands(con *console.SliverConsoleClient) {
f.String("F", "limit-fileexists", "", "limit execution to hosts with this file in the filesystem")
f.String("f", "format", "exe", "Specifies the output formats, valid values are: 'exe', 'shared' (for dynamic libraries), 'service' (see `psexec` for more info) and 'shellcode' (windows only)")
f.String("s", "save", "", "directory/file to the binary to")
f.Int("t", "timeout", defaultTimeout, "command timeout in seconds")
@@ -827,6 +1018,59 @@ func BindCommands(con *console.SliverConsoleClient) {
},
HelpGroup: consts.GenericHelpGroup,
}
generateCmd.AddCommand(&grumble.Command{
Name: consts.BeaconStr,
Help: "Generate a beacon binary",
LongHelp: help.GetHelpFor([]string{consts.GenerateStr, consts.BeaconStr}),
Flags: func(f *grumble.Flags) {
f.Int64("D", "days", 0, "beacon interval days")
f.Int64("H", "hours", 0, "beacon interval hours")
f.Int64("M", "minutes", 0, "beacon interval minutes")
f.Int64("S", "seconds", 60, "beacon interval seconds")
f.Int64("J", "jitter", 30, "beacon interval jitter in seconds")
// Generate flags
f.String("o", "os", "windows", "operating system")
f.String("a", "arch", "amd64", "cpu architecture")
f.String("N", "name", "", "agent name")
f.Bool("d", "debug", false, "enable debug features")
f.Bool("e", "evasion", false, "enable evasion features")
f.Bool("l", "skip-symbols", false, "skip symbol obfuscation")
f.String("c", "canary", "", "canary domain(s)")
f.String("m", "mtls", "", "mtls connection strings")
f.String("g", "wg", "", "wg connection strings")
f.String("b", "http", "", "http(s) connection strings")
f.String("n", "dns", "", "dns connection strings")
f.String("p", "named-pipe", "", "named-pipe connection strings")
f.String("i", "tcp-pivot", "", "tcp-pivot connection strings")
f.Int("X", "key-exchange", generate.DefaultWGKeyExPort, "wg key-exchange port")
f.Int("T", "tcp-comms", generate.DefaultWGNPort, "wg c2 comms port")
f.Int("j", "reconnect", generate.DefaultReconnect, "attempt to reconnect every n second(s)")
f.Int("P", "poll-timeout", generate.DefaultPollTimeout, "long poll request timeout")
f.Int("k", "max-errors", generate.DefaultMaxErrors, "max number of connection errors")
f.String("w", "limit-datetime", "", "limit execution to before datetime")
f.Bool("x", "limit-domainjoined", false, "limit execution to domain joined machines")
f.String("y", "limit-username", "", "limit execution to specified username")
f.String("z", "limit-hostname", "", "limit execution to specified hostname")
f.String("F", "limit-fileexists", "", "limit execution to hosts with this file in the filesystem")
f.String("f", "format", "exe", "Specifies the output formats, valid values are: 'exe', 'shared' (for dynamic libraries), 'service' (see `psexec` for more info) and 'shellcode' (windows only)")
f.String("s", "save", "", "directory/file to the binary to")
f.Int("t", "timeout", defaultTimeout, "command timeout in seconds")
},
Run: func(ctx *grumble.Context) error {
con.Println()
generate.GenerateBeaconCmd(ctx, con)
con.Println()
return nil
},
})
generateCmd.AddCommand(&grumble.Command{
Name: consts.StagerStr,
Help: "Generate a implant stager using MSF",
@@ -946,7 +1190,7 @@ func BindCommands(con *console.SliverConsoleClient) {
f.Int("j", "reconnect", generate.DefaultReconnect, "attempt to reconnect every n second(s)")
f.Int("k", "max-errors", generate.DefaultMaxErrors, "max number of connection errors")
f.Int("P", "poll", generate.DefaultPoll, "attempt to poll every n second(s)")
f.Int("P", "poll-timeout", generate.DefaultPollTimeout, "attempt to poll every n second(s)")
f.String("w", "limit-datetime", "", "limit execution to before datetime")
f.Bool("x", "limit-domainjoined", false, "limit execution to domain joined machines")
@@ -956,7 +1200,8 @@ func BindCommands(con *console.SliverConsoleClient) {
f.String("f", "format", "exe", "Specifies the output formats, valid values are: 'exe', 'shared' (for dynamic libraries), 'service' (see `psexec` for more info) and 'shellcode' (windows only)")
f.String("N", "profile-name", "", "profile name")
f.String("R", "profile-name", "", "profile name")
f.String("N", "name", "", "agent name")
f.Int("t", "timeout", defaultTimeout, "command timeout in seconds")
},
@@ -1024,9 +1269,9 @@ func BindCommands(con *console.SliverConsoleClient) {
con.App.AddCommand(implantBuildsCmd)
con.App.AddCommand(&grumble.Command{
Name: consts.ListCanariesStr,
Name: consts.CanariesStr,
Help: "List previously generated canaries",
LongHelp: help.GetHelpFor([]string{consts.ListCanariesStr}),
LongHelp: help.GetHelpFor([]string{consts.CanariesStr}),
Flags: func(f *grumble.Flags) {
f.Bool("b", "burned", false, "show only triggered/burned canaries")
@@ -1214,6 +1459,8 @@ func BindCommands(con *console.SliverConsoleClient) {
Help: "View network interface configurations",
LongHelp: help.GetHelpFor([]string{consts.IfconfigStr}),
Flags: func(f *grumble.Flags) {
f.Bool("A", "all", false, "show all network adapters (default only shows IPv4)")
f.Int("t", "timeout", defaultTimeout, "command timeout in seconds")
},
Run: func(ctx *grumble.Context) error {
@@ -1257,6 +1504,8 @@ func BindCommands(con *console.SliverConsoleClient) {
f.String("e", "exe", "", "filter based on executable name")
f.String("o", "owner", "", "filter based on owner")
f.Bool("c", "print-cmdline", false, "print command line arguments")
f.Bool("O", "overflow", false, "overflow terminal width (display truncated rows)")
f.Int("S", "skip-pages", 0, "skip the first n page(s)")
f.Int("t", "timeout", defaultTimeout, "command timeout in seconds")
},
@@ -1276,6 +1525,8 @@ func BindCommands(con *console.SliverConsoleClient) {
Flags: func(f *grumble.Flags) {
f.Int("p", "pid", -1, "target pid")
f.String("n", "name", "", "target process name")
f.String("s", "save", "", "save to file (will overwrite if exists)")
f.Int("t", "timeout", defaultTimeout, "command timeout in seconds")
},
Run: func(ctx *grumble.Context) error {
@@ -1506,6 +1757,7 @@ func BindCommands(con *console.SliverConsoleClient) {
Help: "Take a screenshot",
LongHelp: help.GetHelpFor([]string{consts.ScreenshotStr}),
Flags: func(f *grumble.Flags) {
f.String("s", "save", "", "save to file (will overwrite if exists)")
f.Bool("X", "loot", false, "save output as loot")
f.Int("t", "timeout", defaultTimeout, "command timeout in seconds")
@@ -1541,6 +1793,74 @@ func BindCommands(con *console.SliverConsoleClient) {
},
})
// [ Beacons ] ---------------------------------------------
beaconsCmd := &grumble.Command{
Name: consts.BeaconsStr,
Help: "Manage beacons",
LongHelp: help.GetHelpFor([]string{consts.BeaconsStr}),
Flags: func(f *grumble.Flags) {
f.String("k", "kill", "", "kill a beacon")
f.Bool("K", "kill-all", false, "kill all beacons")
f.Int("t", "timeout", defaultTimeout, "command timeout in seconds")
},
HelpGroup: consts.GenericHelpGroup,
Run: func(ctx *grumble.Context) error {
con.Println()
beacons.BeaconsCmd(ctx, con)
con.Println()
return nil
},
}
beaconsCmd.AddCommand(&grumble.Command{
Name: consts.RmStr,
Help: "Remove a beacon",
LongHelp: help.GetHelpFor([]string{consts.BeaconsStr, consts.RmStr}),
Flags: func(f *grumble.Flags) {
f.Int("t", "timeout", defaultTimeout, "command timeout in seconds")
},
HelpGroup: consts.SliverWinHelpGroup,
Run: func(ctx *grumble.Context) error {
con.Println()
beacons.BeaconsRmCmd(ctx, con)
con.Println()
return nil
},
})
beaconsCmd.AddCommand(&grumble.Command{
Name: consts.WatchStr,
Help: "Watch your beacons",
LongHelp: help.GetHelpFor([]string{consts.BeaconsStr, consts.WatchStr}),
Flags: func(f *grumble.Flags) {
f.Int("t", "timeout", defaultTimeout, "command timeout in seconds")
},
HelpGroup: consts.SliverWinHelpGroup,
Run: func(ctx *grumble.Context) error {
con.Println()
beacons.BeaconsWatchCmd(ctx, con)
con.Println()
return nil
},
})
beaconsCmd.AddCommand(&grumble.Command{
Name: consts.PruneStr,
Help: "Prune stale beacons automatically",
LongHelp: help.GetHelpFor([]string{consts.BeaconsStr, consts.PruneStr}),
Flags: func(f *grumble.Flags) {
f.String("d", "duration", "1h", "duration to prune beacons that have missed their last checkin")
f.Int("t", "timeout", defaultTimeout, "command timeout in seconds")
},
HelpGroup: consts.SliverWinHelpGroup,
Run: func(ctx *grumble.Context) error {
con.Println()
beacons.BeaconsPruneCmd(ctx, con)
con.Println()
return nil
},
})
con.App.AddCommand(beaconsCmd)
// [ Macros ] ---------------------------------------------
con.App.AddCommand(&grumble.Command{
@@ -1968,6 +2288,58 @@ func BindCommands(con *console.SliverConsoleClient) {
})
con.App.AddCommand(portfwdCmd)
// [ Socks ] --------------------------------------------------------------
socksCmd := &grumble.Command{
Name: consts.Socks5Str,
Help: "In-band SOCKS5 Proxy",
LongHelp: help.GetHelpFor([]string{consts.Socks5Str}),
Flags: func(f *grumble.Flags) {
f.Int("t", "timeout", defaultTimeout, "router timeout in seconds")
},
Run: func(ctx *grumble.Context) error {
con.Println()
socks.SocksCmd(ctx, con)
con.Println()
return nil
},
HelpGroup: consts.SliverHelpGroup,
}
socksCmd.AddCommand(&grumble.Command{
Name: "add",
Help: "Create a new Socks5 Proxy",
LongHelp: help.GetHelpFor([]string{consts.Socks5Str}),
Flags: func(f *grumble.Flags) {
f.String("H", "host", "127.0.0.1", "Bind a Socks5 Host")
f.String("P", "port", "1081", "Bind a Socks5 Port")
f.String("u", "user", "", "socks5 auth username (will generate random password)")
},
Run: func(ctx *grumble.Context) error {
con.Println()
socks.SocksAddCmd(ctx, con)
con.Println()
return nil
},
HelpGroup: consts.SliverHelpGroup,
})
socksCmd.AddCommand(&grumble.Command{
Name: "rm",
Help: "Remove a Socks5 Proxy",
LongHelp: help.GetHelpFor([]string{consts.Socks5Str}),
Flags: func(f *grumble.Flags) {
f.Int("t", "timeout", defaultTimeout, "router timeout in seconds")
f.Int("i", "id", 0, "id of portfwd to remove")
},
Run: func(ctx *grumble.Context) error {
con.Println()
socks.SocksRmCmd(ctx, con)
con.Println()
return nil
},
HelpGroup: consts.SliverHelpGroup,
})
con.App.AddCommand(socksCmd)
// [ Monitor ] --------------------------------------------------------------
monitorCmd := &grumble.Command{
@@ -2092,9 +2464,9 @@ func BindCommands(con *console.SliverConsoleClient) {
HelpGroup: consts.GenericHelpGroup,
})
lootCmd.AddCommand(&grumble.Command{
Name: consts.LootFetchStr,
Name: consts.FetchStr,
Help: "Fetch a piece of loot from the server's loot store",
LongHelp: help.GetHelpFor([]string{consts.LootStr, consts.LootFetchStr}),
LongHelp: help.GetHelpFor([]string{consts.LootStr, consts.FetchStr}),
Flags: func(f *grumble.Flags) {
f.String("s", "save", "", "save loot to a local file")
f.String("f", "filter", "", "filter based on loot type")
@@ -2341,4 +2713,60 @@ func BindCommands(con *console.SliverConsoleClient) {
},
})
con.App.AddCommand(extensionCmd)
// [ Prelude's Operator ] ------------------------------------------------------------
operatorCmd := &grumble.Command{
Name: consts.PreludeOperatorStr,
Help: "Manage connection to Prelude's Operator",
LongHelp: help.GetHelpFor([]string{consts.PreludeOperatorStr}),
HelpGroup: consts.GenericHelpGroup,
Run: func(ctx *grumble.Context) error {
con.Println()
operator.OperatorCmd(ctx, con)
con.Println()
return nil
},
}
operatorCmd.AddCommand(&grumble.Command{
Name: consts.ConnectStr,
Help: "Connect with Prelude's Operator",
LongHelp: help.GetHelpFor([]string{consts.PreludeOperatorStr, consts.ConnectStr}),
HelpGroup: consts.GenericHelpGroup,
Run: func(ctx *grumble.Context) error {
con.Println()
operator.ConnectCmd(ctx, con)
con.Println()
return nil
},
Args: func(a *grumble.Args) {
a.String("connection-string", "connection string to the Operator Host")
},
Flags: func(f *grumble.Flags) {
f.Bool("s", "skip-existing", false, "Do not add existing sessions as Operator Agents")
f.String("a", "aes-key", "abcdefghijklmnopqrstuvwxyz012345", "AES key for communication encryption")
f.String("r", "range", "sliver", "Agents range")
},
})
con.App.AddCommand(operatorCmd)
// [ LibInject ] -----------------------------------------------------------------
libInjectCmd := &grumble.Command{
Name: consts.LibInjectStr,
Help: "Inject a Linux shared library into a process",
LongHelp: help.GetHelpFor([]string{consts.LibInjectStr}),
HelpGroup: consts.SliverHelpGroup,
Run: func(ctx *grumble.Context) error {
con.Println()
exec.LibInjectCmd(ctx, con)
con.Println()
return nil
},
Args: func(a *grumble.Args) {
a.Uint64("pid", "Target process ID")
a.String("library-path", "Path to the shared library to inject")
},
Flags: func(f *grumble.Flags) {
f.Int("t", "timeout", defaultTimeout, "command timeout in seconds")
},
}
con.App.AddCommand(libInjectCmd)
}
+4 -4
View File
@@ -24,7 +24,7 @@ import (
"io/ioutil"
"github.com/bishopfox/sliver/client/console"
"github.com/bishopfox/sliver/protobuf/sliverpb"
"github.com/bishopfox/sliver/protobuf/clientpb"
"github.com/desertbit/grumble"
)
@@ -39,7 +39,7 @@ func DllHijackCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
targetDLLData []byte
err error
)
session := con.ActiveSession.GetInteractive()
session := con.ActiveTarget.GetSessionInteractive()
if session == nil {
return
}
@@ -78,12 +78,12 @@ func DllHijackCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
ctrl := make(chan bool)
msg := fmt.Sprintf("Crafting and planting DLL at %s ...", targetPath)
con.SpinUntil(msg, ctrl)
_, err = con.Rpc.HijackDLL(context.Background(), &sliverpb.DllHijackReq{
_, err = con.Rpc.HijackDLL(context.Background(), &clientpb.DllHijackReq{
ReferenceDLLPath: referencePath,
TargetLocation: targetPath,
ReferenceDLL: localRefData,
TargetDLL: targetDLLData,
Request: con.ActiveSession.Request(ctx),
Request: con.ActiveTarget.Request(ctx),
ProfileName: profileName,
})
ctrl <- true
+25 -4
View File
@@ -22,28 +22,49 @@ import (
"context"
"github.com/bishopfox/sliver/client/console"
"github.com/bishopfox/sliver/protobuf/clientpb"
"github.com/bishopfox/sliver/protobuf/sliverpb"
"github.com/desertbit/grumble"
"google.golang.org/protobuf/proto"
)
// EnvGetCmd - Get a remote environment variable
func EnvGetCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
session := con.ActiveSession.Get()
if session == nil {
session, beacon := con.ActiveTarget.GetInteractive()
if session == nil && beacon == nil {
return
}
name := ctx.Args.String("name")
envInfo, err := con.Rpc.GetEnv(context.Background(), &sliverpb.EnvReq{
Name: name,
Request: con.ActiveSession.Request(ctx),
Request: con.ActiveTarget.Request(ctx),
})
if err != nil {
con.PrintErrorf("%s\n", err)
return
}
if envInfo.Response != nil && envInfo.Response.Async {
con.AddBeaconCallback(envInfo.Response.TaskID, func(task *clientpb.BeaconTask) {
err = proto.Unmarshal(task.Response, envInfo)
if err != nil {
con.PrintErrorf("Failed to decode response %s\n", err)
return
}
PrintGetEnvInfo(envInfo, con)
})
con.PrintAsyncResponse(envInfo.Response)
} else {
PrintGetEnvInfo(envInfo, con)
}
}
// PrintGetEnvInfo - Print the results of the env get command
func PrintGetEnvInfo(envInfo *sliverpb.EnvInfo, con *console.SliverConsoleClient) {
if envInfo.Response != nil && envInfo.Response.Err != "" {
con.PrintErrorf("%s\n", envInfo.Response.Err)
return
}
for _, envVar := range envInfo.Variables {
con.Printf("%s=%s\n", envVar.Key, envVar.Value)
}
+23 -3
View File
@@ -22,15 +22,17 @@ import (
"context"
"github.com/bishopfox/sliver/client/console"
"github.com/bishopfox/sliver/protobuf/clientpb"
"github.com/bishopfox/sliver/protobuf/commonpb"
"github.com/bishopfox/sliver/protobuf/sliverpb"
"github.com/desertbit/grumble"
"google.golang.org/protobuf/proto"
)
// EnvSetCmd - Set a remote environment variable
func EnvSetCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
session := con.ActiveSession.Get()
if session == nil {
session, beacon := con.ActiveTarget.GetInteractive()
if session == nil && beacon == nil {
return
}
@@ -46,12 +48,30 @@ func EnvSetCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
Key: name,
Value: value,
},
Request: con.ActiveSession.Request(ctx),
Request: con.ActiveTarget.Request(ctx),
})
if err != nil {
con.PrintErrorf("%s\n", err)
return
}
if envInfo.Response != nil && envInfo.Response.Async {
con.AddBeaconCallback(envInfo.Response.TaskID, func(task *clientpb.BeaconTask) {
err = proto.Unmarshal(task.Response, envInfo)
if err != nil {
con.PrintErrorf("Failed to decode response %s\n", err)
return
}
PrintSetEnvInfo(name, value, envInfo, con)
})
con.PrintAsyncResponse(envInfo.Response)
} else {
PrintSetEnvInfo(name, value, envInfo, con)
}
}
// PrintSetEnvInfo - Print the set environment info
func PrintSetEnvInfo(name string, value string, envInfo *sliverpb.SetEnv, con *console.SliverConsoleClient) {
if envInfo.Response != nil && envInfo.Response.Err != "" {
con.PrintErrorf("%s\n", envInfo.Response.Err)
return
+24 -5
View File
@@ -22,14 +22,16 @@ import (
"context"
"github.com/bishopfox/sliver/client/console"
"github.com/bishopfox/sliver/protobuf/clientpb"
"github.com/bishopfox/sliver/protobuf/sliverpb"
"github.com/desertbit/grumble"
"google.golang.org/protobuf/proto"
)
// EnvUnsetCmd - Unset a remote environment variable
func EnvUnsetCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
session := con.ActiveSession.Get()
if session == nil {
session, beacon := con.ActiveTarget.GetInteractive()
if session == nil && beacon == nil {
return
}
@@ -41,16 +43,33 @@ func EnvUnsetCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
unsetResp, err := con.Rpc.UnsetEnv(context.Background(), &sliverpb.UnsetEnvReq{
Name: name,
Request: con.ActiveSession.Request(ctx),
Request: con.ActiveTarget.Request(ctx),
})
if err != nil {
con.PrintErrorf("%s\n", err)
return
}
if unsetResp.Response != nil && unsetResp.Response.Async {
con.AddBeaconCallback(unsetResp.Response.TaskID, func(task *clientpb.BeaconTask) {
err = proto.Unmarshal(task.Response, unsetResp)
if err != nil {
con.PrintErrorf("Failed to decode response %s\n", err)
return
}
PrintUnsetEnvInfo(name, unsetResp, con)
})
con.PrintAsyncResponse(unsetResp.Response)
} else {
PrintUnsetEnvInfo(name, unsetResp, con)
}
if unsetResp.Response != nil && unsetResp.Response.Err != "" {
con.PrintErrorf("%s\n", unsetResp.Response.Err)
}
// PrintUnsetEnvInfo - Print the set environment info
func PrintUnsetEnvInfo(name string, envInfo *sliverpb.UnsetEnv, con *console.SliverConsoleClient) {
if envInfo.Response != nil && envInfo.Response.Err != "" {
con.PrintErrorf("%s\n", envInfo.Response.Err)
return
}
con.PrintInfof("Successfully unset %s\n", name)
+54 -20
View File
@@ -3,14 +3,17 @@ package exec
/*
Sliver Implant Framework
Copyright (C) 2019 Bishop Fox
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
@@ -20,26 +23,27 @@ import (
"fmt"
"io/ioutil"
"os"
"path"
"path/filepath"
"strings"
"github.com/bishopfox/sliver/client/command/loot"
"github.com/bishopfox/sliver/client/console"
"github.com/bishopfox/sliver/protobuf/clientpb"
"github.com/bishopfox/sliver/protobuf/sliverpb"
"github.com/desertbit/grumble"
"google.golang.org/protobuf/proto"
)
// ExecuteAssemblyCmd - Execute a .NET assembly in-memory
func ExecuteAssemblyCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
session := con.ActiveSession.GetInteractive()
if session == nil {
session, beacon := con.ActiveTarget.GetInteractive()
if session == nil && beacon == nil {
return
}
filePath := ctx.Args.String("filepath")
assemblyPath := ctx.Args.String("filepath")
isDLL := false
if filepath.Ext(filePath) == ".dll" {
if filepath.Ext(assemblyPath) == ".dll" {
isDLL = true
}
if isDLL {
@@ -48,7 +52,7 @@ func ExecuteAssemblyCmd(ctx *grumble.Context, con *console.SliverConsoleClient)
return
}
}
assemblyBytes, err := ioutil.ReadFile(filePath)
assemblyBytes, err := ioutil.ReadFile(assemblyPath)
if err != nil {
con.PrintErrorf("%s", err.Error())
return
@@ -59,8 +63,8 @@ func ExecuteAssemblyCmd(ctx *grumble.Context, con *console.SliverConsoleClient)
ctrl := make(chan bool)
con.SpinUntil("Executing assembly ...", ctrl)
executeAssembly, err := con.Rpc.ExecuteAssembly(context.Background(), &sliverpb.ExecuteAssemblyReq{
Request: con.ActiveSession.Request(ctx),
execAssembly, err := con.Rpc.ExecuteAssembly(context.Background(), &sliverpb.ExecuteAssemblyReq{
Request: con.ActiveTarget.Request(ctx),
IsDLL: isDLL,
Process: process,
Arguments: strings.Join(assemblyArgs, " "),
@@ -72,30 +76,50 @@ func ExecuteAssemblyCmd(ctx *grumble.Context, con *console.SliverConsoleClient)
})
ctrl <- true
<-ctrl
if err != nil {
con.PrintErrorf("Error: %v", err)
con.PrintErrorf("%s", err)
return
}
hostname := getHostname(session, beacon)
if execAssembly.Response != nil && execAssembly.Response.Async {
con.AddBeaconCallback(execAssembly.Response.TaskID, func(task *clientpb.BeaconTask) {
err = proto.Unmarshal(task.Response, execAssembly)
if err != nil {
con.PrintErrorf("Failed to decode response %s\n", err)
return
}
PrintExecuteAssembly(execAssembly, hostname, assemblyPath, ctx, con)
})
con.PrintAsyncResponse(execAssembly.Response)
} else {
PrintExecuteAssembly(execAssembly, hostname, assemblyPath, ctx, con)
}
}
// PrintExecuteAssembly - Print the results of an assembly execution
func PrintExecuteAssembly(execAssembly *sliverpb.ExecuteAssembly, hostname string,
assemblyPath string, ctx *grumble.Context, con *console.SliverConsoleClient) {
if execAssembly.GetResponse().GetErr() != "" {
con.PrintErrorf("Error: %s\n", execAssembly.GetResponse().GetErr())
return
}
if executeAssembly.GetResponse().GetErr() != "" {
con.PrintErrorf("Error: %s\n", executeAssembly.GetResponse().GetErr())
return
}
var outFilePath *os.File
var err error
if ctx.Flags.Bool("save") {
outFile := path.Base(fmt.Sprintf("%s_%s*.log", ctx.Command.Name, session.GetHostname()))
outFile := filepath.Base(fmt.Sprintf("%s_%s*.log", ctx.Command.Name, hostname))
outFilePath, err = ioutil.TempFile("", outFile)
}
con.PrintInfof("Assembly output:\n%s", string(executeAssembly.GetOutput()))
con.PrintInfof("Assembly output:\n%s", string(execAssembly.GetOutput()))
if outFilePath != nil {
outFilePath.Write(executeAssembly.GetOutput())
outFilePath.Write(execAssembly.GetOutput())
con.PrintInfof("Output saved to %s\n", outFilePath.Name())
}
if ctx.Flags.Bool("loot") && 0 < len(executeAssembly.GetOutput()) {
name := fmt.Sprintf("[execute-assembly] %s", filepath.Base(filePath))
err = loot.AddLootFile(con.Rpc, name, "console.txt", executeAssembly.GetOutput(), false)
if ctx.Flags.Bool("loot") && 0 < len(execAssembly.GetOutput()) {
name := fmt.Sprintf("[execute-assembly] %s", filepath.Base(assemblyPath))
err = loot.AddLootFile(con.Rpc, name, "console.txt", execAssembly.GetOutput(), false)
if err != nil {
con.PrintErrorf("Failed to save output as loot: %s\n", err)
} else {
@@ -103,3 +127,13 @@ func ExecuteAssemblyCmd(ctx *grumble.Context, con *console.SliverConsoleClient)
}
}
}
func getHostname(session *clientpb.Session, beacon *clientpb.Beacon) string {
if session != nil {
return session.Hostname
}
if beacon != nil {
return beacon.Hostname
}
return ""
}
+36 -12
View File
@@ -29,20 +29,26 @@ import (
"github.com/bishopfox/sliver/client/console"
"github.com/bishopfox/sliver/client/core"
"github.com/bishopfox/sliver/protobuf/clientpb"
"github.com/bishopfox/sliver/protobuf/sliverpb"
"golang.org/x/crypto/ssh/terminal"
"google.golang.org/protobuf/proto"
"github.com/desertbit/grumble"
)
// ExecuteShellcodeCmd - Execute shellcode in-memory
func ExecuteShellcodeCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
session := con.ActiveSession.GetInteractive()
if session == nil {
session, beacon := con.ActiveTarget.GetInteractive()
if session == nil && beacon == nil {
return
}
interactive := ctx.Flags.Bool("interactive")
if interactive && beacon != nil {
con.PrintErrorf("Interactive shellcode can only be executed in a session\n")
return
}
pid := ctx.Flags.Uint("pid")
shellcodePath := ctx.Args.String("filepath")
shellcodeBin, err := ioutil.ReadFile(shellcodePath)
@@ -61,11 +67,11 @@ func ExecuteShellcodeCmd(ctx *grumble.Context, con *console.SliverConsoleClient)
ctrl := make(chan bool)
msg := fmt.Sprintf("Sending shellcode to %s ...", session.GetName())
con.SpinUntil(msg, ctrl)
task, err := con.Rpc.Task(context.Background(), &sliverpb.TaskReq{
shellcodeTask, err := con.Rpc.Task(context.Background(), &sliverpb.TaskReq{
Data: shellcodeBin,
RWXPages: ctx.Flags.Bool("rwx-pages"),
Pid: uint32(pid),
Request: con.ActiveSession.Request(ctx),
Request: con.ActiveTarget.Request(ctx),
})
ctrl <- true
<-ctrl
@@ -73,16 +79,34 @@ func ExecuteShellcodeCmd(ctx *grumble.Context, con *console.SliverConsoleClient)
con.PrintErrorf("%s\n", err)
return
}
if shellcodeTask.Response != nil && shellcodeTask.Response.Async {
con.AddBeaconCallback(shellcodeTask.Response.TaskID, func(task *clientpb.BeaconTask) {
err = proto.Unmarshal(task.Response, shellcodeTask)
if err != nil {
con.PrintErrorf("Failed to decode response %s\n", err)
return
}
PrintExecuteShellcode(shellcodeTask, con)
})
con.PrintAsyncResponse(shellcodeTask.Response)
} else {
PrintExecuteShellcode(shellcodeTask, con)
}
}
// PrintExecuteShellcode - Display result of shellcode execution
func PrintExecuteShellcode(task *sliverpb.Task, con *console.SliverConsoleClient) {
if task.Response.GetErr() != "" {
con.PrintErrorf("%s\n", task.Response.GetErr())
return
} else {
con.PrintInfof("Executed shellcode on target\n")
}
con.PrintInfof("Executed shellcode on target\n")
}
func executeInteractive(ctx *grumble.Context, hostProc string, shellcode []byte, rwxPages bool, con *console.SliverConsoleClient) {
// Check active session
session := con.ActiveSession.GetInteractive()
session := con.ActiveTarget.GetSessionInteractive()
if session == nil {
return
}
@@ -97,21 +121,21 @@ func executeInteractive(ctx *grumble.Context, hostProc string, shellcode []byte,
})
if err != nil {
con.PrintErrorf("Error: %v\n", err)
con.PrintErrorf("%s\n", err)
return
}
tunnel := core.Tunnels.Start(rpcTunnel.GetTunnelID(), rpcTunnel.GetSessionID())
shell, err := con.Rpc.Shell(context.Background(), &sliverpb.ShellReq{
Request: con.ActiveSession.Request(ctx),
Request: con.ActiveTarget.Request(ctx),
Path: hostProc,
EnablePTY: !noPty,
TunnelID: tunnel.ID,
})
if err != nil {
con.PrintErrorf("Error: %v\n", err)
con.PrintErrorf("%s\n", err)
return
}
// Retrieve PID and start remote task
@@ -121,7 +145,7 @@ func executeInteractive(ctx *grumble.Context, hostProc string, shellcode []byte,
msg := fmt.Sprintf("Sending shellcode to %s ...", session.GetName())
con.SpinUntil(msg, ctrl)
_, err = con.Rpc.Task(context.Background(), &sliverpb.TaskReq{
Request: con.ActiveSession.Request(ctx),
Request: con.ActiveTarget.Request(ctx),
Pid: pid,
Data: shellcode,
RWXPages: rwxPages,
@@ -130,7 +154,7 @@ func executeInteractive(ctx *grumble.Context, hostProc string, shellcode []byte,
<-ctrl
if err != nil {
con.PrintErrorf("Error: %v", err)
con.PrintErrorf("%s\n", err)
return
}
+87 -23
View File
@@ -22,58 +22,122 @@ import (
"github.com/bishopfox/sliver/client/command/loot"
"github.com/bishopfox/sliver/client/console"
"github.com/bishopfox/sliver/protobuf/clientpb"
"github.com/bishopfox/sliver/protobuf/sliverpb"
"github.com/desertbit/grumble"
"google.golang.org/protobuf/proto"
)
// ExecuteCmd - Run a command on the remote system
func ExecuteCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
session := con.ActiveSession.GetInteractive()
if session == nil {
session, beacon := con.ActiveTarget.GetInteractive()
if session == nil && beacon == nil {
return
}
cmdPath := ctx.Args.String("command")
args := ctx.Args.StringList("arguments")
output := ctx.Flags.Bool("silent")
token := ctx.Flags.Bool("token")
output := ctx.Flags.Bool("output")
stdout := ctx.Flags.String("stdout")
stderr := ctx.Flags.String("stderr")
if output && beacon != nil {
con.PrintWarnf("Using --output in beacon mode, if the command blocks the task will never complete\n\n")
}
var exec *sliverpb.Execute
var err error
ctrl := make(chan bool)
con.SpinUntil(fmt.Sprintf("Executing %s %s ...", cmdPath, strings.Join(args, " ")), ctrl)
if token {
exec, err = con.Rpc.ExecuteToken(context.Background(), &sliverpb.ExecuteTokenReq{
Request: con.ActiveSession.Request(ctx),
Request: con.ActiveTarget.Request(ctx),
Path: cmdPath,
Args: args,
Output: !output,
Output: output,
Stderr: stderr,
Stdout: stdout,
})
} else {
exec, err = con.Rpc.Execute(context.Background(), &sliverpb.ExecuteReq{
Request: con.ActiveSession.Request(ctx),
Request: con.ActiveTarget.Request(ctx),
Path: cmdPath,
Args: args,
Output: !output,
Output: output,
Stderr: stderr,
Stdout: stdout,
})
}
ctrl <- true
<-ctrl
if err != nil {
con.PrintErrorf("%s", err)
} else if !output {
if exec.Status != 0 {
con.PrintErrorf("Exited with status %d!\n", exec.Status)
if exec.Result != "" {
con.PrintInfof("Output:\n%s\n", exec.Result)
return
}
if exec.Response != nil && exec.Response.Async {
con.AddBeaconCallback(exec.Response.TaskID, func(task *clientpb.BeaconTask) {
err = proto.Unmarshal(task.Response, exec)
if err != nil {
con.PrintErrorf("Failed to decode response %s\n", err)
return
}
PrintExecute(exec, ctx, con)
})
con.PrintAsyncResponse(exec.Response)
} else {
PrintExecute(exec, ctx, con)
}
}
// PrintExecute - Print the output of an executed command
func PrintExecute(exec *sliverpb.Execute, ctx *grumble.Context, con *console.SliverConsoleClient) {
ignoreStderr := ctx.Flags.Bool("ignore-stderr")
saveLoot := ctx.Flags.Bool("loot")
stdout := ctx.Flags.String("stdout")
stderr := ctx.Flags.String("stderr")
cmdPath := ctx.Args.String("command")
args := ctx.Args.StringList("arguments")
output := ctx.Flags.Bool("output")
if !output {
if exec.Status == 0 {
con.PrintInfof("Command executed successfully\n")
} else {
con.PrintInfof("Output:\n%s\n", exec.Result)
if ctx.Flags.Bool("loot") && 0 < len(exec.Result) {
name := fmt.Sprintf("[exec] %s %s", cmdPath, strings.Join(args, " "))
err = loot.AddLootFile(con.Rpc, name, "console.txt", []byte(exec.Result), false)
if err != nil {
con.PrintErrorf("Failed to save output as loot: %s\n", err)
} else {
con.PrintInfof("Output saved as loot\n")
}
}
con.PrintErrorf("Exit code %d\n", exec.Status)
}
return
}
combined := ""
if stdout == "" {
combined = string(exec.Stdout)
con.PrintInfof("Output:\n%s", combined)
} else {
con.PrintInfof("Stdout saved at %s\n", stdout)
}
if stderr == "" {
if !ignoreStderr && 0 < len(exec.Stderr) {
combined = fmt.Sprintf("%s\nStderr:\n%s", combined, string(exec.Stderr))
con.PrintInfof("Stderr:\n%s", string(exec.Stderr))
}
} else {
con.PrintInfof("Stderr saved at %s\n", stderr)
}
if exec.Status != 0 {
con.PrintErrorf("Exited with status %d!\n", exec.Status)
}
if saveLoot && 0 < len(combined) {
name := fmt.Sprintf("[exec] %s %s", cmdPath, strings.Join(args, " "))
err := loot.AddLootFile(con.Rpc, name, "console.txt", []byte(combined), false)
if err != nil {
con.PrintErrorf("Failed to save output as loot: %s\n", err)
} else {
con.PrintInfof("Output saved as loot\n")
}
}
}
+58
View File
@@ -0,0 +1,58 @@
package exec
import (
"context"
"fmt"
"io/ioutil"
"github.com/bishopfox/sliver/client/console"
"github.com/bishopfox/sliver/protobuf/clientpb"
"github.com/bishopfox/sliver/protobuf/sliverpb"
"github.com/desertbit/grumble"
"google.golang.org/protobuf/proto"
)
func LibInjectCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
session, beacon := con.ActiveTarget.GetInteractive()
if session == nil && beacon == nil {
return
}
libPath := ctx.Args.String("library-path")
pid := ctx.Args.Uint64("pid")
data, err := ioutil.ReadFile(libPath)
if err != nil {
con.PrintErrorf("%s", err)
return
}
ctrl := make(chan bool)
con.SpinUntil(fmt.Sprintf("Injecting %s into %d...", libPath, pid), ctrl)
libInject, err := con.Rpc.LibInject(context.Background(), &sliverpb.LibInjectReq{
Request: con.ActiveTarget.Request(ctx),
Pid: pid,
Data: data,
})
ctrl <- true
<-ctrl
if err != nil {
con.PrintErrorf("%s", err)
return
}
if libInject.Response != nil && libInject.Response.Async {
con.AddBeaconCallback(libInject.Response.TaskID, func(task *clientpb.BeaconTask) {
err = proto.Unmarshal(task.Response, libInject)
if err != nil {
con.PrintErrorf("Failed to decode response: %s", err)
return
}
con.PrintInfof("Injected %s into %d\n", libPath, pid)
})
con.PrintAsyncResponse(libInject.Response)
} else {
con.PrintInfof("Injected %s into %d\n", libPath, pid)
}
}
+2 -2
View File
@@ -26,7 +26,7 @@ import (
// MigrateCmd - Windows only, inject an implant into another process
func MigrateCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
session := con.ActiveSession.Get()
session := con.ActiveTarget.GetSession()
if session == nil {
return
}
@@ -38,7 +38,7 @@ func MigrateCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
migrate, err := con.Rpc.Migrate(context.Background(), &clientpb.MigrateReq{
Pid: uint32(pid),
Config: config,
Request: con.ActiveSession.Request(ctx),
Request: con.ActiveTarget.Request(ctx),
})
ctrl <- true
<-ctrl
+23 -4
View File
@@ -25,13 +25,15 @@ import (
"github.com/bishopfox/sliver/client/console"
consts "github.com/bishopfox/sliver/client/constants"
"github.com/bishopfox/sliver/protobuf/clientpb"
"github.com/bishopfox/sliver/protobuf/sliverpb"
"google.golang.org/protobuf/proto"
"github.com/desertbit/grumble"
)
// MsfInjectCmd - Inject a metasploit payload into a remote process
func MsfInjectCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
session := con.ActiveSession.GetInteractive()
session := con.ActiveTarget.GetSessionInteractive()
if session == nil {
return
}
@@ -57,8 +59,8 @@ func MsfInjectCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
msg := fmt.Sprintf("Injecting payload %s %s/%s -> %s:%d ...",
payloadName, session.OS, session.Arch, lhost, lport)
con.SpinUntil(msg, ctrl)
_, err := con.Rpc.MsfRemote(context.Background(), &clientpb.MSFRemoteReq{
Request: con.ActiveSession.Request(ctx),
msfTask, err := con.Rpc.MsfRemote(context.Background(), &clientpb.MSFRemoteReq{
Request: con.ActiveTarget.Request(ctx),
Payload: payloadName,
LHost: lhost,
LPort: uint32(lport),
@@ -70,7 +72,24 @@ func MsfInjectCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
<-ctrl
if err != nil {
con.PrintErrorf("%s\n", err)
return
}
if msfTask.Response != nil && msfTask.Response.Async {
con.AddBeaconCallback(msfTask.Response.TaskID, func(task *clientpb.BeaconTask) {
err = proto.Unmarshal(task.Response, msfTask)
if err != nil {
con.PrintErrorf("Failed to decode response %s\n", err)
return
}
PrintMsfRemote(msfTask, con)
})
con.PrintAsyncResponse(msfTask.Response)
} else {
con.PrintInfof("Executed payload on target\n")
PrintMsfRemote(msfTask, con)
}
}
func PrintMsfRemote(msfRemote *sliverpb.Task, con *console.SliverConsoleClient) {
}
+2 -2
View File
@@ -31,7 +31,7 @@ import (
// MsfCmd - Inject a metasploit payload into the current remote process
func MsfCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
session := con.ActiveSession.GetInteractive()
session := con.ActiveTarget.GetSessionInteractive()
if session == nil {
return
}
@@ -52,7 +52,7 @@ func MsfCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
payloadName, session.OS, session.Arch, lhost, lport)
con.SpinUntil(msg, ctrl)
_, err := con.Rpc.Msf(context.Background(), &clientpb.MSFReq{
Request: con.ActiveSession.Request(ctx),
Request: con.ActiveTarget.Request(ctx),
Payload: payloadName,
LHost: lhost,
LPort: uint32(lport),
+10 -10
View File
@@ -21,11 +21,12 @@ package exec
import (
"context"
"fmt"
"math/rand"
insecureRand "math/rand"
"strings"
"time"
"github.com/bishopfox/sliver/client/command/generate"
"github.com/bishopfox/sliver/client/command/settings"
"github.com/bishopfox/sliver/client/console"
"github.com/bishopfox/sliver/protobuf/clientpb"
"github.com/bishopfox/sliver/protobuf/commonpb"
@@ -36,14 +37,14 @@ import (
// PsExecCmd - psexec command implementation.
func PsExecCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
session := con.ActiveSession.GetInteractive()
session := con.ActiveTarget.GetSessionInteractive()
if session == nil {
return
}
hostname := ctx.Args.String("hostname")
if hostname == "" {
con.PrintWarnf("you need to provide a target host, see `help psexec` for examples")
con.PrintErrorf("You need to provide a target host, see `help psexec` for examples")
return
}
profile := ctx.Flags.String("profile")
@@ -53,9 +54,9 @@ func PsExecCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
uploadPath := fmt.Sprintf(`\\%s\%s`, hostname, strings.ReplaceAll(strings.ToLower(ctx.Flags.String("binpath")), "c:", "C$"))
if serviceName == "Sliver" || serviceDesc == "Sliver implant" {
con.PrintWarnf("Warning: You're going to deploy the following service:\n- Name: %s\n- Description: %s\n", serviceName, serviceDesc)
con.PrintWarnf("You're going to deploy the following service:\n- Name: %s\n- Description: %s\n", serviceName, serviceDesc)
con.PrintWarnf("You might want to change that before going further...\n")
if !con.IsUserAnAdult() {
if !settings.IsUserAnAdult(con) {
return
}
}
@@ -96,7 +97,7 @@ func PsExecCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
Encoder: "gzip",
Data: uploadGzip,
Path: filePath,
Request: con.ActiveSession.Request(ctx),
Request: con.ActiveTarget.Request(ctx),
})
uploadCtrl <- true
<-uploadCtrl
@@ -119,7 +120,7 @@ func PsExecCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
start, err := con.Rpc.StartService(context.Background(), &sliverpb.StartServiceReq{
BinPath: binaryPath,
Hostname: hostname,
Request: con.ActiveSession.Request(ctx),
Request: con.ActiveTarget.Request(ctx),
ServiceDescription: serviceDesc,
ServiceName: serviceName,
Arguments: "",
@@ -142,7 +143,7 @@ func PsExecCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
Hostname: hostname,
ServiceName: serviceName,
},
Request: con.ActiveSession.Request(ctx),
Request: con.ActiveTarget.Request(ctx),
})
removeChan <- true
<-removeChan
@@ -159,10 +160,9 @@ func PsExecCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
func randomString(length int) string {
var charset = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"
var seededRand *rand.Rand = rand.New(rand.NewSource(time.Now().UnixNano()))
b := make([]byte, length)
for i := range b {
b[i] = charset[seededRand.Intn(len(charset))]
b[i] = charset[insecureRand.Intn(len(charset))]
}
return string(b)
}
+34 -6
View File
@@ -3,14 +3,17 @@ package exec
/*
Sliver Implant Framework
Copyright (C) 2019 Bishop Fox
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
@@ -20,19 +23,20 @@ import (
"fmt"
"io/ioutil"
"os"
"path"
"path/filepath"
"strings"
"github.com/bishopfox/sliver/client/console"
"github.com/bishopfox/sliver/protobuf/clientpb"
"github.com/bishopfox/sliver/protobuf/sliverpb"
"github.com/desertbit/grumble"
"google.golang.org/protobuf/proto"
)
// SideloadCmd - Sideload a shared library on the remote system
func SideloadCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
session := con.ActiveSession.Get()
if session == nil {
session, beacon := con.ActiveTarget.GetInteractive()
if session == nil && beacon == nil {
return
}
@@ -51,7 +55,7 @@ func SideloadCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
ctrl := make(chan bool)
con.SpinUntil(fmt.Sprintf("Sideloading %s ...", binPath), ctrl)
sideload, err := con.Rpc.Sideload(context.Background(), &sliverpb.SideloadReq{
Request: con.ActiveSession.Request(ctx),
Request: con.ActiveTarget.Request(ctx),
Args: args,
Data: binData,
EntryPoint: entryPoint,
@@ -66,14 +70,38 @@ func SideloadCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
return
}
hostname := getHostname(session, beacon)
if sideload.Response != nil && sideload.Response.Async {
con.AddBeaconCallback(sideload.Response.TaskID, func(task *clientpb.BeaconTask) {
err = proto.Unmarshal(task.Response, sideload)
if err != nil {
con.PrintErrorf("Failed to decode response %s\n", err)
return
}
PrintSideload(sideload, hostname, ctx, con)
})
con.PrintAsyncResponse(sideload.Response)
} else {
PrintSideload(sideload, hostname, ctx, con)
}
}
// PrintSideload - Print the sideload command output
func PrintSideload(sideload *sliverpb.Sideload, hostname string, ctx *grumble.Context, con *console.SliverConsoleClient) {
if sideload.GetResponse().GetErr() != "" {
con.PrintErrorf("Error: %s\n", sideload.GetResponse().GetErr())
con.PrintErrorf("%s\n", sideload.GetResponse().GetErr())
return
}
var outFilePath *os.File
var err error
if ctx.Flags.Bool("save") {
outFile := path.Base(fmt.Sprintf("%s_%s*.log", ctx.Command.Name, session.GetHostname()))
outFile := filepath.Base(fmt.Sprintf("%s_%s*.log", ctx.Command.Name, hostname))
outFilePath, err = ioutil.TempFile("", outFile)
if err != nil {
con.PrintErrorf("%s\n", err)
return
}
}
con.PrintInfof("Output:\n%s", sideload.GetResult())
if outFilePath != nil {
+34 -8
View File
@@ -5,18 +5,20 @@ import (
"fmt"
"io/ioutil"
"os"
"path"
"path/filepath"
"strings"
"github.com/bishopfox/sliver/client/console"
"github.com/bishopfox/sliver/protobuf/clientpb"
"github.com/bishopfox/sliver/protobuf/sliverpb"
"github.com/desertbit/grumble"
"google.golang.org/protobuf/proto"
)
// SpawnDllCmd - Spawn execution of a DLL on the remote system
func SpawnDllCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
session := con.ActiveSession.Get()
if session == nil {
session, beacon := con.ActiveTarget.GetInteractive()
if session == nil && beacon == nil {
return
}
dllArgs := strings.Join(ctx.Args.StringList("arguments"), " ")
@@ -36,24 +38,48 @@ func SpawnDllCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
ProcessName: processName,
Args: dllArgs,
EntryPoint: exportName,
Request: con.ActiveSession.Request(ctx),
Request: con.ActiveTarget.Request(ctx),
Kill: !ctx.Flags.Bool("keep-alive"),
})
if err != nil {
con.PrintErrorf("Error: %s\n", err)
con.PrintErrorf("%s\n", err)
return
}
ctrl <- true
<-ctrl
hostname := getHostname(session, beacon)
if spawndll.Response != nil && spawndll.Response.Async {
con.AddBeaconCallback(spawndll.Response.TaskID, func(task *clientpb.BeaconTask) {
err = proto.Unmarshal(task.Response, spawndll)
if err != nil {
con.PrintErrorf("Failed to decode response %s\n", err)
return
}
PrintSpawnDll(spawndll, hostname, ctx, con)
})
con.PrintAsyncResponse(spawndll.Response)
} else {
PrintSpawnDll(spawndll, hostname, ctx, con)
}
}
// PrintSpawnDll - Print the SpawnDll command response
func PrintSpawnDll(spawndll *sliverpb.SpawnDll, hostname string, ctx *grumble.Context, con *console.SliverConsoleClient) {
if spawndll.GetResponse().GetErr() != "" {
con.PrintErrorf("Error: %s\n", spawndll.GetResponse().GetErr())
con.PrintErrorf("Failed to spawn dll: %s\n", spawndll.GetResponse().GetErr())
return
}
var outFilePath *os.File
var err error
if ctx.Flags.Bool("save") {
outFile := path.Base(fmt.Sprintf("%s_%s*.log", ctx.Command.Name, session.GetHostname()))
outFile := filepath.Base(fmt.Sprintf("%s_%s*.log", ctx.Command.Name, hostname))
outFilePath, err = ioutil.TempFile("", outFile)
if err != nil {
con.PrintErrorf("%s\n", err)
return
}
}
con.PrintInfof("Output:\n%s", spawndll.GetResult())
if outFilePath != nil {
+30 -13
View File
@@ -11,6 +11,7 @@ import (
"github.com/bishopfox/sliver/protobuf/clientpb"
"github.com/bishopfox/sliver/protobuf/sliverpb"
"github.com/desertbit/grumble"
"google.golang.org/protobuf/proto"
)
// SSHCmd - A built-in SSH client command for the remote system (doesn't shell out)
@@ -19,7 +20,7 @@ func SSHCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
privKey []byte
err error
)
session := con.ActiveSession.GetInteractive()
session := con.ActiveTarget.GetSessionInteractive()
if session == nil {
return
}
@@ -51,33 +52,49 @@ func SSHCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
}
}
commandResp, err := con.Rpc.RunSSHCommand(context.Background(), &sliverpb.SSHCommandReq{
sshCmd, err := con.Rpc.RunSSHCommand(context.Background(), &sliverpb.SSHCommandReq{
Username: username,
Hostname: hostname,
Port: uint32(port),
PrivKey: privKey,
Password: password,
Command: strings.Join(command, " "),
Request: con.ActiveSession.Request(ctx),
Request: con.ActiveTarget.Request(ctx),
})
if err != nil {
con.PrintErrorf("%s\n", err)
return
}
if sshCmd.Response != nil && sshCmd.Response.Async {
con.AddBeaconCallback(sshCmd.Response.TaskID, func(task *clientpb.BeaconTask) {
err = proto.Unmarshal(task.Response, sshCmd)
if err != nil {
con.PrintErrorf("Failed to decode response %s\n", err)
return
}
PrintSSHCmd(sshCmd, con)
})
con.PrintAsyncResponse(sshCmd.Response)
} else {
PrintSSHCmd(sshCmd, con)
}
}
if commandResp.Response != nil && commandResp.Response.Err != "" {
con.PrintErrorf("Error: %s\n", commandResp.Response.Err)
if commandResp.StdErr != "" {
con.PrintErrorf("StdErr: %s\n", commandResp.StdErr)
// PrintSSHCmd - Print the ssh command response
func PrintSSHCmd(sshCmd *sliverpb.SSHCommand, con *console.SliverConsoleClient) {
if sshCmd.Response != nil && sshCmd.Response.Err != "" {
con.PrintErrorf("Error: %s\n", sshCmd.Response.Err)
if sshCmd.StdErr != "" {
con.PrintErrorf("StdErr: %s\n", sshCmd.StdErr)
}
return
}
if commandResp.StdOut != "" {
con.PrintInfof("Output:")
con.Println(commandResp.StdOut)
if commandResp.StdErr != "" {
con.PrintInfof("StdErr")
con.Println(commandResp.StdErr)
if sshCmd.StdOut != "" {
con.PrintInfof("Output:\n")
con.Println(sshCmd.StdOut)
if sshCmd.StdErr != "" {
con.PrintInfof("StdErr:\n")
con.Println(sshCmd.StdErr)
}
}
}
+10 -72
View File
@@ -3,7 +3,6 @@ package extensions
import (
"bytes"
"context"
"encoding/binary"
"encoding/json"
"errors"
"fmt"
@@ -13,10 +12,9 @@ import (
"path/filepath"
"strings"
"golang.org/x/text/encoding/unicode"
"github.com/bishopfox/sliver/client/console"
consts "github.com/bishopfox/sliver/client/constants"
"github.com/bishopfox/sliver/client/core"
"github.com/bishopfox/sliver/protobuf/clientpb"
"github.com/bishopfox/sliver/protobuf/sliverpb"
"github.com/desertbit/grumble"
@@ -158,13 +156,13 @@ func RegisterExtensionCommand(extCmd *extensionCommand, con *console.SliverConso
}
func ListCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
session := con.ActiveSession.GetInteractive()
session := con.ActiveTarget.GetSessionInteractive()
if session == nil {
return
}
extList, err := con.Rpc.ListExtensions(context.Background(), &sliverpb.ListExtensionsReq{
Request: con.ActiveSession.Request(ctx),
Request: con.ActiveTarget.Request(ctx),
})
if err != nil {
con.PrintErrorf("Error: %s", err)
@@ -192,7 +190,7 @@ func loadExtension(ctx *grumble.Context, session *clientpb.Session, con *console
// Try to find the extension in the loaded extensions
if len(session.Extensions) == 0 {
extList, err := con.Rpc.ListExtensions(context.Background(), &sliverpb.ListExtensionsReq{
Request: con.ActiveSession.Request(ctx),
Request: con.ActiveTarget.Request(ctx),
})
if err != nil {
con.PrintErrorf("Error: %s\n", err.Error())
@@ -255,7 +253,7 @@ func registerExtension(con *console.SliverConsoleClient, ext *extensionCommand,
Data: binData,
OS: session.OS,
Init: ext.Init,
Request: con.ActiveSession.Request(ctx),
Request: con.ActiveTarget.Request(ctx),
})
if err != nil {
return err
@@ -290,7 +288,7 @@ func runExtensionCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
extName string
entryPoint string
)
session := con.ActiveSession.GetInteractive()
session := con.ActiveTarget.GetSessionInteractive()
if session == nil {
return
}
@@ -302,6 +300,7 @@ func runExtensionCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
}
if err = loadExtension(ctx, session, con, &ext); err != nil {
con.PrintErrorf("Could not load extension: %s\n", err)
return
}
@@ -350,7 +349,7 @@ func runExtensionCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
Name: extName,
Export: entryPoint,
Args: extensionArgs,
Request: con.ActiveSession.Request(ctx),
Request: con.ActiveTarget.Request(ctx),
})
ctrl <- true
<-ctrl
@@ -378,7 +377,7 @@ func getBOFArgs(ctx *grumble.Context, binPath string, ext extensionCommand) ([]b
if err != nil {
return nil, err
}
argsBuffer := BOFArgsBuffer{
argsBuffer := core.BOFArgsBuffer{
Buffer: new(bytes.Buffer),
}
// Parse BOF arguments from grumble
@@ -427,7 +426,7 @@ func getBOFArgs(ctx *grumble.Context, binPath string, ext extensionCommand) ([]b
return nil, err
}
// Now build the extension's argument buffer
extensionArgsBuffer := BOFArgsBuffer{
extensionArgsBuffer := core.BOFArgsBuffer{
Buffer: new(bytes.Buffer),
}
err = extensionArgsBuffer.AddString(ext.Entrypoint)
@@ -462,64 +461,3 @@ func cmdExists(name string, app *grumble.App) bool {
func init() {
commandMap = make(map[string]extensionCommand)
}
// BOF Specific code
type BOFArgsBuffer struct {
Buffer *bytes.Buffer
}
func (b *BOFArgsBuffer) AddData(d []byte) error {
dataLen := uint32(len(d))
err := binary.Write(b.Buffer, binary.LittleEndian, &dataLen)
if err != nil {
return err
}
return binary.Write(b.Buffer, binary.LittleEndian, &d)
}
func (b *BOFArgsBuffer) AddShort(d uint16) error {
return binary.Write(b.Buffer, binary.LittleEndian, &d)
}
func (b *BOFArgsBuffer) AddInt(d uint32) error {
return binary.Write(b.Buffer, binary.LittleEndian, &d)
}
func (b *BOFArgsBuffer) AddString(d string) error {
stringLen := uint32(len(d)) + 1
err := binary.Write(b.Buffer, binary.LittleEndian, &stringLen)
if err != nil {
return err
}
dBytes := append([]byte(d), 0x00)
return binary.Write(b.Buffer, binary.LittleEndian, dBytes)
}
func (b *BOFArgsBuffer) AddWString(d string) error {
encoder := unicode.UTF16(unicode.LittleEndian, unicode.IgnoreBOM).NewEncoder()
strBytes := append([]byte(d), 0x00)
utf16Data, err := encoder.Bytes(strBytes)
if err != nil {
return err
}
stringLen := uint32(len(utf16Data))
err = binary.Write(b.Buffer, binary.LittleEndian, &stringLen)
if err != nil {
return err
}
return binary.Write(b.Buffer, binary.LittleEndian, utf16Data)
}
func (b *BOFArgsBuffer) GetBuffer() ([]byte, error) {
outBuffer := new(bytes.Buffer)
err := binary.Write(outBuffer, binary.LittleEndian, uint32(b.Buffer.Len()))
if err != nil {
return nil, err
}
err = binary.Write(outBuffer, binary.LittleEndian, b.Buffer.Bytes())
if err != nil {
return nil, err
}
return outBuffer.Bytes(), nil
}
+27 -11
View File
@@ -28,16 +28,18 @@ import (
"github.com/alecthomas/chroma/lexers"
"github.com/alecthomas/chroma/styles"
"github.com/bishopfox/sliver/client/console"
"github.com/bishopfox/sliver/protobuf/clientpb"
"github.com/bishopfox/sliver/protobuf/sliverpb"
"github.com/bishopfox/sliver/util/encoders"
"google.golang.org/protobuf/proto"
"github.com/desertbit/grumble"
)
// CatCmd - Display the contents of a remote file
func CatCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
session := con.ActiveSession.GetInteractive()
if session == nil {
session, beacon := con.ActiveTarget.GetInteractive()
if session == nil && beacon == nil {
return
}
@@ -48,13 +50,35 @@ func CatCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
}
download, err := con.Rpc.Download(context.Background(), &sliverpb.DownloadReq{
Request: con.ActiveSession.Request(ctx),
Request: con.ActiveTarget.Request(ctx),
Path: filePath,
})
if err != nil {
con.PrintErrorf("%s\n", err)
return
}
if download.Response != nil && download.Response.Async {
con.AddBeaconCallback(download.Response.TaskID, func(task *clientpb.BeaconTask) {
err = proto.Unmarshal(task.Response, download)
if err != nil {
con.PrintErrorf("Failed to decode response %s\n", err)
return
}
PrintCat(download, ctx, con)
})
con.PrintAsyncResponse(download.Response)
} else {
PrintCat(download, ctx, con)
}
}
// PrintCat - Print the download to stdout
func PrintCat(download *sliverpb.Download, ctx *grumble.Context, con *console.SliverConsoleClient) {
var err error
if download.Response != nil && download.Response.Err != "" {
con.PrintErrorf("%s\n", download.Response.Err)
return
}
if download.Encoder == "gzip" {
download.Data, err = new(encoders.Gzip).Decode(download.Data)
if err != nil {
@@ -73,14 +97,6 @@ func CatCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
con.Println(string(download.Data))
}
}
// if ctx.Flags.Bool("loot") && 0 < len(download.Data) {
// err = AddLootFile(rpc, fmt.Sprintf("[cat] %s", filepath.Base(filePath)), filePath, download.Data, false)
// if err != nil {
// con.PrintErrorf("Failed to save output as loot: %s", err)
// } else {
// fmt.Printf(clearln + Info + "Output saved as loot\n")
// }
// }
}
func colorize(f *sliverpb.Download) error {
+18 -4
View File
@@ -22,26 +22,40 @@ import (
"context"
"github.com/bishopfox/sliver/client/console"
"github.com/bishopfox/sliver/protobuf/clientpb"
"github.com/bishopfox/sliver/protobuf/sliverpb"
"google.golang.org/protobuf/proto"
"github.com/desertbit/grumble"
)
// CdCmd - Change directory on the remote system
func CdCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
session := con.ActiveSession.GetInteractive()
if session == nil {
session, beacon := con.ActiveTarget.GetInteractive()
if session == nil && beacon == nil {
return
}
filePath := ctx.Args.String("path")
pwd, err := con.Rpc.Cd(context.Background(), &sliverpb.CdReq{
Request: con.ActiveSession.Request(ctx),
Request: con.ActiveTarget.Request(ctx),
Path: filePath,
})
if err != nil {
con.PrintErrorf("%s\n", err)
return
}
if pwd.Response != nil && pwd.Response.Async {
con.AddBeaconCallback(pwd.Response.TaskID, func(task *clientpb.BeaconTask) {
err = proto.Unmarshal(task.Response, pwd)
if err != nil {
con.PrintErrorf("Failed to decode response %s\n", err)
return
}
PrintPwd(pwd, con)
})
con.PrintAsyncResponse(pwd.Response)
} else {
con.PrintInfof("%s\n", pwd.Path)
PrintPwd(pwd, con)
}
}
+48 -21
View File
@@ -27,16 +27,18 @@ import (
"github.com/AlecAivazis/survey/v2"
"github.com/bishopfox/sliver/client/console"
"github.com/bishopfox/sliver/protobuf/clientpb"
"github.com/bishopfox/sliver/protobuf/sliverpb"
"github.com/bishopfox/sliver/util/encoders"
"google.golang.org/protobuf/proto"
"github.com/desertbit/grumble"
)
// DownloadCmd - Download a file from the remote system
func DownloadCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
session := con.ActiveSession.GetInteractive()
if session == nil {
session, beacon := con.ActiveTarget.GetInteractive()
if session == nil && beacon == nil {
return
}
@@ -55,19 +57,10 @@ func DownloadCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
dst = path.Join(dst, fileName)
}
if _, err := os.Stat(dst); err == nil {
overwrite := false
prompt := &survey.Confirm{Message: "Overwrite local file?"}
survey.AskOne(prompt, &overwrite, nil)
if !overwrite {
return
}
}
ctrl := make(chan bool)
con.SpinUntil(fmt.Sprintf("%s -> %s", fileName, dst), ctrl)
download, err := con.Rpc.Download(context.Background(), &sliverpb.DownloadReq{
Request: con.ActiveSession.Request(ctx),
Request: con.ActiveTarget.Request(ctx),
Path: remotePath,
})
ctrl <- true
@@ -76,7 +69,50 @@ func DownloadCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
con.PrintErrorf("%s\n", err)
return
}
if download.Response != nil && download.Response.Async {
con.AddBeaconCallback(download.Response.TaskID, func(task *clientpb.BeaconTask) {
err = proto.Unmarshal(task.Response, download)
if err != nil {
con.PrintErrorf("Failed to decode response %s\n", err)
return
}
PrintDownload(download, ctx, con)
})
con.PrintAsyncResponse(download.Response)
} else {
PrintDownload(download, ctx, con)
}
}
// PrintDownload - Print the download response, and save file to disk
func PrintDownload(download *sliverpb.Download, ctx *grumble.Context, con *console.SliverConsoleClient) {
if download.Response != nil && download.Response.Err != "" {
con.PrintErrorf("%s\n", download.Response.Err)
return
}
remotePath := ctx.Args.String("remote-path")
localPath := ctx.Args.String("local-path")
src := remotePath
fileName := filepath.Base(src)
dst, _ := filepath.Abs(localPath)
fi, err := os.Stat(dst)
if err != nil && !os.IsNotExist(err) {
con.PrintErrorf("%s\n", err)
return
}
if err == nil && fi.IsDir() {
dst = path.Join(dst, fileName)
}
if _, err := os.Stat(dst); err == nil {
overwrite := false
prompt := &survey.Confirm{Message: "Overwrite local file?"}
survey.AskOne(prompt, &overwrite, nil)
if !overwrite {
return
}
}
if download.Encoder == "gzip" {
download.Data, err = new(encoders.Gzip).Decode(download.Data)
if err != nil {
@@ -96,13 +132,4 @@ func DownloadCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
} else {
con.PrintInfof("Wrote %d bytes to %s\n", n, dstFile.Name())
}
// if ctx.Flags.Bool("loot") && 0 < len(download.Data) {
// err = AddLootFile(rpc, fmt.Sprintf("[download] %s", filepath.Base(remotePath)), remotePath, download.Data, false)
// if err != nil {
// con.PrintErrorf("Failed to save output as loot: %s", err)
// } else {
// fmt.Printf(Info + "Output saved as loot\n")
// }
// }
}
+28 -9
View File
@@ -29,16 +29,18 @@ import (
"time"
"github.com/bishopfox/sliver/client/console"
"github.com/bishopfox/sliver/protobuf/clientpb"
"github.com/bishopfox/sliver/protobuf/sliverpb"
"github.com/bishopfox/sliver/util"
"google.golang.org/protobuf/proto"
"github.com/desertbit/grumble"
)
// LsCmd - List the contents of a remote directory
func LsCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
session := con.ActiveSession.GetInteractive()
if session == nil {
session, beacon := con.ActiveTarget.GetInteractive()
if session == nil && beacon == nil {
return
}
@@ -60,9 +62,9 @@ func LsCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
of the client does not necessarily match the OS of the
implant
*/
lastSeparatorOccurence := strings.LastIndex(testPath, "/")
lastSeparatorOccurrence := strings.LastIndex(testPath, "/")
if lastSeparatorOccurence == -1 {
if lastSeparatorOccurrence == -1 {
// Then this is only a filter
filter = remotePath
remotePath = "."
@@ -70,8 +72,8 @@ func LsCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
// Then we need to test for a filter on the end of the string
// The indicies should be the same because we did not change the length of the string
baseDir := remotePath[:lastSeparatorOccurence]
potentialFilter := remotePath[lastSeparatorOccurence+1:]
baseDir := remotePath[:lastSeparatorOccurrence+1]
potentialFilter := remotePath[lastSeparatorOccurrence+1:]
_, err := filepath.Match(potentialFilter, "")
@@ -84,18 +86,35 @@ func LsCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
}
ls, err := con.Rpc.Ls(context.Background(), &sliverpb.LsReq{
Request: con.ActiveSession.Request(ctx),
Request: con.ActiveTarget.Request(ctx),
Path: remotePath,
})
if err != nil {
con.PrintWarnf("%s\n", err)
return
}
if ls.Response != nil && ls.Response.Async {
con.AddBeaconCallback(ls.Response.TaskID, func(task *clientpb.BeaconTask) {
err = proto.Unmarshal(task.Response, ls)
if err != nil {
con.PrintErrorf("Failed to decode response %s\n", err)
return
}
PrintLs(ls, ctx.Flags, filter, con)
})
con.PrintAsyncResponse(ls.Response)
} else {
PrintLs(ls, con, ctx.Flags, filter)
PrintLs(ls, ctx.Flags, filter, con)
}
}
// PrintLs - Display an sliverpb.Ls object
func PrintLs(ls *sliverpb.Ls, con *console.SliverConsoleClient, flags grumble.FlagMap, filter string) {
func PrintLs(ls *sliverpb.Ls, flags grumble.FlagMap, filter string, con *console.SliverConsoleClient) {
if ls.Response != nil && ls.Response.Err != "" {
con.PrintErrorf("%s\n", ls.Response.Err)
return
}
con.Printf("%s\n", ls.Path)
con.Printf("%s\n", strings.Repeat("=", len(ls.Path)))
+27 -4
View File
@@ -22,15 +22,17 @@ import (
"context"
"github.com/bishopfox/sliver/client/console"
"github.com/bishopfox/sliver/protobuf/clientpb"
"github.com/bishopfox/sliver/protobuf/sliverpb"
"google.golang.org/protobuf/proto"
"github.com/desertbit/grumble"
)
// MkdirCmd - Make a remote directory
func MkdirCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
session := con.ActiveSession.GetInteractive()
if session == nil {
session, beacon := con.ActiveTarget.GetInteractive()
if session == nil && beacon == nil {
return
}
@@ -42,12 +44,33 @@ func MkdirCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
}
mkdir, err := con.Rpc.Mkdir(context.Background(), &sliverpb.MkdirReq{
Request: con.ActiveSession.Request(ctx),
Request: con.ActiveTarget.Request(ctx),
Path: filePath,
})
if err != nil {
con.PrintErrorf("%s\n", err)
return
}
if mkdir.Response != nil && mkdir.Response.Async {
con.AddBeaconCallback(mkdir.Response.TaskID, func(task *clientpb.BeaconTask) {
err = proto.Unmarshal(task.Response, mkdir)
if err != nil {
con.PrintErrorf("Failed to decode response %s\n", err)
return
}
PrintMkdir(mkdir, con)
})
con.PrintAsyncResponse(mkdir.Response)
} else {
con.PrintInfof("%s\n", mkdir.Path)
PrintMkdir(mkdir, con)
}
}
// PrintMkdir - Print make directory
func PrintMkdir(mkdir *sliverpb.Mkdir, con *console.SliverConsoleClient) {
if mkdir.Response != nil && mkdir.Response.Err != "" {
con.PrintErrorf("%s\n", mkdir.Response.Err)
return
}
con.PrintInfof("%s\n", mkdir.Path)
}
+27 -5
View File
@@ -22,24 +22,46 @@ import (
"context"
"github.com/bishopfox/sliver/client/console"
"github.com/bishopfox/sliver/protobuf/clientpb"
"github.com/bishopfox/sliver/protobuf/sliverpb"
"google.golang.org/protobuf/proto"
"github.com/desertbit/grumble"
)
// PwdCmd - Print the remote working directory
func PwdCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
session := con.ActiveSession.GetInteractive()
if session == nil {
session, beacon := con.ActiveTarget.GetInteractive()
if session == nil && beacon == nil {
return
}
pwd, err := con.Rpc.Pwd(context.Background(), &sliverpb.PwdReq{
Request: con.ActiveSession.Request(ctx),
Request: con.ActiveTarget.Request(ctx),
})
if err != nil {
con.PrintErrorf("%s\n", err)
return
}
if pwd.Response != nil && pwd.Response.Async {
con.AddBeaconCallback(pwd.Response.TaskID, func(task *clientpb.BeaconTask) {
err = proto.Unmarshal(task.Response, pwd)
if err != nil {
con.PrintErrorf("Failed to decode response %s\n", err)
return
}
PrintPwd(pwd, con)
})
con.PrintAsyncResponse(pwd.Response)
} else {
con.PrintInfof("%s\n", pwd.Path)
PrintPwd(pwd, con)
}
}
// PrintPwd - Print the remote working directory
func PrintPwd(pwd *sliverpb.Pwd, con *console.SliverConsoleClient) {
if pwd.Response != nil && pwd.Response.Err != "" {
con.PrintErrorf("%s\n", pwd.Response.Err)
return
}
con.PrintInfof("%s\n", pwd.Path)
}
+27 -4
View File
@@ -22,15 +22,17 @@ import (
"context"
"github.com/bishopfox/sliver/client/console"
"github.com/bishopfox/sliver/protobuf/clientpb"
"github.com/bishopfox/sliver/protobuf/sliverpb"
"google.golang.org/protobuf/proto"
"github.com/desertbit/grumble"
)
// RmCmd - Remove a directory from the remote file system
func RmCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
session := con.ActiveSession.GetInteractive()
if session == nil {
session, beacon := con.ActiveTarget.GetInteractive()
if session == nil && beacon == nil {
return
}
@@ -42,14 +44,35 @@ func RmCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
}
rm, err := con.Rpc.Rm(context.Background(), &sliverpb.RmReq{
Request: con.ActiveSession.Request(ctx),
Request: con.ActiveTarget.Request(ctx),
Path: filePath,
Recursive: ctx.Flags.Bool("recursive"),
Force: ctx.Flags.Bool("force"),
})
if err != nil {
con.PrintErrorf("%s\n", err)
return
}
if rm.Response != nil && rm.Response.Async {
con.AddBeaconCallback(rm.Response.TaskID, func(task *clientpb.BeaconTask) {
err = proto.Unmarshal(task.Response, rm)
if err != nil {
con.PrintErrorf("Failed to decode response %s\n", err)
return
}
PrintRm(rm, con)
})
con.PrintAsyncResponse(rm.Response)
} else {
con.PrintInfof("%s\n", rm.Path)
PrintRm(rm, con)
}
}
// PrintRm - Print the rm response
func PrintRm(rm *sliverpb.Rm, con *console.SliverConsoleClient) {
if rm.Response != nil && rm.Response.Err != "" {
con.PrintErrorf("%s\n", rm.Response.Err)
return
}
con.PrintInfof("%s\n", rm.Path)
}
+27 -4
View File
@@ -26,16 +26,18 @@ import (
"path/filepath"
"github.com/bishopfox/sliver/client/console"
"github.com/bishopfox/sliver/protobuf/clientpb"
"github.com/bishopfox/sliver/protobuf/sliverpb"
"github.com/bishopfox/sliver/util/encoders"
"google.golang.org/protobuf/proto"
"github.com/desertbit/grumble"
)
// UploadCmd - Upload a file to the remote system
func UploadCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
session := con.ActiveSession.GetInteractive()
if session == nil {
session, beacon := con.ActiveTarget.GetInteractive()
if session == nil && beacon == nil {
return
}
@@ -67,7 +69,7 @@ func UploadCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
ctrl := make(chan bool)
con.SpinUntil(fmt.Sprintf("%s -> %s", src, dst), ctrl)
upload, err := con.Rpc.Upload(context.Background(), &sliverpb.UploadReq{
Request: con.ActiveSession.Request(ctx),
Request: con.ActiveTarget.Request(ctx),
Path: dst,
Data: uploadGzip,
Encoder: "gzip",
@@ -77,7 +79,28 @@ func UploadCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
<-ctrl
if err != nil {
con.PrintErrorf("%s\n", err)
return
}
if upload.Response != nil && upload.Response.Async {
con.AddBeaconCallback(upload.Response.TaskID, func(task *clientpb.BeaconTask) {
err = proto.Unmarshal(task.Response, upload)
if err != nil {
con.PrintErrorf("Failed to decode response %s\n", err)
return
}
PrintUpload(upload, con)
})
con.PrintAsyncResponse(upload.Response)
} else {
con.PrintInfof("Wrote file to %s\n", upload.Path)
PrintUpload(upload, con)
}
}
// PrintUpload - Print the result of the upload command
func PrintUpload(upload *sliverpb.Upload, con *console.SliverConsoleClient) {
if upload.Response != nil && upload.Response.Err != "" {
con.PrintErrorf("%s\n", upload.Response.Err)
return
}
con.PrintInfof("Wrote file to %s\n", upload.Path)
}
@@ -0,0 +1,48 @@
package generate
import (
"fmt"
"os"
"time"
"github.com/bishopfox/sliver/client/console"
"github.com/bishopfox/sliver/protobuf/clientpb"
"github.com/desertbit/grumble"
)
var (
minBeaconInterval = 5 * time.Second
ErrBeaconIntervalTooShort = fmt.Errorf("Beacon interval must be %v or greater", minBeaconInterval)
)
// GenerateBeaconCmd - The main command used to generate implant binaries
func GenerateBeaconCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
config := parseCompileFlags(ctx, con)
if config == nil {
return
}
config.IsBeacon = true
err := parseBeaconFlags(ctx, con, config)
if err != nil {
con.PrintErrorf("%s\n", err)
return
}
save := ctx.Flags.String("save")
if save == "" {
save, _ = os.Getwd()
}
compile(config, save, con)
}
func parseBeaconFlags(ctx *grumble.Context, con *console.SliverConsoleClient, config *clientpb.ImplantConfig) error {
interval := time.Duration(ctx.Flags.Int64("days")) * time.Hour * 24
interval += time.Duration(ctx.Flags.Int64("hours")) * time.Hour
interval += time.Duration(ctx.Flags.Int64("minutes")) * time.Minute
interval += time.Duration(ctx.Flags.Int64("seconds")) * time.Second
if interval < minBeaconInterval {
return ErrBeaconIntervalTooShort
}
config.BeaconInterval = int64(interval)
config.BeaconJitter = int64(time.Duration(ctx.Flags.Int64("jitter")) * time.Second)
return nil
}
+44 -50
View File
@@ -62,8 +62,8 @@ const (
// DefaultReconnect is the default reconnect time
DefaultReconnect = 60
// DefaultPoll is the default poll interval
DefaultPoll = 1
// DefaultPollTimeout is the default poll timeout
DefaultPollTimeout = 360 // 6 minutes
// DefaultMaxErrors is the default max reconnection errors before giving up
DefaultMaxErrors = 1000
)
@@ -82,31 +82,6 @@ var (
"windows/386": true,
"windows/amd64": true,
}
// validFormats = []string{
// "bash",
// "c",
// "csharp",
// "dw",
// "dword",
// "hex",
// "java",
// "js_be",
// "js_le",
// "num",
// "perl",
// "pl",
// "powershell",
// "ps1",
// "py",
// "python",
// "raw",
// "rb",
// "ruby",
// "sh",
// "vbapplication",
// "vbscript",
// }
)
// GenerateCmd - The main command used to generate implant binaries
@@ -122,11 +97,21 @@ func GenerateCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
compile(config, save, con)
}
func expandPath(path string) string {
// unless path starts with ~
if len(path) == 0 || path[0] != 126 {
return path
}
return filepath.Join(os.Getenv("HOME"), path[1:])
}
func saveLocation(save, DefaultName string) (string, error) {
var saveTo string
if save == "" {
save, _ = os.Getwd()
}
save = expandPath(save)
fi, err := os.Stat(save)
if os.IsNotExist(err) {
log.Printf("%s does not exist\n", save)
@@ -193,22 +178,22 @@ func parseCompileFlags(ctx *grumble.Context, con *console.SliverConsoleClient) *
c2s := []*clientpb.ImplantC2{}
mtlsC2 := parseMTLSc2(ctx.Flags.String("mtls"))
mtlsC2 := ParseMTLSc2(ctx.Flags.String("mtls"))
c2s = append(c2s, mtlsC2...)
wgC2 := parseWGc2(ctx.Flags.String("wg"))
wgC2 := ParseWGc2(ctx.Flags.String("wg"))
c2s = append(c2s, wgC2...)
httpC2 := parseHTTPc2(ctx.Flags.String("http"))
httpC2 := ParseHTTPc2(ctx.Flags.String("http"))
c2s = append(c2s, httpC2...)
dnsC2 := parseDNSc2(ctx.Flags.String("dns"))
dnsC2 := ParseDNSc2(ctx.Flags.String("dns"))
c2s = append(c2s, dnsC2...)
namedPipeC2 := parseNamedPipec2(ctx.Flags.String("named-pipe"))
namedPipeC2 := ParseNamedPipec2(ctx.Flags.String("named-pipe"))
c2s = append(c2s, namedPipeC2...)
tcpPivotC2 := parseTCPPivotc2(ctx.Flags.String("tcp-pivot"))
tcpPivotC2 := ParseTCPPivotc2(ctx.Flags.String("tcp-pivot"))
c2s = append(c2s, tcpPivotC2...)
var symbolObfuscation bool
@@ -235,7 +220,7 @@ func parseCompileFlags(ctx *grumble.Context, con *console.SliverConsoleClient) *
}
reconnectInterval := ctx.Flags.Int("reconnect")
pollInterval := ctx.Flags.Int("poll")
pollTimeout := ctx.Flags.Int("poll-timeout")
maxConnectionErrors := ctx.Flags.Int("max-errors")
limitDomainJoined := ctx.Flags.Bool("limit-domainjoined")
@@ -308,8 +293,8 @@ func parseCompileFlags(ctx *grumble.Context, con *console.SliverConsoleClient) *
WGKeyExchangePort: uint32(ctx.Flags.Int("key-exchange")),
WGTcpCommsPort: uint32(ctx.Flags.Int("tcp-comms")),
ReconnectInterval: uint32(reconnectInterval),
PollInterval: uint32(pollInterval),
ReconnectInterval: int64(reconnectInterval) * int64(time.Second),
PollTimeout: int64(pollTimeout) * int64(time.Second),
MaxConnectionErrors: uint32(maxConnectionErrors),
LimitDomainJoined: limitDomainJoined,
@@ -349,11 +334,11 @@ func getTargets(targetOS string, targetArch string, con *console.SliverConsoleCl
target := fmt.Sprintf("%s/%s", targetOS, targetArch)
if _, ok := SupportedCompilerTargets[target]; !ok {
con.Printf("⚠️ Unsupported compiler target %s%s%s, but we can try to compile a Default implant.\n",
con.Printf("⚠️ Unsupported compiler target %s%s%s, but we can try to compile a generic implant.\n",
console.Bold, target, console.Normal,
)
con.Printf("⚠️ Default implants do not support all commands/features.\n")
prompt := &survey.Confirm{Message: "Compile a Default build?"}
con.Printf("⚠️ Generic implants do not support all commands/features.\n")
prompt := &survey.Confirm{Message: "Attempt to build generic implant?"}
var confirm bool
survey.AskOne(prompt, &confirm)
if !confirm {
@@ -364,7 +349,8 @@ func getTargets(targetOS string, targetArch string, con *console.SliverConsoleCl
return targetOS, targetArch
}
func parseMTLSc2(args string) []*clientpb.ImplantC2 {
// ParseMTLSc2 - Parse mtls connection string arg
func ParseMTLSc2(args string) []*clientpb.ImplantC2 {
c2s := []*clientpb.ImplantC2{}
if args == "" {
return c2s
@@ -383,7 +369,8 @@ func parseMTLSc2(args string) []*clientpb.ImplantC2 {
return c2s
}
func parseWGc2(args string) []*clientpb.ImplantC2 {
// ParseWGc2 - Parse wg connect string arg
func ParseWGc2(args string) []*clientpb.ImplantC2 {
c2s := []*clientpb.ImplantC2{}
if args == "" {
return c2s
@@ -403,7 +390,8 @@ func parseWGc2(args string) []*clientpb.ImplantC2 {
return c2s
}
func parseHTTPc2(args string) []*clientpb.ImplantC2 {
// ParseHTTPc2 - Parse HTTP connection string arg
func ParseHTTPc2(args string) []*clientpb.ImplantC2 {
c2s := []*clientpb.ImplantC2{}
if args == "" {
return c2s
@@ -433,7 +421,8 @@ func parseHTTPc2(args string) []*clientpb.ImplantC2 {
return c2s
}
func parseDNSc2(args string) []*clientpb.ImplantC2 {
// ParseDNSc2 - Parse DNS connection string arg
func ParseDNSc2(args string) []*clientpb.ImplantC2 {
c2s := []*clientpb.ImplantC2{}
if args == "" {
return c2s
@@ -458,7 +447,8 @@ func parseDNSc2(args string) []*clientpb.ImplantC2 {
return c2s
}
func parseNamedPipec2(args string) []*clientpb.ImplantC2 {
// ParseNamedPipec2 - Parse named pipe connection string arg
func ParseNamedPipec2(args string) []*clientpb.ImplantC2 {
c2s := []*clientpb.ImplantC2{}
if args == "" {
return c2s
@@ -479,7 +469,8 @@ func parseNamedPipec2(args string) []*clientpb.ImplantC2 {
return c2s
}
func parseTCPPivotc2(args string) []*clientpb.ImplantC2 {
// ParseTCPPivotc2 - Parse tcp pivot connection string arg
func ParseTCPPivotc2(args string) []*clientpb.ImplantC2 {
c2s := []*clientpb.ImplantC2{}
if args == "" {
return c2s
@@ -500,9 +491,12 @@ func parseTCPPivotc2(args string) []*clientpb.ImplantC2 {
}
func compile(config *clientpb.ImplantConfig, save string, con *console.SliverConsoleClient) (*commonpb.File, error) {
con.PrintInfof("Generating new %s/%s implant binary\n", config.GOOS, config.GOARCH)
if config.IsBeacon {
interval := time.Duration(config.BeaconInterval)
con.PrintInfof("Generating new %s/%s beacon implant binary (%v)\n", config.GOOS, config.GOARCH, interval)
} else {
con.PrintInfof("Generating new %s/%s implant binary\n", config.GOOS, config.GOARCH)
}
if config.ObfuscateSymbols {
con.PrintInfof("%sSymbol obfuscation is enabled%s\n", console.Bold, console.Normal)
} else if !config.Debug {
@@ -572,7 +566,7 @@ func checkBuildTargetCompatibility(format clientpb.OutputFormat, targetOS string
compilers, err := con.Rpc.GetCompiler(context.Background(), &commonpb.Empty{})
if err != nil {
con.PrintWarnf("Failed to check target compatibility: %s\n", err)
con.PrintErrorf("Failed to check target compatibility: %s\n", err)
return true
}
@@ -607,7 +601,7 @@ func hasCC(targetOS string, targetArch string, crossCompilers []*clientpb.CrossC
}
func warnMissingCrossCompiler(format clientpb.OutputFormat, targetOS string, targetArch string, con *console.SliverConsoleClient) bool {
con.PrintWarnf("WARNING: Missing cross-compiler for %s on %s/%s\n", nameOfOutputFormat(format), targetOS, targetArch)
con.PrintWarnf("Missing cross-compiler for %s on %s/%s\n", nameOfOutputFormat(format), targetOS, targetArch)
switch targetOS {
case "windows":
con.PrintWarnf("The server cannot find an installation of mingw")
+9 -2
View File
@@ -45,8 +45,15 @@ func printHelp(con *console.SliverConsoleClient) {
groups := make(map[string]*grumble.Commands)
for _, c := range con.App.Commands().All() {
key := c.HelpGroup
if con.ActiveSession.Get() != nil {
if con.ActiveSession.Get().GetOS() != "windows" && key == consts.SliverWinHelpGroup {
targetOS := ""
session, beacon := con.ActiveTarget.GetInteractive()
if session != nil {
targetOS = session.OS
} else if beacon != nil {
targetOS = beacon.OS
}
if beacon != nil || session != nil {
if targetOS != "windows" && key == consts.SliverWinHelpGroup {
continue
}
} else {
+21 -21
View File
@@ -173,7 +173,7 @@ Execution limits can be used to restrict the execution of a Sliver implant to ma
[[.Bold]][[.Underline]]++ Profiles ++[[.Normal]]
Due to the large number of options and C2s this can be a lot of typing. If you'd like to have a reusable a Sliver config
see 'help new-profile'. All "generate" flags can be saved into a profile, you can view existing profiles with the "profiles"
see 'help profiles new'. All "generate" flags can be saved into a profile, you can view existing profiles with the "profiles"
command.
`
generateStagerHelp = `[[.Bold]]Command:[[.Normal]] generate stager <options>
@@ -201,23 +201,23 @@ When a stager calls back to this URL, a sliver corresponding to the said profile
stage-listener --url tcp://1.2.3.4:8080 --profile my-sliver-profile
To create a profile, use the [[.Bold]]new-profile[[.Normal]] command. A common scenario is to create a profile that generates a shellcode, which can act as a stage 2:
To create a profile, use the [[.Bold]]profiles new[[.Normal]] command. A common scenario is to create a profile that generates a shellcode, which can act as a stage 2:
new-profile --profile-name windows-shellcode --format shellcode --mtls 1.2.3.4 --skip-symbols
profiles new --profile-name windows-shellcode --format shellcode --mtls 1.2.3.4 --skip-symbols
`
newProfileHelp = `[[.Bold]]Command:[[.Normal]] new [--profile-name] <options>
[[.Bold]]About:[[.Normal]] Create a new profile with a given name and options, a name is required.
[[.Bold]][[.Underline]]++ Profiles ++[[.Normal]]
Profiles are an easy way to save a sliver configurate and easily generate multiple copies of the binary with the same
settings, but will still have per-binary certificates/obfuscation/etc. This command is used with generate-profile:
new-profile --profile-name mtls-profile --mtls foo.example.com --canary 1.foobar.com
Profiles are an easy way to save an implant configuration and easily generate multiple copies of the binary with the same
settings. Generated implants will still have per-binary certificates/obfuscation/etc. This command is used with generate-profile:
profiles new --profile-name mtls-profile --mtls foo.example.com --canary 1.foobar.com
generate-profile mtls-profile
`
generateProfileHelp = `[[.Bold]]Command:[[.Normal]] generate-profile [name] <options>
[[.Bold]]About:[[.Normal]] Generate a Sliver from a saved profile (see new-profile).`
[[.Bold]]About:[[.Normal]] Generate an implant from a saved profile (see 'profiles new --help').`
msfHelp = `[[.Bold]]Command:[[.Normal]] msf [--lhost] <options>
[[.Bold]]About:[[.Normal]] Execute a metasploit payload in the current process.`
@@ -228,12 +228,12 @@ settings, but will still have per-binary certificates/obfuscation/etc. This comm
psHelp = `[[.Bold]]Command:[[.Normal]] ps <options>
[[.Bold]]About:[[.Normal]] List processes on remote system.`
pingHelp = `[[.Bold]]Command:[[.Normal]] ping <sliver name/session>
[[.Bold]]About:[[.Normal]] Ping Sliver by name or the active sliver. This does NOT send an ICMP packet, it just sends an empty
c2 message round trip to ensure the remote Sliver is still responding to commands.`
pingHelp = `[[.Bold]]Command:[[.Normal]] ping <implant name/session>
[[.Bold]]About:[[.Normal]] Ping session by name or the active session. This does NOT send an ICMP packet, it just sends a small
C2 message round trip to ensure the remote implant is still responding to commands.`
killHelp = `[[.Bold]]Command:[[.Normal]] kill <sliver name/session>
[[.Bold]]About:[[.Normal]] Kill a remote sliver process (does not delete file).`
killHelp = `[[.Bold]]Command:[[.Normal]] kill <implant name/session>
[[.Bold]]About:[[.Normal]] Kill a remote implant process (does not delete file).`
lsHelp = `[[.Bold]]Command:[[.Normal]] ls <remote path>
[[.Bold]]About:[[.Normal]] List remote files in current directory, or path if provided.
@@ -263,10 +263,10 @@ On Windows, escaping is disabled. Instead, '\\' is treated as path separator.
`
cdHelp = `[[.Bold]]Command:[[.Normal]] cd [remote path]
[[.Bold]]About:[[.Normal]] Change working directory of the active Sliver.`
[[.Bold]]About:[[.Normal]] Change working directory of the active session.`
pwdHelp = `[[.Bold]]Command:[[.Normal]] pwd
[[.Bold]]About:[[.Normal]] Print working directory of the active Sliver.`
[[.Bold]]About:[[.Normal]] Print working directory of the active session.`
mkdirHelp = `[[.Bold]]Command:[[.Normal]] mkdir [remote path]
[[.Bold]]About:[[.Normal]] Create a remote directory.`
@@ -290,20 +290,20 @@ On Windows, escaping is disabled. Instead, '\\' is treated as path separator.
[[.Bold]]About:[[.Normal]] (Windows Only) Run a new process in the context of the designated user`
impersonateHelp = `[[.Bold]]Command:[[.Normal]] impersonate USERNAME
[[.Bold]]About:[[.Normal]] (Windows Only) Steal the token of a logged in user. Sliver commands that runs new processes (like [[.Bold]]shell[[.Normal]] or [[.Bold]]execute-command[[.Normal]]) will impersonate this user.`
[[.Bold]]About:[[.Normal]] (Windows Only) Steal the token of a logged in user. Sliver commands that run new processes (like [[.Bold]]shell[[.Normal]] or [[.Bold]]execute-command[[.Normal]]) will impersonate this user.`
revToSelfHelp = `[[.Bold]]Command:[[.Normal]] rev2self
[[.Bold]]About:[[.Normal]] (Windows Only) Call RevertToSelf, lose the stolen token.`
elevateHelp = `[[.Bold]]Command:[[.Normal]] elevate
[[.Bold]]About:[[.Normal]] (Windows Only) Spawn a new sliver session as an elevated process (UAC bypass)`
[[.Bold]]About:[[.Normal]] (Windows Only) Spawn a new Sliver session as an elevated process (UAC bypass)`
executeAssemblyHelp = `[[.Bold]]Command:[[.Normal]] execute-assembly [local path to assembly] [arguments]
[[.Bold]]About:[[.Normal]] (Windows Only) Executes the .NET assembly in a child process.
`
executeShellcodeHelp = `[[.Bold]]Command:[[.Normal]] execute-shellcode [local path to raw shellcode]
[[.Bold]]About:[[.Normal]] Executes the given shellcode in the Sliver process.
[[.Bold]]About:[[.Normal]] Executes the given shellcode in the implant's process.
[[.Bold]][[.Underline]]++ Shellcode ++[[.Normal]]
Shellcode files should be binary encoded, you can generate Sliver shellcode files with the generate command:
@@ -428,9 +428,9 @@ Each command will have the [[.Bold]]--process[[.Normal]] flag defined, which all
This command uploads a Sliver binary generated on the fly from a profile.
The profile must be created with the [[.Bold]]service[[.Normal]] format, so that the service manager can properly start and stop the binary.
To create such a profile, use the [[.Bold]]new-profile[[.Normal]] command:
To create such a profile, use the [[.Bold]]profiles new[[.Normal]] command:
new-profile --format service --skip-symbols --mtls a.bc.de --profile-name win-svc64
profiles new --format service --skip-symbols --mtls a.bc.de --profile-name win-svc64
Once the profile has been created, run the [[.Bold]]psexec[[.Normal]] command:
@@ -442,7 +442,7 @@ The [[.Bold]]psexec[[.Normal]] command will use the credentials of the Windows u
[[.Bold]]About:[[.Normal]] Inject a sliver shellcode into an existing file on the target system.
[[.Bold]]Example:[[.Normal]] backdoor --profile windows-shellcode "c:\windows\system32\calc.exe"
[[.Bold]]Remark:[[.Normal]] you must first create a profile that will serve as your base shellcode, with the following command: new-profile --format shellcode --profile-name whatever --http ab.cd
[[.Bold]]Remark:[[.Normal]] you must first create a profile that will serve as your base shellcode, with the following command: profiles new --format shellcode --profile-name whatever --http ab.cd
`
makeTokenHelp = `[[.Bold]]Command:[[.Normal]] make-token -u USERNAME -d DOMAIN -p PASSWORD
[[.Bold]]About:[[.Normal]] Creates a new Logon Session from the specified credentials and impersonate the resulting token.
@@ -654,7 +654,7 @@ supplied with the --profile flag.
dllhijack --reference-path c:\\windows\\system32\\msasn1.dll --file /tmp/blah.dll c:\\users\\bob\\appdata\\slack\\app-4.18.0\\msasn1.dll
# Use a Sliver generated DLL for the hijack
new-profile --format shared --mtls 1.2.3.4:1234 --profile-name dll
profiles new --format shared --mtls 1.2.3.4:1234 --profile-name dll
dllhijack --reference-path c:\\windows\\system32\\msasn1.dll --profile dll c:\\users\\bob\\appdata\\slack\\app-4.18.0\\msasn1.dll
# Use a local DLL as the reference DLL
+26 -4
View File
@@ -28,6 +28,7 @@ import (
"text/tabwriter"
"github.com/AlecAivazis/survey/v2"
"github.com/bishopfox/sliver/client/command/settings"
"github.com/bishopfox/sliver/client/console"
"github.com/bishopfox/sliver/protobuf/clientpb"
"github.com/bishopfox/sliver/protobuf/commonpb"
@@ -59,14 +60,15 @@ func HostsCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
func hostsTable(hosts []*clientpb.Host, con *console.SliverConsoleClient) string {
tw := table.NewWriter()
tw.SetStyle(table.StyleLight)
tw.SetStyle(settings.GetTableStyle(con))
tw.AppendHeader(table.Row{
"ID",
"Hostname",
"Operating System",
"Sessions",
"Beacons",
"IOCs",
"Extension Data",
"ID (Short)",
"Extensions",
})
for _, host := range hosts {
var shortID string
@@ -76,12 +78,13 @@ func hostsTable(hosts []*clientpb.Host, con *console.SliverConsoleClient) string
shortID = host.HostUUID[:8]
}
tw.AppendRow(table.Row{
shortID,
host.Hostname,
host.OSVersion,
hostSessionNumbers(host.HostUUID, con),
hostBeacons(host.HostUUID, con),
len(host.IOCs),
len(host.ExtensionData),
shortID,
})
}
return tw.Render()
@@ -99,6 +102,25 @@ func hostSessionNumbers(hostUUID string, con *console.SliverConsoleClient) strin
return strings.Join(sessionNumbers, ", ")
}
func hostBeacons(hostUUID string, con *console.SliverConsoleClient) string {
beacons, err := con.Rpc.GetBeacons(context.Background(), &commonpb.Empty{})
if err != nil {
return "Error"
}
count := 0
for _, beacon := range beacons.Beacons {
if beacon.UUID == hostUUID {
count++
}
}
if count == 0 {
return "None"
} else {
return fmt.Sprintf("%d", count)
}
}
// SessionsForHost - Find session for a given host by id
func SessionsForHost(hostUUID string, con *console.SliverConsoleClient) []*clientpb.Session {
sessions, err := con.Rpc.GetSessions(context.Background(), &commonpb.Empty{})
if err != nil {
+51 -22
View File
@@ -21,23 +21,18 @@ package info
import (
"github.com/bishopfox/sliver/client/console"
consts "github.com/bishopfox/sliver/client/constants"
"github.com/bishopfox/sliver/protobuf/clientpb"
"github.com/desertbit/grumble"
)
// InfoCmd - Display information about the active session
func InfoCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
var session *clientpb.Session
sessionName := ctx.Args.String("session")
if con.ActiveSession.GetInteractive() != nil {
session = con.ActiveSession.GetInteractive()
} else if sessionName != "" {
session = con.GetSession(sessionName)
session, beacon := con.ActiveTarget.GetInteractive()
if session == nil && beacon == nil {
return
}
if session != nil {
con.Printf(console.Bold+" ID: %s%d\n", console.Normal, session.ID)
con.Printf(console.Bold+" Name: %s%s\n", console.Normal, session.Name)
con.Printf(console.Bold+" Hostname: %s%s\n", console.Normal, session.Hostname)
@@ -51,8 +46,26 @@ func InfoCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
con.Printf(console.Bold+" Arch: %s%s\n", console.Normal, session.Arch)
con.Printf(console.Bold+" Remote Address: %s%s\n", console.Normal, session.RemoteAddress)
con.Printf(console.Bold+" Proxy URL: %s%s\n", console.Normal, session.ProxyURL)
con.Printf(console.Bold+" Poll Interval: %s%d\n", console.Normal, session.PollInterval)
con.Printf(console.Bold+"Reconnect Interval: %s%d\n", console.Normal, session.ReconnectInterval)
} else if beacon != nil {
con.Printf(console.Bold+" ID: %s%s\n", console.Normal, beacon.ID)
con.Printf(console.Bold+" Name: %s%s\n", console.Normal, beacon.Name)
con.Printf(console.Bold+" Hostname: %s%s\n", console.Normal, beacon.Hostname)
con.Printf(console.Bold+" UUID: %s%s\n", console.Normal, beacon.UUID)
con.Printf(console.Bold+" Username: %s%s\n", console.Normal, beacon.Username)
con.Printf(console.Bold+" UID: %s%s\n", console.Normal, beacon.UID)
con.Printf(console.Bold+" GID: %s%s\n", console.Normal, beacon.GID)
con.Printf(console.Bold+" PID: %s%d\n", console.Normal, beacon.PID)
con.Printf(console.Bold+" OS: %s%s\n", console.Normal, beacon.OS)
con.Printf(console.Bold+" Version: %s%s\n", console.Normal, beacon.Version)
con.Printf(console.Bold+" Arch: %s%s\n", console.Normal, beacon.Arch)
con.Printf(console.Bold+" Remote Address: %s%s\n", console.Normal, beacon.RemoteAddress)
con.Printf(console.Bold+" Proxy URL: %s%s\n", console.Normal, beacon.ProxyURL)
con.Printf(console.Bold+" Interval: %s%d\n", console.Normal, beacon.Interval)
con.Printf(console.Bold+" Jitter: %s%d\n", console.Normal, beacon.Jitter)
} else {
con.PrintErrorf("No target session, see `help %s`\n", consts.InfoStr)
}
@@ -60,36 +73,52 @@ func InfoCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
// PIDCmd - Get the active session's PID
func PIDCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
session := con.ActiveSession.GetInteractive()
if session == nil {
session, beacon := con.ActiveTarget.GetInteractive()
if session == nil && beacon == nil {
return
}
con.Printf("%d\n", session.PID)
if session != nil {
con.Printf("%d\n", session.PID)
} else if beacon != nil {
con.Printf("%d\n", beacon.PID)
}
}
// UIDCmd - Get the active session's UID
func UIDCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
session := con.ActiveSession.GetInteractive()
if session == nil {
session, beacon := con.ActiveTarget.GetInteractive()
if session == nil && beacon == nil {
return
}
con.Printf("%s\n", session.UID)
if session != nil {
con.Printf("%s\n", session.UID)
} else if beacon != nil {
con.Printf("%s\n", beacon.UID)
}
}
// GIDCmd - Get the active session's GID
func GIDCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
session := con.ActiveSession.GetInteractive()
if session == nil {
session, beacon := con.ActiveTarget.GetInteractive()
if session == nil && beacon == nil {
return
}
con.Printf("%s\n", session.GID)
if session != nil {
con.Printf("%s\n", session.GID)
} else if beacon != nil {
con.Printf("%s\n", beacon.GID)
}
}
// WhoamiCmd - Displays the current user of the active session
func WhoamiCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
session := con.ActiveSession.GetInteractive()
if session == nil {
session, beacon := con.ActiveTarget.GetInteractive()
if session == nil && beacon == nil {
return
}
con.Printf("%s\n", session.Username)
if session != nil {
con.Printf("%s\n", session.Username)
} else if beacon != nil {
con.Printf("%s\n", beacon.Username)
}
}
+2 -2
View File
@@ -11,7 +11,7 @@ import (
// PingCmd - Send a round trip C2 message to an implant (does not use ICMP)
func PingCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
session := con.ActiveSession.GetInteractive()
session := con.ActiveTarget.GetSessionInteractive()
if session == nil {
return
}
@@ -20,7 +20,7 @@ func PingCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
con.PrintInfof("Ping %d\n", nonce)
pong, err := con.Rpc.Ping(context.Background(), &sliverpb.Ping{
Nonce: int32(nonce),
Request: con.ActiveSession.Request(ctx),
Request: con.ActiveTarget.Request(ctx),
})
if err != nil {
con.PrintErrorf("%s\n", err)
+21 -6
View File
@@ -20,6 +20,7 @@ package jobs
import (
"context"
"time"
"github.com/bishopfox/sliver/client/console"
"github.com/bishopfox/sliver/protobuf/clientpb"
@@ -31,15 +32,29 @@ func HTTPListenerCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
domain := ctx.Flags.String("domain")
lhost := ctx.Flags.String("lhost")
lport := uint16(ctx.Flags.Int("lport"))
disableOTP := ctx.Flags.Bool("disable-otp")
longPollTimeout, err := time.ParseDuration(ctx.Flags.String("long-poll-timeout"))
if err != nil {
con.PrintErrorf("%s\n", err)
return
}
longPollJitter, err := time.ParseDuration(ctx.Flags.String("long-poll-jitter"))
if err != nil {
con.PrintErrorf("%s\n", err)
return
}
con.PrintInfof("Starting HTTP %s:%d listener ...\n", domain, lport)
http, err := con.Rpc.StartHTTPListener(context.Background(), &clientpb.HTTPListenerReq{
Domain: domain,
Website: ctx.Flags.String("website"),
Host: lhost,
Port: uint32(lport),
Secure: false,
Persistent: ctx.Flags.Bool("persistent"),
Domain: domain,
Website: ctx.Flags.String("website"),
Host: lhost,
Port: uint32(lport),
Secure: false,
Persistent: ctx.Flags.Bool("persistent"),
EnforceOTP: !disableOTP,
LongPollTimeout: int64(longPollTimeout),
LongPollJitter: int64(longPollJitter),
})
if err != nil {
con.PrintErrorf("%s\n", err)
+25 -9
View File
@@ -21,6 +21,7 @@ package jobs
import (
"context"
"io/ioutil"
"time"
"github.com/bishopfox/sliver/client/console"
"github.com/bishopfox/sliver/protobuf/clientpb"
@@ -34,6 +35,18 @@ func HTTPSListenerCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
lhost := ctx.Flags.String("lhost")
lport := uint16(ctx.Flags.Int("lport"))
disableOTP := ctx.Flags.Bool("disable-otp")
longPollTimeout, err := time.ParseDuration(ctx.Flags.String("long-poll-timeout"))
if err != nil {
con.PrintErrorf("%s\n", err)
return
}
longPollJitter, err := time.ParseDuration(ctx.Flags.String("long-poll-jitter"))
if err != nil {
con.PrintErrorf("%s\n", err)
return
}
cert, key, err := getLocalCertificatePair(ctx)
if err != nil {
con.Println()
@@ -43,15 +56,18 @@ func HTTPSListenerCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
con.PrintInfof("Starting HTTPS %s:%d listener ...\n", domain, lport)
https, err := con.Rpc.StartHTTPSListener(context.Background(), &clientpb.HTTPListenerReq{
Domain: domain,
Website: website,
Host: lhost,
Port: uint32(lport),
Secure: true,
Cert: cert,
Key: key,
ACME: ctx.Flags.Bool("lets-encrypt"),
Persistent: ctx.Flags.Bool("persistent"),
Domain: domain,
Website: website,
Host: lhost,
Port: uint32(lport),
Secure: true,
Cert: cert,
Key: key,
ACME: ctx.Flags.Bool("lets-encrypt"),
Persistent: ctx.Flags.Bool("persistent"),
EnforceOTP: !disableOTP,
LongPollTimeout: int64(longPollTimeout),
LongPollJitter: int64(longPollJitter),
})
con.Println()
if err != nil {
+97
View File
@@ -0,0 +1,97 @@
package kill
/*
Sliver Implant Framework
Copyright (C) 2021 Bishop Fox
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
import (
"context"
"errors"
"github.com/AlecAivazis/survey/v2"
"github.com/bishopfox/sliver/client/console"
"github.com/bishopfox/sliver/protobuf/clientpb"
"github.com/bishopfox/sliver/protobuf/commonpb"
"github.com/bishopfox/sliver/protobuf/sliverpb"
"github.com/desertbit/grumble"
)
// KillCmd - Kill the active session (not to be confused with TerminateCmd)
func KillCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
session, beacon := con.ActiveTarget.GetInteractive()
// Confirm with the user, just in case they confused kill with terminate
confirm := false
promptSession := &survey.Confirm{Message: "Kill the active session?"}
promptBeacon := &survey.Confirm{Message: "Kill the active beacon?"}
if session != nil {
survey.AskOne(promptSession, &confirm, nil)
if !confirm {
return
}
err := KillSession(session, ctx.Flags.Bool("force"), con)
if err != nil {
con.PrintErrorf("%s\n", err)
return
}
con.PrintInfof("Killed %s (%d)\n", session.Name, session.ID)
con.ActiveTarget.Background()
return
}
if beacon != nil {
survey.AskOne(promptBeacon, &confirm, nil)
if !confirm {
return
}
err := KillBeacon(beacon, ctx.Flags.Bool("force"), con)
if err != nil {
con.PrintErrorf("%s\n", err)
return
}
con.PrintInfof("Killed %s (%s)\n", beacon.Name, beacon.ID)
con.ActiveTarget.Background()
return
}
con.PrintErrorf("No active session or beacon\n")
return
}
func KillSession(session *clientpb.Session, force bool, con *console.SliverConsoleClient) error {
if session == nil {
return errors.New("session does not exist")
}
_, err := con.Rpc.Kill(context.Background(), &sliverpb.KillReq{
Request: &commonpb.Request{
SessionID: session.ID,
},
Force: force,
})
return err
}
func KillBeacon(beacon *clientpb.Beacon, force bool, con *console.SliverConsoleClient) error {
if beacon == nil {
return errors.New("session does not exist")
}
_, err := con.Rpc.Kill(context.Background(), &sliverpb.KillReq{
Request: &commonpb.Request{
BeaconID: beacon.ID,
},
Force: force,
})
return err
}
+1 -1
View File
@@ -46,7 +46,7 @@ func LootCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
if filter == "" {
allLoot, err = con.Rpc.LootAll(context.Background(), &commonpb.Empty{})
if err != nil {
con.PrintWarnf("Failed to fetch loot %s\n", err)
con.PrintErrorf("Failed to fetch loot %s\n", err)
return
}
} else {
+2 -2
View File
@@ -33,7 +33,7 @@ import (
// LootAddRemoteCmd - Add a file from the remote system to the server as loot
func LootAddRemoteCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
session := con.ActiveSession.GetInteractive()
session := con.ActiveTarget.GetSessionInteractive()
if session == nil {
return
}
@@ -60,7 +60,7 @@ func LootAddRemoteCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
con.SpinUntil(fmt.Sprintf("Looting remote file %s", remotePath), ctrl)
download, err := con.Rpc.Download(context.Background(), &sliverpb.DownloadReq{
Request: con.ActiveSession.Request(ctx),
Request: con.ActiveTarget.Request(ctx),
Path: remotePath,
})
if err != nil {
+1 -1
View File
@@ -1,4 +1,4 @@
Extensions
Macros
===========
Wraps external DLLs/tool in Sliver console commands.
+4 -4
View File
@@ -185,7 +185,7 @@ func LoadMacroCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
}
func runMacroCommand(ctx *grumble.Context, con *console.SliverConsoleClient) {
session := con.ActiveSession.GetInteractive()
session := con.ActiveTarget.GetSessionInteractive()
if session == nil {
return
}
@@ -246,7 +246,7 @@ func runMacroCommand(ctx *grumble.Context, con *console.SliverConsoleClient) {
msg := fmt.Sprintf("Executing %s %s ...", ctx.Command.Name, extArgs)
con.SpinUntil(msg, ctrl)
executeAssemblyResp, err := con.Rpc.ExecuteAssembly(context.Background(), &sliverpb.ExecuteAssemblyReq{
Request: con.ActiveSession.Request(ctx),
Request: con.ActiveTarget.Request(ctx),
IsDLL: isDLL,
Process: processName,
Arguments: extArgs,
@@ -272,7 +272,7 @@ func runMacroCommand(ctx *grumble.Context, con *console.SliverConsoleClient) {
msg := fmt.Sprintf("Executing %s %s ...", ctx.Command.Name, extArgs)
con.SpinUntil(msg, ctrl)
spawnDllResp, err := con.Rpc.SpawnDll(context.Background(), &sliverpb.InvokeSpawnDllReq{
Request: con.ActiveSession.Request(ctx),
Request: con.ActiveTarget.Request(ctx),
Args: strings.Trim(extArgs, " "),
Data: binData,
ProcessName: processName,
@@ -297,7 +297,7 @@ func runMacroCommand(ctx *grumble.Context, con *console.SliverConsoleClient) {
msg := fmt.Sprintf("Executing %s %s ...", ctx.Command.Name, extArgs)
con.SpinUntil(msg, ctrl)
sideloadResp, err := con.Rpc.Sideload(context.Background(), &sliverpb.SideloadReq{
Request: con.ActiveSession.Request(ctx),
Request: con.ActiveTarget.Request(ctx),
Args: extArgs,
Data: binData,
EntryPoint: entryPoint,
+68 -16
View File
@@ -20,37 +20,74 @@ package network
import (
"context"
"fmt"
"sort"
"strconv"
"strings"
"github.com/desertbit/grumble"
"github.com/bishopfox/sliver/client/command/settings"
"github.com/bishopfox/sliver/client/console"
"github.com/bishopfox/sliver/protobuf/clientpb"
"github.com/bishopfox/sliver/protobuf/sliverpb"
"github.com/desertbit/grumble"
"github.com/jedib0t/go-pretty/v6/table"
"google.golang.org/protobuf/proto"
)
// IfconfigCmd - Display network interfaces on the remote system
func IfconfigCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
session := con.ActiveSession.GetInteractive()
if session == nil {
session, beacon := con.ActiveTarget.GetInteractive()
if session == nil && beacon == nil {
return
}
ifconfig, err := con.Rpc.Ifconfig(context.Background(), &sliverpb.IfconfigReq{
Request: con.ActiveSession.Request(ctx),
Request: con.ActiveTarget.Request(ctx),
})
if err != nil {
con.PrintErrorf("%s\n", err)
return
}
all := ctx.Flags.Bool("all")
if ifconfig.Response != nil && ifconfig.Response.Async {
con.AddBeaconCallback(ifconfig.Response.TaskID, func(task *clientpb.BeaconTask) {
err = proto.Unmarshal(task.Response, ifconfig)
if err != nil {
con.PrintErrorf("Failed to decode response %s\n", err)
return
}
PrintIfconfig(ifconfig, all, con)
})
con.PrintAsyncResponse(ifconfig.Response)
} else {
PrintIfconfig(ifconfig, all, con)
}
}
for ifaceIndex, iface := range ifconfig.NetInterfaces {
con.Printf("%s%s%s (%d)\n", console.Bold, iface.Name, console.Normal, ifaceIndex)
// PrintIfconfig - Print the ifconfig response
func PrintIfconfig(ifconfig *sliverpb.Ifconfig, all bool, con *console.SliverConsoleClient) {
var err error
interfaces := ifconfig.NetInterfaces
sort.Slice(interfaces, func(i, j int) bool {
return interfaces[i].Index < interfaces[j].Index
})
hidden := 0
for index, iface := range interfaces {
tw := table.NewWriter()
tw.SetStyle(settings.GetTableWithBordersStyle(con))
tw.SetTitle(fmt.Sprintf(console.Bold+"%s"+console.Normal, iface.Name))
tw.SetColumnConfigs([]table.ColumnConfig{
{Name: "#", AutoMerge: true},
{Name: "IP Address", AutoMerge: true},
{Name: "MAC Address", AutoMerge: true},
})
rowConfig := table.RowConfig{AutoMerge: true}
tw.AppendHeader(table.Row{"#", "IP Addresses", "MAC Address"}, rowConfig)
macAddress := ""
if 0 < len(iface.MAC) {
con.Printf(" MAC Address: %s\n", iface.MAC)
macAddress = iface.MAC
}
ips := []string{}
for _, ip := range iface.IPAddresses {
// Try to find local IPs and colorize them
subnet := -1
if strings.Contains(ip, "/") {
@@ -61,15 +98,30 @@ func IfconfigCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
subnet = -1
}
}
if 0 < subnet && subnet <= 32 && !isLoopback(ip) {
con.Printf(console.Bold+console.Green+" IP Address: %s%s\n", ip, console.Normal)
} else if 32 < subnet && !isLoopback(ip) {
con.Printf(console.Bold+console.Cyan+" IP Address: %s%s\n", ip, console.Normal)
} else {
con.Printf(" IP Address: %s\n", ip)
ips = append(ips, fmt.Sprintf(console.Bold+console.Green+"%s"+console.Normal, ip))
} else if all {
ips = append(ips, fmt.Sprintf("%s", ip))
}
}
if !all && len(ips) < 1 {
hidden++
continue
}
if 0 < len(ips) {
for _, ip := range ips {
tw.AppendRow(table.Row{iface.Index, ip, macAddress}, rowConfig)
}
} else {
tw.AppendRow(table.Row{iface.Index, " ", macAddress}, rowConfig)
}
con.Printf("%s\n", tw.Render())
if index+1 < len(interfaces) {
con.Println()
}
}
if !all {
con.Printf("%d adapters not shown.\n", hidden)
}
}
+61 -25
View File
@@ -22,17 +22,20 @@ import (
"context"
"fmt"
"net"
"strings"
"github.com/bishopfox/sliver/client/command/settings"
"github.com/bishopfox/sliver/client/console"
"github.com/bishopfox/sliver/protobuf/clientpb"
"github.com/bishopfox/sliver/protobuf/sliverpb"
"github.com/desertbit/grumble"
"github.com/jedib0t/go-pretty/v6/table"
"google.golang.org/protobuf/proto"
)
// NetstatCmd - Display active network connections on the remote system
func NetstatCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
session := con.ActiveSession.GetInteractive()
if session == nil {
session, beacon := con.ActiveTarget.GetInteractive()
if session == nil && beacon == nil {
return
}
@@ -42,8 +45,11 @@ func NetstatCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
tcp := ctx.Flags.Bool("tcp")
udp := ctx.Flags.Bool("udp")
implantPID := getPID(session, beacon)
activeC2 := getActiveC2(session, beacon)
netstat, err := con.Rpc.Netstat(context.Background(), &sliverpb.NetstatReq{
Request: con.ActiveSession.Request(ctx),
Request: con.ActiveTarget.Request(ctx),
TCP: tcp,
UDP: udp,
Listening: listening,
@@ -54,10 +60,22 @@ func NetstatCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
con.PrintErrorf("%s\n", err)
return
}
displayEntries(netstat.Entries, con)
if netstat.Response != nil && netstat.Response.Async {
con.AddBeaconCallback(netstat.Response.TaskID, func(task *clientpb.BeaconTask) {
err = proto.Unmarshal(task.Response, netstat)
if err != nil {
con.PrintErrorf("Failed to decode response %s\n", err)
return
}
PrintNetstat(netstat, implantPID, activeC2, con)
})
con.PrintAsyncResponse(netstat.Response)
} else {
PrintNetstat(netstat, implantPID, activeC2, con)
}
}
func displayEntries(entries []*sliverpb.SockTabEntry, con *console.SliverConsoleClient) {
func PrintNetstat(netstat *sliverpb.Netstat, implantPID int32, activeC2 string, con *console.SliverConsoleClient) {
lookup := func(skaddr *sliverpb.SockTabEntry_SockAddr) string {
const IPv4Strlen = 17
addr := skaddr.Ip
@@ -71,30 +89,48 @@ func displayEntries(entries []*sliverpb.SockTabEntry, con *console.SliverConsole
return fmt.Sprintf("%s:%d", addr, skaddr.Port)
}
con.Printf("Proto %-23s %-23s %-12s %-16s\n", "Local Addr", "Foreign Addr", "State", "PID/Program name")
session := con.ActiveSession.GetInteractive()
for _, e := range entries {
p := ""
if e.Process != nil {
p = fmt.Sprintf("%d/%s", e.Process.Pid, e.Process.Executable)
tw := table.NewWriter()
tw.SetStyle(settings.GetTableStyle(con))
tw.AppendHeader(table.Row{"Protocol", "Local Address", "Foreign Address", "State", "PID/Program name"})
for _, entry := range netstat.Entries {
pid := ""
if entry.Process != nil {
pid = fmt.Sprintf("%d/%s", entry.Process.Pid, entry.Process.Executable)
}
srcAddr := lookup(e.LocalAddr)
dstAddr := lookup(e.RemoteAddr)
if e.Process != nil && e.Process.Pid == session.PID && isSliverAddr(dstAddr, con) {
con.Printf("%s%-5s %-23.23s %-23.23s %-12s %-16s%s\n",
console.Green, e.Protocol, srcAddr, dstAddr, e.SkState, p, console.Normal)
srcAddr := lookup(entry.LocalAddr)
dstAddr := lookup(entry.RemoteAddr)
if entry.Process != nil && entry.Process.Pid == implantPID {
tw.AppendRow(table.Row{
fmt.Sprintf(console.Green+"%s"+console.Normal, entry.Protocol),
fmt.Sprintf(console.Green+"%s"+console.Normal, srcAddr),
fmt.Sprintf(console.Green+"%s"+console.Normal, dstAddr),
fmt.Sprintf(console.Green+"%s"+console.Normal, entry.SkState),
fmt.Sprintf(console.Green+"%s"+console.Normal, pid),
})
} else {
con.Printf("%-5s %-23.23s %-23.23s %-12s %-16s\n",
e.Protocol, srcAddr, dstAddr, e.SkState, p)
tw.AppendRow(table.Row{entry.Protocol, srcAddr, dstAddr, entry.SkState, pid})
}
}
con.Printf("%s\n", tw.Render())
}
func isSliverAddr(dstAddr string, con *console.SliverConsoleClient) bool {
parts := strings.Split(dstAddr, ":")
if len(parts) != 3 {
return false
func getActiveC2(session *clientpb.Session, beacon *clientpb.Beacon) string {
if session != nil {
return session.ActiveC2
}
c2Addr := strings.Split(con.ActiveSession.GetInteractive().ActiveC2, "://")[1]
return strings.Join(parts[:2], ":") == c2Addr
if beacon != nil {
return beacon.ActiveC2
}
return ""
}
func getPID(session *clientpb.Session, beacon *clientpb.Beacon) int32 {
if session != nil {
return session.PID
}
if beacon != nil {
return beacon.PID
}
return -1
}
+15 -39
View File
@@ -19,17 +19,15 @@ package operators
*/
import (
"bytes"
"context"
"fmt"
"strings"
"text/tabwriter"
"github.com/bishopfox/sliver/client/command/settings"
"github.com/bishopfox/sliver/client/console"
"github.com/bishopfox/sliver/protobuf/clientpb"
"github.com/bishopfox/sliver/protobuf/commonpb"
"github.com/desertbit/grumble"
"github.com/jedib0t/go-pretty/v6/table"
)
// OperatorsCmd - Display operators and current online status
@@ -45,46 +43,24 @@ func OperatorsCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
}
func displayOperators(operators []*clientpb.Operator, con *console.SliverConsoleClient) {
outputBuf := bytes.NewBufferString("")
table := tabwriter.NewWriter(outputBuf, 0, 2, 2, ' ', 0)
// Column Headers
fmt.Fprintln(table, "Operator\tStatus\t")
fmt.Fprintf(table, "%s\t%s\t\n",
strings.Repeat("=", len("Operator")),
strings.Repeat("=", len("Status")),
)
colorRow := []string{"", ""} // Two uncolored rows for the headers
tw := table.NewWriter()
tw.SetStyle(settings.GetTableStyle(con))
tw.AppendHeader(table.Row{
"Name",
"Status",
})
for _, operator := range operators {
// This is the CA, but I guess you could also name an operator
// "multiplayer" and it'll never show up in the list
if operator.Name == "multiplayer" {
continue
}
fmt.Fprintf(table, "%s\t%s\t\n", operator.Name, status(operator.Online))
if operator.Online {
colorRow = append(colorRow, console.Bold+console.Green)
} else {
colorRow = append(colorRow, "")
}
}
table.Flush()
lines := strings.Split(outputBuf.String(), "\n")
for lineNumber, line := range lines {
if len(line) == 0 {
continue
}
con.Printf("%s%s%s\n", colorRow[lineNumber], line, console.Normal)
tw.AppendRow(table.Row{
console.Bold + operator.Name + console.Normal,
status(operator.Online),
})
}
con.Printf("%s\n", tw.Render())
}
func status(isOnline bool) string {
if isOnline {
return "Online"
return console.Bold + console.Green + "Online" + console.Normal
}
return "Offline"
return console.Bold + console.Red + "Offline" + console.Normal
}
+2 -2
View File
@@ -10,7 +10,7 @@ import (
// NamedPipeListenerCmd - Start a named pipe pivot listener on the remote system
func NamedPipeListenerCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
session := con.ActiveSession.GetInteractive()
session := con.ActiveTarget.GetSessionInteractive()
if session == nil {
return
}
@@ -28,7 +28,7 @@ func NamedPipeListenerCmd(ctx *grumble.Context, con *console.SliverConsoleClient
_, err := con.Rpc.NamedPipes(context.Background(), &sliverpb.NamedPipesReq{
PipeName: pipeName,
Request: con.ActiveSession.Request(ctx),
Request: con.ActiveTarget.Request(ctx),
})
if err != nil {
+1 -1
View File
@@ -44,7 +44,7 @@ func PivotsCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
}
printPivots(session, int64(timeout), con)
} else {
session := con.ActiveSession.Get()
session := con.ActiveTarget.GetSession()
if session != nil {
printPivots(session, int64(timeout), con)
} else {
+2 -2
View File
@@ -11,7 +11,7 @@ import (
// TCPListenerCmd - Start a TCP pivot listener on the remote system
func TCPListenerCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
session := con.ActiveSession.GetInteractive()
session := con.ActiveTarget.GetSessionInteractive()
if session == nil {
return
}
@@ -22,7 +22,7 @@ func TCPListenerCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
_, err := con.Rpc.TCPListener(context.Background(), &sliverpb.TCPPivotReq{
Address: address,
Request: con.ActiveSession.Request(ctx),
Request: con.ActiveTarget.Request(ctx),
})
if err != nil {
+1 -1
View File
@@ -31,7 +31,7 @@ import (
// PortfwdAddCmd - Add a new tunneled port forward
func PortfwdAddCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
session := con.ActiveSession.GetInteractive()
session := con.ActiveTarget.GetSessionInteractive()
if session == nil {
return
}
@@ -0,0 +1,4 @@
Prelude Operator
=================
Connection code for [Prelude Operator](https://www.prelude.org/)
@@ -0,0 +1,63 @@
package operator
/*
Sliver Implant Framework
Copyright (C) 2021 Bishop Fox
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
import (
"context"
"github.com/bishopfox/sliver/client/console"
"github.com/bishopfox/sliver/client/prelude"
"github.com/bishopfox/sliver/protobuf/commonpb"
"github.com/desertbit/grumble"
)
func ConnectCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
url := ctx.Args.String("connection-string")
aesKey := ctx.Flags.String("aes-key")
agentRange := ctx.Flags.String("range")
skipExisting := ctx.Flags.Bool("skip-existing")
config := &prelude.OperatorConfig{
Range: agentRange,
OperatorURL: url,
RPC: con.Rpc,
AESKey: aesKey,
}
sessionMapper := prelude.InitSessionMapper(config)
con.PrintInfof("Connected to Operator at %s\n", url)
if !skipExisting {
sessions, err := con.Rpc.GetSessions(context.Background(), &commonpb.Empty{})
if err != nil {
con.PrintErrorf("Could not get session list: %s", err)
return
}
if len(sessions.Sessions) > 0 {
con.PrintInfof("Adding existing sessions ...\n")
for _, session := range sessions.Sessions {
err = sessionMapper.AddSession(session)
if err != nil {
con.PrintErrorf("Could not add session %s to session mapper: %s", session.Name, err)
}
}
con.PrintInfof("Done !\n")
}
}
}
@@ -0,0 +1,33 @@
package operator
/*
Sliver Implant Framework
Copyright (C) 2021 Bishop Fox
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
import (
"github.com/bishopfox/sliver/client/console"
"github.com/bishopfox/sliver/client/prelude"
"github.com/desertbit/grumble"
)
func OperatorCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
if prelude.SessionMapper != nil {
con.PrintInfof("Connected to Operator at %s\n", prelude.SessionMapper.GetConfig().OperatorURL)
return
}
con.PrintInfof("Not connected to any Operator server. Use `operator connect` to connect to one.")
}
+59 -22
View File
@@ -1,15 +1,5 @@
package privilege
import (
"context"
"strconv"
"strings"
"github.com/bishopfox/sliver/client/console"
"github.com/bishopfox/sliver/protobuf/sliverpb"
"github.com/desertbit/grumble"
)
/*
Sliver Implant Framework
Copyright (C) 2021 Bishop Fox
@@ -28,38 +18,65 @@ import (
along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
func GetPrivsCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
var processName string = "Current Process"
import (
"context"
"strconv"
"strings"
session := con.ActiveSession.GetInteractive()
if session == nil {
"github.com/bishopfox/sliver/client/console"
"github.com/bishopfox/sliver/protobuf/clientpb"
"github.com/bishopfox/sliver/protobuf/sliverpb"
"github.com/desertbit/grumble"
"google.golang.org/protobuf/proto"
)
// GetPrivsCmd - Get the current process privileges (Windows only)
func GetPrivsCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
session, beacon := con.ActiveTarget.GetInteractive()
if session == nil && beacon == nil {
return
}
if session.OS != "windows" {
con.PrintErrorf("Command not supported on this operating system.")
targetOS := getOS(session, beacon)
if targetOS != "windows" {
con.PrintErrorf("Command only supported on Windows.\n")
return
}
privs, err := con.Rpc.GetPrivs(context.Background(), &sliverpb.GetPrivsReq{
Request: con.ActiveSession.Request(ctx),
Request: con.ActiveTarget.Request(ctx),
})
if err != nil {
con.PrintErrorf("%s\n", err)
return
}
pid := getPID(session, beacon)
if privs.Response != nil && privs.Response.Async {
con.AddBeaconCallback(privs.Response.TaskID, func(task *clientpb.BeaconTask) {
err = proto.Unmarshal(task.Response, privs)
if err != nil {
con.PrintErrorf("Failed to decode response %s\n", err)
return
}
PrintGetPrivs(privs, pid, con)
})
con.PrintAsyncResponse(privs.Response)
} else {
PrintGetPrivs(privs, pid, con)
}
}
// PrintGetPrivs - Print the results of the get privs command
func PrintGetPrivs(privs *sliverpb.GetPrivs, pid int32, con *console.SliverConsoleClient) {
// Response is the Envelope (see RPC API), Err is part of it.
if privs.Response != nil && privs.Response.Err != "" {
con.PrintErrorf("NOTE: Information may be incomplete due to an error:\n")
con.PrintErrorf("%s\n", privs.Response.Err)
}
if privs.PrivInfo == nil {
return
}
var processName string = "Current Process"
if privs.ProcessName != "" {
processName = privs.ProcessName
}
@@ -68,7 +85,7 @@ func GetPrivsCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
// for column width
var nameColumnWidth int = 0
var descriptionColumnWidth int = 0
var introWidth int = 34 + len(processName) + len(strconv.Itoa(int(session.PID)))
var introWidth int = 34 + len(processName) + len(strconv.Itoa(int(pid)))
for _, entry := range privs.PrivInfo {
if len(entry.Name) > nameColumnWidth {
@@ -83,7 +100,7 @@ func GetPrivsCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
nameColumnWidth += 1
descriptionColumnWidth += 1
con.Printf("Privilege Information for %s (PID: %d)\n", processName, session.PID)
con.Printf("Privilege Information for %s (PID: %d)\n", processName, pid)
con.Println(strings.Repeat("-", introWidth))
con.Printf("\nProcess Integrity Level: %s\n\n", privs.ProcessIntegrity)
con.Printf("%-*s\t%-*s\t%s\n", nameColumnWidth, "Name", descriptionColumnWidth, "Description", "Attributes")
@@ -107,3 +124,23 @@ func GetPrivsCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
con.Printf("\n")
}
}
func getOS(session *clientpb.Session, beacon *clientpb.Beacon) string {
if session != nil {
return session.OS
}
if beacon != nil {
return beacon.OS
}
panic("no session or beacon")
}
func getPID(session *clientpb.Session, beacon *clientpb.Beacon) int32 {
if session != nil {
return session.PID
}
if beacon != nil {
return beacon.PID
}
panic("no session or beacon")
}
+31 -7
View File
@@ -23,34 +23,58 @@ import (
"github.com/bishopfox/sliver/client/console"
"github.com/bishopfox/sliver/protobuf/clientpb"
"github.com/bishopfox/sliver/protobuf/sliverpb"
"github.com/desertbit/grumble"
"google.golang.org/protobuf/proto"
)
// GetSystemCmd - Windows only, attempt to get SYSTEM on the remote system
func GetSystemCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
session := con.ActiveSession.GetInteractive()
if session == nil {
session, beacon := con.ActiveTarget.GetInteractive()
if session == nil && beacon == nil {
return
}
targetOS := getOS(session, beacon)
if targetOS != "windows" {
con.PrintErrorf("Command only supported on Windows.\n")
return
}
process := ctx.Flags.String("process")
config := con.GetActiveSessionConfig()
ctrl := make(chan bool)
con.SpinUntil("Attempting to create a new sliver session as 'NT AUTHORITY\\SYSTEM'...", ctrl)
getsystemResp, err := con.Rpc.GetSystem(context.Background(), &clientpb.GetSystemReq{
Request: con.ActiveSession.Request(ctx),
getSystem, err := con.Rpc.GetSystem(context.Background(), &clientpb.GetSystemReq{
Request: con.ActiveTarget.Request(ctx),
Config: config,
HostingProcess: process,
})
ctrl <- true
<-ctrl
if err != nil {
con.PrintErrorf("%s\n", err)
return
}
if getsystemResp.GetResponse().GetErr() != "" {
if getSystem.Response != nil && getSystem.Response.Async {
con.AddBeaconCallback(getSystem.Response.TaskID, func(task *clientpb.BeaconTask) {
err = proto.Unmarshal(task.Response, getSystem)
if err != nil {
con.PrintErrorf("Failed to decode response %s\n", err)
return
}
PrintGetSystem(getSystem, con)
})
con.PrintAsyncResponse(getSystem.Response)
} else {
PrintGetSystem(getSystem, con)
}
}
// PrintGetSystem - Print the results of get system
func PrintGetSystem(getsystemResp *sliverpb.GetSystem, con *console.SliverConsoleClient) {
if getsystemResp.Response != nil && getsystemResp.Response.GetErr() != "" {
con.PrintErrorf("%s\n", getsystemResp.GetResponse().GetErr())
return
}
+27 -7
View File
@@ -22,28 +22,48 @@ import (
"context"
"github.com/bishopfox/sliver/client/console"
"github.com/bishopfox/sliver/protobuf/clientpb"
"github.com/bishopfox/sliver/protobuf/sliverpb"
"github.com/desertbit/grumble"
"google.golang.org/protobuf/proto"
)
// ImpersonateCmd - Windows only, impersonate a user token
func ImpersonateCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
session := con.ActiveSession.GetInteractive()
if session == nil {
session, beacon := con.ActiveTarget.GetInteractive()
if session == nil && beacon == nil {
return
}
username := ctx.Args.String("username")
impResp, err := con.Rpc.Impersonate(context.Background(), &sliverpb.ImpersonateReq{
Request: con.ActiveSession.Request(ctx),
impersonate, err := con.Rpc.Impersonate(context.Background(), &sliverpb.ImpersonateReq{
Request: con.ActiveTarget.Request(ctx),
Username: username,
})
if err != nil {
con.PrintErrorf("%s", err)
return
}
if impResp.GetResponse().GetErr() != "" {
con.PrintErrorf("%s\n", impResp.GetResponse().GetErr())
if impersonate.Response != nil && impersonate.Response.Async {
con.AddBeaconCallback(impersonate.Response.TaskID, func(task *clientpb.BeaconTask) {
err = proto.Unmarshal(task.Response, impersonate)
if err != nil {
con.PrintErrorf("Failed to decode response %s\n", err)
return
}
PrintImpersonate(impersonate, username, con)
})
con.PrintAsyncResponse(impersonate.Response)
} else {
PrintImpersonate(impersonate, username, con)
}
}
// PrintImpersonate - Print the results of the attempted impersonation
func PrintImpersonate(impersonate *sliverpb.Impersonate, username string, con *console.SliverConsoleClient) {
if impersonate.Response != nil && impersonate.Response.GetErr() != "" {
con.PrintErrorf("%s\n", impersonate.Response.GetErr())
return
}
con.PrintInfof("Successfully impersonated %s\n", username)
+25 -7
View File
@@ -22,16 +22,19 @@ import (
"context"
"github.com/bishopfox/sliver/client/console"
"github.com/bishopfox/sliver/protobuf/clientpb"
"github.com/bishopfox/sliver/protobuf/sliverpb"
"github.com/desertbit/grumble"
"google.golang.org/protobuf/proto"
)
// MakeTokenCmd - Windows only, create a token using "valid" credentails
func MakeTokenCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
session := con.ActiveSession.GetInteractive()
if session == nil {
session, beacon := con.ActiveTarget.GetInteractive()
if session == nil && beacon == nil {
return
}
username := ctx.Flags.String("username")
password := ctx.Flags.String("password")
domain := ctx.Flags.String("domain")
@@ -45,22 +48,37 @@ func MakeTokenCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
con.SpinUntil("Creating new logon session ...", ctrl)
makeToken, err := con.Rpc.MakeToken(context.Background(), &sliverpb.MakeTokenReq{
Request: con.ActiveSession.Request(ctx),
Request: con.ActiveTarget.Request(ctx),
Username: username,
Domain: domain,
Password: password,
})
ctrl <- true
<-ctrl
if err != nil {
con.PrintErrorf("%s\n", err)
return
}
if makeToken.GetResponse().GetErr() != "" {
con.PrintErrorf("%s\n", makeToken.GetResponse().GetErr())
if makeToken.Response != nil && makeToken.Response.Async {
con.AddBeaconCallback(makeToken.Response.TaskID, func(task *clientpb.BeaconTask) {
err = proto.Unmarshal(task.Response, makeToken)
if err != nil {
con.PrintErrorf("Failed to decode response %s\n", err)
return
}
PrintMakeToken(makeToken, domain, username, con)
})
con.PrintAsyncResponse(makeToken.Response)
} else {
PrintMakeToken(makeToken, domain, username, con)
}
}
// PrintMakeToken - Print the results of attempting to make a token
func PrintMakeToken(makeToken *sliverpb.MakeToken, domain string, username string, con *console.SliverConsoleClient) {
if makeToken.Response != nil && makeToken.Response.GetErr() != "" {
con.PrintErrorf("%s\n", makeToken.Response.GetErr())
return
}
con.Println()
+30 -6
View File
@@ -22,22 +22,46 @@ import (
"context"
"github.com/bishopfox/sliver/client/console"
"github.com/bishopfox/sliver/protobuf/clientpb"
"github.com/bishopfox/sliver/protobuf/sliverpb"
"github.com/desertbit/grumble"
"google.golang.org/protobuf/proto"
)
// RevToSelfCmd - Drop any impersonated tokens
func RevToSelfCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
session := con.ActiveSession.GetInteractive()
if session == nil {
session, beacon := con.ActiveTarget.GetInteractive()
if session == nil && beacon == nil {
return
}
_, err := con.Rpc.RevToSelf(context.Background(), &sliverpb.RevToSelfReq{
Request: con.ActiveSession.Request(ctx),
})
revert, err := con.Rpc.RevToSelf(context.Background(), &sliverpb.RevToSelfReq{
Request: con.ActiveTarget.Request(ctx),
})
if err != nil {
con.PrintErrorf("%s", err)
con.PrintErrorf("%s\n", err)
return
}
if revert.Response != nil && revert.Response.Async {
con.AddBeaconCallback(revert.Response.TaskID, func(task *clientpb.BeaconTask) {
err = proto.Unmarshal(task.Response, revert)
if err != nil {
con.PrintErrorf("Failed to decode response %s\n", err)
return
}
PrintRev2Self(revert, con)
})
con.PrintAsyncResponse(revert.Response)
} else {
PrintRev2Self(revert, con)
}
}
// PrintRev2Self - Print the result of revert to self
func PrintRev2Self(revert *sliverpb.RevToSelf, con *console.SliverConsoleClient) {
if revert.Response != nil && revert.Response.GetErr() != "" {
con.PrintErrorf("%s\n", revert.Response.GetErr())
return
}
con.PrintInfof("Back to self...")
+39 -9
View File
@@ -22,16 +22,19 @@ import (
"context"
"github.com/bishopfox/sliver/client/console"
"github.com/bishopfox/sliver/protobuf/clientpb"
"github.com/bishopfox/sliver/protobuf/sliverpb"
"github.com/desertbit/grumble"
"google.golang.org/protobuf/proto"
)
// RunAsCmd - Run a command as another user on the remote system
func RunAsCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
session := con.ActiveSession.GetInteractive()
if session == nil {
session, beacon := con.ActiveTarget.GetInteractive()
if session == nil && beacon == nil {
return
}
username := ctx.Flags.String("username")
process := ctx.Flags.String("process")
arguments := ctx.Flags.String("args")
@@ -46,22 +49,49 @@ func RunAsCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
return
}
runAsResp, err := con.Rpc.RunAs(context.Background(), &sliverpb.RunAsReq{
Request: con.ActiveSession.Request(ctx),
runAs, err := con.Rpc.RunAs(context.Background(), &sliverpb.RunAsReq{
Request: con.ActiveTarget.Request(ctx),
Username: username,
ProcessName: process,
Args: arguments,
})
if err != nil {
con.PrintErrorf("%s", err)
return
}
if runAsResp.GetResponse().GetErr() != "" {
con.PrintErrorf("%s\n", runAsResp.GetResponse().GetErr())
return
name := getName(session, beacon)
if runAs.Response != nil && runAs.Response.Async {
con.AddBeaconCallback(runAs.Response.TaskID, func(task *clientpb.BeaconTask) {
err = proto.Unmarshal(task.Response, runAs)
if err != nil {
con.PrintErrorf("Failed to decode response %s\n", err)
return
}
PrintRunAs(runAs, process, arguments, name, con)
})
con.PrintAsyncResponse(runAs.Response)
} else {
PrintRunAs(runAs, process, arguments, name, con)
}
con.PrintInfof("Successfully ran %s %s on %s\n", process, arguments, session.GetName())
}
// PrintRunAs - Print the result of run as
func PrintRunAs(runAs *sliverpb.RunAs, process string, args string, name string, con *console.SliverConsoleClient) {
if runAs.Response != nil && runAs.Response.GetErr() != "" {
con.PrintErrorf("%s\n", runAs.Response.GetErr())
return
}
con.PrintInfof("Successfully ran %s %s on %s\n", process, args, name)
}
func getName(session *clientpb.Session, beacon *clientpb.Beacon) string {
if session != nil {
return session.Name
}
if beacon != nil {
return beacon.Name
}
panic("no session or beacon")
}
+55 -12
View File
@@ -22,22 +22,26 @@ import (
"context"
"fmt"
"io/ioutil"
"path"
"os"
"path/filepath"
"github.com/bishopfox/sliver/client/console"
"github.com/bishopfox/sliver/protobuf/clientpb"
"github.com/bishopfox/sliver/protobuf/sliverpb"
"github.com/desertbit/grumble"
"google.golang.org/protobuf/proto"
)
// ProcdumpCmd - Dump the memory of a remote process
func ProcdumpCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
session := con.ActiveSession.GetInteractive()
if session == nil {
session, beacon := con.ActiveTarget.GetInteractive()
if session == nil && beacon == nil {
return
}
pid := ctx.Flags.Int("pid")
name := ctx.Flags.String("name")
saveTo := ctx.Flags.String("save")
if pid == -1 && name != "" {
pid = GetPIDByName(ctx, name, con)
@@ -55,7 +59,7 @@ func ProcdumpCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
ctrl := make(chan bool)
con.SpinUntil("Dumping remote process memory ...", ctrl)
dump, err := con.Rpc.ProcessDump(context.Background(), &sliverpb.ProcessDumpReq{
Request: con.ActiveSession.Request(ctx),
Request: con.ActiveTarget.Request(ctx),
Pid: int32(pid),
Timeout: int32(ctx.Flags.Int("timeout") - 1),
})
@@ -66,13 +70,52 @@ func ProcdumpCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
return
}
hostname := session.Hostname
tmpFileName := path.Base(fmt.Sprintf("procdump_%s_%d_*", hostname, pid))
tmpFile, err := ioutil.TempFile("", tmpFileName)
if err != nil {
con.PrintErrorf("Error creating temporary file: %v\n", err)
return
hostname := getHostname(session, beacon)
if dump.Response != nil && dump.Response.Async {
con.AddBeaconCallback(dump.Response.TaskID, func(task *clientpb.BeaconTask) {
err = proto.Unmarshal(task.Response, dump)
if err != nil {
con.PrintErrorf("Failed to decode response %s\n", err)
return
}
PrintProcessDump(dump, saveTo, hostname, pid, con)
})
con.PrintAsyncResponse(dump.Response)
} else {
PrintProcessDump(dump, saveTo, hostname, pid, con)
}
tmpFile.Write(dump.GetData())
con.PrintInfof("Process dump stored in: %s\n", tmpFile.Name())
}
// PrintProcessDump - Handle the results of a process dump
func PrintProcessDump(dump *sliverpb.ProcessDump, saveTo string, hostname string, pid int, con *console.SliverConsoleClient) {
var err error
var saveToFile *os.File
if saveTo == "" {
tmpFileName := filepath.Base(fmt.Sprintf("procdump_%s_%d_*", hostname, pid))
saveToFile, err = ioutil.TempFile("", tmpFileName)
if err != nil {
con.PrintErrorf("Error creating temporary file: %s\n", err)
return
}
} else {
saveToFile, err = os.OpenFile(saveTo, os.O_WRONLY, 600)
if err != nil {
con.PrintErrorf("Error creating file: %s\n", err)
return
}
}
defer saveToFile.Close()
saveToFile.Write(dump.GetData())
con.PrintInfof("Process dump stored in: %s\n", saveToFile.Name())
}
func getHostname(session *clientpb.Session, beacon *clientpb.Beacon) string {
if session != nil {
return session.Hostname
}
if beacon != nil {
return beacon.Hostname
}
return ""
}
+114 -82
View File
@@ -19,134 +19,156 @@ package processes
*/
import (
"bytes"
"context"
"fmt"
"strings"
"text/tabwriter"
// "time"
"github.com/bishopfox/sliver/client/command/settings"
"github.com/bishopfox/sliver/client/console"
"github.com/bishopfox/sliver/protobuf/clientpb"
"github.com/bishopfox/sliver/protobuf/commonpb"
"github.com/bishopfox/sliver/protobuf/sliverpb"
"github.com/desertbit/grumble"
"github.com/jedib0t/go-pretty/v6/table"
"google.golang.org/protobuf/proto"
)
var (
// Stylizes known processes in the `ps` command
knownProcs = map[string]string{
"ccSvcHst.exe": console.Red, // SEP
"cb.exe": console.Red, // Carbon Black
"MsMpEng.exe": console.Red, // Windows Defender
"smartscreen.exe": console.Red, // Windows Defender Smart Screen
knownSecurityTools = map[string]string{
"ccSvcHst.exe": console.Red, // SEP
"cb.exe": console.Red, // Carbon Black
"MsMpEng.exe": console.Red, // Windows Defender
"smartscreen.exe": console.Red, // Windows Defender Smart Screen
"bdservicehost.exe": console.Red, // Bitdefender (Total Security)
"bdagent.exe": console.Red, // Bitdefender (Total Security)
"bdredline.exe": console.Red, // Bitdefender Redline Update Service (Source https://community.bitdefender.com/en/discussion/82135/bdredline-exe-bitdefender-total-security-2020)
}
)
// PsCmd - List processes on the remote system
func PsCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
session := con.ActiveSession.GetInteractive()
if session == nil {
session, beacon := con.ActiveTarget.GetInteractive()
if session == nil && beacon == nil {
return
}
pidFilter := ctx.Flags.Int("pid")
exeFilter := ctx.Flags.String("exe")
ownerFilter := ctx.Flags.String("owner")
ps, err := con.Rpc.Ps(context.Background(), &sliverpb.PsReq{
Request: con.ActiveSession.Request(ctx),
Request: con.ActiveTarget.Request(ctx),
})
if err != nil {
con.PrintErrorf("%s\n", err)
return
}
os := getOS(session, beacon)
if ps.Response != nil && ps.Response.Async {
con.AddBeaconCallback(ps.Response.TaskID, func(task *clientpb.BeaconTask) {
err = proto.Unmarshal(task.Response, ps)
if err != nil {
con.PrintErrorf("Failed to decode response %s\n", err)
return
}
PrintPS(os, ps, false, ctx, con)
})
con.PrintAsyncResponse(ps.Response)
} else {
PrintPS(os, ps, true, ctx, con)
}
}
outputBuf := bytes.NewBufferString("")
table := tabwriter.NewWriter(outputBuf, 0, 2, 2, ' ', tabwriter.DiscardEmptyColumns)
func getOS(session *clientpb.Session, beacon *clientpb.Beacon) string {
if session != nil {
return session.OS
} else if beacon != nil {
return beacon.OS
}
return ""
}
switch session.GetOS() {
// PrintPS - Prints the process list
func PrintPS(os string, ps *sliverpb.Ps, interactive bool, ctx *grumble.Context, con *console.SliverConsoleClient) {
pidFilter := ctx.Flags.Int("pid")
exeFilter := ctx.Flags.String("exe")
ownerFilter := ctx.Flags.String("owner")
overflow := ctx.Flags.Bool("overflow")
skipPages := ctx.Flags.Int("skip-pages")
tw := table.NewWriter()
tw.SetStyle(settings.GetTableStyle(con))
switch os {
case "windows":
fmt.Fprintf(table, "pid\tppid\towner\texecutable\tsession\n")
fmt.Fprintf(table, "%s\t%s\t%s\t%s\t%s\t\n",
strings.Repeat("=", len("pid")),
strings.Repeat("=", len("ppid")),
strings.Repeat("=", len("owner")),
strings.Repeat("=", len("executable")),
strings.Repeat("=", len("session")),
)
tw.AppendHeader(table.Row{"pid", "ppid", "owner", "executable", "session"})
case "darwin":
fallthrough
case "linux":
fmt.Fprintf(table, "pid\tppid\towner\texecutable\t\n")
fmt.Fprintf(table, "%s\t%s\t%s\t%s\t\n",
strings.Repeat("=", len("pid")),
strings.Repeat("=", len("ppid")),
strings.Repeat("=", len("owner")),
strings.Repeat("=", len("executable")),
)
tw.AppendHeader(table.Row{"pid", "ppid", "owner", "executable"})
default:
fmt.Fprintf(table, "pid\tppid\towner\texecutable\t\n")
fmt.Fprintf(table, "%s\t%s\t%s\t%s\t\n",
strings.Repeat("=", len("pid")),
strings.Repeat("=", len("ppid")),
strings.Repeat("=", len("owner")),
strings.Repeat("=", len("executable")),
)
tw.AppendHeader(table.Row{"pid", "ppid", "owner", "executable"})
}
cmdLine := ctx.Flags.Bool("print-cmdline")
lineColors := []string{}
for _, proc := range ps.Processes {
var lineColor = ""
if pidFilter != -1 && proc.Pid == int32(pidFilter) {
lineColor = printProcInfo(table, proc, cmdLine, con)
}
if exeFilter != "" && strings.HasPrefix(proc.Executable, exeFilter) {
lineColor = printProcInfo(table, proc, cmdLine, con)
}
if ownerFilter != "" && strings.HasPrefix(proc.Owner, ownerFilter) {
lineColor = printProcInfo(table, proc, cmdLine, con)
}
if pidFilter == -1 && exeFilter == "" && ownerFilter == "" {
lineColor = printProcInfo(table, proc, cmdLine, con)
}
// Should be set to normal/green if we rendered the line
if lineColor != "" {
lineColors = append(lineColors, lineColor)
}
}
table.Flush()
for index, line := range strings.Split(outputBuf.String(), "\n") {
if len(line) == 0 {
if pidFilter != -1 && proc.Pid != int32(pidFilter) {
continue
}
// We need to account for the two rows of column headers
if 0 < len(line) && 2 <= index {
lineColor := lineColors[index-2]
con.Printf("%s%s%s\n", lineColor, line, console.Normal)
} else {
con.Printf("%s\n", line)
if exeFilter != "" && !strings.Contains(strings.ToLower(proc.Executable), strings.ToLower(exeFilter)) {
continue
}
if ownerFilter != "" && !strings.Contains(strings.ToLower(proc.Owner), strings.ToLower(ownerFilter)) {
continue
}
procRow(tw, proc, cmdLine, con)
}
tw.SortBy([]table.SortBy{
{Name: "pid", Mode: table.Asc},
{Name: "ppid", Mode: table.Asc},
})
settings.PaginateTable(tw, skipPages, overflow, interactive, con)
}
// printProcInfo - Stylizes the process information
func printProcInfo(table *tabwriter.Writer, proc *commonpb.Process, cmdLine bool, con *console.SliverConsoleClient) string {
// procRow - Stylizes the process information
func procRow(tw table.Writer, proc *commonpb.Process, cmdLine bool, con *console.SliverConsoleClient) {
session, beacon := con.ActiveTarget.GetInteractive()
color := console.Normal
if modifyColor, ok := knownProcs[proc.Executable]; ok {
if modifyColor, ok := knownSecurityTools[proc.Executable]; ok {
color = modifyColor
}
session := con.ActiveSession.GetInteractive()
if session != nil && proc.Pid == session.PID {
color = console.Green
}
if beacon != nil && proc.Pid == beacon.PID {
color = console.Green
}
var row table.Row
switch session.GetOS() {
case "windows":
fmt.Fprintf(table, "%d\t%d\t%s\t%s\t%d\t\n", proc.Pid, proc.Ppid, proc.Owner, proc.Executable, proc.SessionID)
if cmdLine {
var args string
if len(proc.CmdLine) >= 1 {
args = strings.Join(proc.CmdLine, " ")
} else {
args = proc.Executable
}
row = table.Row{
fmt.Sprintf(color+"%d"+console.Normal, proc.Pid),
fmt.Sprintf(color+"%d"+console.Normal, proc.Ppid),
fmt.Sprintf(color+"%s"+console.Normal, proc.Owner),
fmt.Sprintf(color+"%s"+console.Normal, args),
fmt.Sprintf(color+"%d"+console.Normal, proc.SessionID),
}
} else {
row = table.Row{
fmt.Sprintf(color+"%d"+console.Normal, proc.Pid),
fmt.Sprintf(color+"%d"+console.Normal, proc.Ppid),
fmt.Sprintf(color+"%s"+console.Normal, proc.Owner),
fmt.Sprintf(color+"%s"+console.Normal, proc.Executable),
fmt.Sprintf(color+"%d"+console.Normal, proc.SessionID),
}
}
case "darwin":
fallthrough
case "linux":
@@ -159,18 +181,28 @@ func printProcInfo(table *tabwriter.Writer, proc *commonpb.Process, cmdLine bool
} else {
args = proc.Executable
}
fmt.Fprintf(table, "%d\t%d\t%s\t%s\t\n", proc.Pid, proc.Ppid, proc.Owner, args)
row = table.Row{
fmt.Sprintf(color+"%d"+console.Normal, proc.Pid),
fmt.Sprintf(color+"%d"+console.Normal, proc.Ppid),
fmt.Sprintf(color+"%s"+console.Normal, proc.Owner),
fmt.Sprintf(color+"%s"+console.Normal, args),
}
} else {
fmt.Fprintf(table, "%d\t%d\t%s\t%s\t\n", proc.Pid, proc.Ppid, proc.Owner, proc.Executable)
row = table.Row{
fmt.Sprintf(color+"%d"+console.Normal, proc.Pid),
fmt.Sprintf(color+"%d"+console.Normal, proc.Ppid),
fmt.Sprintf(color+"%s"+console.Normal, proc.Owner),
fmt.Sprintf(color+"%s"+console.Normal, proc.Executable),
}
}
}
return color
tw.AppendRow(row)
}
// GetPIDByName - Get a PID by name from the active session
func GetPIDByName(ctx *grumble.Context, name string, con *console.SliverConsoleClient) int {
ps, err := con.Rpc.Ps(context.Background(), &sliverpb.PsReq{
Request: con.ActiveSession.Request(ctx),
Request: con.ActiveTarget.Request(ctx),
})
if err != nil {
return -1
+24 -5
View File
@@ -22,27 +22,46 @@ import (
"context"
"github.com/bishopfox/sliver/client/console"
"github.com/bishopfox/sliver/protobuf/clientpb"
"github.com/bishopfox/sliver/protobuf/sliverpb"
"github.com/desertbit/grumble"
"google.golang.org/protobuf/proto"
)
// TerminateCmd - Terminate a process on the remote system
func TerminateCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
session := con.ActiveSession.GetInteractive()
session := con.ActiveTarget.GetSessionInteractive()
if session == nil {
return
}
pid := ctx.Args.Uint("pid")
terminated, err := con.Rpc.Terminate(context.Background(), &sliverpb.TerminateReq{
Request: con.ActiveSession.Request(ctx),
Request: con.ActiveTarget.Request(ctx),
Pid: int32(pid),
Force: ctx.Flags.Bool("force"),
})
if err != nil {
con.PrintErrorf("%s\n", err)
if terminated.Response != nil && terminated.Response.Async {
con.AddBeaconCallback(terminated.Response.TaskID, func(task *clientpb.BeaconTask) {
err = proto.Unmarshal(task.Response, terminated)
if err != nil {
con.PrintErrorf("Failed to decode response %s\n", err)
return
}
PrintTerminate(terminated, con)
})
con.PrintAsyncResponse(terminated.Response)
} else {
PrintTerminate(terminated, con)
}
}
// PrintTerminate - Print the results of the terminate command
func PrintTerminate(terminated *sliverpb.Terminate, con *console.SliverConsoleClient) {
if terminated.Response != nil && terminated.Response.GetErr() != "" {
con.PrintErrorf("%s\n", terminated.Response.GetErr())
} else {
con.PrintInfof("Process %d has been terminated\n", terminated.Pid)
}
}
+26 -20
View File
@@ -19,15 +19,15 @@ package reaction
*/
import (
"bytes"
"fmt"
"strings"
"text/tabwriter"
"github.com/bishopfox/sliver/client/command/settings"
"github.com/bishopfox/sliver/client/console"
consts "github.com/bishopfox/sliver/client/constants"
"github.com/bishopfox/sliver/client/core"
"github.com/desertbit/grumble"
"github.com/jedib0t/go-pretty/v6/table"
)
// ReactionCmd - Manage reactions to events
@@ -36,6 +36,9 @@ func ReactionCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
for _, eventType := range core.ReactableEvents {
reactions := core.Reactions.On(eventType)
if 0 < len(reactions) {
if totalReactions != 0 {
con.Printf("\n") // Add newline between each table after the first
}
displayReactionsTable(eventType, reactions, con)
}
totalReactions += len(reactions)
@@ -46,25 +49,25 @@ func ReactionCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
}
func displayReactionsTable(eventType string, reactions []core.Reaction, con *console.SliverConsoleClient) {
// Title
con.Printf("%s%s%s\n", console.Bold, EventTypeToTitle(eventType), console.Normal)
// Table
outputBuf := bytes.NewBufferString("")
table := tabwriter.NewWriter(outputBuf, 0, 2, 2, ' ', 0)
fmt.Fprintf(table, "ID\tCommands\t\n")
fmt.Fprintf(table, "%s\t%s\t\n",
strings.Repeat("=", len("ID")),
strings.Repeat("=", len("Commands")),
)
for _, react := range reactions {
fmt.Fprintf(table, "%d\t%s\t\n",
react.ID, strings.Join(react.Commands, ","),
)
tw := table.NewWriter()
tw.SetStyle(settings.GetTableStyle(con))
tw.SetTitle(fmt.Sprintf(console.Bold+"%s"+console.Normal, EventTypeToTitle(eventType)))
tw.AppendSeparator()
slackSpace := len(EventTypeToTitle(eventType)) - len("Commands") - len("ID") - 3
if slackSpace < 0 {
slackSpace = 1
}
table.Flush()
con.Printf("%s", outputBuf.String())
tw.AppendHeader(table.Row{
"ID",
"Commands" + strings.Repeat(" ", slackSpace), // Leave space for title
})
for _, react := range reactions {
tw.AppendRow(table.Row{
react.ID,
strings.Join(react.Commands, ","),
})
}
con.Printf("%s\n", tw.Render())
}
// EventTypeToTitle - Convert an eventType to a more human friendly string
@@ -78,6 +81,9 @@ func EventTypeToTitle(eventType string) string {
case consts.SessionUpdateEvent:
return "Session Updated"
case consts.BeaconRegisteredEvent:
return "Beacon Registered"
case consts.CanaryEvent:
return "Canary Trigger"
+1 -1
View File
@@ -29,7 +29,7 @@ import (
// ReactionSaveCmd - Manage reactions to events
func ReactionReloadCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
if _, err := os.Stat(GetReactionFilePath()); os.IsNotExist(err) {
con.PrintWarnf("Missing reaction file %s\n", GetReactionFilePath())
con.PrintErrorf("Missing reaction file %s\n", GetReactionFilePath())
return
}
confirm := false
+1 -1
View File
@@ -47,7 +47,7 @@ func ReactionUnsetCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
con.Println()
con.PrintInfof("Successfully removed reaction with id %d", reactionID)
} else {
con.PrintWarnf("No reaction found with id %d", reactionID)
con.PrintErrorf("No reaction found with id %d", reactionID)
}
con.Println()
}
+41 -7
View File
@@ -23,14 +23,21 @@ import (
"strings"
"github.com/bishopfox/sliver/client/console"
"github.com/bishopfox/sliver/protobuf/clientpb"
"github.com/bishopfox/sliver/protobuf/sliverpb"
"github.com/desertbit/grumble"
"google.golang.org/protobuf/proto"
)
// RegCreateKeyCmd - Create a new Windows registry key
func RegCreateKeyCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
session := con.ActiveSession.Get()
if session == nil {
session, beacon := con.ActiveTarget.GetInteractive()
if session == nil && beacon == nil {
return
}
targetOS := getOS(session, beacon)
if targetOS != "windows" {
con.PrintErrorf("Registry operations can only target Windows\n")
return
}
@@ -60,22 +67,49 @@ func RegCreateKeyCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
}
finalPath := regPath[:pathBaseIdx]
key := regPath[pathBaseIdx+1:]
createKeyResp, err := con.Rpc.RegistryCreateKey(context.Background(), &sliverpb.RegistryCreateKeyReq{
createKey, err := con.Rpc.RegistryCreateKey(context.Background(), &sliverpb.RegistryCreateKeyReq{
Hive: hive,
Path: finalPath,
Key: key,
Hostname: hostname,
Request: con.ActiveSession.Request(ctx),
Request: con.ActiveTarget.Request(ctx),
})
if err != nil {
con.PrintErrorf("%s\n", err)
return
}
if createKeyResp.Response != nil && createKeyResp.Response.Err != "" {
con.PrintErrorf("%s", createKeyResp.Response.Err)
if createKey.Response != nil && createKey.Response.Async {
con.AddBeaconCallback(createKey.Response.TaskID, func(task *clientpb.BeaconTask) {
err = proto.Unmarshal(task.Response, createKey)
if err != nil {
con.PrintErrorf("Failed to decode response %s\n", err)
return
}
PrintCreateKey(createKey, finalPath, key, con)
})
con.PrintAsyncResponse(createKey.Response)
} else {
PrintCreateKey(createKey, finalPath, key, con)
}
}
// PrintCreateKey - Print the results of the crate key command
func PrintCreateKey(createKey *sliverpb.RegistryCreateKey, regPath string, key string, con *console.SliverConsoleClient) {
if createKey.Response != nil && createKey.Response.Err != "" {
con.PrintErrorf("%s", createKey.Response.Err)
return
}
con.PrintInfof("Key created at %s\\%s", regPath, key)
}
func getOS(session *clientpb.Session, beacon *clientpb.Beacon) string {
if session != nil {
return session.OS
}
if beacon != nil {
return beacon.OS
}
panic("no session or beacon")
}
+76 -17
View File
@@ -1,50 +1,93 @@
package registry
/*
Sliver Implant Framework
Copyright (C) 2021 Bishop Fox
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
import (
"context"
"github.com/bishopfox/sliver/client/console"
"github.com/bishopfox/sliver/protobuf/clientpb"
"github.com/bishopfox/sliver/protobuf/sliverpb"
"github.com/desertbit/grumble"
"google.golang.org/protobuf/proto"
)
// RegListSubKeysCmd - List sub registry keys
func RegListSubKeysCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
session := con.ActiveSession.GetInteractive()
if session == nil {
session, beacon := con.ActiveTarget.GetInteractive()
if session == nil && beacon == nil {
return
}
targetOS := getOS(session, beacon)
if targetOS != "windows" {
con.PrintErrorf("Registry operations can only target Windows\n")
return
}
path := ctx.Args.String("registry-path")
regPath := ctx.Args.String("registry-path")
hive := ctx.Flags.String("hive")
hostname := ctx.Flags.String("hostname")
regList, err := con.Rpc.RegistryListSubKeys(context.Background(), &sliverpb.RegistrySubKeyListReq{
Hive: hive,
Hostname: hostname,
Path: path,
Request: con.ActiveSession.Request(ctx),
Path: regPath,
Request: con.ActiveTarget.Request(ctx),
})
if err != nil {
con.PrintErrorf("Error: %s\n", err.Error())
con.PrintErrorf("%s\n", err)
return
}
if regList.Response != nil && regList.Response.Async {
con.AddBeaconCallback(regList.Response.TaskID, func(task *clientpb.BeaconTask) {
err = proto.Unmarshal(task.Response, regList)
if err != nil {
con.PrintErrorf("Failed to decode response %s\n", err)
return
}
PrintListSubKeys(regList, hive, regPath, con)
})
con.PrintAsyncResponse(regList.Response)
} else {
PrintListSubKeys(regList, hive, regPath, con)
}
}
// PrintListSubKeys - Print the list sub keys command result
func PrintListSubKeys(regList *sliverpb.RegistrySubKeyList, hive string, regPath string, con *console.SliverConsoleClient) {
if regList.Response != nil && regList.Response.Err != "" {
con.PrintErrorf("Error: %s\n", regList.Response.Err)
con.PrintErrorf("%s\n", regList.Response.Err)
return
}
if len(regList.Subkeys) > 0 {
con.PrintInfof("Sub keys under %s:\\%s:\n", hive, path)
if 0 < len(regList.Subkeys) {
con.PrintInfof("Sub keys under %s:\\%s:\n", hive, regPath)
}
for _, subKey := range regList.Subkeys {
con.Println(subKey)
}
}
// RegListValuesCmd - List registry values
func RegListValuesCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
session := con.ActiveSession.GetInteractive()
if session == nil {
session, beacon := con.ActiveTarget.GetInteractive()
if session == nil && beacon == nil {
return
}
@@ -56,19 +99,35 @@ func RegListValuesCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
Hive: hive,
Hostname: hostname,
Path: regPath,
Request: con.ActiveSession.Request(ctx),
Request: con.ActiveTarget.Request(ctx),
})
if err != nil {
con.PrintErrorf("Error: %s\n", err.Error())
con.PrintErrorf("%s\n", err)
return
}
if regList.Response != nil && regList.Response.Async {
con.AddBeaconCallback(regList.Response.TaskID, func(task *clientpb.BeaconTask) {
err = proto.Unmarshal(task.Response, regList)
if err != nil {
con.PrintErrorf("Failed to decode response %s\n", err)
return
}
PrintListValues(regList, hive, regPath, con)
})
con.PrintAsyncResponse(regList.Response)
} else {
PrintListValues(regList, hive, regPath, con)
}
}
// PrintListValues - Print the registry list values
func PrintListValues(regList *sliverpb.RegistryValuesList, hive string, regPath string, con *console.SliverConsoleClient) {
if regList.Response != nil && regList.Response.Err != "" {
con.PrintErrorf("Error: %s\n", regList.Response.Err)
con.PrintErrorf("%s\n", regList.Response.Err)
return
}
if len(regList.ValueNames) > 0 {
if 0 < len(regList.ValueNames) {
con.PrintInfof("Values under %s:\\%s:\n", hive, regPath)
}
for _, val := range regList.ValueNames {
+26 -6
View File
@@ -24,8 +24,10 @@ import (
"strings"
"github.com/bishopfox/sliver/client/console"
"github.com/bishopfox/sliver/protobuf/clientpb"
"github.com/bishopfox/sliver/protobuf/sliverpb"
"github.com/desertbit/grumble"
"google.golang.org/protobuf/proto"
)
var validHives = []string{
@@ -76,12 +78,13 @@ func RegReadCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
finalPath string
key string
)
session := con.ActiveSession.GetInteractive()
if session == nil {
session, beacon := con.ActiveTarget.GetInteractive()
if session == nil && beacon == nil {
return
}
if session.OS != "windows" {
con.PrintErrorf("Command not supported on this operating system.")
targetOS := getOS(session, beacon)
if targetOS != "windows" {
con.PrintErrorf("Registry operations can only target Windows\n")
return
}
@@ -112,19 +115,36 @@ func RegReadCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
}
finalPath = regPath[:pathBaseIdx]
key = regPath[pathBaseIdx+1:]
regRead, err := con.Rpc.RegistryRead(context.Background(), &sliverpb.RegistryReadReq{
Hive: hive,
Path: finalPath,
Key: key,
Hostname: hostname,
Request: con.ActiveSession.Request(ctx),
Request: con.ActiveTarget.Request(ctx),
})
if err != nil {
con.PrintErrorf("%s\n", err)
return
}
if regRead.Response != nil && regRead.Response.Async {
con.AddBeaconCallback(regRead.Response.TaskID, func(task *clientpb.BeaconTask) {
err = proto.Unmarshal(task.Response, regRead)
if err != nil {
con.PrintErrorf("Failed to decode response %s\n", err)
return
}
PrintRegRead(regRead, con)
})
con.PrintAsyncResponse(regRead.Response)
} else {
PrintRegRead(regRead, con)
}
}
// PrintRegRead - Print the results of the registry read command
func PrintRegRead(regRead *sliverpb.RegistryRead, con *console.SliverConsoleClient) {
if regRead.Response != nil && regRead.Response.Err != "" {
con.PrintErrorf("%s\n", regRead.Response.Err)
return
+26 -6
View File
@@ -26,18 +26,21 @@ import (
"strings"
"github.com/bishopfox/sliver/client/console"
"github.com/bishopfox/sliver/protobuf/clientpb"
"github.com/bishopfox/sliver/protobuf/sliverpb"
"github.com/desertbit/grumble"
"google.golang.org/protobuf/proto"
)
// RegWriteCmd - Write to a Windows registry key: registry write --hive HKCU --type dword "software\google\chrome\blbeacon\hello" 32
func RegWriteCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
session := con.ActiveSession.GetInteractive()
if session == nil {
session, beacon := con.ActiveTarget.GetInteractive()
if session == nil && beacon == nil {
return
}
if session.OS != "windows" {
con.PrintErrorf("Error: command not supported on this operating system.")
targetOS := getOS(session, beacon)
if targetOS != "windows" {
con.PrintErrorf("Registry operations can only target Windows\n")
return
}
@@ -123,7 +126,7 @@ func RegWriteCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
return
}
regWrite, err := con.Rpc.RegistryWrite(context.Background(), &sliverpb.RegistryWriteReq{
Request: con.ActiveSession.Request(ctx),
Request: con.ActiveTarget.Request(ctx),
Hostname: hostname,
Hive: hive,
Path: finalPath,
@@ -134,11 +137,28 @@ func RegWriteCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
QWordValue: qwordValue,
ByteValue: binaryValue,
})
if err != nil {
con.PrintErrorf("%s\n", err)
return
}
if regWrite.Response != nil && regWrite.Response.Async {
con.AddBeaconCallback(regWrite.Response.TaskID, func(task *clientpb.BeaconTask) {
err = proto.Unmarshal(task.Response, regWrite)
if err != nil {
con.PrintErrorf("Failed to decode response %s\n", err)
return
}
PrintRegWrite(regWrite, con)
})
con.PrintAsyncResponse(regWrite.Response)
} else {
PrintRegWrite(regWrite, con)
}
}
// PrintRegWrite - Print the registry write operation
func PrintRegWrite(regWrite *sliverpb.RegistryWrite, con *console.SliverConsoleClient) {
if regWrite.Response != nil && regWrite.Response.Err != "" {
con.PrintErrorf("%s", regWrite.Response.Err)
return
+72 -15
View File
@@ -22,52 +22,89 @@ import (
"context"
"fmt"
"io/ioutil"
"path"
"os"
"path/filepath"
"time"
"github.com/bishopfox/sliver/client/command/loot"
"github.com/bishopfox/sliver/client/console"
"github.com/bishopfox/sliver/protobuf/clientpb"
"github.com/bishopfox/sliver/protobuf/sliverpb"
"github.com/bishopfox/sliver/util"
"google.golang.org/protobuf/proto"
"github.com/desertbit/grumble"
)
// ScreenshotCmd - Take a screenshot of the remote system
func ScreenshotCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
session := con.ActiveSession.GetInteractive()
if session == nil {
session, beacon := con.ActiveTarget.GetInteractive()
if session == nil && beacon == nil {
return
}
if session.OS != "windows" && session.OS != "linux" {
con.PrintErrorf("Not implemented for %s\n", session.OS)
targetOS := getOS(session, beacon)
if targetOS != "windows" && targetOS != "linux" {
con.PrintWarnf("Target platform may not support screenshots!\n")
return
}
screenshot, err := con.Rpc.Screenshot(context.Background(), &sliverpb.ScreenshotReq{
Request: con.ActiveSession.Request(ctx),
Request: con.ActiveTarget.Request(ctx),
})
if err != nil {
con.PrintErrorf("%s\n", err)
return
}
timestamp := time.Now().Format("20060102150405")
tmpFileName := path.Base(fmt.Sprintf("screenshot_%s_%d_%s_*.png", session.Name, session.ID, timestamp))
tmpFile, err := ioutil.TempFile("", tmpFileName)
if err != nil {
con.PrintErrorf("%s\n", err)
return
hostname := getHostname(session, beacon)
if screenshot.Response != nil && screenshot.Response.Async {
con.AddBeaconCallback(screenshot.Response.TaskID, func(task *clientpb.BeaconTask) {
err = proto.Unmarshal(task.Response, screenshot)
if err != nil {
con.PrintErrorf("Failed to decode response %s\n", err)
return
}
PrintScreenshot(screenshot, hostname, ctx, con)
})
con.PrintAsyncResponse(screenshot.Response)
} else {
PrintScreenshot(screenshot, hostname, ctx, con)
}
err = ioutil.WriteFile(tmpFile.Name(), screenshot.Data, 0600)
}
// PrintScreenshot - Handle the screenshot command response
func PrintScreenshot(screenshot *sliverpb.Screenshot, hostname string, ctx *grumble.Context, con *console.SliverConsoleClient) {
timestamp := time.Now().Format("20060102150405")
saveTo := ctx.Flags.String("save")
var saveToFile *os.File
var err error
if saveTo == "" {
tmpFileName := filepath.Base(fmt.Sprintf("screenshot_%s_%s_*.png", filepath.Base(hostname), timestamp))
saveToFile, err = ioutil.TempFile("", tmpFileName)
if err != nil {
con.PrintErrorf("%s\n", err)
return
}
} else {
saveToFile, err = os.OpenFile(saveTo, os.O_WRONLY, 600)
if err != nil {
con.PrintErrorf("Error creating file: %s\n", err)
return
}
}
defer saveToFile.Close()
var n int
n, err = saveToFile.Write(screenshot.Data)
if err != nil {
con.PrintErrorf("Error writting file: %s\n", err)
return
}
con.Printf(console.Bold+"Screenshot written to %s\n", tmpFile.Name())
con.PrintInfof("Screenshot written to %s (%s)\n", saveToFile.Name(), util.ByteCountBinary(int64(n)))
if ctx.Flags.Bool("loot") && 0 < len(screenshot.Data) {
err = loot.AddLootFile(con.Rpc, fmt.Sprintf("[screenshot] %s", timestamp), tmpFileName, screenshot.Data, false)
err = loot.AddLootFile(con.Rpc, fmt.Sprintf("[screenshot] %s", timestamp), saveToFile.Name(), screenshot.Data, false)
if err != nil {
con.PrintErrorf("Failed to save output as loot: %s\n", err)
} else {
@@ -75,3 +112,23 @@ func ScreenshotCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
}
}
}
func getOS(session *clientpb.Session, beacon *clientpb.Beacon) string {
if session != nil {
return session.OS
}
if beacon != nil {
return beacon.OS
}
panic("no session or beacon")
}
func getHostname(session *clientpb.Session, beacon *clientpb.Beacon) string {
if session != nil {
return session.Hostname
}
if beacon != nil {
return beacon.Hostname
}
panic("no session or beacon")
}
+1 -1
View File
@@ -7,6 +7,6 @@ import (
// BackgroundCmd - Background the active session
func BackgroundCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
con.ActiveSession.Background()
con.ActiveTarget.Background()
con.PrintInfof("Background ...\n")
}
+88
View File
@@ -0,0 +1,88 @@
package sessions
/*
Sliver Implant Framework
Copyright (C) 2021 Bishop Fox
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
import (
"context"
"time"
"github.com/bishopfox/sliver/client/command/generate"
"github.com/bishopfox/sliver/client/console"
"github.com/bishopfox/sliver/protobuf/clientpb"
"github.com/bishopfox/sliver/protobuf/sliverpb"
"github.com/desertbit/grumble"
)
// InteractiveCmd - Beacon only command to open an interactive session
func InteractiveCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
beacon := con.ActiveTarget.GetBeaconInteractive()
if beacon == nil {
return
}
delay, err := time.ParseDuration(ctx.Flags.String("delay"))
if err != nil {
con.PrintErrorf("%s\n", err)
return
}
c2s := []*clientpb.ImplantC2{}
mtlsC2 := generate.ParseMTLSc2(ctx.Flags.String("mtls"))
c2s = append(c2s, mtlsC2...)
wgC2 := generate.ParseWGc2(ctx.Flags.String("wg"))
c2s = append(c2s, wgC2...)
httpC2 := generate.ParseHTTPc2(ctx.Flags.String("http"))
c2s = append(c2s, httpC2...)
dnsC2 := generate.ParseDNSc2(ctx.Flags.String("dns"))
c2s = append(c2s, dnsC2...)
namedPipeC2 := generate.ParseNamedPipec2(ctx.Flags.String("named-pipe"))
c2s = append(c2s, namedPipeC2...)
tcpPivotC2 := generate.ParseTCPPivotc2(ctx.Flags.String("tcp-pivot"))
c2s = append(c2s, tcpPivotC2...)
if len(mtlsC2) == 0 && len(wgC2) == 0 && len(httpC2) == 0 && len(dnsC2) == 0 && len(namedPipeC2) == 0 && len(tcpPivotC2) == 0 {
con.PrintErrorf("Must specify at least one of --mtls, --wg, --http, --dns, --named-pipe, or --tcp-pivot\n")
return
}
openSession := &sliverpb.OpenSession{
Request: con.ActiveTarget.Request(ctx),
C2S: []string{},
Delay: int64(delay),
}
for _, c2 := range c2s {
openSession.C2S = append(openSession.C2S, c2.URL)
}
openSession, err = con.Rpc.OpenSession(context.Background(), openSession)
if err != nil {
con.PrintErrorf("%s\n", err)
}
if openSession.Response != nil && openSession.Response.Async {
con.PrintAsyncResponse(openSession.Response)
} else {
con.PrintErrorf("rpc response missing!\n")
}
}
-50
View File
@@ -1,50 +0,0 @@
package sessions
import (
"context"
"errors"
"github.com/AlecAivazis/survey/v2"
"github.com/bishopfox/sliver/client/console"
"github.com/bishopfox/sliver/protobuf/clientpb"
"github.com/bishopfox/sliver/protobuf/commonpb"
"github.com/bishopfox/sliver/protobuf/sliverpb"
"github.com/desertbit/grumble"
)
// KillCmd - Kill the active session (not to be confused with TerminateCmd)
func KillCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
session := con.ActiveSession.GetInteractive()
if session == nil {
con.PrintWarnf("No active session\n")
return
}
// Confirm with the user, just in case they confused kill with terminate
confirm := false
prompt := &survey.Confirm{Message: "Kill the active session?"}
survey.AskOne(prompt, &confirm, nil)
if !confirm {
return
}
err := killSession(session, ctx.Flags.Bool("force"), con)
if err != nil {
con.PrintErrorf("%s\n", err)
return
}
con.PrintInfof("Killed %s (%d)\n", session.Name, session.ID)
con.ActiveSession.Background()
}
func killSession(session *clientpb.Session, force bool, con *console.SliverConsoleClient) error {
if session == nil {
return errors.New("session does not exist")
}
_, err := con.Rpc.KillSession(context.Background(), &sliverpb.KillSessionReq{
Request: &commonpb.Request{
SessionID: session.ID,
},
Force: force,
})
return err
}
+20 -1
View File
@@ -1,8 +1,27 @@
package sessions
/*
Sliver Implant Framework
Copyright (C) 2021 Bishop Fox
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
import (
"context"
"github.com/bishopfox/sliver/client/command/kill"
"github.com/bishopfox/sliver/client/console"
"github.com/bishopfox/sliver/protobuf/commonpb"
"github.com/desertbit/grumble"
@@ -22,7 +41,7 @@ func SessionsPruneCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
for _, session := range sessions.GetSessions() {
if session.IsDead {
con.Printf("Pruning session #%d ...", session.ID)
err = killSession(session, true, con)
err = kill.KillSession(session, true, con)
if err != nil {
con.Printf("failed!\n")
con.PrintErrorf("%s\n", err)
+7 -5
View File
@@ -21,6 +21,7 @@ package sessions
import (
"context"
"regexp"
"time"
"github.com/bishopfox/sliver/client/console"
"github.com/bishopfox/sliver/protobuf/clientpb"
@@ -30,7 +31,7 @@ import (
// SessionsReconfigCmd - Reconfigure metadata about a sessions
func SessionsReconfigCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
session := con.ActiveSession.GetInteractive()
session := con.ActiveTarget.GetSessionInteractive()
if session == nil {
return
}
@@ -51,11 +52,12 @@ func SessionsReconfigCmd(ctx *grumble.Context, con *console.SliverConsoleClient)
// Option to change the reconnect interval
poll := ctx.Flags.Int("poll")
oldSession := con.ActiveTarget.GetSession()
session, err := con.Rpc.UpdateSession(context.Background(), &clientpb.UpdateSession{
SessionID: con.ActiveSession.Session.ID,
SessionID: oldSession.ID,
Name: name,
ReconnectInterval: int32(reconnect),
PollInterval: int32(poll),
ReconnectInterval: int64(reconnect) * int64(time.Second),
PollInterval: int64(poll) * int64(time.Second),
})
if err != nil {
@@ -63,5 +65,5 @@ func SessionsReconfigCmd(ctx *grumble.Context, con *console.SliverConsoleClient)
return
}
con.ActiveSession.Set(session)
con.ActiveTarget.Set(session, nil)
}
+49 -85
View File
@@ -19,25 +19,24 @@ package sessions
*/
import (
"bytes"
"context"
"fmt"
"sort"
"strings"
"text/tabwriter"
"time"
"github.com/bishopfox/sliver/client/command/kill"
"github.com/bishopfox/sliver/client/command/settings"
"github.com/bishopfox/sliver/client/console"
"github.com/bishopfox/sliver/protobuf/clientpb"
"github.com/bishopfox/sliver/protobuf/commonpb"
"github.com/desertbit/grumble"
"github.com/jedib0t/go-pretty/v6/table"
)
// SessionsCmd - Display/interact with sessions
func SessionsCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
interact := ctx.Flags.String("interact")
kill := ctx.Flags.String("kill")
killFlag := ctx.Flags.String("kill")
killAll := ctx.Flags.Bool("kill-all")
clean := ctx.Flags.Bool("clean")
@@ -48,9 +47,9 @@ func SessionsCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
}
if killAll {
con.ActiveSession.Background()
con.ActiveTarget.Background()
for _, session := range sessions.Sessions {
err := killSession(session, true, con)
err := kill.KillSession(session, true, con)
if err != nil {
con.PrintErrorf("%s\n", err)
}
@@ -61,10 +60,10 @@ func SessionsCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
}
if clean {
con.ActiveSession.Background()
con.ActiveTarget.Background()
for _, session := range sessions.Sessions {
if session.IsDead {
err := killSession(session, true, con)
err := kill.KillSession(session, true, con)
if err != nil {
con.PrintErrorf("%s\n", err)
}
@@ -74,13 +73,13 @@ func SessionsCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
}
return
}
if kill != "" {
session := con.GetSession(kill)
activeSession := con.ActiveSession.Get()
if killFlag != "" {
session := con.GetSession(killFlag)
activeSession := con.ActiveTarget.GetSession()
if activeSession != nil && session.ID == activeSession.ID {
con.ActiveSession.Background()
con.ActiveTarget.Background()
}
err := killSession(session, true, con)
err := kill.KillSession(session, true, con)
if err != nil {
con.PrintErrorf("%s\n", err)
}
@@ -90,7 +89,7 @@ func SessionsCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
if interact != "" {
session := con.GetSession(interact)
if session != nil {
con.ActiveSession.Set(session)
con.ActiveTarget.Set(session, nil)
con.PrintInfof("Active session %s (%d)\n", session.Name, session.ID)
} else {
con.PrintErrorf("Invalid session name or session number: %s\n", interact)
@@ -101,55 +100,34 @@ func SessionsCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
sessionsMap[session.ID] = session
}
if 0 < len(sessionsMap) {
printSessions(sessionsMap, con)
PrintSessions(sessionsMap, con)
} else {
con.PrintInfof("No sessions 🙁\n")
}
}
}
/*
So this method is a little more complex than you'd maybe think,
this is because Go's tabwriter aligns columns by counting bytes
and since we want to modify the color of the active sliver row
the number of bytes per row won't line up. So we render the table
into a buffer and note which row the active sliver is in. Then we
write each line to the term and insert the ANSI codes just before
we display the row.
*/
func printSessions(sessions map[uint32]*clientpb.Session, con *console.SliverConsoleClient) {
outputBuf := bytes.NewBufferString("")
table := tabwriter.NewWriter(outputBuf, 0, 2, 2, ' ', 0)
// PrintSessions - Print the current sessions
func PrintSessions(sessions map[uint32]*clientpb.Session, con *console.SliverConsoleClient) {
tw := table.NewWriter()
tw.SetStyle(settings.GetTableStyle(con))
tw.AppendHeader(table.Row{
"ID",
"Name",
"Transport",
"Remote Address",
"Hostname",
"Username",
"Operating System",
"Last Check-in",
"Health",
})
// Column Headers
fmt.Fprintln(table, "ID\tName\tTransport\tRemote Address\tHostname\tUsername\tOperating System\tLast Check-in\tHealth\t")
fmt.Fprintf(table, "%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s\t\n",
strings.Repeat("=", len("ID")),
strings.Repeat("=", len("Name")),
strings.Repeat("=", len("Transport")),
strings.Repeat("=", len("Remote Address")),
strings.Repeat("=", len("Hostname")),
strings.Repeat("=", len("Username")),
strings.Repeat("=", len("Operating System")),
strings.Repeat("=", len("Last Check-in")),
strings.Repeat("=", len("Health")),
)
// strings.Repeat("=", len("Burned")))
// Sort the keys because maps have a randomized order
var keys []int
for _, session := range sessions {
keys = append(keys, int(session.ID))
}
sort.Ints(keys) // Fucking Go can't sort int32's, so we convert to/from int's
activeIndex := -1
for index, key := range keys {
session := sessions[uint32(key)]
if con.ActiveSession.Get() != nil && con.ActiveSession.Get().ID == session.ID {
activeIndex = index + 2 // Two lines for the headers
color := console.Normal
if con.ActiveTarget.GetSession() != nil && con.ActiveTarget.GetSession().ID == session.ID {
color = console.Green
}
var SessionHealth string
if session.IsDead {
SessionHealth = console.Bold + console.Red + "[DEAD]" + console.Normal
@@ -160,35 +138,21 @@ func printSessions(sessions map[uint32]*clientpb.Session, con *console.SliverCon
if session.Burned {
burned = "🔥"
}
fmt.Fprintf(table, "%d\t%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s\n",
session.ID,
session.Name,
session.Transport,
session.RemoteAddress,
session.Hostname,
session.Username,
fmt.Sprintf("%s/%s", session.OS, session.Arch),
session.LastCheckin,
SessionHealth,
burned,
)
tw.AppendRow(table.Row{
fmt.Sprintf(color+"%d"+console.Normal, session.ID),
fmt.Sprintf(color+"%s"+console.Normal, session.Name),
fmt.Sprintf(color+"%s"+console.Normal, session.Transport),
fmt.Sprintf(color+"%s"+console.Normal, session.RemoteAddress),
fmt.Sprintf(color+"%s"+console.Normal, session.Hostname),
fmt.Sprintf(color+"%s"+console.Normal, session.Username),
fmt.Sprintf(color+"%s/%s"+console.Normal, session.OS, session.Arch),
fmt.Sprintf(color+"%s"+console.Normal, time.Unix(session.LastCheckin, 0).Format(time.RFC1123)),
burned + SessionHealth,
})
}
table.Flush()
tw.SortBy([]table.SortBy{
{Name: "ID", Mode: table.Asc},
})
if activeIndex != -1 {
lines := strings.Split(outputBuf.String(), "\n")
for lineNumber, line := range lines {
if len(line) == 0 {
continue
}
if lineNumber == activeIndex {
con.Printf("%s%s%s\n", console.Green, line, console.Normal)
} else {
con.Printf("%s\n", line)
}
}
} else {
con.Printf(outputBuf.String())
}
con.Printf("%s\n", tw.Render())
}
-39
View File
@@ -1,39 +0,0 @@
package sessions
import (
"github.com/bishopfox/sliver/client/console"
"github.com/bishopfox/sliver/protobuf/clientpb"
"github.com/desertbit/grumble"
)
// UseCmd - Change the active session
func UseCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
sessionArg := ctx.Args.String("session")
if sessionArg != "" {
session := con.GetSession(sessionArg)
if session == nil {
con.PrintErrorf("Invalid session name or session number '%s'\n", ctx.Args.String("session"))
} else {
activate(session, con)
}
} else {
session, err := SelectSession(false, con)
if session != nil {
activate(session, con)
} else if err != nil {
switch err {
case ErrNoSessions:
con.PrintErrorf("No sessions available\n")
case ErrNoSelection:
con.PrintErrorf("No session selected\n")
default:
con.PrintErrorf("%s\n", err)
}
}
}
}
func activate(session *clientpb.Session, con *console.SliverConsoleClient) {
con.ActiveSession.Set(session)
con.PrintInfof("Active session %s (%d)\n", session.Name, session.ID)
}
+4
View File
@@ -0,0 +1,4 @@
Style
======
Defines terminal interface styles.
+39
View File
@@ -0,0 +1,39 @@
package settings
/*
Sliver Implant Framework
Copyright (C) 2021 Bishop Fox
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
import (
"github.com/bishopfox/sliver/client/assets"
"github.com/bishopfox/sliver/client/console"
"github.com/desertbit/grumble"
)
// SettingsBeaconsAutoResultCmd - The client settings command
func SettingsBeaconsAutoResultCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
var err error
if con.Settings == nil {
con.Settings, err = assets.LoadSettings()
if err != nil {
con.PrintErrorf("%s\n", err)
return
}
}
con.Settings.BeaconAutoResults = !con.Settings.BeaconAutoResults
con.PrintInfof("Beacon Auto Result = %v\n", con.Settings.BeaconAutoResults)
}
+62
View File
@@ -0,0 +1,62 @@
package settings
/*
Sliver Implant Framework
Copyright (C) 2021 Bishop Fox
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
import (
"github.com/AlecAivazis/survey/v2"
"github.com/bishopfox/sliver/client/assets"
"github.com/bishopfox/sliver/client/console"
"github.com/desertbit/grumble"
)
// SettingsAutoAdultCmd - The client settings command
func SettingsAutoAdultCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
var err error
if con.Settings == nil {
con.Settings, err = assets.LoadSettings()
if err != nil {
con.PrintErrorf("%s\n", err)
return
}
}
con.Settings.AutoAdult = !con.Settings.AutoAdult
con.PrintInfof("Auto Adult = %v\n", con.Settings.AutoAdult)
}
// IsUserAnAdult - This should be called for any dangerous (OPSEC-wise) functions
func IsUserAnAdult(con *console.SliverConsoleClient) bool {
if GetAutoAdult(con) {
return true
}
confirm := false
prompt := &survey.Confirm{Message: "This action is bad OPSEC, are you an adult?"}
survey.AskOne(prompt, &confirm, nil)
return confirm
}
// GetAutoAdult - Get the current auto adult setting
func GetAutoAdult(con *console.SliverConsoleClient) bool {
if con.Settings == nil {
con.Settings, _ = assets.LoadSettings()
}
if con.Settings != nil {
return con.Settings.AutoAdult
}
return false
}
+97
View File
@@ -0,0 +1,97 @@
package settings
/*
Sliver Implant Framework
Copyright (C) 2021 Bishop Fox
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
import (
"github.com/AlecAivazis/survey/v2"
"github.com/bishopfox/sliver/client/assets"
"github.com/bishopfox/sliver/client/console"
"github.com/desertbit/grumble"
"github.com/jedib0t/go-pretty/v6/table"
)
// SettingsCmd - The client settings command
func SettingsCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
var err error
if con.Settings == nil {
con.Settings, err = assets.LoadSettings()
if err != nil {
con.PrintErrorf("%s\n", err)
return
}
}
tw := table.NewWriter()
tw.SetStyle(GetTableStyle(con))
tw.AppendHeader(table.Row{"Name", "Value", "Description"})
tw.AppendRow(table.Row{"Tables", con.Settings.TableStyle, "Set the stylization of tables"})
tw.AppendRow(table.Row{"Auto Adult", con.Settings.AutoAdult, "Automatically accept OPSEC warnings"})
tw.AppendRow(table.Row{"Beacon Auto Results", con.Settings.BeaconAutoResults, "Automatically display beacon results when tasks complete"})
con.Printf("%s\n", tw.Render())
}
// SettingsTablesCmd - The client settings command
func SettingsTablesCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
var err error
if con.Settings == nil {
con.Settings, err = assets.LoadSettings()
if err != nil {
con.PrintErrorf("%s\n", err)
return
}
}
options := []string{}
for option := range tableStyles {
options = append(options, option)
}
style := ""
prompt := &survey.Select{
Message: "Choose a style:",
Options: options,
}
err = survey.AskOne(prompt, &style)
if err != nil {
con.PrintErrorf("No selection\n")
return
}
if _, ok := tableStyles[style]; ok {
con.Settings.TableStyle = style
} else {
con.PrintErrorf("Invalid style\n")
}
}
// SettingsSaveCmd - The client settings command
func SettingsSaveCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
var err error
if con.Settings == nil {
con.Settings, err = assets.LoadSettings()
if err != nil {
con.PrintErrorf("%s\n", err)
return
}
}
err = assets.SaveSettings(con.Settings)
if err != nil {
con.PrintErrorf("%s\n", err)
} else {
con.PrintInfof("Settings saved to disk\n")
}
}
+234
View File
@@ -0,0 +1,234 @@
package settings
/*
Sliver Implant Framework
Copyright (C) 2021 Bishop Fox
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
import (
"fmt"
"strings"
"github.com/AlecAivazis/survey/v2"
"github.com/bishopfox/sliver/client/assets"
"github.com/bishopfox/sliver/client/console"
"github.com/jedib0t/go-pretty/v6/table"
"github.com/jedib0t/go-pretty/v6/text"
"golang.org/x/crypto/ssh/terminal"
)
var (
tableStyles = map[string]table.Style{
// Sliver styles
SliverDefault.Name: SliverDefault,
// Go Pretty styles
table.StyleBold.Name: table.StyleBold,
table.StyleColoredBright.Name: table.StyleColoredBright,
table.StyleLight.Name: table.StyleLight,
table.StyleColoredDark.Name: table.StyleColoredDark,
table.StyleColoredBlackOnBlueWhite.Name: table.StyleColoredBlackOnBlueWhite,
}
SliverDefault = table.Style{
Name: "SliverDefault",
Box: table.BoxStyle{
BottomLeft: " ",
BottomRight: " ",
BottomSeparator: " ",
Left: " ",
LeftSeparator: " ",
MiddleHorizontal: "=",
MiddleSeparator: " ",
MiddleVertical: " ",
PaddingLeft: " ",
PaddingRight: " ",
Right: " ",
RightSeparator: " ",
TopLeft: " ",
TopRight: " ",
TopSeparator: " ",
UnfinishedRow: "~~",
},
Color: table.ColorOptions{
IndexColumn: text.Colors{},
Footer: text.Colors{},
Header: text.Colors{},
Row: text.Colors{},
RowAlternate: text.Colors{},
},
Format: table.FormatOptions{
Footer: text.FormatDefault,
Header: text.FormatTitle,
Row: text.FormatDefault,
},
Options: table.Options{
DrawBorder: false,
SeparateColumns: true,
SeparateFooter: false,
SeparateHeader: true,
SeparateRows: false,
},
}
sliverBordersDefault = table.Style{
Name: "SliverBordersDefault",
Box: table.BoxStyle{
BottomLeft: "+",
BottomRight: "+",
BottomSeparator: "-",
Left: "|",
LeftSeparator: "+",
MiddleHorizontal: "-",
MiddleSeparator: "+",
MiddleVertical: "|",
PaddingLeft: " ",
PaddingRight: " ",
Right: "|",
RightSeparator: "+",
TopLeft: "+",
TopRight: "+",
TopSeparator: "-",
UnfinishedRow: "~~",
},
Color: table.ColorOptions{
IndexColumn: text.Colors{},
Footer: text.Colors{},
Header: text.Colors{},
Row: text.Colors{},
RowAlternate: text.Colors{},
},
Format: table.FormatOptions{
Footer: text.FormatDefault,
Header: text.FormatTitle,
Row: text.FormatDefault,
},
Options: table.Options{
DrawBorder: true,
SeparateColumns: true,
SeparateFooter: false,
SeparateHeader: true,
SeparateRows: false,
},
}
)
// GetTableStyle - Get the current table style
func GetTableStyle(con *console.SliverConsoleClient) table.Style {
if con.Settings == nil {
con.Settings, _ = assets.LoadSettings()
}
if con.Settings != nil {
if value, ok := tableStyles[con.Settings.TableStyle]; ok {
return value
}
}
return tableStyles[SliverDefault.Name]
}
// GetTableWithBordersStyle - Get the table style with borders
func GetTableWithBordersStyle(con *console.SliverConsoleClient) table.Style {
if con.Settings == nil {
con.Settings, _ = assets.LoadSettings()
}
value, ok := tableStyles[con.Settings.TableStyle]
if !ok || con.Settings.TableStyle == SliverDefault.Name {
return sliverBordersDefault
}
return value
}
// GetPageSize - Page size for tables
func GetPageSize() int {
return 10
}
// PagesOf - Return the pages of a table
func PagesOf(renderedTable string) [][]string {
lines := strings.Split(renderedTable, "\n")
if len(lines) < 2 {
return [][]string{}
}
token := lines[0]
pages := [][]string{}
page := []string{token}
for _, line := range lines[1:] {
if line != token {
page = append(page, line)
} else {
pages = append(pages, page)
page = []string{token}
}
}
pages = append(pages, page)
return pages
}
// PaginateTable - Render paginated table to console
func PaginateTable(tw table.Writer, skipPages int, overflow bool, interactive bool, con *console.SliverConsoleClient) {
renderedTable := tw.Render()
lineCount := strings.Count(renderedTable, "\n")
if !overflow {
// Only paginate if the number of lines is at least 2x the terminal height
width, height, err := terminal.GetSize(0)
if err == nil && 2*height < lineCount {
if 7 < height {
tw.SetPageSize(height - 6)
tw.SetAllowedRowLength(width)
} else {
tw.SetPageSize(2)
tw.SetAllowedRowLength(width)
}
renderedTable = tw.Render()
}
}
pages := PagesOf(renderedTable)
for pageNumber, page := range pages {
if pageNumber+1 < skipPages {
continue
}
for _, line := range page {
if len(line) == 0 {
continue
}
con.Printf("%s\n", line)
}
con.Println()
if interactive {
if 1 < len(pages) {
if pageNumber+1 < len(pages) {
nextPage := false
prompt := &survey.Confirm{
Message: fmt.Sprintf("[%d/%d] Continue?", pageNumber+1, len(pages)),
}
survey.AskOne(prompt, &nextPage)
if !nextPage {
break
}
con.Println()
} else {
con.Printf(console.Bold+"Page [%d/%d]\n", pageNumber+1, len(pages))
}
}
} else {
if 1 < len(pages) {
con.Printf(console.Bold+"Page [%d/%d]\n", pageNumber+1, len(pages))
}
break
}
}
}
+6 -5
View File
@@ -25,6 +25,7 @@ import (
"log"
"os"
"github.com/bishopfox/sliver/client/command/settings"
"github.com/bishopfox/sliver/client/console"
"github.com/bishopfox/sliver/client/core"
"github.com/bishopfox/sliver/protobuf/sliverpb"
@@ -41,18 +42,18 @@ const (
// ShellCmd - Start an interactive shell on the remote system
func ShellCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
session := con.ActiveSession.GetInteractive()
session := con.ActiveTarget.GetSessionInteractive()
if session == nil {
return
}
if !con.IsUserAnAdult() {
if !settings.IsUserAnAdult(con) {
return
}
shellPath := ctx.Flags.String("shell-path")
noPty := ctx.Flags.Bool("no-pty")
if con.ActiveSession.Get().OS != linux && con.ActiveSession.Get().OS != darwin {
if con.ActiveTarget.GetSession().OS != linux && con.ActiveTarget.GetSession().OS != darwin {
noPty = true // Sliver's PTYs are only supported on linux/darwin
}
runInteractive(ctx, shellPath, noPty, con)
@@ -61,7 +62,7 @@ func ShellCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
func runInteractive(ctx *grumble.Context, shellPath string, noPty bool, con *console.SliverConsoleClient) {
con.PrintInfof("Opening shell tunnel (EOF to exit) ...\n\n")
session := con.ActiveSession.Get()
session := con.ActiveTarget.GetSession()
if session == nil {
return
}
@@ -80,7 +81,7 @@ func runInteractive(ctx *grumble.Context, shellPath string, noPty bool, con *con
tunnel := core.Tunnels.Start(rpcTunnel.TunnelID, rpcTunnel.SessionID)
shell, err := con.Rpc.Shell(context.Background(), &sliverpb.ShellReq{
Request: con.ActiveSession.Request(ctx),
Request: con.ActiveTarget.Request(ctx),
Path: shellPath,
EnablePTY: !noPty,
TunnelID: tunnel.ID,
+90
View File
@@ -0,0 +1,90 @@
package socks
/*
Sliver Implant Framework
Copyright (C) 2021 Bishop Fox
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
import (
"crypto/rand"
"encoding/base64"
"fmt"
"net"
"time"
"github.com/bishopfox/sliver/client/console"
"github.com/bishopfox/sliver/client/core"
"github.com/desertbit/grumble"
"gopkg.in/AlecAivazis/survey.v1"
)
// SocksAddCmd - Add a new tunneled port forward
func SocksAddCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
session := con.ActiveTarget.GetSessionInteractive()
if session == nil {
return
}
// listener
host := ctx.Flags.String("host")
port := ctx.Flags.String("port")
bindAddr := fmt.Sprintf("%s:%s", host, port)
ln, err := net.Listen("tcp", bindAddr)
if err != nil {
con.PrintErrorf("Socks5 Listen %s \n", err.Error())
return
}
username := ctx.Flags.String("user")
if err != nil {
return
}
password := ""
if username != "" {
con.PrintWarnf("SOCKS proxy authentication credentials are tunneled to the implant\n")
con.PrintWarnf("These credentials are recoverable from the implant's memory!\n\n")
confirm := false
prompt := &survey.Confirm{Message: "Do you understand the implication?"}
survey.AskOne(prompt, &confirm, nil)
if !confirm {
return
}
password = randomPassword()
con.Printf("\n")
}
channelProxy := &core.TcpProxy{
Rpc: con.Rpc,
Session: session,
Listener: ln,
BindAddr: bindAddr,
Username: username,
Password: password,
KeepAlivePeriod: 60 * time.Second,
DialTimeout: 30 * time.Second,
}
go func(channelProxy *core.TcpProxy) {
core.SocksProxies.Start(channelProxy)
}(core.SocksProxies.Add(channelProxy).ChannelProxy)
con.PrintInfof("Started SOCKS5 %s %s %s %s\n", host, port, username, password)
con.PrintWarnf("In-band SOCKS proxies can be a little unstable depending on protocol\n")
}
func randomPassword() string {
buf := make([]byte, 16)
rand.Read(buf)
return base64.RawStdEncoding.EncodeToString(buf)
}
+46
View File
@@ -0,0 +1,46 @@
package socks
/*
Sliver Implant Framework
Copyright (C) 2021 Bishop Fox
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
import (
"context"
"github.com/bishopfox/sliver/client/console"
"github.com/bishopfox/sliver/client/core"
"github.com/bishopfox/sliver/protobuf/sliverpb"
"github.com/desertbit/grumble"
)
// SocksRmCmd - Remove an existing tunneled port forward
func SocksRmCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
socksID := ctx.Flags.Int("id")
if socksID < 1 {
con.PrintErrorf("Must specify a valid portfwd id\n")
return
}
found := core.SocksProxies.Remove(socksID)
if !found {
con.PrintErrorf("No portfwd with id %d\n", socksID)
} else {
con.PrintInfof("Removed portfwd\n")
}
// close
con.Rpc.CloseSocks(context.Background(), &sliverpb.Socks{})
}
+56
View File
@@ -0,0 +1,56 @@
package socks
/*
Sliver Implant Framework
Copyright (C) 2021 Bishop Fox
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
import (
"sort"
"github.com/bishopfox/sliver/client/command/settings"
"github.com/bishopfox/sliver/client/console"
"github.com/bishopfox/sliver/client/core"
"github.com/desertbit/grumble"
"github.com/jedib0t/go-pretty/v6/table"
)
// SocksCmd - Display information about tunneled port forward(s)
func SocksCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
socks := core.SocksProxies.List()
if len(socks) == 0 {
con.PrintInfof("No socks5 proxies\n")
return
}
sort.Slice(socks[:], func(i, j int) bool {
return socks[i].ID < socks[j].ID
})
tw := table.NewWriter()
tw.SetStyle(settings.GetTableStyle(con))
tw.AppendHeader(table.Row{
"ID",
"Session ID",
"Bind Address",
"Username",
"Passwords",
})
for _, p := range socks {
tw.AppendRow(table.Row{p.ID, p.SessionID, p.BindAddr, p.Username, p.Password})
}
con.Printf("%s\n", tw.Render())
}
+5
View File
@@ -0,0 +1,5 @@
Tasks
=======
Manage and interact with Beacon tasks
+675
View File
@@ -0,0 +1,675 @@
package tasks
/*
Sliver Implant Framework
Copyright (C) 2021 Bishop Fox
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
import (
"context"
"io/ioutil"
"os"
"strings"
"time"
"github.com/AlecAivazis/survey/v2"
"github.com/bishopfox/sliver/client/command/environment"
"github.com/bishopfox/sliver/client/command/exec"
"github.com/bishopfox/sliver/client/command/filesystem"
"github.com/bishopfox/sliver/client/command/network"
"github.com/bishopfox/sliver/client/command/privilege"
"github.com/bishopfox/sliver/client/command/processes"
"github.com/bishopfox/sliver/client/command/registry"
"github.com/bishopfox/sliver/client/command/settings"
"github.com/bishopfox/sliver/client/console"
"github.com/bishopfox/sliver/protobuf/clientpb"
"github.com/bishopfox/sliver/protobuf/sliverpb"
"github.com/bishopfox/sliver/util"
"github.com/desertbit/grumble"
"github.com/jedib0t/go-pretty/v6/table"
"google.golang.org/protobuf/proto"
)
// TasksFetchCmd - Manage beacon tasks
func TasksFetchCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
beacon := con.ActiveTarget.GetBeaconInteractive()
if beacon == nil {
return
}
beaconTasks, err := con.Rpc.GetBeaconTasks(context.Background(), &clientpb.Beacon{ID: beacon.ID})
if err != nil {
con.PrintErrorf("%s\n", err)
return
}
tasks := beaconTasks.Tasks
if len(tasks) == 0 {
con.PrintErrorf("No tasks for beacon\n")
return
}
idArg := ctx.Args.String("id")
if idArg != "" {
tasks = filterTasksByID(idArg, tasks)
if len(tasks) == 0 {
con.PrintErrorf("No beacon task found with id %s\n", idArg)
return
}
}
filter := ctx.Flags.String("filter")
if filter != "" {
tasks = filterTasksByTaskType(filter, tasks)
if len(tasks) == 0 {
con.PrintErrorf("No beacon tasks with filter type '%s'\n", filter)
return
}
}
var task *clientpb.BeaconTask
if 1 < len(tasks) {
task, err = SelectBeaconTask(tasks)
if err != nil {
con.PrintErrorf("%s\n", err)
return
}
con.Printf(console.UpN+console.Clearln, 1)
} else {
task = tasks[0]
}
task, err = con.Rpc.GetBeaconTaskContent(context.Background(), &clientpb.BeaconTask{ID: task.ID})
if err != nil {
con.PrintErrorf("Failed to fetch task content: %s\n", err)
return
}
PrintTask(task, con)
}
func filterTasksByID(taskID string, tasks []*clientpb.BeaconTask) []*clientpb.BeaconTask {
filteredTasks := []*clientpb.BeaconTask{}
for _, task := range tasks {
if strings.HasPrefix(task.ID, strings.ToLower(taskID)) {
filteredTasks = append(filteredTasks, task)
}
}
return filteredTasks
}
func filterTasksByTaskType(taskType string, tasks []*clientpb.BeaconTask) []*clientpb.BeaconTask {
filteredTasks := []*clientpb.BeaconTask{}
for _, task := range tasks {
if strings.HasPrefix(strings.ToLower(task.Description), strings.ToLower(taskType)) {
filteredTasks = append(filteredTasks, task)
}
}
return filteredTasks
}
// PrintTask - Print the details of a beacon task
func PrintTask(task *clientpb.BeaconTask, con *console.SliverConsoleClient) {
tw := table.NewWriter()
tw.SetStyle(settings.GetTableWithBordersStyle(con))
tw.AppendRow(table.Row{console.Bold + "Beacon Task" + console.Normal, task.ID})
tw.AppendSeparator()
tw.AppendRow(table.Row{"State", emojiState(task.State) + " " + prettyState(strings.Title(task.State))})
tw.AppendRow(table.Row{"Description", task.Description})
tw.AppendRow(table.Row{"Created", time.Unix(task.CreatedAt, 0).Format(time.RFC1123)})
if !time.Unix(task.SentAt, 0).IsZero() {
tw.AppendRow(table.Row{"Sent", time.Unix(task.SentAt, 0).Format(time.RFC1123)})
}
if !time.Unix(task.CompletedAt, 0).IsZero() {
tw.AppendRow(table.Row{"Completed", time.Unix(task.CompletedAt, 0).Format(time.RFC1123)})
}
tw.AppendRow(table.Row{"Request Size", util.ByteCountBinary(int64(len(task.Request)))})
if !time.Unix(task.CompletedAt, 0).IsZero() {
tw.AppendRow(table.Row{"Response Size", util.ByteCountBinary(int64(len(task.Response)))})
}
tw.AppendSeparator()
con.Printf("%s\n", tw.Render())
if !time.Unix(task.CompletedAt, 0).IsZero() {
con.Println()
if 0 < len(task.Response) {
renderTaskResponse(task, con)
} else {
con.PrintInfof("No task response\n")
}
}
}
func emojiState(state string) string {
switch strings.ToLower(state) {
case "completed":
return "✅"
case "pending":
return "⏳"
case "failed":
return "❌"
default:
return "❓"
}
}
// Decode and render message specific content
func renderTaskResponse(task *clientpb.BeaconTask, con *console.SliverConsoleClient) {
reqEnvelope := &sliverpb.Envelope{}
proto.Unmarshal(task.Request, reqEnvelope)
switch reqEnvelope.Type {
// ---------------------
// Environment commands
// ---------------------
case sliverpb.MsgEnvInfo:
envInfo := &sliverpb.EnvInfo{}
err := proto.Unmarshal(task.Request, envInfo)
if err != nil {
con.PrintErrorf("Failed to decode task response: %s\n", err)
return
}
environment.PrintGetEnvInfo(envInfo, con)
case sliverpb.MsgSetEnvReq:
setEnvReq := &sliverpb.SetEnvReq{}
err := proto.Unmarshal(task.Request, setEnvReq)
if err != nil {
con.PrintErrorf("Failed to decode task request: %s\n", err)
return
}
setEnv := &sliverpb.SetEnv{}
err = proto.Unmarshal(task.Response, setEnv)
if err != nil {
con.PrintErrorf("Failed to decode task response: %s\n", err)
return
}
environment.PrintSetEnvInfo(setEnvReq.Variable.Key, setEnvReq.Variable.Value, setEnv, con)
case sliverpb.MsgUnsetEnvReq:
unsetEnvReq := &sliverpb.UnsetEnvReq{}
err := proto.Unmarshal(task.Request, unsetEnvReq)
if err != nil {
con.PrintErrorf("Failed to decode task request: %s\n", err)
return
}
unsetEnv := &sliverpb.UnsetEnv{}
err = proto.Unmarshal(task.Response, unsetEnv)
if err != nil {
con.PrintErrorf("Failed to decode task response: %s\n", err)
return
}
environment.PrintUnsetEnvInfo(unsetEnvReq.Name, unsetEnv, con)
// ---------------------
// Exec commands
// ---------------------
case sliverpb.MsgExecuteAssemblyReq:
execAssembly := &sliverpb.ExecuteAssembly{}
err := proto.Unmarshal(task.Response, execAssembly)
if err != nil {
con.PrintErrorf("Failed to decode task response: %s\n", err)
return
}
beacon, _ := con.Rpc.GetBeacon(context.Background(), &clientpb.Beacon{ID: task.BeaconID})
hostname := "hostname"
if beacon != nil {
hostname = beacon.Hostname
}
assemblyPath := ""
ctx := &grumble.Context{
Command: &grumble.Command{Name: "execute-assembly"},
Flags: grumble.FlagMap{
"save": &grumble.FlagMapItem{Value: false, IsDefault: true},
"loot": &grumble.FlagMapItem{Value: false, IsDefault: true},
},
}
exec.PrintExecuteAssembly(execAssembly, hostname, assemblyPath, ctx, con)
// execute-shellcode
case sliverpb.MsgTaskReq:
shellcodeExec := &sliverpb.Task{}
err := proto.Unmarshal(task.Response, shellcodeExec)
if err != nil {
con.PrintErrorf("Failed to decode task response: %s\n", err)
return
}
exec.PrintExecuteShellcode(shellcodeExec, con)
case sliverpb.MsgExecuteReq:
execReq := &sliverpb.ExecuteReq{}
err := proto.Unmarshal(reqEnvelope.Data, execReq)
if err != nil {
con.PrintErrorf("Failed to decode task response: %s\n", err)
return
}
execResult := &sliverpb.Execute{}
err = proto.Unmarshal(task.Response, execResult)
if err != nil {
con.PrintErrorf("Failed to decode task response: %s\n", err)
return
}
ctx := &grumble.Context{
Flags: grumble.FlagMap{
"ignore-stderr": &grumble.FlagMapItem{Value: false},
"loot": &grumble.FlagMapItem{Value: false},
"stdout": &grumble.FlagMapItem{Value: ""},
"stderr": &grumble.FlagMapItem{Value: ""},
"output": &grumble.FlagMapItem{Value: true},
},
Args: grumble.ArgMap{
"command": &grumble.ArgMapItem{Value: execReq.Path},
"arguments": &grumble.ArgMapItem{Value: execReq.Args},
},
}
exec.PrintExecute(execResult, ctx, con)
case sliverpb.MsgSideloadReq:
sideload := &sliverpb.Sideload{}
err := proto.Unmarshal(task.Response, sideload)
if err != nil {
con.PrintErrorf("Failed to decode task response: %s\n", err)
return
}
beacon, _ := con.Rpc.GetBeacon(context.Background(), &clientpb.Beacon{ID: task.BeaconID})
hostname := "hostname"
if beacon != nil {
hostname = beacon.Hostname
}
ctx := &grumble.Context{
Command: &grumble.Command{Name: "sideload"},
Flags: grumble.FlagMap{
"save": &grumble.FlagMapItem{Value: false},
},
}
exec.PrintSideload(sideload, hostname, ctx, con)
case sliverpb.MsgSpawnDllReq:
spawnDll := &sliverpb.SpawnDll{}
err := proto.Unmarshal(task.Response, spawnDll)
if err != nil {
con.PrintErrorf("Failed to decode task response: %s\n", err)
return
}
beacon, _ := con.Rpc.GetBeacon(context.Background(), &clientpb.Beacon{ID: task.BeaconID})
hostname := "hostname"
if beacon != nil {
hostname = beacon.Hostname
}
ctx := &grumble.Context{
Command: &grumble.Command{Name: "spawndll"},
Flags: grumble.FlagMap{
"save": &grumble.FlagMapItem{Value: false},
},
}
exec.PrintSpawnDll(spawnDll, hostname, ctx, con)
case sliverpb.MsgSSHCommandReq:
sshCommand := &sliverpb.SSHCommand{}
err := proto.Unmarshal(task.Response, sshCommand)
if err != nil {
con.PrintErrorf("Failed to decode task response: %s\n", err)
return
}
exec.PrintSSHCmd(sshCommand, con)
// ---------------------
// File system commands
// ---------------------
// Cat = download
case sliverpb.MsgCdReq:
pwd := &sliverpb.Pwd{}
err := proto.Unmarshal(task.Response, pwd)
if err != nil {
con.PrintErrorf("Failed to decode task response: %s\n", err)
return
}
filesystem.PrintPwd(pwd, con)
case sliverpb.MsgDownload:
download := &sliverpb.Download{}
err := proto.Unmarshal(task.Response, download)
if err != nil {
con.PrintErrorf("Failed to decode task response: %s\n", err)
return
}
taskResponseDownload(download, con)
case sliverpb.MsgLsReq:
ls := &sliverpb.Ls{}
err := proto.Unmarshal(task.Response, ls)
if err != nil {
con.PrintErrorf("Failed to decode task response: %s\n", err)
return
}
flags := grumble.FlagMap{
"reverse": &grumble.FlagMapItem{Value: false},
"modified": &grumble.FlagMapItem{Value: false},
"size": &grumble.FlagMapItem{Value: false},
}
filesystem.PrintLs(ls, flags, "", con)
case sliverpb.MsgMkdirReq:
mkdir := &sliverpb.Mkdir{}
err := proto.Unmarshal(task.Response, mkdir)
if err != nil {
con.PrintErrorf("Failed to decode task response: %s\n", err)
return
}
filesystem.PrintMkdir(mkdir, con)
case sliverpb.MsgPwdReq:
pwd := &sliverpb.Pwd{}
err := proto.Unmarshal(task.Response, pwd)
if err != nil {
con.PrintErrorf("Failed to decode task response: %s\n", err)
return
}
filesystem.PrintPwd(pwd, con)
case sliverpb.MsgRmReq:
rm := &sliverpb.Rm{}
err := proto.Unmarshal(task.Response, rm)
if err != nil {
con.PrintErrorf("Failed to decode task response: %s\n", err)
return
}
filesystem.PrintRm(rm, con)
case sliverpb.MsgUpload:
upload := &sliverpb.Upload{}
err := proto.Unmarshal(task.Response, upload)
if err != nil {
con.PrintErrorf("Failed to decode task response: %s\n", err)
return
}
filesystem.PrintUpload(upload, con)
// ---------------------
// Network commands
// ---------------------
case sliverpb.MsgIfconfigReq:
ifconfig := &sliverpb.Ifconfig{}
err := proto.Unmarshal(task.Response, ifconfig)
if err != nil {
con.PrintErrorf("Failed to decode task response: %s\n", err)
return
}
network.PrintIfconfig(ifconfig, true, con)
case sliverpb.MsgNetstatReq:
netstat := &sliverpb.Netstat{}
err := proto.Unmarshal(task.Response, netstat)
if err != nil {
con.PrintErrorf("Failed to decode task response: %s\n", err)
return
}
beacon, err := con.Rpc.GetBeacon(context.Background(), &clientpb.Beacon{ID: task.BeaconID})
if err != nil {
con.PrintErrorf("Failed to fetch beacon: %s\n", err)
return
}
network.PrintNetstat(netstat, beacon.PID, beacon.ActiveC2, con)
// ---------------------
// Privilege commands
// ---------------------
case sliverpb.MsgGetPrivsReq:
privs := &sliverpb.GetPrivs{}
err := proto.Unmarshal(task.Response, privs)
if err != nil {
con.PrintErrorf("Failed to decode task response: %s\n", err)
return
}
beacon, err := con.Rpc.GetBeacon(context.Background(), &clientpb.Beacon{ID: task.BeaconID})
if err != nil {
con.PrintErrorf("Failed to fetch beacon: %s\n", err)
return
}
privilege.PrintGetPrivs(privs, beacon.PID, con)
case sliverpb.MsgInvokeGetSystemReq:
getSystem := &sliverpb.GetSystem{}
err := proto.Unmarshal(task.Response, getSystem)
if err != nil {
con.PrintErrorf("Failed to decode task response: %s\n", err)
return
}
privilege.PrintGetSystem(getSystem, con)
case sliverpb.MsgImpersonateReq:
impersonateReq := &sliverpb.ImpersonateReq{}
err := proto.Unmarshal(task.Response, impersonateReq)
if err != nil {
con.PrintErrorf("Failed to decode task request: %s\n", err)
return
}
impersonate := &sliverpb.Impersonate{}
err = proto.Unmarshal(task.Response, impersonate)
if err != nil {
con.PrintErrorf("Failed to decode task response: %s\n", err)
return
}
privilege.PrintImpersonate(impersonate, impersonateReq.Username, con)
case sliverpb.MsgMakeTokenReq:
makeTokenReq := &sliverpb.MakeTokenReq{}
err := proto.Unmarshal(task.Response, makeTokenReq)
if err != nil {
con.PrintErrorf("Failed to decode task request: %s\n", err)
return
}
makeToken := &sliverpb.MakeToken{}
err = proto.Unmarshal(task.Response, makeToken)
if err != nil {
con.PrintErrorf("Failed to decode task request: %s\n", err)
return
}
privilege.PrintMakeToken(makeToken, makeTokenReq.Domain, makeTokenReq.Username, con)
case sliverpb.MsgRunAsReq:
runAsReq := &sliverpb.RunAsReq{}
err := proto.Unmarshal(task.Response, runAsReq)
if err != nil {
con.PrintErrorf("Failed to decode task request: %s\n", err)
return
}
runAs := &sliverpb.RunAs{}
err = proto.Unmarshal(task.Response, runAs)
if err != nil {
con.PrintErrorf("Failed to decode task request: %s\n", err)
return
}
beacon, err := con.Rpc.GetBeacon(context.Background(), &clientpb.Beacon{ID: task.BeaconID})
if err != nil {
con.PrintErrorf("Failed to fetch beacon: %s\n", err)
return
}
privilege.PrintRunAs(runAs, runAsReq.ProcessName, runAsReq.Args, beacon.Name, con)
// ---------------------
// Processes commands
// ---------------------
case sliverpb.MsgProcessDumpReq:
dump := &sliverpb.ProcessDump{}
err := proto.Unmarshal(task.Response, dump)
if err != nil {
con.PrintErrorf("Failed to decode task response: %s\n", err)
return
}
promptSaveToFile(dump.Data, con)
case sliverpb.MsgPsReq:
ps := &sliverpb.Ps{}
err := proto.Unmarshal(task.Response, ps)
if err != nil {
con.PrintErrorf("Failed to decode task response: %s\n", err)
return
}
beacon, err := con.Rpc.GetBeacon(context.Background(), &clientpb.Beacon{ID: task.BeaconID})
if err != nil {
con.PrintErrorf("Failed to get beacon: %s\n", err)
return
}
ctx := &grumble.Context{
Flags: grumble.FlagMap{
"pid": &grumble.FlagMapItem{Value: -1},
"exe": &grumble.FlagMapItem{Value: ""},
"owner": &grumble.FlagMapItem{Value: ""},
"overflow": &grumble.FlagMapItem{Value: false},
"skip-pages": &grumble.FlagMapItem{Value: 0},
"print-cmdline": &grumble.FlagMapItem{Value: true},
},
}
processes.PrintPS(beacon.OS, ps, true, ctx, con)
case sliverpb.MsgTerminateReq:
terminate := &sliverpb.Terminate{}
err := proto.Unmarshal(task.Response, terminate)
if err != nil {
con.PrintErrorf("Failed to decode task response: %s\n", err)
return
}
processes.PrintTerminate(terminate, con)
// ---------------------
// Registry commands
// ---------------------
case sliverpb.MsgRegistryCreateKeyReq:
createKeyReq := &sliverpb.RegistryCreateKeyReq{}
err := proto.Unmarshal(task.Request, createKeyReq)
if err != nil {
con.PrintErrorf("Failed to decode task response: %s\n", err)
return
}
createKey := &sliverpb.RegistryCreateKey{}
err = proto.Unmarshal(task.Response, createKey)
if err != nil {
con.PrintErrorf("Failed to decode task response: %s\n", err)
return
}
registry.PrintCreateKey(createKey, createKeyReq.Path, createKeyReq.Key, con)
case sliverpb.MsgRegistryListValuesReq:
listValuesReq := &sliverpb.RegistryListValuesReq{}
err := proto.Unmarshal(task.Request, listValuesReq)
if err != nil {
con.PrintErrorf("Failed to decode task response: %s\n", err)
return
}
regList := &sliverpb.RegistryValuesList{}
err = proto.Unmarshal(task.Response, regList)
if err != nil {
con.PrintErrorf("Failed to decode task response: %s\n", err)
return
}
registry.PrintListValues(regList, listValuesReq.Hive, listValuesReq.Path, con)
case sliverpb.MsgRegistrySubKeysListReq:
listValuesReq := &sliverpb.RegistrySubKeyListReq{}
err := proto.Unmarshal(task.Request, listValuesReq)
if err != nil {
con.PrintErrorf("Failed to decode task response: %s\n", err)
return
}
regList := &sliverpb.RegistrySubKeyList{}
err = proto.Unmarshal(task.Response, regList)
if err != nil {
con.PrintErrorf("Failed to decode task response: %s\n", err)
return
}
registry.PrintListSubKeys(regList, listValuesReq.Hive, listValuesReq.Path, con)
case sliverpb.MsgRegistryReadReq:
regRead := &sliverpb.RegistryRead{}
err := proto.Unmarshal(task.Response, regRead)
if err != nil {
con.PrintErrorf("Failed to decode task response: %s\n", err)
return
}
registry.PrintRegRead(regRead, con)
case sliverpb.MsgRegistryWriteReq:
regWrite := &sliverpb.RegistryWrite{}
err := proto.Unmarshal(task.Response, regWrite)
if err != nil {
con.PrintErrorf("Failed to decode task response: %s\n", err)
return
}
registry.PrintRegWrite(regWrite, con)
// ---------------------
// Screenshot
// ---------------------
case sliverpb.MsgScreenshot:
screenshot := &sliverpb.Screenshot{}
err := proto.Unmarshal(task.Response, screenshot)
if err != nil {
con.PrintErrorf("Failed to decode task response: %s\n", err)
return
}
promptSaveToFile(screenshot.Data, con)
// ---------------------
// Default
// ---------------------
default:
con.PrintErrorf("Cannot render task response for msg type %v\n", reqEnvelope.Type)
}
}
func taskResponseDownload(download *sliverpb.Download, con *console.SliverConsoleClient) {
const (
dump = "Dump Contents"
saveTo = "Save to File ..."
)
action := saveTo
prompt := &survey.Select{
Message: "Choose an option:",
Options: []string{dump, saveTo},
}
err := survey.AskOne(prompt, &action, survey.WithValidator(survey.Required))
if err != nil {
con.PrintErrorf("%s\n", err)
return
}
switch action {
case dump:
con.Printf("%s\n", string(download.Data))
default:
promptSaveToFile(download.Data, con)
}
}
func promptSaveToFile(data []byte, con *console.SliverConsoleClient) {
saveTo := ""
saveToPrompt := &survey.Input{Message: "Save to: "}
err := survey.AskOne(saveToPrompt, &saveTo)
if err != nil {
con.PrintErrorf("%s\n", err)
return
}
if _, err := os.Stat(saveTo); !os.IsNotExist(err) {
confirm := false
prompt := &survey.Confirm{Message: "Overwrite existing file?"}
survey.AskOne(prompt, &confirm)
if !confirm {
return
}
}
err = ioutil.WriteFile(saveTo, data, 0600)
if err != nil {
con.PrintErrorf("Failed to save file: %s\n", err)
return
}
con.PrintInfof("Wrote %d byte(s) to %s", len(data), saveTo)
}
+46
View File
@@ -0,0 +1,46 @@
package tasks
import (
"bytes"
"errors"
"fmt"
"strings"
"text/tabwriter"
"github.com/AlecAivazis/survey/v2"
"github.com/bishopfox/sliver/protobuf/clientpb"
)
// SelectBeaconTask - Select a beacon task interactively
func SelectBeaconTask(tasks []*clientpb.BeaconTask) (*clientpb.BeaconTask, error) {
// Render selection table
buf := bytes.NewBufferString("")
table := tabwriter.NewWriter(buf, 0, 2, 2, ' ', 0)
for _, task := range tasks {
shortID := strings.Split(task.ID, "-")[0]
fmt.Fprintf(table, "%s\t%s\t%s\t\n", shortID, task.Description, prettyState(task.State))
}
table.Flush()
options := strings.Split(buf.String(), "\n")
options = options[:len(options)-1]
if len(options) == 0 {
return nil, errors.New("no task to select from")
}
selected := ""
prompt := &survey.Select{
Message: "Select a beacon task:",
Options: options,
}
err := survey.AskOne(prompt, &selected)
if err != nil {
return nil, err
}
for index, value := range options {
if value == selected {
return tasks[index], nil
}
}
return nil, errors.New("task not found")
}
Loaded 100 of 763 files, more files were not shown because too many files have changed in this diff. Show more