From cd54ffb2fc1761cfba8bc97f4b1985932ca025e3 Mon Sep 17 00:00:00 2001 From: John Hammond Date: Wed, 13 May 2020 00:20:51 -0400 Subject: [PATCH] Corrected some nonsense while accidentially reading command echoes --- pwncat/file.py | 8 ++++++-- pwncat/privesc/setuid.py | 2 +- pwncat/pty.py | 37 +++++++++++++++++++++---------------- 3 files changed, 28 insertions(+), 19 deletions(-) diff --git a/pwncat/file.py b/pwncat/file.py index be6c531..53feaa2 100644 --- a/pwncat/file.py +++ b/pwncat/file.py @@ -84,10 +84,12 @@ class RemoteBinaryPipe(RawIOBase): except (BlockingIOError, socket.error): pass - obj = bytes(b) + # obj = bytes(b) + obj = bytes(b[:n]) # Check for EOF if self.delim in obj: + self.on_eof() n = obj.find(self.delim) return n @@ -96,7 +98,8 @@ class RemoteBinaryPipe(RawIOBase): for i in range(1, len(self.delim)): # See if a piece of the delimeter is at the end of this block piece = self.delim[:i] - if bytes(b[-i:]) == piece: + # if bytes(b[-i:]) == piece: + if obj[-i:] == piece: try: # Peak the next bytes, to see if this is actually the # delimeter @@ -113,6 +116,7 @@ class RemoteBinaryPipe(RawIOBase): # Adjust result n -= len(piece) # Set EOF for next read + self.on_eof() return n diff --git a/pwncat/privesc/setuid.py b/pwncat/privesc/setuid.py index 3090d4a..68ce5c5 100644 --- a/pwncat/privesc/setuid.py +++ b/pwncat/privesc/setuid.py @@ -38,7 +38,7 @@ class SetuidMethod(Method): # Spawn a find command to locate the setuid binaries files = [] with self.pty.subprocess( - "find / -perm -4000 -print 2>/dev/null", mode="r" + "find / -perm -4000 -print 2>/dev/null", mode="r", no_job=True ) as stream: util.progress("searching for setuid binaries") for path in stream: diff --git a/pwncat/pty.py b/pwncat/pty.py index 1a58ef8..20c0309 100644 --- a/pwncat/pty.py +++ b/pwncat/pty.py @@ -1166,12 +1166,19 @@ class PtyHandler: # DANGER if "b" in mode: self.raw(echo=False) - self.run("echo") # restabilize the shell to get output - self.flush_output() + self.client.send(b"echo\n") + time.sleep(0.1) + self.flush_output(some=True) self.client.sendall(command + b"\n") - self.recvuntil(sdelim) + + response = self.recvuntil(sdelim) + + # If we see part of our command on the response, there is an echo. Read again. + if b"export PS1=" in response: + self.recvuntil(sdelim) + self.recvuntil("\n") # Send the data if requested @@ -1187,13 +1194,6 @@ class PtyHandler: else: pipe = io.BufferedReader(pipe) - # if "b" not in mode: - # if "w" in mode: - # pipe = io.BufferedRWPair(pipe, pipe) - # pipe = io.TextIOWrapper(pipe) - # else: - # pipe = io.TextIOWrapper(io.BufferedReader(pipe)) - return pipe def do_test(self, argv): @@ -1312,7 +1312,8 @@ class PtyHandler: def raw(self, echo: bool = False): self.stty_saved = self.run("stty -g").decode("utf-8").strip() - self.run("stty raw -echo", wait=False) + # self.run("stty raw -echo", wait=False) + self.process("stty raw -echo", delim=False) self.has_cr = False self.has_echo = False @@ -1324,17 +1325,21 @@ class PtyHandler: self.run("echo") self.run(f"export PS1='{self.remote_prefix} {self.remote_prompt}'") - def flush_output(self): + def flush_output(self, some=False): + output = b"" old_timeout = self.client.gettimeout() self.client.settimeout(0) while True: try: - output = self.client.recv(4096) - if len(output) == 0: - break + new = self.client.recv(4096) + if len(new) == 0: + if len(output) > 0 or some == False: + break + output += new except (socket.timeout, BlockingIOError): - break + if len(output) > 0 or some == False: + break self.client.settimeout(old_timeout)