Ben-Lichtman / ropr

A blazing fast™ multithreaded ROP Gadget finder. ropper / ropgadget alternative
477 stars 27 forks source link

Add --nouniq option #13

Closed ptr-yudai closed 2 years ago

ptr-yudai commented 2 years ago

Description

This PR introduces a new option --nouniq or -u, which enables ropr to show non-unique gadgets.

Motivation and Context

The current ropr deduplicates gadgets and shows only unique ones. However, sometimes it's desirable to see every gadget available. (i.e. avoid 0x0A in the gadget address / use gadgets with lower address for kernel exploitation)

Changes

I've added a new field unique_id to Gadget struct. This field is set to the address of the gadget when --nouniq is enabled, otherwise 0. This change can switch the behavior when it's inserted into HashMap.

How Has This Been Tested?

I've tested some gadgets such as pop rax; ret; on libc binary and checked if it outputs the same gadgets as those by rp-lin-x64.

Ben-Lichtman commented 2 years ago

Hey there, thank you for the contribution.

I will have to mull this one over a bit because I'm not totally convinced on its usefulness compared to doing directly what the user wants (eg. avoiding bytes in the address etc). I think that this would be the preferred path but I could probably be convinced otherwise.

Also note that there currently is an address range filtering feature for the low address range thing.

ptr-yudai commented 2 years ago

Thanks for the quick response.

Actually I hadn't met any problems for a long time but I got a situation recently where I needed this feature. There is a very rare case that the gadget doesn't work when kASLR is enabled in kernel exploitation. The gadget comes from an instruction like

mov    al,BYTE PTR [rdi-0xXXXXXXXX]

where the value 0xXXXXXXXX is recognized as pop rcx; ret; gadget.

$ ropr vmlinux -R "^pop rcx; ret;"
0xffffffff812ea083: pop rcx; ret;

==> Found 1 gadgets in 1.042 seconds

This works fine when kASLR is disabled:

pwndbg> x/4i 0xffffffff812ea083
   0xffffffff812ea083:  pop    rcx
   0xffffffff812ea084:  ret    
   0xffffffff812ea085:  add    ebx,0x100ff81
   0xffffffff812ea08b:  add    BYTE PTR [rax],al

However, the gadget changes when kASLR is enabled:

pwndbg> x/4i 0xffffffff9e600000 + 0x2ea083
   0xffffffff9e8ea083:  pop    rcx
   0xffffffff9e8ea084:  and    ebx,DWORD PTR [rdi+0xff81c3]
   0xffffffff9e8ea08a:  add    DWORD PTR [rax],eax
   0xffffffff9e8ea08c:  add    BYTE PTR [rcx],bl

I'm still investigation why this happens in a normal Linux kernel but I guess it changes a part of the code dynamically on load. This behavior happened to some other people too. I believe this will be a common problem if FGKASLR gets enabled by default. Address range filtering would also work for this problem but I think just printing all gadgets would be more convenient.

Still, I'm not good at programming Rust so please do not trust my code. It'd be nice if you could implement this feature in a more beautiful way.

Thank you for your consideration.

Ben-Lichtman commented 2 years ago

That's some very strange behaviour. Plz update if you figure out why it happens.

It will probably be a few weeks until I can do anything about this PR anyway.

Ben-Lichtman commented 2 years ago

I like the solution of adding a unique ID to the gadgets. This seems OK to merge. Thanks for the contribution.

There is a chance that this may be removed in the future if I find a solution to this kernel self-patching thing, but for now I think it's ok.