Rop'n'roll
April 18, 2015
You may have already read this article 8 months ago, but since we changed a lot the ROP-related syntax, we’re quite sure that you won’t mind reading an updated version
As attackers are moving forwards, so does the defense. Since a couple of years, every decent operating system has non-executable stack, defeating the classic ‘put your shellcode on the stack and execute it’ modus operanti.
This is why attackers are now using (among other things) Return Oriented Programming, also known as ROP, to bypass this protection.
Because radare2 (also) aims to be useful to exploits writers and make their life easier, it can:
- hunt for gadgets, with a configurable depth
- filter gadgets
- do this for multiples archs
[0x08048320]> /R
Do you want to print 468.9K chars? (y/N)
Well, let’s filter.
[0x08048350]> /R call eax
0x080483a3 0085c0741155 add byte [ebp + 0x551174c0], al
0x080483a9 89e5 mov ebp, esp
0x080483ab 83ec14 sub esp, 0x14
0x080483ae 6824a00408 push 0x804a024
0x080483b3 ffd0 call eax
0x080483a8 55 push ebp
0x080483a9 89e5 mov ebp, esp
0x080483ab 83ec14 sub esp, 0x14
0x080483ae 6824a00408 push 0x804a024
0x080483b3 ffd0 call eax
0x080483ac ec in al, dx
0x080483ad 1468 adc al, 0x68
0x080483af 24a0 and al, 0xa0
0x080483b1 0408 add al, 8
0x080483b3 ffd0 call eax
[0x08048350]>
You can also display them in a linear manner, à la ROPGadget, you just have to use /Rl
:
[0x08048350]> /Rl leave
0x080483b3: call eax; add esp, 0x10; leave; ret;
0x080483b6: les edx, [eax]; leave; ret;
0x080483ed: call ecx; add esp, 0x10; leave; ret;
0x080483f0: les edx, [eax]; leave; ret;
0x0804840f: call 0x8048390; mov byte [0x804a024], 1; leave; ret;
0x08048419: or byte [ecx], al; leave; ret;
0x08048440: call edx; add esp, 0x10; leave; jmp 0x80483c0;
0x08048443: les edx, [eax]; leave; jmp 0x80483c0;
0x080484af: call 0x8048320; add esp, 0x10; mov edi, dword [ebp - 4]; leave; ret;
0x080484b3: inc dword [ebx + 0x7d8b10c4]; cld; leave; ret;
0x080484b5: les edx, [eax]; mov edi, dword [ebp - 4]; leave; ret;
0x080484b8: jge 0x80484b6; leave; ret;
0x080484ee: adc byte [eax], bh; mov ecx, dword [ebp - 4]; leave; lea esp, [ecx - 4]; ret;
0x080484ef: mov eax, 0; mov ecx, dword [ebp - 4]; leave; lea esp, [ecx - 4]; ret;
0x080484f2: add byte [eax], al; mov ecx, dword [ebp - 4]; leave; lea esp, [ecx - 4]; ret;
0x080484f5: dec ebp; cld; leave; lea esp, [ecx - 4]; ret;
If you’re searching for a ret-to-reg gadget, you’re only interested into call reg
ones; you can do this with regexp, with /R/
[0x08048350]> /R/ call e[abcd]x
0x080483a3 0085c0741155 add byte [ebp + 0x551174c0], al
0x080483a9 89e5 mov ebp, esp
0x080483ab 83ec14 sub esp, 0x14
0x080483ae 6824a00408 push 0x804a024
0x080483b3 ffd0 call eax
0x080483a8 55 push ebp
0x080483a9 89e5 mov ebp, esp
0x080483ab 83ec14 sub esp, 0x14
0x080483ae 6824a00408 push 0x804a024
0x080483b3 ffd0 call eax
0x080483ac ec in al, dx
0x080483ad 1468 adc al, 0x68
0x080483af 24a0 and al, 0xa0
0x080483b1 0408 add al, 8
0x080483b3 ffd0 call eax
0x080483e2 89e5 mov ebp, esp
0x080483e4 83ec10 sub esp, 0x10
0x080483e7 50 push eax
0x080483e8 6824a00408 push 0x804a024
0x080483ed ffd1 call ecx
0x080483e5 ec in al, dx
0x080483e6 105068 adc byte [eax + 0x68], dl
0x080483e9 24a0 and al, 0xa0
0x080483eb 0408 add al, 8
0x080483ed ffd1 call ecx
0x08048434 0085d274f255 add byte [ebp + 0x55f274d2], al
0x0804843a 89e5 mov ebp, esp
0x0804843c 83ec14 sub esp, 0x14
0x0804843f 50 push eax
0x08048440 ffd2 call edx
0x08048436 d274f255 sal byte [edx + esi*8 + 0x55], cl
0x0804843a 89e5 mov ebp, esp
0x0804843c 83ec14 sub esp, 0x14
0x0804843f 50 push eax
0x08048440 ffd2 call edx
0x08048438 f255 push ebp
0x0804843a 89e5 mov ebp, esp
0x0804843c 83ec14 sub esp, 0x14
0x0804843f 50 push eax
0x08048440 ffd2 call edx
0x08048439 55 push ebp
0x0804843a 89e5 mov ebp, esp
0x0804843c 83ec14 sub esp, 0x14
0x0804843f 50 push eax
0x08048440 ffd2 call edx
0x0804843b e583 in eax, -0x7d
0x0804843d ec in al, dx
0x0804843e 1450 adc al, 0x50
0x08048440 ffd2 call edx
Well, we only want the call reg
part, we don’t care about the previous operands:
[0x08048350]> /R/ call e[abcd]x~call
0x080483b3 ffd0 call eax
0x080483b3 ffd0 call eax
0x080483b3 ffd0 call eax
0x080483ed ffd1 call ecx
0x080483ed ffd1 call ecx
0x08048440 ffd2 call edx
0x08048440 ffd2 call edx
0x08048440 ffd2 call edx
0x08048440 ffd2 call edx
0x08048440 ffd2 call edx
Ho, by the way, if you want to search for several gadgets, the separator is ;
, which also happen to be the one to seperate commands in r2. This is why you need to quote the whole command like this:
[0x08048350]> "/R/ inc *;ret"
0x08048413 ffc6 inc esi
0x08048415 0524a00408 add eax, 0x804a024
0x0804841a 01c9 add ecx, ecx
0x0804841c f3c3 ret
0x080484b3 ff83c4108b7d inc dword [ebx + 0x7d8b10c4]
0x080484b9 fc cld
0x080484ba c9 leave
0x080484bb c3 ret
0x0804867c 41 inc ecx
0x0804867d c3 ret
[0x08048350]>
It’s possible to change the depth of the search, to speed-up the hunt:
[0x08048320]> e search.roplen = 4
[0x08048320]> /R mov ebp,call eax
0x08048386 call eax
0x0804837a 89e5 mov ebp, esp
0x0804837c 83ec18 sub esp, 0x18
0x0804837f c7042420a00408 mov dword [esp], 0x804a020
0x08048386 ffd0 call eax
0x0804840f call eax
0x08048403 89e5 mov ebp, esp
0x08048405 83ec18 sub esp, 0x18
0x08048408 c70424109f0408 mov dword [esp], 0x8049f10
0x0804840f ffd0 call eax
[0x08048320]>
And as always, you can append j
to get a JSON output.
The next step might be ROP chain assembling and manipulation, and why not automatic-construction, à la mona.py? Or maybe a semantic search powered by ESIL?
Anyway, contributions are welcome, and if you’re using radare2 to pop somes shells, we’ll be delighted to know about it!