본문 바로가기

My Study/Exploit

Windows ShellCode 만들기 ( DEP란.. )

이번에는 간단하게 윈도우에서 cmd창을 띄우는 쉘코드를 만들어보도록 하겠습니다.
갈길은 한참 멀지만 차근차근 해보려고 합니다..;
==============================================
간단하게 cmd창을 띄울 때 사용하는 함수는 WinExec함수를 사용하도록 하겠습니다.
일단 C코드로 간단하게 보겠습니다.

WinExec함수는 내부적으로는 CreateProcessA -> CreateProcessInternalA -> CreateProcessInternalW
쭉쭉 이런식으로 호출되면서 결국 유니코드 스트링으로 처리가 되는데 일단 WinExec함수만을 봐보면 아스키를 사용하므로 이 쉘코드를 만들 땐 큰 어려움이 없습니다. 유니코드 인자로 사용하는 경우는 쉘코드를 만들 때 0x80보다 큰 문자가 들어오면 안됩니다.

C코드를 어셈블리로 봐보겠습니다.

단순하게 2개의 인자가 들어가고 kernel32.dll에 존재하는 0x75EDE76D(WinExec)를 호출합니다.

그러면 이 내용을 토대로 인라인어셈을 사용해 코드를 만들어보겠습니다.

그냥 하나의 함수형태로 만들기 위해 함수 프롤로그 에필로그 또한 넣어주었습니다.
일단 WinExec함수의 주소는 하드코딩 했습니다.
원래 WinExec함수의 주소는 kernel32.dll이 어디에 로드가 되는지에 따라서 최상위 16bit값이 달라지며
또한 kernel32.dll의 버전에 따라서 하위 16bit값 또한 달라지게 됩니다.

이렇게 하드코딩을 하면 쉘코드가 작동할 확율이 0% 가깝습니다.
이걸 해결하는 방법은 뒤에서 잠깐 설명하겠습니다. 일단은 하드코딩으로 해놓고 실행하겠습니다.

코드는 완성됬으니 한번 실행을 해보겠습니다.

cmd창 띄우는건 성공을 했습니다. 이제 코드를 \x형태로 바꾸겠습니다. 올디를 열어서 보면 됩니다.


옆에 있는 opcode값 입니다. 한번 써보겠습니다.

Shell 1 : \x55\x8B\xEC\x52\x57\x33\xD2\x68
WinExec Address : \x6D\xE7\x80\x76
Shell 2 : \x8b\xFC\x83\xEC\x08\x88\x55\xF3\xC6\x45
         \xF2\x65\xC6\x45\xF1\x78\xC6\x45\xF0\x65\xC7
         \x45\xEC\x63\x6D\x64\x2E\x8B\xD4\x6A\x01\x52
         \xFF\x17\x83\xC4\x0C\x5F\x5A\x8B\xE5\x5D

WinExec주소는 자꾸 바뀌기 때문에 저렇게 빼놨습니다. 이 쉘코드를 가지고 cmd창을 띄우는 코드를 보시겠습니다.

간단하게 인라인 어셈으로 해당 쉘코드가 있는 주소로 점프를 하게 했습니다.

이제 정상적으로 작동할까요?? 아닙니다. Windows XP라면 cmd창이 떴을 태지만 
Windows Vista 이후 버전 부터는 DEP설정이 디폴트로 On되어 있습니다.

DEP는 무엇일까요??
풀네임은 Data Execution Prevention 입니다.
말 그대로 데이터 실행을 보호한다는 것입니다.
해커가 특정 프로그램으로부터 취약점을 찾았습니다. 그래서 해커는 그 취약점을 사용해 쉘코드를 심고
쉘코드를 작동시킵니다. 이렇게 되면 사용자의 쉘을 따낼 수 있겠지요.

하지만 OS는 이를 막기위해 실행이 불가능한 영역에서 코드를 실행하려고 하면 예외를 발생시켜 버리고 프로그램을 종료해버립니다. 쉘코드는 보통 스택, 힙영역, data섹션.. 이런곳에 들어있을 탠데 해당 위치들은 데이터 read, write를 위한 공간이지 execution을 위한 공간이 아닙니다. 그래서 OS는 실행 불가능한 영역에서 코드가 실행되려고 하면 이를 막아버립니다.
바로 이게 DEP라는 기술입니다.

제가 위에서 실행했던 코드가 작동에 실패했던 이유는 힙영역에 있던 쉘코드를 실행하려고 했기 때문에 막힌 것입니다.

malloc에 의해 할당된 메모리는 0x5B12F0이며 해당 주소가 있는 위치의 Access를 보니 RW입니다.
실행 권한은 없는 것이지요. 그렇기 때문에 해당 주소로 가서 코드를 실행하려고 하는 순간!
예외가 발생해버리지요.

그래서 이 방법을 우회해서 쉘코드 실행을 성공할 수 있는 방법이 있습니다. ROP를 사용하는 방법인데 이에 관련된 내용은 다음 포스팅 때 올려보도록 하겠습니다. ( 공부를 해야합니다... ㅠㅠ )

전 이렇게 비정상적인 방법으로 DEP를 우회해 쉘코드를 실행시키는 방법이 아닌 정상적으로 쉘코드를 실행시키는 방법으로 해보겠습니다. 전 지금 공격하는게 아니라 쉘코드가 정상적으로 작동하는지 테스트를 해보기 위함이니까요.

첫번째는 해당 프로세스의 DEP기능을 꺼버리는 것이고, 두번째는 VirtualAlloc을 사용해 새로 메모리 공간 할당을 하고 해당 페이지의 Access를 RWE로 해버리는 것입니다.

일단 첫번째 방법인 DEP기능을 끄는 것입니다.

링커 - 고급을 가시면 Default로 DEP가 /NXCOMPAT되어 있는데 이 기능을 꺼주시면 됩니다.
이 기능을 켜 놓고 컴파일을 하게 되면 PE구조에서 값이 하나 생깁니다.

OPTIONAL_HEADER에서 DLL Characteristics를 보면 빨간색 네모친 값이 더 있습니다. 
헥사 에디터로 열어서 저 부분을 0으로 해주니 DEP기능은 사라지더군요.

두번째 방법인 VirtualAlloc을 사용하는 방법입니다. 코드를 보시겠습니다.

이렇게 VirtualAlloc함수 마지막 인자로 RWE권한을 줘서 해당 메모리에 쉘코드를 넣으면 됩니다.

이 두가지 방법은 나의 쉘코드가 정상적으로 작동하는지 테스트 해볼 때 하는 것이고 실제로 공격할 땐 DEP우회 ASLR우회 이런 것을 해줘야 할 것 같습니다. 추후 공부해서 올리도록 하겠습니다.

여기서 DEP관련된 API함수 3개를 봐보도록 하겠습니다.
DEP_SYSTEM_POLICY_TYPE WINAPI GetSystemDEPPolicy(void);
시스템에 셋팅되어 있는 DEP 정책을 가져온다.

DEP_SYSTEM_POLICY_TYPE -> enum
AlwaysOff 0 DEP기능 중지
AlwaysOn 1 예외없이 모든 프로세들은 DEP에 의해 보호
OptIn 2 제한된 모듈이나 바이너리만이 DEP에 의해 보호
OptOut 예외 리스트 내의 프로세들을 제외한 모든 프로세스들은 DEP에 의해 보호
Windows 7에서 실행해보니 결과 값은 2가 나왔습니다. 즉, 모든 프로세스가 보호 받는 것이 아닌 DEP가 셋팅된 프로그램만이 DEP보호를 받는 것입니다. 아까 위에서도 보셨듯이 링커 옵션에서 설정을 해줄 수가 있습니다.

BOOL WINAPI GetProcessDEPPolicy(
  __in   HANDLE hProcess,
  __out  LPDWORD lpFlags,
  __out  PBOOL lpPermanent
);
32bit 프로세스 환경에서 셋팅 된 DEP 그리고 DEP-ATL thunk에뮬레이션을 가져온다.

hProcess : 프로세스 핸들 ( Windows XP SP3은 이 파라미터가 무시된다. )
lpFlags : 아래 값들 중 하나 혹은 다수를 받는다.
0 : 특정 프로세스의 DEP는 비활성화 되어있다.
PROCESS_DEP_ENABLE 0x00000001 : 특정 프로세스의 DEP는 활성화 되어 있다.
PROCESS_DEP_DISABLE_ATL_THUNK_EMULATION 0x00000002 : 특정 프로세스의 DEP-ATL thunk emulation는 비활성화.
PBOOL : 특정 프로세스의 DEP가 영구적으로 활성화 됬거나 비활성화 됬다면 TRUE, 아니면 FALSE
        만약 이 파라미터가 TRUE이면 프로세스가 살아있는 동안 DEP 셋팅 상태(활성화 혹은 비활성화)는 지속되고                   SetProcessDEPPolicy 함수를 호출해도 DEP상태를 바꿀 수 없다.
이번에는 시스템 DEP가 아닌 프로세스 DEP입니다.
Windows7 기준으로 두번째 인자의 값은 0x3입니다. 0x1, 0x2가 OR연산 되어 있군요.
그리고 세번째 인자는 링커 옵션에서 DEP활성화 했을 땐 1이고 활성화 하지 않았을 땐 0입니다.
DEP상태를 바꿀 수 있는 함수가 SetProcessDEPPolicy함수인데 링커 옵션에서 DEP설정이 되어 있다면 SetProcessDEPPolicy함수를 사용해도 DEP를 비활성화 시킬 수 없습니다.

BOOL WINAPI SetProcessDEPPolicy(
  __in  DWORD dwFlags
);
32bit 프로세스 환경에서 DEP그리고 DEP-ATL thunk emulation셋팅 상태를 바꾼다.

dwFlags : 아래 값들 중 하나 혹은 다수(OR연산)
0 : DEP 비활성화 (시스템 DEP가 OptIn 혹은 OptOut 인 경우)
PROCESS_DEP_ENABLE 0x00000001 : 현재 프로세스에서 DEP를 영구적으로 셋팅. 한번 셋팅되면 프로세스가 죽을 때 까지 비활성화 할 수 없음
PROCESS_DEP_DISABLE_ATL_THUNK_EMULATION 0x00000002 : 현재 프로세스의 DEP-ATL thunk emulation 비활성화
현재 프로세스의 DEP정책을 바꾸는 것입니다.
각 플래그 값들에 대한 설명은 전부 해놨습니다.

위 3개의 함수가 DEP관련된 함수입니다.

이제 마지막으로 위 쉘코드에서 WinExec함수 주소를 하드코딩 하므로써 사용했는데 저 주소를 직접 얻어오는 방식으로 바꿔야 할탠데 다음에 PEB를 사용해 해당 주소를 직접 얻어오는 글도 올리겠습니다.
파일 분석을 하면서 알게된 방법입니다. 이 방법을 사용해 kernel32.dll 의 export테이블에서 함수 주소를 가져옵니다.

아직은 시작에 불과합니다. 아직도 모르는것 천국이군요 +_+;;