제가 분석한 바로는 EMET 4.1 에서는 ROP를 차단하기 위해 주요 함수들 - VirtualProtect / VitualAlloc 등을 후킹 한 뒤, 해당 함수들의 호출 지점을 디스어셈블링 하여 해당 함수가 Call로 호출되는지 판단합니다.

패킹된 EXE면 항상 Call 한다는 보장이 없기 때문에, 테스트를 해보았습니다.

 

해당 EXE를 빌드 후, CodeVirtualizing 하였습니다

그 다음 해당 EXE를 EMET로 보호 후, 디버거를 붙인 다음 VirtualProtect 지점에 BP를 걸었습니다.

 

ESP가 가리키는 리턴 주소가 0x40A277입니다. 따라가봅니다.

 

0x40A277 부분이 CALL이 아닌 JMP군요. 논패킹 EXE라면 아래 그림과 같이 되어있습니다.

 

EMET는 호출 지점이 Call이 아니면 진단합니다.

  

보통 ROP는 RETN / JMP 로 함수를 호출하기 때문에 이런 방어법은 강력한 차단 수단이 될 수 있지만, 패킹된 프로그램의 경우 오진이 발생하니 패킹 여부를 인식할 필요가 있을 것 같습니다. 

 

항상 JMP로 4바이트 점프만 해오다 JMP SHORT으로 1바이트 점프할 일이 생겨 정리를 하게 되었습니다.

결론부터 말씀드리면, 기준주소에서 -0x7E(126바이트), +0x81(129바이트) 까지 총 0xFF(255바이트) 점프할 수 있습니다.

 

# 앞 주소로 점프하는 경우

기준 주소 0x7243F281입니다. 최대 0x7243F203, 즉 -0x7E까지 점프할 수 있습니다.

오프셋 계산은 점프 할 주소 - 기준 주소 - 2 = 0x80

위 그림을 확인하여 주세요.

 

 # 뒷 주소로 점프하는 경우

 기준 주소 0x7243F281입니다. 최대 0x7243F302, 즉 +0x81까지 점프할 수 있습니다.

 

오프셋 계산은 점프 할 주소 - 기준 주소 - 2 = 0x7F

위 그림을 확인하여 주세요.

 

 

최근 자주 쓰이는 공격 기법중에 하나가 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