profile image

L o a d i n g . . .

Return Oriented Programming(ROP) -x86

  • ROP( Return-oriented programming )란? 공격자가 실행 공간 보호(NXbit) 및 코드 서명(Code signing)과 같은 보안 방어가있는 상태에서 코드를 실행할 수있게 해주는 기술이다.
  • RTL + Gadgets

 

  • 이 기법에서 공격자는 프로그램의 흐름을 변경하기 위해 Stack Overflow 취약성이 필요하고"가젯(Gadgets)"이라고 하는 해당 프로그램이 사용하는 메모리에 이미 있는 기계 명령어가 필요하다.

 

Gadgets - POP; POP; POP; RET

ROP는 기본적으로 RTL 기법을 이용하며, 공격자는 RTL과 Gadgets을 이용해 공격에 필요한 코드를 프로그래밍 하는 것이다.

  • 01.RTL(Return to Libc) - x86 페이지에서 system() 함수만 호출하였다.
  • 하지만 프로그램 및 운영체제,등 다양한 상황에 따라 여러 개의 함수 호출이 필요할 수 있다.

 

여러 개의 함수를 호출하기 위해 사용되는 것이 Gadgets이며, 기본적으로 다음과 같은 Gadgets 이 사용된다.

  • 호출 하는 함수의 인자가 3개 일 경우 : "pop; pop; pop; ret"
  • 호출 하는 함수의 인자가 2개 일 경우 : "pop; pop; ret"
  • 호출 하는 함수의 인자가 1개 일 경우 : "pop; ret"
  • 호출 하는 함수의 인자가 없을 경우 : "ret"

 

해당 Gadgets들의 역할은 ESP 레지스터의 값을 증가시키는 것이다.

  • RTL에 의해 호출되는 함수에 전달되는 인자 값이 저장된 영역을 지나 다음 함수가 호출될 수 있도록 하는 것.

 

다음과 같은 방법으로 여러 개의 함수를 연속해서 실행할 수 있다.

  • RTL에서 호출할 함수(주소 값이 저장된)의 다음 영역은 해당 함수가 종료된 후 이동할 Return Address 영역이다.
  • 해당 영역에 Gadgets의 주소를 저장함으로써 연속해서 다음 함수가 호출될 수 있다.
  • 아래 예제는 read() 함수 호출 후 System() 함수를 호출하게 된다.

 


PLT & GOT

프로시저 링키지 테이블(PLT, Procedure linkage table)에는 동적 링커가 공유 라이브러리의 함수를 호출하기 위한 코드가 저장되어 있다.

  • 해당 정보들은 ".plt" 섹션에 저장되어 있다.

 

  • 전역 오프셋 테이블(GOT, Global offset table)에는 동적 링커에 의해 공유 라이브러리에서 호출할 함수의 주소가 저장된다.
    • 이 정보들은 ".got.plt" 섹션에 저장된다.
    • 이 섹션은 공격자들의 공격 대상이 되며, 주로 힙, ".bss" Exploit에 의해 포인터 값을 변조 한다.

 

  • ROP에서는 해당 정보들을 유용하게 활용할 수 있다.

 


Overflow

실습에 쓸 rop.c 코드이다.

다음과 같이 빌드한다.

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

 

다음과 같이 Breakpoints를 설정한다.

  • 0x0804843b : vuln 함수 코드 첫부분
  • 0x0804844f : read() 함수 호출 전

 

다음과 같이 Overflow를 확인할 수 있다.

  • Return address(0xffffd00c) - buf 변수의 시작 주소 (0xffffcfce) = 62
  • 즉, 62개 이상의 문자를 입력함으로써 Return address 영역을 덮어 쓸 수 있다.

ret 주소 : 0xffffd00c

 

buf 주소 : 0xffffcfce

 

offset : 62

 


 

Exploit method

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

  1. read 함수를 이용해 "/bin/sh" 명령을 쓰기 가능한 메모리 영역에 저장
  2. write 함수를 이용해 read 함수의 .got 영역에 저장된 값을 출력
  3. read 함수를 이용해 read 함수의 .got 영역에 system 함수의 주소로 덮어씀
  4. read 함수 호출 - read .got 영역에 system 함수의 주소가 저장되어 있기 때문에 system 함수가 호출됨

 

이를 코드로 표현하면 다음과 같다.

read(0,writableArea,len(str(binsh)))
write(1,read_got,len(str(read_got)))
read(0,read_got,len(str(read_got)))
system(writableArea)

 

 

-> payload를 바탕으로 공격을 위해 알아내어야 할 정보는 다음과 같다.

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

 


이제 위에서 언급한 필요한 것들을 모두 구해보자!

 

Find a writable memory space

해당 바이너리의 0x0804a000 ~ 0x0804b000 영역에 쓰기권한이 부여되어 있다.

vmmap 명령어 사용

 

 

bss 영역이 writable section에 속하니 이를 "/bin/sh" 넣을 시작주소로 선택

 

 

Find gadget

rp-lin-x86 -f ./rop -r 4 | grep "pop"

"pop; pop; pop; ret"

 

 

Find plt, got address - read, write

read_plt : 0x8058300

write_plt : 0x8048320

 

read_got : 0x804a00c

 

wirte_got : 0x804a014

 

 

Find the address of the system() function

read_system_offset = 0x9ae50


Exploit

 

 

 

위의 논리대로 payload를 작성해보았다!

 

 

성공적으로 익스한 모습을 볼 수 있다.

 

 

참고
www.lazenca.net/display/TEC/01.ROP%28Return+Oriented+Programming%29-x86

'Hacking > Pwnable' 카테고리의 다른 글

[Pwnable] python으로 인자 및 stdin 전달  (0) 2021.04.01
[Pwnable] Lazenca - ROP(x64) 정리  (0) 2021.03.30
[Pwnable] PLT, GOT  (0) 2021.03.21
[Pwnable] Lazenca - RTL(x64) 정리  (0) 2021.03.21
[Pwnable] Lazenca - RTL(x86) 정리  (0) 2021.03.20
복사했습니다!