ROP Emporium’s ret2win (x64) with Radare2

Updated 2021: I’ve made some minor tweaks to match updates made to the challenges.

This series is going to focus basic x64 return-orientated programming (ROP), using the fantastic buffer overflow challenges from ROP Emporium. These challenges get progressively harder as they introduce new concepts and force you to be creative. We’ll use Radare2 for all debugging, and in my case, everything will be done in an Ubuntu 18.08 container, though this should work on most *nix systems.

If you have no idea how buffer overflows work, try instead going through Sam Bowne’s series covering the basics. If you’re new to x64 assembly but have a foundation in x32, reading this cheat sheet is a strongly recommended: x64 Cheat Sheet — CS Brown. Finally I’m also going to assume you’re familiar with the basics of Radare2, but if not, first check out my series focusing on teaching it by attacking the CMU Bomb Lab challenge.

The first challenge is basically a warm-up, so we’ll use it as an excuse to cover some basics of overflows with r2. You can download the ret2win challenge here: https://ropemporium.com/binary/ret2win.zip

Recon

First, we should check which stack protections have been set on this binary. Use rabin2 -I to show binary info

$ rabin2 -I ret2win<SNIP>
nx true
pic false
relro partial

With nx set to true, we know shellcode cannot be executed off the stack. With pic set to false and relro partial, we know the binary has ASLR disabled, but not for the OS. You can check system-wide ASLR by checking the value of /proc/sys/kernle/randomize_va_space.

$ cat /proc/sys/kernel/randomize_va_space 
2

The 2 indicates full ASLR is enabled system-wide, so this confirms return-orientated programming is the best strategy. This protection can be disabled by setting the value to a 0, but ASLR is not an issue for us, so leave it on.

Analyzing the Binary

Run r2 with ret2win as an argument, then use aaa to analyze the binary. Disassembling the main function with pdf @ main shows the only interesting call it makes is to sym.pwnme. Disassemble that function with pdf @ sym.pwnme.

Picking out the important bits, the function allocates 32 (0x20) bytes of space on the stack with memset, then copies 56 (0x38) bytes into it from stdin with fgets. It’s worth noting that since the function uses fgets, stdin is terminated only by newlines (0xa) or if it reaches the maximum expected characters. This allows many characters that other vulnerable functions would not, such as null bytes. Read more about fgets here.

Finding offsets with r2

Since we’re dealing with x64 assembly, we want to target rsp when overflowing the buffer. We will use ragg2 to generate a debruijn pattern (a non-repeating pattern), which can be easily identified in memory, and used to calculate offsets. We know fgets will only read 58 bytes, so that will also be the length of our pattern.

$ ragg2 -P 58 -r

Copy the output to clipboard, then open ret2win with r2 in Debug mode, seek to sym.pwnme, then set a breakpoint after the call to fgets. Let’s choose the return instruction at the end for our breakpoint with db @ 0x00400755. Use dc to continue execution and paste in the offset pattern in clipboard.

After hitting the next breakpoint, use drr to to show the registers, and their references (telescoping). You can also use pxq 8 @ rsp to print the chars that have overwritten the saved rsp.

Copy the hex at rsp to your clipboard, then type wopO and paste the hex after to calculate the offset for rsp.

We now know how rsp will be overwritten after sending 40 bytes. Now what?

ret2win

Analyze the binary again with aaa, then use afl to list functions. The obvious choice is sym.ret2win.

Disassemble it and you’ll see it calls system with cat flag.txt as an argument. ret2win itself doesn’t require any arguments, so calling it should be as simple as overwriting rsp with the address of sym.ret2win. The payload will be very simple:

[40 chars of junk] + [address of ret2win]

Let’s do this with…perl. Why? Because I don’t like how Python3 handles byte printing, while perl is consistent and ubiquitous. Don’t let Python2 be a crutch, because it’s going away.

perl -e ‘print “\xcc”x40 . “\x56\x07\x40\x00”’| ./ret2win

Printing bytes with perl is very similar to Python, with a few minor differences.

  1. Instead of -c command, perl uses -e command
  2. Instead of * for multiplication, perl uses x
  3. Instead of + to concatenate strings, perl uses .

Hopefully most of that was review, because next we’ll actually see what return-oriented programming can do in split!

Note to Ubuntu 18 users: You have an additional ‘quirk’ that you have to work around. As ROP Emporium explains:

The version of GLIBC packaged with Ubuntu 18.04 uses movaps instructions to move data onto the stack in some functions. The 64 bit calling convention requires the stack to be 16 byte aligned before a call instruction but this is easily violated during ROP chain execution, causing all further calls from that function to be made with a misaligned stack. movaps triggers a general protection fault when operating on unaligned data, so try padding your ROP chain with an extra ret before returning into a function or return further into a function to skip a push instruction.

Our stack is not 16 byte aligned, so this will crash when it hits certain instructions, many of them being in library function calls like system. You could add an extra return gadget, but in this case by skipping the first instruction (push rbp) the stack aligns fine. Simply add 1 to the target address.

Your payload will be:

perl -e ‘print “\xcc”x40 . "\x57\x07\x40\x00"’| ./ret2win

Annoying, yes but get used to it — each of these challenges has quirks with Ubuntu 18, and they’ll soon be in the other distros.

--

--

--

OSCE | OSCP | I like computers

Love podcasts or audiobooks? Learn on the go with our new app.

Recommended from Medium

Introduction to NumPy (Part-II)

Hadoop and Ansible

An Unreal Experience — Alpha Build

Common Git Command for Beginner

What you need to know before selecting a Django development company in the USA

Deploy project on GCP virtual machine via Gitlab CI runner

Follow This Realistic Programming Path And Start Making 6 Figures

CS371p Spring 2022: Fazal Ali: Final Entry

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store
Mark Higgins

Mark Higgins

OSCE | OSCP | I like computers

More from Medium

Defeating OTP through probabilistic attacks and how to mitigate

Google Images best alternative — Naver Images API

Project 2 : Simple I/O Program Using ESP32