SafeSEH 우회

SafeSEH는 SEH 체인에 등록된 Next SEH와 핸들러를 덮어씌워 공격하는 SEH Overwrite 공격을 차단하기 위해 만들어진 보호 기법이다.


프로그램 실행 시 예외가 발생하면 SEH 체인에 등록 된 예외 처리 핸들러를 호출하기 전 ntdll.dll의 KiUserExceptionDispatcher 함수가 호출된다.


이 함수가 호출되면 예외 처리 핸들러의 주소가 변조되었는지 확인 후 적절한 핸들러라면 예외 처리 핸들러가 호출된다.

 

만약, 핸들러의 주소가 변조되면 핸들러를 호출하지 않고, 핸들러의 주소가 변조되지 않으면 핸들러를 호출하여 예외 처리를 한다. 현재 예외를 처리하지 못하면 Next SEH 체인으로 넘어가게 되는데 이 때마다 검증 과정을 거친다.


구분 내용
1 예외 처리 핸들러의 주소가 스택 주소를 가리키고 있다면 예외 처리 핸들러는 호출되지 않음
2 예외 처리 핸들러의 주소가 스택 주소를 가리키고 있지 않고, 프로그램에서 로드 된모듈 주소 중 SafeSEH가 적용 된 모듈 주소(ntdll.dll 등)를 가리키고 있다면 로드 설정 디렉토리(Load Configuration Directory)와 비교하여 일치하지 않을 경우 예외 처리 핸들러는 호출되지 않음

safeseh_reader.cpp는 입력 받은 파일의 내용을 1000 바이트 읽어 500 바이트 크기의 readbuf 변수에 저장할 때 스택 버퍼 오버플로우가 발생한다.


SafeSEH를 실습하기 위해 컴파일러 옵션을 설정하고, 컴파일하면 스택 쿠키와 SafeSEH가 적용된 safeseh_reader.exe 파일이 생성된다.


#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <windows.h>
 
int main(int argc, char* argv[])
{
         char readbuf[500] = {0, };
         printf(" # text reader #\n");
         if (argc != 2) {
                 printf(" Usage : reader.exe filename\n", argv[0]);
                 exit(1);
         }
         FILE *f = fopen(argv[1], "r");
         fgets(readbuf, 1000, f);
         printf("File Contents : %s\n", readbuf);
}

프로젝트 속성 > 구성 속성 > C/C++ > 코드 생성 > 보안 검사 : 보안 검사 사용(/GS)


컴파일러 옵션

프로젝트 속성 > 구성 속성 > 링커 > 고급

○ 임의 기준 주소 : 아니오(/DYNAMICBASE:NO)

○ DEP(데이터 실행 방지) : 아니요(/NXCOMPAT:NO)

○ 이미지에 안전한 예외 처리기 포함 : 예(/SAFESEH)


컴파일러 옵션


safeseh_reader.exe 파일을 인자([표 2-20]의 exploit1.txt) 지정하여 열면 예외가 발생하여 프로그램이 종료된다.


프로그램 실행 시 예외 발생


이뮤니티 디버거로 !mona exchain 명령어를 입력하면 현재 등록 된 SEH 체인을 확인할 수 있다. 예외가 발생하면 첫 번째 예외 처리 핸들러(0x6a02a0d5)가 호출된다.


이 주소는 검증 시 적절한 주소라고 판단하여 호출된다. 하지만, 다음 예외 처리 핸들러(0x401530)는 비교 루틴을 거치게 된다. 비교 루틴 거친 결과 적절한 주소가 아니므로 해당 예외 처리 핸들러는 호출되지 않고 다음 예외 처리 핸들러(0x00)를 검증하게 된다.


SafeSEH가 어떤 식으로 검증하는지 확인하고 싶으면 예외가 발생한 지점, 첫 번째 예외 처리 핸들러에 각 브레이크 포인트를 설정하고 디버깅하기 바란다.


예외 발생 후 SEH 체인


현재 프로그램은 SafeSEH 옵션을 활성화하여 컴파일하였으므로 SafeSEH가 적용되어 있다.


다른 프로그램에 SafeSEH가 적용되어있는지 확인하려면 !mona modules 명령어를 입력하면 현재 실행중인 프로그램 및 모듈에 SafeSEH가 적용 유무를 확인할 수 있다.


○ !mona modules


SafeSEH 적용 여부

SafeSEH가 적용되었는지 확인하는 또 다른 방법으로 PEview 프로그램이 있다. 이 프로그램을 이용하여 SafeSEH 적용 유무 확인 후 SafeSEH Handler Table에 등록 된 예외 처리 핸들러(_except_handler)를 찾아가 보자.


PEview 프로그램으로 safeseh_reader.exe 파일을 열어 IMAGE_OPTIONAL_HEADER > LOAD CONFIGURATION Table 주소를 확인한다.


○ IMAGE_OPTIONAL_HEADER > LOAD CONFIGURATION Table


LOAD CONFIGURATION Table

PEview 프로그램에서 확인한 LOAD CONFIGURATION Table 주소(0x402160) 찾아가보면 SafeSEH Handler Table 주소(0x402290)를 확인할 수 있다.


○ 덤프 창 > Ctrl + G > 402160


LOAD CONFIGURATION Table


IMAGE_LOAD_CONFIG_DIRECTORY 구조체의 마지막 두 번째 멤버가 SafeSEH Handler Table이다. 이 멤버는 예외 처리 핸들러의 목록을 가지고 있는 멤버로 프로그램 실행 시 여기에 있는 주소가 아니면 실행되지 않는다.


IMAGE_LOAD_CONFIG_DIRECTORY


/* winnt.h - IMAGE_LOAD_CONFIG_DIRECTORY32 */
 
typedef struct {
    DWORD   Size;
    DWORD   TimeDateStamp;
    WORD    MajorVersion;
    WORD    MinorVersion;
    DWORD   GlobalFlagsClear;
    DWORD   GlobalFlagsSet;
    DWORD   CriticalSectionDefaultTimeout;
    DWORD   DeCommitFreeBlockThreshold;
    DWORD   DeCommitTotalFreeThreshold;
    DWORD   LockPrefixTable;            // VA
    DWORD   MaximumAllocationSize;
    DWORD   VirtualMemoryThreshold;
    DWORD   ProcessHeapFlags;
    DWORD   ProcessAffinityMask;
    WORD    CSDVersion;
    WORD    Reserved1;
    DWORD   EditList;                   // VA
    DWORD   SecurityCookie;             // VA
    DWORD   SEHandlerTable;             // VA
    DWORD   SEHandlerCount;
} IMAGE_LOAD_CONFIG_DIRECTORY32, *PIMAGE_LOAD_CONFIG_DIRECTORY32;

VA & RVA
VA(Virtual Address)는 프로세스 가상 메모리의 절대 주소이며, 실제 물리적인 주소를 가상 주소로 사용한다.

RVA(Relative Virtual Address)는 기준 위치(ImageBase)부터의 상대 주소이다. VA와 RVA는 "RVA + ImageBase = VA" 관계식이 성립한다.

LOAD CONFIGURATION Table 주소는 0x2160이며 RVA이다. 이 주소에 ImageBase(0x400000) 주소를 더하면 VA(0x402160) 값을 확인할 수 있다.

SafeSEH Handler Table 주소(0x402290)를 따라가보면 예외 처리 핸들러 주소(0x401899)를 확인할 수 있다.


SafeSEH Handler Table


예외 발생 전 SEH 체인


SafeSEH 우회 방법은 총 세가지로 구분되며


첫째, safeseh_reader.exe 파일은 실습용으로 간단하게 제작한 프로그램이다. 실질적으로 사용하는 프로그램은 이 보다 많은 기능을 가지고 있고, 필요에 따라 다양한 DLL 파일을 로드해서 사용한다.


하나의 프로그램에 수 많은 DLL 파일 중에 SafeSEH가 적용되지 않는 모듈이 있다면 그 모듈의 POP POP RET 등과 같은 코드 조각을 이용하면 쉽게 우회가 가능하다.


둘째, 공격 코드가 힙 주소의 어떤 위치에 로드되고, 어떤 위치에 프로그램의 코드가 위치하고 있는지 사전에 파악해야 우회가 가능가다.


셋째, 프로그램에서 다른 메모리 영역의 모듈 주소를 이용하면 우회가 가능하다. 이 방법은 윈도우 XP에서 unicode.nls 모듈의 "CALL DWORD PTR [EBP+0x30] : FF 55 30" 코드 조각을 이용하면 우회가 가능하다.


unicode.nls 모듈은 여러 프로세스에서 사용하는 모듈로 정적인 주소이다. 하지만, 윈도우 7 이상부터 unicode.nls 모듈이 존재하지 않는다.


구분 내용
1 프로그램에서 로드 된 모듈 중 SafeSEH가 적용되지 않는 모듈이 있다면 예외 처리 핸들러는 호출됨
2 예외 처리 핸들러의 주소가 힙 주소로 덮어씌워져 있다면 예외 처리 핸들러는 호출됨
3 예외 처리 핸들러의 주소가 프로그램에서 로드 된 모듈이 아닌 다른 메모리 영역의 모듈 주소를 가리키고 있다면 예외 처리 핸들러는 호출됨

SEH Overwrite, SafeSEH 우회 공격은 핸들러에 Next SEH로 이동하는 코드를 주입해야 한다. SEH Overwrite는 POP POP RET를 이용해 우회를 했지만, 해당 코드 이외에도 우회할 수 있는 코드 조각이 있다.


○ CALL DWORD PTR [ESP+n]

○ JMP DWORD PTR [ESP+n]

○ CALL DWORD PTR [EBP+n]

○ JMP DWORD PTR [EBP+n]

○ CALL DWORD PTR [EBP-n]

○ JMP DWORD PTR [EBP-n]

○ CALL DWORD PTR [ESP-n]

○ JMP DWORD PTR [ESP-n]

○ ESP-16, ESP+8, ESP+16, ESP+1C, ESP+2C, ESP+32, ESP+40 등

○ EBP-18 등


▶ Tomabo MP4 Player 3.11.6 취약점 분석 (SEH Based Stack Overflow)

▶ Stack Adjustment - Stack BOF

▶ SEH Overwrite - Stack BOF

▶ SEH(Structured Exception Handler) - Stack BOF

▶ Stack Cookie(GS Cookie) - Stack BOF

▶ Easy RM to MP3 Converter(Stack Buffer Overflow) 취약점 분석

▶ UAC(User Account Control) 우회 - PowerShell

  • 카카오톡-공유
  • 네이버-블로그-공유
  • 네이버-밴드-공유
  • 페이스북-공유
  • 트위터-공유
  • 카카오스토리-공유