-->

RTL(Return to Library) Chaining 이란?

역시 정리하지 않으면 잊어버리는 것이 사람인 것 같다. 나만 그럴수도... ROP 개념을 정리하는 와중에 먼저 RTL Chaning 부터 제대로 정리하자는 생각이 들어 여기에 정리한다.

 

 

RTL(Return to Library) 이란

일단, RTL은 메모리에 이미 적재되어있는 공유 라이브러리를 이용해 원하는 함수를 실행시키는 기법이다. func1 함수를 실행시켜야 한다는 가정에서 아래 예를 봐보자. [buf + SFP +RET] 의 RET 자리에 func1 함수의 주소값이 들어갔고 4바이트의 dummy 후에 func1함수의 인자값이 들어간 구조가 됐다.

 

참고로 여기서 설명을 위해 사용하는 func1은 인자가 1개인 함수이고 func2는 인자가 2개가 필요한 함수라는 가정이다.

 

// 기존 스택 상황
buf + SFP + RET

// RTL을 적용한 스택 상황
buf + SFP + func1 address + dummy + func1 argv[0]

 

여기서 먼저, RET라는 어셈블리에 대해 알아야 할 것이있다. RET는 첫번째로 pop을 함으로써 다음 실행 주소가되는 eip에 현재 스택에 있는 값을 넣고 (pop을 하는 순간 esp는 +4가 됨) 그 값으로 점프하는 명령어이다. 

 

// RET
pop eip // eip에 return 주소를 넣음
jmp eip // return 주소로 점프

 

 

즉, [buf + SFP + func1 address + dummy + func1 argv[0]] 의 스택구조를 인위적으로 만들게 되면, 원래의 RET 자리에 system 함수의 주소값이 왔으므로 eip가 func1 함수의 주소가 되어 func1 함수가 실행이 된다. 그리고 esp +4에 func1 함수의 인자값을 구성해주었기 때문에 'func1(func1 함수 인자)'가 실행되게 된다. 아래 순서표를 보면, 좀더 쉽게 이해가 갈 것이다.

 

 

1) 원래의 RET 자리에 func1 함수 주소가 있음, eip에 현재의 esp 값인 func1 함수 주소가 들어감

 

buf SFP func1 addr dummy (func1 ret) func1 argv
    esp --> eip esp+4  

 

 

2) pop에 의해 esp는 +4가 되고 func1 함수 주소값으로 jmp

 

buf SFP func1 addr dummy (func1 ret) func1 argv
    eip esp  

 

 

3) esp는 func1 함수의 리턴주소, esp+4는 인자값이므로 func1(func1 argv[0])가 실행됨

 

buf SFP func1 addr dummy (func1 ret) func1 argv
      esp esp+4

 

 

원래 dummy 자리는 func1의 RET 자리이지만 어차피 함수 실행이 목적이므로 그 이후의 RET은 따로 신경쓰지는 않았기에 그냥 dummy를 주었다.

 

 

RTL Chaining 이란

RTL Chaninig 이란 위에서 살펴본 RTL을 체인처럼 엮어서 연속적으로 수행하는 것을 말한다. 이 때, 위와 같은 상황을 연속적으로 만들어주기 위해선 PPR(pop-pop-rtr)가젯이 필요한데 P의 갯수는 필요한 인자값에 따라 달라진다. system 함수보다 먼저 실행시켜주어야 하는 setreuid의 경우 인자값이 2개이기 때문이다.

 

여기서 ppr 가젯이 필요한 이유는 pop이 esp를 올려주고 ret이 esp가 가리키는 곳으로 돌아가기 때문이다. 이 ppr 가젯을 func1과 func2 구성 사이에 채워주면 func2 실행 후 다시 func1이 실행될 수 있게끔 esp 값을 올려줄 수가 있다.

 

// 단일 RTL
buf + SFP + func1 address + dummy + func1 argv[0]

// RTL Chaining (func2 -> func1)
buf + SFP + func2 address + PPR Gadget + func2 argv[0] + func2 argv[1] + func1 address + dummy + func1 argv[0]

 

 

다음의 사실들을 잘 인지하면서 아래 순서표를 보면 이해하기 쉬울 것이다.

 

  • pop은 esp를 올려준다. 
  • 예를 들어, pop eip는 현재 esp 값을 eip에 넣는다는 뜻이다. (그리고 esp는 +4가 됨) 
  • ret은 pop eip, jmp eip 이다. (따라서 esp는 +4가 됨)

 

1) RET 자리의 func2의 주소값에 의해 func2(func2 argv[0], argv[1])이 실행됨

 

buf SFP func2 addr PPR func2 argv[0] func2 argv[1] func1 addr dummy func1 argv[0]
    eip esp esp+4 esp+8      

 

 

2) func2 실행 후 esp가 가리키고 있는 PPR 가젯으로 리턴, esp는 +4가 됨

 

buf SFP func2 addr PPR func2 argv[0] func2 argv[1] func1 addr dummy func1 argv[0]
      eip esp esp+4 esp+8    

 

참고로, PPR 가젯 주소를 구하는 방법은 여러가지가 있지만 아래처럼 objdump로 구할 수 있다.

 

 

 

3) PPR의 pop pop 실행으로 인해 esp가 +8이 됨 

 

buf SFP func2 addr PPR func2 argv[0] func2 argv[1] func1 addr dummy func1 argv[0]
            esp    

 

 

4) PPR의 ret 실행으로 인해 현재 esp 위치에 있는 func1 주소로 점프, func1(func1 argv[0])이 실행됨

 

buf SFP func2 addr PPR func2 argv[0] func2 argv[1] func1 addr dummy func1 argv[0]
            eip esp esp+4

 

댓글

Designed by JB FACTORY