moloch-- / sliver-py

A Python gRPC Client Library for Sliver
GNU General Public License v3.0
62 stars 13 forks source link

InteractiveBeacon tasks don't seem to execute #3

Closed thespicybyte closed 1 year ago

thespicybyte commented 2 years ago

Version: sliver-py==0.0.16

I am attempting to execute a tasks when a new beacon is registered using code based on the interacting with beacons (https://sliverpy.readthedocs.io/en/latest/getting-started.html#interactive-beacons)

import os
import asyncio

from sliver import SliverClientConfig, SliverClient, client_pb2

async def main():
    client = await login(CONFIG_PATH)

    async for event in client.on('beacon-registered'):
        beacon_id = event.Data[2:38].decode()

        beacon = await client.interact_beacon(beacon_id)
        print('new beacon registered: %s' % beacon.beacon_id)
        print('Hostname: %s' % beacon.hostname)

        pwd_task = await beacon.pwd()
        pwd = await pwd_task

        print('PWD: %s' % pwd)

if __name__ == '__main__':
    loop = asyncio.get_event_loop()
    loop.run_until_complete(main())

Output (when beacon is executed):

new beacon registered: 0b1d292c-bc04-4dc0-83d8-7fda5d22862e
Hostname: client1

I get my future object but it just hangs there indefinitely. I also attempted with a file upload and never saw the file appear on target which makes me think it's not executing. Also not seeing anything in sliver.log which would indicate execution as well.

thespicybyte commented 2 years ago

Update: I tried from the server and it worked. There is a difference in python versions so maybe that's causing it? Python 3.9.7 on server Python 3.10.1 on client.

moloch-- commented 2 years ago

Not sure, I'll have to play around debug it a bit more. I'm don't think it would be a Python version problem, but hard to say.

thespicybyte commented 2 years ago

Looks like it was a python version issue. Looking at the asyncio docs for asyncio.get_event_loop() it states "Deprecated since version 3.10: Deprecation warning is emitted if there is no running event loop. In future Python releases, this function will be an alias of get_running_loop()."

Interestingly though, get_event_loop() was working for me on sessions, for example, and it only seemed to break when we called an async method such as tasking a beacon. Also, if you swap it out directly for get_running_loop() you get a runtime error:

    loop = asyncio.get_running_loop()
RuntimeError: no running event loop

Either way, the docs suggested using asyncio.run() instead so I gave that a try and it appears to be working.

if __name__ == '__main__':
    asyncio.run(main())
thespicybyte commented 2 years ago

I think I might have been a little too optimistic... Although I don't get any warnings at startup anymore and it works with one beacon, when I add any more it seems to get hung up and throws some errors. My ultimate goal is to have a script run along side the server that monitors events for new beacon registrations and then run a few commands. When I run the script above and have a beacon register I get:

new beacon registered: 91a7d7c4-c2fb-4fb8-92db-ab91e7aad2dd
Hostname: client1
PWD: Path: "C:\\Users\\Administrator\\Desktop"

And in the sliver client:

[*] Beacon 91a7d7c4 BEAUTIFUL_ASPECT - tcp([::1]:46968)->192.168.254.1 (client1) - windows/amd64 - Tue, 01 Mar 2022 22:38:11 EST

[*] spicy2 has joined the game

sliver (BEAUTIFUL_ASPECT) > use 91a7d7c4-c2fb-4fb8-92db-ab91e7aad2dd

[*] Active beacon BEAUTIFUL_ASPECT (91a7d7c4-c2fb-4fb8-92db-ab91e7aad2dd)

sliver (BEAUTIFUL_ASPECT) > tasks

 ID         State       Message Type   Created                         Sent                            Completed
========== =========== ============== =============================== =============================== ===============================
 66ffaadd   completed   Pwd            Tue, 01 Mar 2022 22:38:11 EST   Tue, 01 Mar 2022 22:38:12 EST   Tue, 01 Mar 2022 22:38:12 EST

That's exactly what I want (wont care about the output of the command once it goes to live but the errors persisted with or without the waiting for results).

But now when I start a second beacon...

new beacon registered: 83a75a79-205e-493a-b19f-9bfc37a99dcd
Hostname: client1
PWD: Path: "C:\\Users\\Administrator\\Desktop"

'5b825908-8c01-4684-8491-d85b7a82f8ab'
Traceback (most recent call last):
  File "/usr/local/lib/python3.9/dist-packages/sliver/beacon.py", line 75, in taskresult_events
    task_future, pb_object = self.beacon_tasks[beacon_task.ID]
KeyError: '5b825908-8c01-4684-8491-d85b7a82f8ab'
sliver (BEAUTIFUL_ASPECT) > use 83a75a79-205e-493a-b19f-9bfc37a99dcd

[*] Active beacon BEAUTIFUL_ASPECT (83a75a79-205e-493a-b19f-9bfc37a99dcd)

sliver (BEAUTIFUL_ASPECT) > tasks

 ID         State       Message Type   Created                         Sent                            Completed
========== =========== ============== =============================== =============================== ===============================
 5b825908   completed   Pwd            Tue, 01 Mar 2022 22:42:08 EST   Tue, 01 Mar 2022 22:42:09 EST   Tue, 01 Mar 2022 22:42:09 EST

We get an error in the script but at least we get the output so could live with that but that isn't always the case. When I kick off three beacons within a few seconds of each other it looks like the api has trouble handling it.

new beacon registered: 1e72da59-1825-4042-b1d5-8dd92663db50
Hostname: client1
new beacon registered: 034099c1-3ef3-4e77-8c54-a0841b01c853
Hostname: client1
'5aba4e24-8f52-4d50-985f-ede3c7fa2039'
Traceback (most recent call last):
  File "/usr/local/lib/python3.9/dist-packages/sliver/beacon.py", line 75, in taskresult_events
    task_future, pb_object = self.beacon_tasks[beacon_task.ID]
KeyError: '5aba4e24-8f52-4d50-985f-ede3c7fa2039'
new beacon registered: e3989f4e-9c83-486f-ae25-8e989d0254f5
Hostname: client1
'2e488cef-3b1d-4563-872e-7679fddfc388'
Traceback (most recent call last):
  File "/usr/local/lib/python3.9/dist-packages/sliver/beacon.py", line 75, in taskresult_events
    task_future, pb_object = self.beacon_tasks[beacon_task.ID]
KeyError: '2e488cef-3b1d-4563-872e-7679fddfc388'
'2e488cef-3b1d-4563-872e-7679fddfc388'
Traceback (most recent call last):
  File "/usr/local/lib/python3.9/dist-packages/sliver/beacon.py", line 75, in taskresult_events
    task_future, pb_object = self.beacon_tasks[beacon_task.ID]
KeyError: '2e488cef-3b1d-4563-872e-7679fddfc388'

In the sliver client I can that the third (e3989f4e) beacon's task was actually tasked to the second (034099c1).

sliver (BEAUTIFUL_ASPECT) > use 1e72da59-1825-4042-b1d5-8dd92663db50

[*] Active beacon BEAUTIFUL_ASPECT (1e72da59-1825-4042-b1d5-8dd92663db50)

sliver (BEAUTIFUL_ASPECT) > tasks

 ID         State       Message Type   Created                         Sent                            Completed
========== =========== ============== =============================== =============================== ===============================
 f88f6c48   completed   Pwd            Tue, 01 Mar 2022 22:58:54 EST   Tue, 01 Mar 2022 22:58:55 EST   Tue, 01 Mar 2022 22:58:55 EST

sliver (BEAUTIFUL_ASPECT) > use 034099c1-3ef3-4e77-8c54-a0841b01c853

[*] Active beacon BEAUTIFUL_ASPECT (034099c1-3ef3-4e77-8c54-a0841b01c853)

sliver (BEAUTIFUL_ASPECT) > tasks

 ID         State       Message Type   Created                         Sent                            Completed
========== =========== ============== =============================== =============================== ===============================
 2e488cef   pending     Pwd            Tue, 01 Mar 2022 22:59:00 EST
 5aba4e24   completed   Pwd            Tue, 01 Mar 2022 22:58:57 EST   Tue, 01 Mar 2022 22:58:58 EST   Tue, 01 Mar 2022 22:58:58 EST

sliver (BEAUTIFUL_ASPECT) > use e3989f4e-9c83-486f-ae25-8e989d0254f5

[*] Active beacon BEAUTIFUL_ASPECT (e3989f4e-9c83-486f-ae25-8e989d0254f5)

sliver (BEAUTIFUL_ASPECT) > tasks

 ID   State   Message Type   Created   Sent   Completed
==== ======= ============== ========= ====== ===========
daddycocoaman commented 1 year ago

Took a quick look and confirmed the issue still exists. For some reason, the task is handled by the wrong beacon although the user is sending it to the right one. The beacon ID to send the task to is correct but the result shows it was handled by a different beacon, as @thespicybyte pointed out.

new beacon registered: e9dfb336-37cd-4419-98bd-4a0cc7509b04
Hostname: d229e225e03a
           DEBUG    Sending task with () | {}:                                                                              beacon.py:171
╭───────────── <class 'sliver.beacon.InteractiveBeacon'> ──────────────╮
│ Wrap all commands that can be executed against a beacon mode implant │
│                                                                      │
│ ╭──────────────────────────────────────────────────────────────────╮ │
│ │ <sliver.beacon.InteractiveBeacon object at 0x0000026018D6B520>   │ │
│ ╰──────────────────────────────────────────────────────────────────╯ │
│                                                                      │
│          active_c2 = 'http://172.30.15.15'                           │
│               arch = 'amd64'                                         │
│          beacon_id = 'e9dfb336-37cd-4419-98bd-4a0cc7509b04'          │
│       beacon_tasks = {}                                              │
│           filename = 'C:\\Users\\ContainerAdministrator\\beacon.exe' │
│                gid = 'S-1-5-93-2-1'                                  │
│           hostname = 'd229e225e03a'                                  │
│       last_checkin = 1661933434                                      │
│               name = 'SMOOTH_TRINKET'                                │
│                 os = 'windows'                                       │
│                pid = 1668                                            │
│ reconnect_interval = 60000000000                                     │
│     remote_address = '172.30.10.45:62624'                            │
│            timeout = 60                                              │
│          transport = 'http(s)'                                       │
│                uid = 'S-1-5-93-2-1'                                  │
│           username = 'User Manager\\ContainerAdministrator'          │
│               uuid = '81a5d94f-b0c6-4708-82e9-fcb85f78d023'          │
│            version = 'Server 2016 build 20348 x86_64'                │
╰──────────────────────────────────────────────────────────────────────╯
╭──────────────────────────── <class 'sliverpb.sliver_pb2.PwdReq'> ────────────────────────────╮
│ ╭──────────────────────────────────────────────────────────────────────────────────────────╮ │
│ │ Request {                                                                                │ │
│ │   Async: true                                                                            │ │
│ │   Timeout: 59                                                                            │ │
│ │   SessionID: "e9dfb336-37cd-4419-98bd-4a0cc7509b04"                                      │ │
│ │ }                                                                                        │ │
│ │                                                                                          │ │
│ ╰──────────────────────────────────────────────────────────────────────────────────────────╯ │
│                                                                                              │
│ DESCRIPTOR = <google.protobuf.pyext._message.MessageDescriptor object at 0x0000026018B5CCD0> │
│ Extensions = AttributeError('Extensions')                                                    │
│    Request = Async: true                                                                     │
│              Timeout: 59                                                                     │
│              SessionID: "e9dfb336-37cd-4419-98bd-4a0cc7509b04"                               │
│                                                                                              │
╰──────────────────────────────────────────────────────────────────────────────────────────────╯
[01:10:37] DEBUG    RESULT:                                                                                                 beacon.py:174
╭───────────────────────────── <class 'sliverpb.sliver_pb2.Pwd'> ──────────────────────────────╮
│ ╭──────────────────────────────────────────────────────────────────────────────────────────╮ │
│ │ Response {                                                                               │ │
│ │   Async: true                                                                            │ │
│ │   BeaconID: "15c21505-ace9-4bd6-bd40-7bf823b5f66d"                                       │ │
│ │   TaskID: "e347d387-60b3-4682-bfa2-e72d872436f2"                                         │ │
│ │ }                                                                                        │ │
│ │                                                                                          │ │
│ ╰──────────────────────────────────────────────────────────────────────────────────────────╯ │
│                                                                                              │
│ DESCRIPTOR = <google.protobuf.pyext._message.MessageDescriptor object at 0x0000026018B5CD00> │
│ Extensions = AttributeError('Extensions')                                                    │
│       Path = ''                                                                              │
│   Response = Async: true                                                                     │
│              BeaconID: "15c21505-ace9-4bd6-bd40-7bf823b5f66d"                                │
│              TaskID: "e347d387-60b3-4682-bfa2-e72d872436f2"                                  │
│                                                                                              │

Checking the Sliver logs shows the beacon checking in and finding no tasks (make sense since the tasking occurs after check-in):

INFO[2022-08-31T01:10:34-07:00] [sliver/server/db/logger.go:20] github.com/bishopfox/sliver/server/db/helpers.go:262 record not found
[0.098ms] [rows:0] SELECT * FROM `beacons` WHERE `beacons`.`id` = "e9dfb336-37cd-4419-98bd-4a0cc7509b04" ORDER BY `beacons`.`id` LIMIT 1
INFO[2022-08-31T01:10:34-07:00] [sliver/server/db/logger.go:20] github.com/bishopfox/sliver/server/handlers/beacons.go:88 record not found
[0.035ms] [rows:0] SELECT * FROM `beacons` WHERE `id` = "e9dfb336-37cd-4419-98bd-4a0cc7509b04" ORDER BY `beacons`.`id` LIMIT 1
INFO[2022-08-31T01:10:34-07:00] [github.com/grpc-ecosystem/go-grpc-middleware@v1.2.2/logging/logrus/options.go:211] finished unary call with code OK
INFO[2022-08-31T01:10:35-07:00] [sliver/server/c2/http.go:396] 172.30.10.45:62626 - /api/namespaces/namespaces/api/api/oauth2callback/samples.php?h=46564122 - Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/98.0.2154.678 Safari/537.36
INFO[2022-08-31T01:10:35-07:00] [sliver/server/handlers/beacons.go:145] Beacon e9dfb336-37cd-4419-98bd-4a0cc7509b04 requested pending task(s)
INFO[2022-08-31T01:10:35-07:00] [sliver/server/handlers/beacons.go:177] Sending 0 task(s) to beacon e9dfb336-37cd-4419-98bd-4a0cc7509b04

But the other Beacon finds a task waiting for it and completes it:

INFO[2022-08-31T01:10:40-07:00] [sliver/server/handlers/beacons.go:177] Sending 1 task(s) to beacon 15c21505-ace9-4bd6-bd40-7bf823b5f66d
INFO[2022-08-31T01:10:40-07:00] [sliver/server/c2/http.go:396] 172.30.15.15:49026 - /jquery.js?b=7919643 - Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/99.0.7751.638 Safari/537.36
INFO[2022-08-31T01:10:40-07:00] [sliver/server/c2/http.go:396] 172.30.15.15:49030 - /namespaces/oauth2callback/database/oauth2/rpc.php?c=43236778 - Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/99.0.7751.638 Safari/537.36
INFO[2022-08-31T01:10:40-07:00] [sliver/server/handlers/beacons.go:140] Beacon 15c21505-ace9-4bd6-bd40-7bf823b5f66d returned 1 task result(s)

Basically, everything shows that the calls to the RPC server are correct. I'm gonna try to debug Sliver and see what's happening when the calls come in.

daddycocoaman commented 1 year ago

Found the issue. Sliver-py sends the PwdReq as SessionID (which is for sessions) not BeaconId (which is for beacons). So there's two issues here:

1) Need to fix the what is going out on the wire because it's the wrong field. 2) Sliver needs to check for empty strings when it's handling the call or else the wrong one gets returned

PwdReq being sent to Windows beacon:

╭──────────────────────────── <class 'sliverpb.sliver_pb2.PwdReq'> ────────────────────────────╮
│ ╭──────────────────────────────────────────────────────────────────────────────────────────╮ │
│ │ Request {                                                                                │ │
│ │   Async: true                                                                            │ │
│ │   Timeout: 59                                                                            │ │
│ │   SessionID: "efaa0639-f868-48ce-99d0-645c2196cd82"                                      │ │
│ │ }                                                                                        │ │
│ │                                                                                          │ │
│ ╰──────────────────────────────────────────────────────────────────────────────────────────╯ │
│                                                                                              │
│ DESCRIPTOR = <google.protobuf.pyext._message.MessageDescriptor object at 0x000001E8A0CDBCD0> │
│ Extensions = AttributeError('Extensions')                                                    │
│    Request = Async: true                                                                     │
│              Timeout: 59                                                                     │
│              SessionID: "efaa0639-f868-48ce-99d0-645c2196cd82"                               │
│                                                                                              │
╰──────────────────────────────────────────────────────────────────────────────────────────────╯

Debugging Sliver - It receives the request but pulls the wrong beacon in db.BeaconById because it's an empty string (which is not nil in Go, similar to how "" is not None in Python). image

daddycocoaman commented 1 year ago

Gonna just note here that this is addressed in the protobuf-gen branch which is a pretty big update of things.

daddycocoaman commented 1 year ago

Fixed in v0.0.18