상세 컨텐츠

본문 제목

01.RTL(Return to Libc) - x86

Pwnable Exploitation/03.RTL(Return to libc)

by RACC8N 2020. 5. 5. 14:40

본문

RTL이란 ?

- Return address 영역에 공유 라이브러리 함수의 주소로 변경해, 해당 함수를 호출하는 방식이다.

  • 해당 기법을 이용해 NX bit(DEP)를 우회 할 수 있다. 

Calling Convention

Cdecl(C declaration)

  • 해당 호출 규약(Calling Convention)은 인텔 x86 기반 시스템의 C/C ++ 에서 사용되는 경우가 많다.
  • 기본적으로 Linux kernel에서는 Cdecl 호출 규약(Calling Convention)을 사용한다.
  • 다음과 같은 특징이 있다.
    • 함수의 인자 값을 Stack에 저장하며, 오른쪽에서 왼쪽 순서로 스택에 저장한다.
    • 함수의 Return 값은 EAX 레지스터에 저장된다.
    • 사용된 Stack 정리는 해당 함수를 호출한 함수가 정리한다.
인자 전달 방법 Stack
인자 전달 순서 오른쪽에서 왼쪽 순서로 스택에 쌓인다
함수의 반환 값 EAX
Stack 정리 호출한 함수가 호출된 함수의 stack 공간을 정리함

[EXAMPLE]

  • "[ebp+0x8]" 부터 "[ebp+0x14]" 까지 vuln() 함수에 전달된 인자 값이다.
  • "[ebp+0x4]" 영역에는 해당 함수 호출 후 돌아갈 Return Address가 저장되어 있다.
  • "[ebp]" 영역에는 이전 호출 프레임이 저장되어 있다.

- 만약 ret했을 때, main함수로 복귀가 아닌 system("/bin/sh")함수를 호출 하고싶다면 다음과 같이 생각할 수 있다.

 > SFP[ebp] + ret("system")[ebp+0x4] + argv1("/bin/sh")[ebp+0x8] 

 

※ 주의 : ret주소에 라이브러리 주소를 넣어서 특정 함수를 call하는 건 일반적인 함수의 Call과는 다른 차이가 있다.

- 일반적인 함수의 Call은 실행후 복귀할 주소를 stack에 PUSH 하고 함수를 호출한다. [SFP + RET + ARGV1...]

  > 그리고 함수 실행이 끝나면 에필로그시 stack에 저장된 복귀 주소를 POP RIP하여 RIP로 JMP 하게 된다.

- 하지만 ret주소에 라이브러리 주소를 넣어서 특정 함수를 call 하게 되면 복귀할 주소를 stack에 PUSH하는 과정이 없다. [SFP + ARGV1...]

  > 따라서 함수 실행이 끝나면 에필로그시 RET주소가 아닌 ARGV1 값을 POP하게 된다. 

 

즉, ret2libc 기법 사용시 인자 값을 전달하기 위해서는 Return Address의 4byte 뒤에 인자 값을 전달해야 한다.

stack 평상 시 ret2libc
ebp-0x? BUF BUF
ebp SFP SFP
ebp+0x4 RET system() 함수 주소
ebp+0x8 Argv1 system() 함수가 끝내고 실행될 주소 (system()'s ret)
ebp+0xc Argv2 Argv1

- 따라서 SFP[ebp] + ret("system")[ebp+0x4] + argv1("/bin/sh")[ebp+0x8] 식은 다음과 같이 바꿔야 한다.

  > SFP[ebp] + (system) [ebp+0x4] + dummy [ebp+0x8] + (/bin/sh) [ebp+0xc]

 

※ 여러개의 함수를 ret을 통해 호출하고 싶을 경우, Gadget을 사용한다.  (Gadget : ret로 끝나는 연속된 명령어)

- 우리가 입력한 next return address를 가리키기 위해 사용했던 인자들을 pop하고, esp를 next return address가 있는 스택으로 맞춰 리턴하기 위해 사용한다.  (인자의 개수에 따라 pop의 개수를 정한다.)

 

[EXAMPLE] ppr Gadget

buf sfp setreuid ppr 3092(esp) 3092 system() dummy /bin/sh

1. setreuid 함수 호출 후 다음 실행할 명령어는 pop pop ret이므로 esp가 가르키고 있는 있는 첫 번째 인자를 pop 한다.

2. 그 다음 인자를 pop 한다.

3. 두번의 pop 완료 후 esp는 system()함수의 주소를 가리키고 있을 것이다. 여기서 ret으로 system 함수를 호출한다.

 

 

Proof of concept

  • main() 함수는 vuln() 함수를 호출한다.
  • vuln() 함수는 read() 함수를 이용해 사용자로 부터 100개의 문자를 입력받는다.
    • 여기에서 취약성이 발생한다. buf 변수의 크기는 50byte이기 때문에 Stack Overflow가 발생한다.
  • libc의 Base address를 얻기 위해 libc 영역에서 printf() 함수의 주소를 출력한다.

- 0x56555659 : vuln 함수가 끝나고 복귀할 주소

 

- 0xffffd50c : vuln 함수의 ret 주소

 

-  0xffffd4ba : buf의 시작 주소

 

  • buf변수의 위치는 0xffffd4ba 이며, Return address 위치와 82byte 떨어져 있다.
  • 즉, 사용자 입력 값으로 문자를 82개 이상 입력하면, Return address를 덮어쓸 수 있다.

- 0xf7e292d0 : printf 주소

 

- printf offset = (printf addr - libc_start_addr) = 0x512d0이다.

 

- system함수와 /bin/sh의 offset을 구했다.

 

Exploit

 

 

REF: https://www.lazenca.net/display/TEC/01.RTL%28Return+to+Libc%29+-+x86

 

01.RTL(Return to Libc) - x86 - TechNote - Lazenca.0x0

Excuse the ads! We need some help to keep our site up. List RTL(Return to Libc) RTL이란 Return address 영역에 공유 라이브러리 함수의 주소로 변경해, 해당 함수를 호출하는 방식입니다.해당 기법을 이용해 NX bit(DEP)�

www.lazenca.net

 

'Pwnable Exploitation > 03.RTL(Return to libc)' 카테고리의 다른 글

02.RTL(Return to Libc) - x64  (0) 2020.05.05

관련글 더보기

댓글 영역