Skip to content

Commit

Permalink
Renamed some args to move away from Python keywords
Browse files Browse the repository at this point in the history
  • Loading branch information
jborean93 committed Feb 24, 2018
1 parent 168b665 commit d0ac01d
Show file tree
Hide file tree
Showing 8 changed files with 77 additions and 81 deletions.
7 changes: 3 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -234,7 +234,7 @@ try:
# run command asynchronously (in background), the rc is the PID of the spawned service
stdout, stderr, rc = c.run_executable("longrunning.exe",
arguments="/s other args",
async=True)
asynchronous=True)
# run whoami.exe as a specific user
stdout, stderr, rc = c.run_executable("whoami",
Expand Down Expand Up @@ -275,7 +275,6 @@ options that can be set to control the process. These args are;
* `password`: The password for `username`. Can be `None` if `python-gssapi` is installed and a ticket has been granted for the user specified
* `port`: Override the default port of `445` when connecting to the server
* `encrypt`: Whether to encrypt the messages or not, default is `True`. Server 2008, 2008 R2 and Windows 7 hosts do not support SMB Encryption and need this to be set to `False`
* `timeout`: Override the default timeout of 60 seconds when waiting for a response from the SMB server


### Run Executable Options
Expand All @@ -286,9 +285,9 @@ how the remote process will work. These args are;
* `executable`: (string) The path to the executable to be run
* `arguments`: (string) Arguments for the executable
* `processors`: (list<int>) A list of processor numbers that the process can run on
* `async`: (bool) Doesn't wait until the process is complete before returning. The `rc` returned by the function is the `PID` of the async process, default is `False`
* `asynchronous`: (bool) Doesn't wait until the process is complete before returning. The `rc` returned by the function is the `PID` of the async process, default is `False`
* `load_profile`: (bool) Load the user's profile, default is `True`
* `session_to_interact_with`: (int) The session ID to display the interactive process when `interactive=True`, default is `0`
* `interactive_session`: (int) The session ID to display the interactive process when `interactive=True`, default is `0`
* `interactive`: (bool) Runs the process as an interactive process. The stdout and stderr buffers will be `None` if `True`, default `False`
* `run_elevated`: (bool) When `username` is defined, will elevated permissions, default `False`
* `run_limited`: (bool) When `username` is defined, will run the process under limited permissions, default `False`
Expand Down
2 changes: 1 addition & 1 deletion pypsexec/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,4 +10,4 @@ def emit(self, record):
logger = logging.getLogger(__name__)
logger.addHandler(NullHandler())

__version__ = '0.0.1.dev3'
__version__ = '0.0.1.dev4'
31 changes: 15 additions & 16 deletions pypsexec/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,13 +30,12 @@
class Client(object):

def __init__(self, server, username=None, password=None, port=445,
encrypt=True, timeout=60):
encrypt=True):
self.server = server
self.port = port
self.pid = os.getpid()
self.current_host = socket.gethostname()
self.connection = Connection(uuid.uuid4(), server, port,
timeout=timeout)
self.connection = Connection(uuid.uuid4(), server, port)
self.session = Session(self.connection, username, password,
require_encryption=encrypt)

Expand All @@ -54,10 +53,10 @@ def __init__(self, server, username=None, password=None, port=445,
% self._unique_id)
self._service = Service(self.service_name, self.session)

def connect(self):
def connect(self, timeout=60):
log.info("Setting up SMB Connection to %s:%d"
% (self.server, self.port))
self.connection.connect()
self.connection.connect(timeout=timeout)
log.info("Authenticating SMB Session")
self.session.connect()
log.info("Opening handle to SCMR and PAExec service")
Expand Down Expand Up @@ -170,8 +169,8 @@ def cleanup(self):
self._delete_file(smb_tree, file_name)

def run_executable(self, executable, arguments=None, processors=None,
async=False, load_profile=True,
session_to_interact_with=0, interactive=False,
asynchronous=False, load_profile=True,
interactive_session=0, interactive=False,
run_elevated=False, run_limited=False, username=None,
password=None, use_system_account=False,
working_dir=None, show_ui_on_win_logon=False,
Expand All @@ -193,13 +192,13 @@ def run_executable(self, executable, arguments=None, processors=None,
:param arguments: (String) Arguments to run with the executable
:param processors: (List<Int>) The processors that the process can run
on, default is all the processors
:param async: (Bool) Whether to run the process and not wait for the
output, it will continue to run in the background. The stdout and
stderr return value will be None and the rc is not reflective of
the running process
:param asynchronous: (Bool) Whether to run the process and not wait for
the output, it will continue to run in the background. The stdout
and stderr return value will be None and the rc is not reflective
of the running process
:param load_profile: (Bool) Whether to load the user profile, default
is True
:param session_to_interact_with: (Int) The session id that an
:param interactive_session: (Int) The session id that an
interactive process will run on, use with interactive=True to
run a process on an existing session
:param interactive: (Bool) Whether to run on an interative session or
Expand Down Expand Up @@ -249,9 +248,9 @@ def run_executable(self, executable, arguments=None, processors=None,

settings = PAExecSettingsBuffer()
settings['processors'] = processors if processors else []
settings['async'] = async
settings['asynchronous'] = asynchronous
settings['dont_load_profile'] = not load_profile
settings['session_to_interact_with'] = session_to_interact_with
settings['interactive_session'] = interactive_session
settings['interactive'] = interactive
settings['run_elevated'] = run_elevated
settings['run_limited'] = run_limited
Expand Down Expand Up @@ -303,7 +302,7 @@ def run_executable(self, executable, arguments=None, processors=None,
log.debug(str(start_msg))
main_pipe.write(start_msg.pack(), 0)

if not interactive and not async:
if not interactive and not asynchronous:
# create a pipe for stdout, stderr, and stdin and run in a separate
# thread
log.info("Connecting to remote pipes to retrieve output")
Expand Down Expand Up @@ -332,7 +331,7 @@ def run_executable(self, executable, arguments=None, processors=None,
exe_result_raw = main_pipe.read(0, 1024)
log.info("Results read of PAExec process")

if not interactive and not async:
if not interactive and not asynchronous:
log.info("Closing PAExec std* pipes")
stdout_pipe.close()
stderr_pipe.close()
Expand Down
6 changes: 3 additions & 3 deletions pypsexec/exceptions.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ class PypsexecException(Exception):
pass


class PAExecException(Exception):
class PAExecException(PypsexecException):

@property
def msg_id(self):
Expand All @@ -26,7 +26,7 @@ def __str__(self):
return self.message


class SCMRException(Exception):
class SCMRException(PypsexecException):

@property
def function(self):
Expand All @@ -49,5 +49,5 @@ def __str__(self):
return self.message


class PDUException(Exception):
class PDUException(PypsexecException):
pass
4 changes: 2 additions & 2 deletions pypsexec/paexec.py
Original file line number Diff line number Diff line change
Expand Up @@ -225,9 +225,9 @@ def __init__(self):
('copy_files', BoolField(size=1)),
('force_copy', BoolField(size=1)),
('copy_if_newer_or_higher_ver', BoolField(size=1)),
('async', BoolField(size=1)),
('asynchronous', BoolField(size=1)),
('dont_load_profile', BoolField(size=1)),
('session_to_interact_with', IntField(size=4)),
('interactive_session', IntField(size=4)),
('interactive', BoolField(size=1)),
('run_elevated', BoolField(size=1)),
('run_limited', BoolField(size=1)),
Expand Down
78 changes: 29 additions & 49 deletions pypsexec/pipe.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import binascii
import time
import logging
import os
import sys
Expand All @@ -12,8 +11,6 @@
FileAttributes, FilePipePrinterAccessMask, ImpersonationLevel, Open
from smbprotocol.structure import BoolField, BytesField, IntField, Structure

from pypsexec.exceptions import PypsexecException

try:
from collections import OrderedDict
except ImportError: # pragma: no cover
Expand Down Expand Up @@ -43,52 +40,35 @@ def open_pipe(tree, name, access_mask, fsctl_wait=False):
log.info("Creating SMB Open for pipe: %s" % name)
pipe = Open(tree, name)

# try 3 times to connect in case the PAExec service didn't come up
connected = False
for i in range(0, 3):
try:
if fsctl_wait:
wait_pipe = SMB2IOCTLRequest()
wait_pipe['ctl_code'] = CtlCode.FSCTL_PIPE_WAIT
wait_pipe['file_id'] = b"\xff" * 16
wait_pipe['flags'] = IOCTLFlags.SMB2_0_IOCTL_IS_FSCTL

fsctl_data = FSCTLPipeWait()
fsctl_data['name'] = name.encode('utf-16-le')
wait_pipe['buffer'] = fsctl_data

log.info("Sending FSCTL_PIPE_WAIT for pipe %s" % name)
log.debug(str(fsctl_data))
request = tree.session.connection.send(
wait_pipe,
sid=tree.session.session_id,
tid=tree.tree_connect_id
)

log.info("Receiving FSCTL_PIPE_WAIT response for pipe: %s"
% name)
tree.session.connection.receive(request)

pipe.open(ImpersonationLevel.Impersonation,
access_mask,
FileAttributes.FILE_ATTRIBUTE_NORMAL,
0,
CreateDisposition.FILE_OPEN,
CreateOptions.FILE_NON_DIRECTORY_FILE |
CreateOptions.FILE_SYNCHRONOUS_IO_NONALERT)
except SMBResponseException as exc:
if exc.status != NtStatus.STATUS_OBJECT_NAME_NOT_FOUND:
raise exc
log.warning("Failing to open pipe: %s - Attempt %d"
% (name, i + 1))
time.sleep(1)
else:
connected = True
break

if not connected:
raise PypsexecException("Timeout while waiting for pipe %s to exist"
% name)
if fsctl_wait:
wait_pipe = SMB2IOCTLRequest()
wait_pipe['ctl_code'] = CtlCode.FSCTL_PIPE_WAIT
wait_pipe['file_id'] = b"\xff" * 16
wait_pipe['flags'] = IOCTLFlags.SMB2_0_IOCTL_IS_FSCTL

fsctl_data = FSCTLPipeWait()
fsctl_data['name'] = name.encode('utf-16-le')
wait_pipe['buffer'] = fsctl_data

log.info("Sending FSCTL_PIPE_WAIT for pipe %s" % name)
log.debug(str(fsctl_data))
request = tree.session.connection.send(
wait_pipe,
sid=tree.session.session_id,
tid=tree.tree_connect_id
)

log.info("Receiving FSCTL_PIPE_WAIT response for pipe: %s"
% name)
tree.session.connection.receive(request)

pipe.open(ImpersonationLevel.Impersonation,
access_mask,
FileAttributes.FILE_ATTRIBUTE_NORMAL,
0,
CreateDisposition.FILE_OPEN,
CreateOptions.FILE_NON_DIRECTORY_FILE |
CreateOptions.FILE_SYNCHRONOUS_IO_NONALERT)

return pipe

Expand Down
Loading

0 comments on commit d0ac01d

Please sign in to comment.