최근 자주 쓰이는 공격 기법중에 하나가 ROP 공격이며, exploit들을 검색해 보셨다면 한번 쯤은 접해보셨을 것입니다.

ROP는 Return Oriented Programming의 약자이며,

흔히 볼 수 있는 위와 같은 유형을 리턴 기반의 프로그래밍이라고 합니다..

그러나 통상적으로 ROP를 일컬을 때는 메모리 상의 명령어들을 모아서 리턴 기반으로 명령어들을 순차적으로 실행하는 것을 말합니다

무슨말인지 감이 잘 안오시죠? 예제 소스를 보면서 설명하겠습니다.

 

attack() 함수를 보면 전형적으로 리턴 주소를 덮어씌우는 공격입니다.

attack()의 수행 후 return 시 main() 함수로 되돌아 가야 하지만 &a+5로 인하여 main()으로 가는 리턴 주소는 rop_gadget 변수로 덮어 씌어졌습니다.

이로써 attack() 함수가 리턴 될 때 스택은 rop_gadget 변수를 가리키고 있습니다.

보시다시피, RETN Breakpoint를 걸고 스택을 살펴보면 rop_gadget 변수로 덮어 씌여져 있습니다.

RETN을 수행하면 현재 스택이 가리키고 있는 0x759900B5로 가게 됩니다.

RETN이 수행되고 0x75990215를 가리키고 있습니다.

Attack() 함수에서 RETN이 수행되었으니 스택은 4가 증가하게 됩니다.

순차적으로 NOP RETN이 실행되고, RETN 시 스택을 살펴보면 0x75990215를 가리키고 있습니다.

마찬가지로 RETN을 수행하면 스택이 가리키고 있는 주소로 가게 됩니다.

0x75990215입니다. 순차적으로 NOP, RETN이 실행되고, 마찬가지로 RETN 시 스택을 살펴보면 0x759DEA4D를 가리키고 있습니다.

 

 

rop_gadget 변수의 마지막입니다. 원리는 같으므로, 설명은 생략하겠습니다.

RETN 시 되돌아 가는 지점을 구성하지 않았기 때문에 RETN을 하면 0x00000000으로 가게 되어 crash가 발생됩니다.

이렇게 구성한 주소의 명령어들을 순차적으로 실행하게 하는 것이 ROP라 하고 이 주소들을 연속적으로 이은 것을 ROP CHAIN, 혹은 ROP GADGET이라고 합니다.

보통 ROP GADGET을 만들 때는 기존 메모리 상에 존재하는 명령어들로 구성하게 됩니다.

이 예제 소스와 같이 NOP RETN을 구성하고 싶다면 메모리 상에서 90 C3을 찾으면 됩니다.

통상적으로 ASLR이 적용되면 모듈이 메모리 주소 공간에 랜덤하게 매핑되므로, JRE 같은 ASLR이 적용되지 않은 모듈을 찾아서 재구성을 해야 합니다. (해당 주소들은 제 환경에 맞게 하드코딩 된 것이므로 직접 찾아서 구성해보시길 바랍니다. 물론 XP의 경우는 해당사항이 없을 것 입니다.)

이로써 ROP의 개념을 살펴보았고 다음 편에서는 좀 더 심화된 내용을 다루겠습니다.

+ Recent posts