Title: Paper notes - Evaluating the effectiveness of current anti-ROP defenses
Date: 2019-01-08 12:40

- Complete title: Evaluating the effectiveness of current anti-ROP defenses
- PDF: [429d9abdea007f8a6e8a8398c2b671900e6d33a4962b9f437c0cd2559d26e13b]({static}/files/papers/429d9abdea007f8a6e8a8398c2b671900e6d33a4962b9f437c0cd2559d26e13b_raid14-rop-effectiveness.pdf)

This fine paper from peoples from the Ruhr-Universität Bochum explains how to
bypass in a generic fashion three different ROP mitigations:
[kBouncer](http://www.cs.columbia.edu/~vpappas/papers/kbouncer.pdf),
[ROPecker](http://www.mysmu.edu/phdis2008/yqcheng.2008/ROPecker-NDSS14.pdf),
and [ROPGuard](https://github.com/ivanfratric/ropguard). All of them are using
the [LBR](https://lwn.net/Articles/680985/) (last branch recording) CPU feature
to detect suspicious control-flows.

*tl;dr* fill the LBR non-suspicious-looking data, and your
ROP-chain won't get detected.

# kBouncer

kBouncer hooks *dangerous functions* (link `VirtualProtect`), checks for
suspicious LBR records, and if none are found, set a "checkpoint" consumed 
when the corresponding syscall is hit; preventing direct calls to syscalls.
An attack is detected either if there is a non call-preceded return,
or a chain of up to 20 gadgets ending in the latest LBR stack.

A possible bypass for kBouncer is to execute enough code before calling a
*dangerous* function to fill the LBR stack with legitimate records,
with things called *LBR-flushing function*.

- On x86-32, those *gadgets* are are looking either like
	`call <anything>; A; jmp {esi, edi, ebx, ebp}` or
	`call <anything>; A; call {esi, edi, ebx, ebp}; B; ret`.
	Interestingly, calling `EtwInitializeProcess` (present in `ntdll.dll`),
	`pre_c_init` (present in all binaries) or even `lstrcmpiW` is enough to flush
	the LBR.
- On x64-64, since the calling convention is different (first arguments passed in
	registers instead of the stack), a
	[JOP](https://www.csc2.ncsu.edu/faculty/xjiang4/pubs/ASIACCS11.pdf)-style
	dispatcher gadget is used to call dummy gadgets to fill the LBR.


# ROPGuard

ROPGuard hooks winapi function, and check is something fishy is going on via
several tricks; the two main ones being apparently:

1. *Past and future control flow analysis*: checking if the return address is
	 call-preceded, and simulating the control flow to check for future non
	 call-preceded returns. Simulation stops after a certain number of
	 instructions, or at the first `call`/`jump`.
2. Stack checks: checking if the stack pointer is pointing inside the correct
	 range (to detect stack pivots).

The aforementioned kBouncer bypasses are enough to fool the first mitigation
(the control flow simulation stops early due to jumps/calls), and the second
one isn't even triggered.

# ROPecker

ROPecker doesn't hook functions, instead it works by catching access violations
outside of a circular buffer of a couple of executable pages, if not attack is
detected upon fault, the page is added to the ring.
The attack detection works by analyzing the past (via LBR) and (simulated) future control
flow. If a sequence of instruction matches all the following criteria, then
it's considered as a ROP-gadget:

1. The last instruction is an indirect branch
2. Doesn't contain any direct branching instruction
6. Is 6 instructions long at most

The *past* detection ends when a branch isn't a ROP-gadget, same for the *future*
detection. If the length of accumulated gadget chain exceed a certain threshold (between 11 and
16, as suggested by the paper), then an attack is detected.

Bypassing ROPecker is a simple matter of interleaving non-gadgets (containing a
branch, or more than 6 instructions) for time to time in their ROP chain to
thwart the detection.
