Remote execution via stdin/stdout messaging.
Project description
implant
A proof-of-concept for asynchronous adhoc remote procedure calls in Python.
This is work in progress and serves basically as an exercise.
Features
Python >= 3.5 asyncio
adhoc transferable remote procedures
remote part of a implant.core.Command may reside in a separate module
a implant.core.Command specific implant.core.Channel enables arbitrary protocols between local and remote side
events
quite small core
tests
Limitations
Python >= 3.5
only pure Python modules are supported for remote import, if no venv is used
implant.core.Command s must reside in a module other then __main__
at the moment sudo must not ask for password
Example
General application
import asyncio
import pathlib
from implant import core, connect, commands
async def remote_tasks():
# create a connector for a python process
connector = connect.Lxd(
container='zesty',
hostname='localhost'
)
connector_args = {
'python_bin': pathlib.Path('/usr/bin/python3')
}
# connect to a remote python process
remote = await connector.launch(**connector_args)
# start remote communication tasks
com_remote = asyncio.ensure_future(remote.communicate())
try:
# execute command
cmd = commands.SystemLoad()
result = await remote.execute(cmd)
print("Remote system load:", result)
finally:
# stop communication tasks
com_remote.cancel()
await com_remote
if __name__ == '__main__':
loop = asyncio.get_event_loop()
loop.run_until_complete(remote_tasks())
loop.close()
An example Echo Command
import logging
import os
from implant import core
log = logging.getLogger(__name__)
class Echo(core.Command):
"""Demonstrate the basic command API."""
async def local(self, context):
"""The local side of the RPC.
:param context: :py:obj:`implant.core.DispatchLocalContext`
"""
# custom protocol
# first: send
await context.channel.send_iteration("send to remote")
# second: receive
from_remote = []
async for x in context.channel:
from_remote.append(x)
log.debug("************ receiving from remote: %s", from_remote)
# third: wait for remote to finish and return result
remote_result = await context.remote_future
result = {
'from_remote': ''.join(from_remote),
}
result.update(remote_result)
return result
async def remote(self, context):
"""The remote side of the RPC.
:param context: :py:obj:`implant.core.DispatchRemoteContext`
"""
# first: receive
from_local = []
async for x in context.channel:
from_local.append(x)
log.debug("************ receiving from local: %s", from_local)
# second: send
await context.channel.send_iteration("send to local")
# third: return result
return {
'from_local': ''.join(from_local),
'remote_self': self,
'pid': os.getpid()
}
Internals
master <-----------------------------------------> remote | stdin/stdout | chunks | channels | --> send ---> | | --> queue --> | module:class/fqin | <-- queue <-- | | <--- send <--
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
File details
Details for the file implant-0.1.2.tar.gz
.
File metadata
- Download URL: implant-0.1.2.tar.gz
- Upload date:
- Size: 34.3 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
File hashes
Algorithm | Hash digest | |
---|---|---|
SHA256 | ace257625b46a2644d74d97ddfc867561c54f3d041f606ec68ef711af4f69a73 |
|
MD5 | 0eafbd15183cbbedf476280ebffbf7d0 |
|
BLAKE2b-256 | 9c3755a8048e40d4ba6497497f87af847910752a929120ce0c87732305b8a411 |
File details
Details for the file implant-0.1.2-py3-none-any.whl
.
File metadata
- Download URL: implant-0.1.2-py3-none-any.whl
- Upload date:
- Size: 40.7 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
File hashes
Algorithm | Hash digest | |
---|---|---|
SHA256 | c08d251be9e63e0027bded83607244a6382f34e784ad4276f586e693ef85973c |
|
MD5 | 9ab1e625b2ec595ae81bda97ce6003e7 |
|
BLAKE2b-256 | 60e172c18f680f6aef28ca4c52c43b20105de25d97375936c32e8f200a5b03d5 |