-
Notifications
You must be signed in to change notification settings - Fork 1.7k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Improve pwnup template, gdbserver detection #1148
Conversation
pwnlib/data/templates/pwnup.mako
Outdated
@@ -161,6 +160,8 @@ continue | |||
|
|||
io = start() | |||
|
|||
if args.GDB: | |||
log.info(io.recvline()) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This should be added in pwnlib.gdb
, not to the template, probably right after this:
Lines 782 to 783 in 20cb049
if pid and context.native: | |
proc.wait_for_debugger(pid) |
The issue is that doesn't actually happen all of the time -- only for certain (newer?) versions of gdbserver
. We can have a .recvline(timeout=0.5)
and then check to see if the line starts how we expect. If not, we'll need to .unrecv(...)
the data to put it back.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'll try adding it after that if statement.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I see there's already been done some handling for this in gdb.debug
:
Lines 465 to 469 in 20cb049
# gdbserver outputs a message when a client connects | |
garbage = gdbserver.recvline(timeout=1) | |
if "Remote debugging from host" not in garbage: | |
gdbserver.unrecv(garbage) |
Maybe gdb.debug
should be used instead?
When running locally gdb.debug
is used, however the fix does not trigger.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
When running locally, gdb.debug
spawns gdbserver
and then invokes gdb.attach
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yep.
I've adjusted the code in gdb.debug
. It should handle gdb's message correctly now.
pwnlib/data/templates/pwnup.mako
Outdated
@@ -131,13 +131,12 @@ def start(argv=[], *a, **kw): | |||
%endif | |||
gdbscript = ''' | |||
%if ctx.binary: | |||
set sysroot |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
IIRC, set sysroot
with no arguments is a no-op. Update: Nope, it's worse.
(gdb) show sysroot
The current system root is "target:".
(gdb) set sysroot
(gdb) show sysroot
The current system root is "".
set sysroot /
(which I think you meant?) is incorrect for SSH-forwarded GDB sessions and Android devices.
set sysroot
will also break for foreign-architecture binaries which are emulated under QEMU:
Lines 424 to 430 in 20cb049
else: | |
qemu_port = random.randint(1024, 65535) | |
qemu_user = qemu.user_path() | |
sysroot = sysroot or qemu.ld_prefix(env) | |
if not qemu_user: | |
log.error("Cannot debug %s binaries without appropriate QEMU binaries" % context.arch) | |
args = [qemu_user, '-g', str(qemu_port)] + args |
Finally, you don't want to set the sysroot in your GDB script. Pass the sysroot=
argument into the gdb.debug()
or gdb.attach()
call, that's what it's there for. (Side bar, we don't actually invoke set sysroot
for native-arch binaries, even if it's provided. This is a small bug.)
You might want to expose a --sysroot
argument to pwn template
to do this conditionally.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If I don't use set sysroot
I get the following error:
Temporary breakpoint 1 at 0x605: file x.c, line 2.
Warning:
Cannot insert breakpoint 1.
Cannot access memory at address 0x605
/tmp/pwnsIcbJL.gdb:7: Error in sourced command file:
Command aborted.
The right side is with set sysroot
, the left without, both include tbreak main
and continue
:
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can you run your script with DEBUG
to see the actual gdbscript
being executed? (i.e. python foo.py LOCAL GDB DEBUG
).
Can you also provide the first line of gdb --version
and all of gdb --configuration
?
EDIT: And gdbserver --version
.
Thanks!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
➜ tmp gdb --version
GNU gdb (GDB) 8.1
Copyright (C) 2018 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law. Type "show copying"
and "show warranty" for details.
This GDB was configured as "x86_64-pc-linux-gnu".
Type "show configuration" for configuration details.
For bug reporting instructions, please see:
<http://www.gnu.org/software/gdb/bugs/>.
Find the GDB manual and other documentation resources online at:
<http://www.gnu.org/software/gdb/documentation/>.
For help, type "help".
Type "apropos word" to search for commands related to "word".
➜ tmp gdb --configuration
This GDB was configured as follows:
configure --host=x86_64-pc-linux-gnu --target=x86_64-pc-linux-gnu
--with-auto-load-dir=$debugdir:$datadir/auto-load
--with-auto-load-safe-path=$debugdir:$datadir/auto-load
--with-expat
--with-gdb-datadir=/usr/share/gdb (relocatable)
--with-jit-reader-dir=/usr/lib/gdb (relocatable)
--without-libunwind-ia64
--with-lzma
--with-python=/usr (relocatable)
--with-guile
--with-separate-debug-dir=/usr/lib/debug (relocatable)
--with-system-gdbinit=/etc/gdb/gdbinit
--without-babeltrace
("Relocatable" means the directory can be moved with the GDB installation
tree, and GDB will still find it.)
➜ tmp gdbserver --version
GNU gdbserver (GDB) 8.1
Copyright (C) 2018 Free Software Foundation, Inc.
gdbserver is free software, covered by the GNU General Public License.
This gdbserver was configured as "x86_64-pc-linux-gnu"
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
pwnlib/data/templates/pwnup.mako
Outdated
break *0x{exe.symbols.main:x} | ||
%else: | ||
break *0x{exe.entry:x} | ||
break main |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is probably a good plan since exe.symbols.main
will be incorrect for PIE / ASLR-enabled binaries.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We should also probably change this to tbreak
, so that the breakpoint is removed after main
is hit.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Changed to tbreak
.
pwnlib/data/templates/pwnup.mako
Outdated
%else: | ||
break *0x{exe.entry:x} | ||
break main | ||
continue |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We always want to continue
, regardless of whether main
is defined. For gdbserver
, continue
begins execution.
pwnlib/data/templates/pwnup.mako
Outdated
%if 'main' in ctx.binary.symbols: | ||
break *0x{exe.symbols.main:x} | ||
%else: | ||
break *0x{exe.entry:x} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This needs to remain. In the event symbols are unavailable, gdbserver
will break at the entry point to the linker, not the entry point to the main binary.
In the event that the binary is PIE (and exe.entry
is a small value ~close to zero), this has the same effect as setting a breakpoint on the first instruction because of a convenient bug in gdb
: https://reverseengineering.stackexchange.com/q/8724
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Setting an invalid breakpoint in the gdbscript appears to be an error:
0x00007f9dc32aefb0 in _start () from target:/lib64/ld-linux-x86-64.so.2
Temporary breakpoint 1 at 0x520
Warning:
Cannot insert breakpoint 1.
Cannot access memory at address 0x520
/tmp/pwnrsyWx3.gdb:8: Error in sourced command file:
Command aborted.
I still end up in _start
and am unable to continue the program from there:
gef➤ continue
Continuing.
Warning:
Cannot insert breakpoint 1.
Cannot access memory at address 0x520
Command aborted.
I thought I should mention it, @zachriggle, thanks a lot for your detailed feedback! |
I've removed the |
Will try to do soon, thanks for the changes!
…On Thu, May 17, 2018 at 4:45 AM Robin Leander Schröder < ***@***.***> wrote:
I've removed the set sysroot as we should resolve this issue separately.
@zachriggle <https://github.com/zachriggle> Could you review the changes
I've made to the gdb.debug function?
—
You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHub
<#1148 (comment)>,
or mute the thread
<https://github.com/notifications/unsubscribe-auth/AAG0GPsy80Y2LAoqqqG-d0ZIXVmvGp4pks5tzWLbgaJpZM4T6HKE>
.
|
Cleaned up the code and made some fixes, I'll merge this once CI passes. |
On Ubuntu 22.04 gdb.debug() takes at least 2 seconds. This is because it prints only "Remote debugging from host 127.0.0.1, port 33398", but the code expects 2 lines. It's very unclear what the second line is supposed to be; the only lead is "* Handle extra newline printed by gdb" in commit 338fbeb ("Improve pwnup template, gdbserver detection (Gallopsled#1148)"), but I could not trace it back to the GDB source code, both historic and modern. Perhaps, there is a non-upstreamed patch in some distro that introduces it. It should still be safe to skip waiting for the second line if the first one already starts with "Remote debugging ...", so do it.
On Ubuntu 22.04 gdb.debug() takes at least 2 seconds. This is because it prints only "Remote debugging from host 127.0.0.1, port 33398", but the code expects 2 lines. It's very unclear what the second line is supposed to be; the only lead is "* Handle extra newline printed by gdb" in commit 338fbeb ("Improve pwnup template, gdbserver detection (Gallopsled#1148)"), but I could not trace it back to the GDB source code, both historic and modern. Perhaps, there is a non-upstreamed patch in some distro that introduces it. It should still be safe to skip waiting for the second line if the first one already starts with "Remote debugging ...", so do it.
On Ubuntu 22.04 gdb.debug() takes at least 2 seconds. This is because it prints only "Remote debugging from host 127.0.0.1, port 33398", but the code expects 2 lines. It's very unclear what the second line is supposed to be; the only lead is "* Handle extra newline printed by gdb" in commit 338fbeb ("Improve pwnup template, gdbserver detection (#1148)"), but I could not trace it back to the GDB source code, both historic and modern. Perhaps, there is a non-upstreamed patch in some distro that introduces it. It should still be safe to skip waiting for the second line if the first one already starts with "Remote debugging ...", so do it.
On Ubuntu 22.04 gdb.debug() takes at least 2 seconds. This is because it prints only "Remote debugging from host 127.0.0.1, port 33398", but the code expects 2 lines. It's very unclear what the second line is supposed to be; the only lead is "* Handle extra newline printed by gdb" in commit 338fbeb ("Improve pwnup template, gdbserver detection (Gallopsled#1148)"), but I could not trace it back to the GDB source code, both historic and modern. Perhaps, there is a non-upstreamed patch in some distro that introduces it. It should still be safe to skip waiting for the second line if the first one already starts with "Remote debugging ...", so do it.
I've modified the template that is used when executing
pwn template
. The changes should allow a smoother workflow with GDB.Using the
set sysroot
command allows gdb to find themain
on its own, if there are symbols.The continue was removed as gdb will stop on entry by default, which is the next best thing without symbols.
log.info(io.recvline())
was added when running with gdb, as gdb will print a line that we want to discard:Please let me know what you think!
I also ran the docker tests, although I'm not sure if templates are covered by them.