From 84877ad00fd799e1001fed9bdfae28ccd98225f2 Mon Sep 17 00:00:00 2001 From: Peace-Maker Date: Wed, 15 Jan 2025 13:50:51 +0100 Subject: [PATCH 1/4] Allow to passthru kwargs on `ssh.__getattr__` convenience function Instead of only passing the command arguments themselves to `ssh.system` when using `ssh.somecommand('args')`, allow to specify keyword arguments as well `ssh.somecommand('args', tty=False)`. --- pwnlib/tubes/ssh.py | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/pwnlib/tubes/ssh.py b/pwnlib/tubes/ssh.py index b714a5660..2808e514d 100644 --- a/pwnlib/tubes/ssh.py +++ b/pwnlib/tubes/ssh.py @@ -1217,7 +1217,9 @@ def __call__(self, attr): return self.run(attr).recvall().strip() def __getattr__(self, attr): - """Permits member access to run commands over SSH + """Permits member access to run commands over SSH. + + Supports other keyword arguments which are passed to :meth:`.system`. Examples: @@ -1228,6 +1230,8 @@ def __getattr__(self, attr): b'travis' >>> s.echo(['huh','yay','args']) b'huh yay args' + >>> s.echo('value: $MYENV', env={'MYENV':'the env'}) + b'value: the env' """ bad_attrs = [ 'trait_names', # ipython tab-complete @@ -1239,7 +1243,7 @@ def __getattr__(self, attr): raise AttributeError @LocalContext - def runner(*args): + def runner(*args, **kwargs): if len(args) == 1 and isinstance(args[0], (list, tuple)): command = [attr] command.extend(args[0]) @@ -1248,7 +1252,7 @@ def runner(*args): command.extend(args) command = b' '.join(packing._need_bytes(arg, min_wrong=0x80) for arg in command) - return self.run(command).recvall().strip() + return self.system(command, **kwargs).recvall().strip() return runner def connected(self): From 54eb1fba33ff76953f694a7f337fa12289229cb0 Mon Sep 17 00:00:00 2001 From: Peace-Maker Date: Wed, 15 Jan 2025 13:52:23 +0100 Subject: [PATCH 2/4] ssh: Don't allocate a tty for internal state fetching If the remote server is printing some motd agressively, this could lead to interpreting the motd instead of the requested output. --- pwnlib/tubes/ssh.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pwnlib/tubes/ssh.py b/pwnlib/tubes/ssh.py index 2808e514d..a3b85eb52 100644 --- a/pwnlib/tubes/ssh.py +++ b/pwnlib/tubes/ssh.py @@ -706,7 +706,7 @@ def __init__(self, user=None, host=None, port=22, password=None, key=None, if self.sftp: with context.quiet: - self.cwd = packing._decode(self.pwd()) + self.cwd = packing._decode(self.pwd(tty=False)) else: self.cwd = '.' @@ -1373,7 +1373,7 @@ def update(has, total): def _download_to_cache(self, remote, p, fingerprint=True): with context.local(log_level='error'): - remote = self.readlink('-f',remote) + remote = self.readlink('-f', remote, tty=False) if not hasattr(remote, 'encode'): remote = remote.decode('utf-8') From 062c5f64e6ee2b652b4c4a8c9e7ba3e934b81dbc Mon Sep 17 00:00:00 2001 From: Peace-Maker Date: Wed, 15 Jan 2025 13:53:12 +0100 Subject: [PATCH 3/4] Use `ssh.system` internally too instead of deprecated `ssh.run` --- pwnlib/tubes/ssh.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/pwnlib/tubes/ssh.py b/pwnlib/tubes/ssh.py index a3b85eb52..6c76746b7 100644 --- a/pwnlib/tubes/ssh.py +++ b/pwnlib/tubes/ssh.py @@ -1140,7 +1140,7 @@ def run_to_end(self, process, tty = False, cwd = None, env = None, wd = None): cwd = wd with context.local(log_level = 'ERROR'): - c = self.run(process, tty, cwd = cwd, env = env, timeout = Timeout.default) + c = self.system(process, tty, cwd = cwd, env = env, timeout = Timeout.default) data = c.recvall() retcode = c.wait() c.close() @@ -1203,7 +1203,7 @@ def __getitem__(self, attr): >>> print(repr(s['echo hello'])) b'hello' """ - return self.run(attr).recvall().strip() + return self.system(attr).recvall().strip() def __call__(self, attr): """Permits function-style access to run commands over SSH @@ -1214,7 +1214,7 @@ def __call__(self, attr): >>> print(repr(s('echo hello'))) b'hello' """ - return self.run(attr).recvall().strip() + return self.system(attr).recvall().strip() def __getattr__(self, attr): """Permits member access to run commands over SSH. @@ -1352,7 +1352,7 @@ def update(has, total): with context.local(log_level = 'ERROR'): cmd = 'cat < ' + sh_string(remote) - c = self.run(cmd) + c = self.system(cmd) data = b'' while True: @@ -1538,7 +1538,7 @@ def upload_data(self, data, remote): with context.local(log_level = 'ERROR'): cmd = 'cat > ' + sh_string(remote) - s = self.run(cmd, tty=False) + s = self.system(cmd, tty=False) s.send(data) s.shutdown('send') data = s.recvall() @@ -1596,7 +1596,7 @@ def upload_dir(self, local, remote=None): remote_tar = self.mktemp('--suffix=.tar.gz') self.upload_file(local_tar, remote_tar) - untar = self.run(b'cd %s && tar -xzf %s' % (sh_string(remote), sh_string(remote_tar))) + untar = self.system(b'cd %s && tar -xzf %s' % (sh_string(remote), sh_string(remote_tar))) message = untar.recvrepeat(2) if untar.wait() != 0: From 37a6626056c73d6b93ab24206e7a1d80baafb2b2 Mon Sep 17 00:00:00 2001 From: Peace-Maker Date: Wed, 15 Jan 2025 13:58:13 +0100 Subject: [PATCH 4/4] Update CHANGELOG --- CHANGELOG.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index f809a8d24..6d464584d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -74,6 +74,10 @@ The table below shows which release corresponds to each branch, and what date th ## 5.0.0 (`dev`) +- [#2517][2517] Allow to passthru kwargs on `ssh.__getattr__` convenience function to fix SSH motd problems + +[2517]: https://github.com/Gallopsled/pwntools/pull/2517 + ## 4.15.0 (`beta`) - [#2508][2508] Ignore a warning when compiling with asm on nix