When playing ctf pwn challenges we usually need the one-gadget RCE (remote code execution),
which leads to call execve('/bin/sh', NULL, NULL)
.
This gem provides such gadgets finder, no need to use objdump or IDA-pro every time like a fool 😉
To use this tool, type one_gadget /path/to/libc
in command line and enjoy the magic 😆
Available on RubyGems.org!
$ gem install one_gadget
Note: requires ruby version >= 2.1.0, you can use ruby --version
to check.
- i386
- amd64 (x86-64)
- aarch64 (ARMv8)
OneGadget uses symbolic execution to find the constraints of gadgets to be successful.
The article introducing how I develop this tool can be found on my blog.
SHELL_OUTPUT_OF(one_gadget)
SHELL_OUTPUT_OF(one_gadget /lib/x86_64-linux-gnu/libc.so.6)
SHELL_OUTPUT_OF(one_gadget -b aad7dbe330f23ea00ca63daf793b766b51aceb5d)
Consider this scenario when exploiting:
- Able to write on GOT (Global Offset Table)
- Base address of libc is unknown
In this scenario you can choose to write two low-byte on a GOT entry with one-gadget's two low-byte. If the function offset on GOT is close enough with the one-gadget, you will have at least 1/16 chance of success.
Reorder gadgets according to the distance of given functions.
SHELL_OUTPUT_OF(one_gadget /lib/x86_64-linux-gnu/libc.so.6 --near exit,mkdir)
Regular expression is acceptable.
SHELL_OUTPUT_OF(one_gadget /lib/x86_64-linux-gnu/libc.so.6 --near 'write.*' --raw)
Pass an ELF file as the argument, OneGadget will take all GOT functions for processing.
SHELL_OUTPUT_OF(one_gadget /lib/x86_64-linux-gnu/libc.so.6 --near spec/data/test_near_file.elf --raw)
Sometimes one_gadget
finds too many gadgets to show them in one screen,
by default gadgets would be filtered automatically according to the difficulty of constraints.
Use option --level 1
to show all gadgets found instead of only those with higher probabilities.
SHELL_OUTPUT_OF(one_gadget /lib/x86_64-linux-gnu/libc.so.6 --level 1)
SHELL_OUTPUT_OF(one_gadget /lib32/libc.so.6)
SHELL_OUTPUT_OF(one_gadget spec/data/aarch64-libc-2.27.so)
Pass your exploit script as one_gadget
's arguments, it can
try all gadgets one by one, so you don't need to try every possible gadgets manually.
$ one_gadget ./spec/data/libc-2.19.so -s 'echo "offset ->"'
require 'one_gadget'
RUBY_OUTPUT_OF(OneGadget.gadgets(file: '/lib/x86_64-linux-gnu/libc.so.6'))
# or in shorter way
RUBY_OUTPUT_OF(one_gadget('/lib/x86_64-linux-gnu/libc.so.6', level: 1))
# from build id
RUBY_OUTPUT_OF(one_gadget('b417c0ba7cc5cf06d1d1bed6652cedb9253c60d0'))
import subprocess
def one_gadget(filename):
return [int(i) for i in subprocess.check_output(['one_gadget', '--raw', filename]).decode().split(' ')]
RUBY_OUTPUT_OF(one_gadget('/lib/x86_64-linux-gnu/libc.so.6'))
Any suggestion or feature request is welcome! Feel free to send a pull request.
Please let me know if you find any libc that make OneGadget fail to find gadgets. And, if you like this work, I'll be happy to be starred 😬