오랫만에 windows 카테고리에 글을 올린다. 


이전까지 했던 bufferoverflow 는 DEP 를 고려하지 않은 기본 상태의 윈도우가 대상이었다.


이번에는 ROP를 이용하여  DEP를 우회할 수 있음을 확인해 보자. 


# DEP ( Data Execution Prevention)

  • 데이터 실행 방지(Data Execution Prevention, DEP)는 현대의 마이크로소프트 윈도 운영 체제에 포함된 보안 기능이며, 실행 방지 메모리 영역의 실행 코드에서응용 프로그램이나 서비스가 실행되지 못하게 막기 위해 고안된 것이다. 이를테면 버퍼 오버플로를 통한 코드를 저장하는 특정한 이용을 막을 수 있다. DEP는 두 가지 모드로 실행된다.:
  • CPU를 위한 하드웨어 강화 DEP: 메모리 페이지를 실행 불가능 상태로 표시한다.
  • 소프트웨어 강화 DEP: CPU가 하드웨어적으로 데이터 실행 방지를 지원하지 못하는 경우 이를 사용한다.

  DEP는 윈도 XP 서비스팩 2에 도입되었으며 윈도 XP 태블릿 PC 에디션 2005, 윈도 서버 2003 서비스팩 

 1, 도 비스타에 포함되어 있다. 나중에 나오는 운영 체제들은 이 기능을 여전히 지원하고 있다.

- 위키피디아 - 


즉, bufferoverflow 를 통한 임의의 코드 실행을 막기 위해 운영체제에 도입된 기능(물론 *nix 에도 있다) 이며,


크게 S/W DEP 와 H/W DEP 가 존재한다. 하지만 최근 CPU는 대부분 DEP를 지원하므로 일반적으로 DEP라 함은


H/W DEP 를 말한다고 생각하면 된다.




# DEP 의 종류


 종류

설명 

 OptIn

지정된 바이너리만 보호 

 OptOut

지정된 바이너리를 제외하고 모두 보호

 AlwaysOn

모든 프로세스를 보호

 AlwaysOff

모든 프로세스를 보호하지 않음 




# OS버전별 DEP 기본정책


 종류

설명 

 Windows XP SP2~, Vista SP0

OptIn

Windows VIsta SP1~

OptIn + AlwaysOn + Permanent DEP

 Windows 7

OptOut + AlwaysOn + Permanent DEP

Windows Server 2003 Sp1~

OptOut 

 Windows Server 2008~

 OptOut + AlwaysOn + Permanent DEP





# DEP가 적용된 후의 bof 공격


[ 그림1 ] DEP 설정 변경




[ 그림2 ] DEP로 인한 실행 방지



일반적인 BOF 시도시 실행권한이 없는 스택영역에서 코드실행이 시도되므로 위와 같이 DEP에 의해 차단된다. 즉 공


격이 성공하기 위해서는 먼저 DEP를 무력화 시켜야 한다. 이 DEP를 무력화 하는 데에는 여러 가지 방법이 존재하며, 


현재 DEP의 상태와 바이너리 상태에 따라 선택하면 된다.



# DEP 우회를 위한 Windows API 체인

 API 체인

설명 

VirtualProtect()

메모리 영역 실행권한 변경

 VirtualAlloc() + memcpy()

            실행가능한 새로운 메모리 할당 후 쉘코드 복사

HeapCreate() + HeapAlloc() + memcpy()

VirtualAlloc 과 유사

SetProcessDEPPolicy()

실행중인 프로세스의 DEP 정책 변경

NtSetInformationProcess()

실행중인 프로세스의 DEP 정책 변경 

WriteProcessMemory()

쉘코드를 쓰기/실행 가능한 영역에 복사하여 실행


위의 API 체인 외에도 전형적인 RTL(Return To Library) 방식으로도 우회가 가능하다. 이 경우에도 ROP를 통해 


인자값을 구성해 주어야 한다.



# VirtualProtect() 를 활용한 DEP 우회


위와 같이 DEP를 우회하는 방법은 다양하다. 상황에 따라 적용하면 되며, 이번에는 VirtualProtect() API 를 이용하여


우회를 해 보자. 먼저 함수의 인자값을 살펴보자.




첫번째 인자 ( lpaddress ) 는 변경할 주소값, 두번째 인자는 변경할 메모리 크기, 세번째 인자는 변경할 Flag(RWX등)


네번쨰 인자는 현재의 Flag 를 저장할 주소다. 이러한 인자값의 구성은 ROP 를 통해 이루어 지며, 먼저 ROP 에 대해


간략히 알아보자.





# ROP 기본 개념


ROP(Return Oriented Programming) 이란, Gadget(RET 로 끝나는 특정 명령 집합) 을 연속으로 호출하여 원하는 


명령을 수행하도록 하는 것이다. 기본적인 개념은 RTL 과 비슷하다. 코드 영역에 있는 영역으로 jump 하여 원하는


명령을 수행한 후, RET 명령을 통해 다시 원래의 스택으로 돌아오고, 다시 다음 가젯을 실행하는 식으로 명령 조각을


실행해 나가는 것이다. 이해를 쉽게 하기 위해 예를 들어보도록 하자.


 ※ RET = POP EIP 의 명령과 동일하므로 스택에 있는 가젯 주소를 차례대로 불러와 실행하게 된다.




# 가젯 예제

 ex1) ESP+18 

   -> ESP+18, RETN  


 ex2) MOV ESI, EAX

   -> PUSH ESI, POP EAX, RETN 



위와 같은 방식으로 목표한 명령이 포함된 가젯을 찾아서 연결해 주면 된다. 이러한 가젯을 쉽게 찾을 수 있도록


도와주는 몇가지 툴이 존재한다. (ropeme, pvefindaddr, mona.py 등) 이는 다음에 자세히 알아보도록 할 것이다.


ex1) ESI 에 0x60  값을 저장

 XOR EAX,EAX / RETN

 EAX 를 0으로 초기화

 ADD EAX,0x30 / RETN

 EAX 에 0x30 을 더함 

 ADD EAX,0x30 / RETN

 EAX 에 0x30 을 더함  

 PUSH EAX / POP ESI / RETN 

 스택을 통해 ESI 에 0x60 저장 


위와 같이 가젯을 4번 호출하여 원하는 명령어인 MOV ESI,0x60 과 동일한 명령을 수행하도록 만들어 냈다.


이러한 원리를 이용하여 DEP 우회를 위한 인자값을 구성하여 준 뒤 함수를 호출하게 되며, 함수 호출 후 쉘코드로


이동하여 기존의 BOF 공격과 동일하게 쉘코드를 실행시키게 된다.





# 신뢰성 있는 가젯을 찾기 위한 조건


 - 가젯의 주소에 0x00 이 없어야 함


 - 가젯이 존재하는 모듈은 ASLR 이 적용되지 않아야 함


 - 가젯이 존재하는 모듈은 재배치 되지 않아야 함 ( DLL Rebase ) 





# 기존 Direct RET Overwrite 의 스택 구성


Low Address

 1

 AAAAAAAAA....

 버퍼를 채우기 위한 쓰레기값

 2

 Jump to Shellcode

 쉘코드로 가기 위한 값 

 - 일반적인 direct EIP overwrite 의 경우 jmp esp 등

 - seh based exploit 의 경우 주로 pop pop ret 사용

   ( nseh + seh + nop + shellcode )

 3

 Nop + Shellcode

 



# VirtualProtect() 를 위한 가젯 구성


Low Address

 1

 AAAAAAAAA....

 버퍼를 채우기 위한 쓰레기값

 2

 Stack Pivot

 ROP 시작부분으로 가기 위한 값 

 - 일반적인 direct EIP overwrite 의 경우 RETN

 - seh based exploit 의 경우 esp+xx 의 pivot 필요 

 3

 ROP1 for Save Stack Pointer

 현재 스택값을 저장 / 인자값 주소 계산 등에 필요

 4

 VirtualProtect() Addr + Parameters

 VirtualProtect()주소, 실행 후 리턴값 및 함수의 인자값4개

 5

 ROP2 for VirtualProtect Parameter1

 Parameter1 값 생성 및 입력

 6

 ROP3 for VirtualProtect Parameter2 

 Parameter2 값 생성 및 입력 

 7

 ROP4 for VirtualProtect Parameter3

 Parameter3 값 생성 및 입력

 8

 ROP5 for VirtualProtect Parameter4

 Parameter4 값 생성 및 입력

 9

 Jump to VirtualProtect()

 4 로 돌아감 

 10

 Nop + Shellcode 

 4에서 VirtualProtect() 실행 후 돌아올 주소

 (쉘코드)

High Address




언뜻 봐도 기존의 ret 를 직접 덮어쓰는 exploit 에 비교해 훨씬 복잡해 보인다. 실제로 매우 복잡하다. 


이제 다음 블로깅에서는 직접 immunity debugger 를 활용하여 exploit 을 만들어 보자.




  1. craft 2013.06.25 15:36

    잘보고갑니다~^^

  2. jin 2013.08.09 07:41

    수고하십니다. 글 읽다가 궁금한 부분이 있어 질문드립니다.
    Ex1)에서 뒤에 ret는 무슨 의미인가요?
    명령어 실행뒤에 다시 ret한다는 의미인가요?
    보시고 조언 좀 부탁드립니다 ^^

+ Recent posts