summaryrefslogtreecommitdiffstats
path: root/sploit/comm/comm.py
diff options
context:
space:
mode:
authorMalfurious <m@lfurio.us>2025-01-01 06:51:10 -0500
committerMalfurious <m@lfurio.us>2025-01-01 06:51:10 -0500
commitf01ec45e773291c3659a1dcaf8cd9a51ece19823 (patch)
tree0db3ef432a6f3b06c07060bdb0dd61c7fd164ad2 /sploit/comm/comm.py
parent3f5532857807d628a5dadaf5c30a384f873878ea (diff)
parent221742f7c5c89dc50ec4374bed5d2ccc0d7534bf (diff)
downloadnsploit-f01ec45e773291c3659a1dcaf8cd9a51ece19823.tar.gz
nsploit-f01ec45e773291c3659a1dcaf8cd9a51ece19823.zip
Merge branch 'pkg-reorg'
This branch is a rework of nsploit's intended package imports. User scripts need only import a given nsploit subpackage to obtain that package's full collection of classes, functions, etc. This is the new intended style for exploit scripts. Along the way, some modules are reorganized into different packages, the "builder" package is renamed to "payload", and some unnecessary files are consolidated. * pkg-reorg: main: Automatically provide top-level sploit modules to user scripts sploit: Expose modules' contents through package Remove extra "main.py" file comm: Promote from module to package log: Move to sploit.util package util: Promote from module to package builder: Rename package to payload and expose contents rev: Expose modules' contents through package Remove outer __init__.py file
Diffstat (limited to 'sploit/comm/comm.py')
-rw-r--r--sploit/comm/comm.py205
1 files changed, 205 insertions, 0 deletions
diff --git a/sploit/comm/comm.py b/sploit/comm/comm.py
new file mode 100644
index 0000000..3bc448e
--- /dev/null
+++ b/sploit/comm/comm.py
@@ -0,0 +1,205 @@
+import subprocess
+import tempfile
+import os
+import sys
+import select
+
+from sploit.until import bind
+from sploit.util.log import *
+
+class Comm:
+ logonread = True
+ logonwrite = False
+ flushonwrite = True
+ readonwrite = False
+ timeout = 250 # milliseconds
+ last = None # result of last discrete read
+
+ def __init__(self, backend):
+ self.back = backend
+
+ def shutdown(self):
+ try:
+ self.back.stdout.close()
+ except BrokenPipeError:
+ pass
+
+ def read(self, size=-1):
+ if size < 0:
+ return self.readall_nonblock()
+ elif size == 0:
+ data = b''
+ else:
+ data = self.back.stdin.read(size)
+ if(data == b''):
+ raise BrokenPipeError('Tried to read on broken pipe')
+ if self.logonread : ilog(data, file=sys.stdout, color=NORMAL)
+ self.last = data
+ return data
+
+ def readline(self):
+ data = self.back.stdin.readline()
+ if(data == b''):
+ raise BrokenPipeError('Tried to read on broken pipe')
+ if data.endswith(b'\n'):
+ data = data[:-1]
+ if self.logonread : ilog(data, file=sys.stdout, color=NORMAL)
+ self.last = data
+ return data
+
+ def readall(self):
+ data = b''
+ try:
+ for line in self.back.stdin:
+ tolog = (line[:-1] if line.endswith(b'\n') else line)
+ if self.logonread : ilog(tolog, file=sys.stdout, color=NORMAL)
+ data += line
+ except KeyboardInterrupt:
+ pass
+ self.last = data
+ return data
+
+ def readall_nonblock(self):
+ try:
+ data = b''
+ os.set_blocking(self.back.stdin.fileno(), False)
+ poll = select.poll()
+ poll.register(self.back.stdin, select.POLLIN)
+ while True:
+ poll.poll(self.timeout)
+ d = self.readall()
+ if len(d) == 0:
+ self.last = data
+ return data
+ data += d
+ finally:
+ os.set_blocking(self.back.stdin.fileno(), True)
+
+ def readuntil(self, pred, /, *args, **kwargs):
+ data = b''
+ pred = bind(pred, *args, **kwargs)
+ l = self.logonread
+ self.logonread = False
+ try:
+ while(True):
+ data += self.read(1)
+ if(pred(data)):
+ break
+ finally:
+ self.logonread = l
+ if self.logonread : ilog(data, file=sys.stdout, color=NORMAL)
+ self.last = data
+ return data
+
+ def readlineuntil(self, pred, /, *args, **kwargs):
+ dataarr = []
+ pred = bind(pred, *args, **kwargs)
+ while(True):
+ dataarr.append(self.readline())
+ if(pred(dataarr)):
+ break
+ self.last = dataarr
+ return dataarr
+
+ def write(self, data):
+ self.back.stdout.write(data)
+ if self.flushonwrite : self.back.stdout.flush()
+ if self.logonwrite : ilog(data, file=sys.stdout, color=ALT)
+ if self.readonwrite : self.readall_nonblock()
+
+ def writeline(self, data=b''):
+ self.write(data + b'\n')
+
+ def interact(self):
+ stdin = sys.stdin.buffer
+ event = select.POLLIN
+
+ def readall_stdin():
+ try:
+ os.set_blocking(stdin.fileno(), False)
+ for line in stdin:
+ self.write(line)
+ finally:
+ os.set_blocking(stdin.fileno(), True)
+
+ readtable = {
+ self.back.stdin.fileno(): self.readall_nonblock,
+ stdin.fileno(): readall_stdin,
+ }
+
+ try:
+ ilog("<--Interact Mode-->")
+ l = self.logonread
+ self.logonread = True
+
+ poll = select.poll()
+ poll.register(self.back.stdin, event)
+ poll.register(stdin, event)
+
+ readtable[self.back.stdin.fileno()]()
+ while True:
+ for fd, e in poll.poll(self.timeout):
+ if not e & event: return
+ readtable[fd]()
+ except KeyboardInterrupt:
+ pass
+ finally:
+ self.logonread = l
+ ilog("<--Interact Mode Done-->")
+
+def popen(cmdline=''):
+ io = Comm((Process(cmdline.split()) if len(cmdline) > 0 else Pipes()))
+ io.readall_nonblock()
+ io.readonwrite = True
+ return io
+
+class Process:
+ def __init__(self, args):
+ ilog(f"Running: {' '.join(args)}")
+ self.proc = subprocess.Popen(args,
+ stdin=subprocess.PIPE,
+ stdout=subprocess.PIPE,
+ stderr=subprocess.STDOUT,
+ preexec_fn=lambda : os.setpgrp())
+ ilog(f"PID: {self.proc.pid}")
+ self.stdin = self.proc.stdout
+ self.stdout = self.proc.stdin
+
+ def __del__(self):
+ if getattr(self, 'proc', None) == None : return
+ if(self.proc.poll() != None):
+ return
+ try:
+ ilog("Waiting on Target Program to End...")
+ ilog("Press Ctrl+C to Forcefully Kill It...")
+ self.proc.wait()
+ except KeyboardInterrupt:
+ self.proc.kill()
+
+class Pipes:
+ def __init__(self, tmp=None):
+ if(tmp == None):
+ self.dir = tempfile.TemporaryDirectory()
+ dirname = self.dir.name
+ else:
+ if(not os.path.exists(tmp)):
+ os.mkdir(tmp)
+ dirname = tmp
+ self.pathin = os.path.join(dirname, "in")
+ self.pathout = os.path.join(dirname, "out")
+ os.mkfifo(self.pathin)
+ os.mkfifo(self.pathout)
+ ilog("Waiting on Target to Connect...", file=sys.stdout)
+ ilog(f"<{self.pathin} >{self.pathout}", file=sys.stdout)
+ self.stdout = open(self.pathin, "wb")
+ self.stdin = open(self.pathout, "rb")
+ ilog("Connected!")
+
+ def __del__(self):
+ try:
+ if getattr(self,'stdout',None) : self.stdout.close()
+ if getattr(self,'stdin',None) : self.stdin.close()
+ except BrokenPipeError:
+ pass
+ if getattr(self,'pathin',None) and os.path.exists(self.pathin) : os.unlink(self.pathin)
+ if getattr(self,'pathout',None) and os.path.exists(self.pathout) : os.unlink(self.pathout)