From 51cbdb465d94b35d0558766584d31559ccffac32 Mon Sep 17 00:00:00 2001 From: ckxckx Date: Tue, 29 Oct 2024 04:06:56 +0800 Subject: [PATCH] Fix attaching to a gdbserver with tuple `gdb.attach(('0.0.0.0',12345))` (#2291) * Patch for #issues/2290 * Return listening process on `pidof(("0.0.0.0", 1234))` Instead of returning the process which is connected to port 1234, return the process which is listening on that port. * Update CHANGELOG --------- Co-authored-by: Peace-Maker --- CHANGELOG.md | 2 ++ pwnlib/gdb.py | 26 ++++++++++++++++++++++++++ pwnlib/util/net.py | 12 ++++++------ pwnlib/util/proc.py | 9 +++++++-- 4 files changed, 41 insertions(+), 8 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 553b16e99..c10b09691 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -84,6 +84,7 @@ The table below shows which release corresponds to each branch, and what date th - [#2482][2482] Throw error when using `sni` and setting `server_hostname` manually in `remote` - [#2478][2478] libcdb-cli: add `--offline-only`, refactor unstrip and add fetch parser for download libc-database - [#2484][2484] Allow to disable caching +- [#2291][2291] Fix attaching to a gdbserver with tuple `gdb.attach(('0.0.0.0',12345))` [2471]: https://github.com/Gallopsled/pwntools/pull/2471 [2358]: https://github.com/Gallopsled/pwntools/pull/2358 @@ -96,6 +97,7 @@ The table below shows which release corresponds to each branch, and what date th [2482]: https://github.com/Gallopsled/pwntools/pull/2482 [2478]: https://github.com/Gallopsled/pwntools/pull/2478 [2484]: https://github.com/Gallopsled/pwntools/pull/2484 +[2291]: https://github.com/Gallopsled/pwntools/pull/2291 ## 4.14.0 (`beta`) diff --git a/pwnlib/gdb.py b/pwnlib/gdb.py index 1d90a9cbb..08c319bc4 100644 --- a/pwnlib/gdb.py +++ b/pwnlib/gdb.py @@ -950,6 +950,8 @@ def attach(target, gdbscript = '', exe = None, gdb_args = None, ssh = None, sysr Process name. The youngest process is selected. :obj:`tuple` Host, port pair of a listening ``gdbserver`` + Tries to look up the target exe from the ``gdbserver`` commandline, + requires explicit ``exe`` argument if the target exe is not in the commandline. :class:`.process` Process to connect to :class:`.sock` @@ -1034,6 +1036,30 @@ def attach(target, gdbscript = '', exe = None, gdb_args = None, ssh = None, sysr >>> io.sendline(b'echo Hello from bash && exit') >>> io.recvall() b'Hello from bash\n' + >>> server.close() + + Attach to a gdbserver / gdbstub running on the local machine + by specifying the host and port tuple it is listening on. + (gdbserver always listens on 0.0.0.0) + + >>> gdbserver = process(['gdbserver', '1.2.3.4:12345', '/bin/bash']) + >>> gdbserver.recvline_contains(b'Listening on port', timeout=10) + b'Listening on port 12345' + >>> pid = gdb.attach(('0.0.0.0', 12345), gdbscript=''' + ... tbreak main + ... commands + ... call puts("Hello from gdbserver debugger!") + ... continue + ... end + ... ''') + >>> gdbserver.recvline(timeout=10) # doctest: +ELLIPSIS + b'Remote debugging from host 127.0.0.1, ...\n' + >>> gdbserver.recvline(timeout=10) + b'Hello from gdbserver debugger!\n' + >>> gdbserver.sendline(b'echo Hello from bash && exit') + >>> gdbserver.recvline(timeout=10) + b'Hello from bash\n' + >>> gdbserver.close() Attach to processes running on a remote machine via an SSH :class:`.ssh` process diff --git a/pwnlib/util/net.py b/pwnlib/util/net.py index fab1dacbb..df8cd5662 100644 --- a/pwnlib/util/net.py +++ b/pwnlib/util/net.py @@ -259,17 +259,17 @@ def sockinfos(addr, f, t): infos |= set(socket.getaddrinfo(sockaddr[0], sockaddr[1], socket.AF_INET6, t, proto, socket.AI_V4MAPPED)) return infos - if local is not None: - local = sockinfos(local, fam, typ) - remote = sockinfos(remote, fam, typ) + local = sockinfos(local, fam, typ) + if remote is not None: + remote = sockinfos(remote, fam, typ) def match(c): laddrs = sockinfos(c.laddr, c.family, c.type) raddrs = sockinfos(c.raddr, c.family, c.type) - if not (raddrs & remote): + if not (laddrs & local): return False - if local is None: + if remote is None: return True - return bool(laddrs & local) + return bool(raddrs & remote) return match diff --git a/pwnlib/util/proc.py b/pwnlib/util/proc.py index 8ebe5d221..9889bb697 100644 --- a/pwnlib/util/proc.py +++ b/pwnlib/util/proc.py @@ -27,6 +27,11 @@ def pidof(target): - :class:`pwnlib.tubes.sock.sock`: singleton list of the PID at the remote end of `target` if it is running on the host. Otherwise an empty list. + - :class:`pwnlib.tubes.ssh.ssh_channel`: singleton list of the PID of + `target` on the remote system. + - :class:`tuple`: singleton list of the PID at the local end of the + connection to `target` if it is running on the host. Otherwise an + empty list. Arguments: target(object): The target whose PID(s) to find. @@ -38,7 +43,7 @@ def pidof(target): >>> l = tubes.listen.listen() >>> p = process(['curl', '-s', 'http://127.0.0.1:%d'%l.lport]) - >>> pidof(p) == pidof(l) == pidof(('127.0.0.1', l.lport)) + >>> pidof(p) == pidof(l) == pidof(('127.0.0.1', l.rport)) True """ if isinstance(target, tubes.ssh.ssh_channel): @@ -51,7 +56,7 @@ def pidof(target): return [c.pid for c in psutil.net_connections() if match(c)] elif isinstance(target, tuple): - match = sock_match(None, target) + match = sock_match(target, None) return [c.pid for c in psutil.net_connections() if match(c)] elif isinstance(target, tubes.process.process):