2015년 11월 24일 화요일

1. Direct Kernel Object Manipulation(DKOM)_운영체제 판단하기

커널 오브젝트를 공부하고 나서 이 부분을 '공격자 입장에서 어떻게 이용할 수 있을까?'해서 알아보게 되었다.

DKOM은 오브젝트 메니저를 거치지 않고 직접적으로 커널 오브젝트에 접근하기 때문에 당연히 커널 오브젝트에 대한 어떤 권한 체크도 이뤄지지 않는다.

DKOM의 문제점은, 견고하지 않다는 것이다. 커널 오브젝트를 변경하기 전에 프로그래머는 해당 오브젝트에 대한 아래와 같은 사항을 이해할 필요가 있다.

  • windbg을 이용하여 오브젝트의 구조체 정보를 알아내야한다.
    • 단순히, 'dt nt! _Object_Name' 형식 , ex) EPROCESS 구조체에 대한 정보을 알고 싶다면 ' dt nt!_EPROCESS '
  • 커널이 오브젝트를 어떤식으로 사용하는지 이해가 필요
  • 운영체제 버전
  • 오브젝트가 사용되는 시점(시점 : OS의 상태)
    • IRQL(Interrupt ReQuest Level)에 따라서 특정 영역의 메모리 접근이나 특정한 함수의 사용이 금지되기 때문에 OS의 상태는 중요하다.
      ex) IRQL이 DISPATCH_LEVEL인 상태에서 동작하는 스레드는 커널에서 페이지 폴트(Page Fault)를 발생시키는 메모리 접근은 수행할 수 없다.

DKOM을 통해 수행할 수 있는 것
  • 프로세스 은닉
  • 디바이스 드라이버 은닉
  • 포트 은닉
  • 스레드 권한 상승, 프로세스 권한 상승
  • 포렌식 회피


운영체제 버전 판단하기


운영체제의 버전과 서비스 팩에 따라서 커널 구조체가 변경되기 때문에 루트킷 개발자는 루트킷이 작동하는 시스템의 버전을 확실히 알아야 한다.


유저모드에서 운영체제 버전 판단


OSVERSIONINFOEX 구조체의 정의는 다음과 같다. (MSDN Link)



위와 같은 구조체를 선언해서 그 포인터를 GetVersionEx 함수의 인자로 사용하면 된다. GetVersionEx함수는 아래와 같은 형태를 갖는다.





운영체제에 따른 dwMajorVersion, dwMinorVersion 값은 아래와 같다.


Operating systemVersion numberdwMajorVersiondwMinorVersionOther
Windows 1010.0*100OSVERSIONINFOEX.wProductType == VER_NT_WORKSTATION
Windows Server 2016 Technical Preview10.0*100OSVERSIONINFOEX.wProductType != VER_NT_WORKSTATION
Windows 8.16.3*63OSVERSIONINFOEX.wProductType == VER_NT_WORKSTATION
Windows Server 2012 R26.3*63OSVERSIONINFOEX.wProductType != VER_NT_WORKSTATION
Windows 86.262OSVERSIONINFOEX.wProductType == VER_NT_WORKSTATION
Windows Server 20126.262OSVERSIONINFOEX.wProductType != VER_NT_WORKSTATION
Windows 76.161OSVERSIONINFOEX.wProductType == VER_NT_WORKSTATION
Windows Server 2008 R26.161OSVERSIONINFOEX.wProductType != VER_NT_WORKSTATION
Windows Server 20086.060OSVERSIONINFOEX.wProductType != VER_NT_WORKSTATION
Windows Vista6.060OSVERSIONINFOEX.wProductType == VER_NT_WORKSTATION
Windows Server 2003 R25.252GetSystemMetrics(SM_SERVERR2) != 0
Windows Server 20035.252GetSystemMetrics(SM_SERVERR2) == 0
Windows XP5.151Not applicable
Windows 20005.050Not applicable

GetVersionEx함수와 OSVERSIONINFOEX 구조체를 이용하여 코드를 짜면 아래와 같이 짤 수 있다. (대상은 Windows XP ServicePack3 이다.)


















커널 모드에서 운영체제 버전 판단


PsGetVersion이라는 함수를 가지고 있다. 수행결과로 얻은 UNICODE 문자열을 파싱하면 서비스 팩 정보를 얻을 수 있다.




혹은 RtlGetVersion함수도 존재한다. 유저모드의 GetVersionEx함수와 유사하며 OSVERSIONINFOW와 OSVERSIONINFOEXW 구조체를 인자로 사용한다. RtlGetVersion 함수의 원형 또한 GetVersionEX 함수와 거의 같다.



인터넷을 보다가 RtlGetVersion 함수를 이용하여 OS 버전을 알아내는 코드를 구할 수 있었다. (출처 :  https://indidev.net/forum/viewtopic.php?f=5&t=474 )





Visual Studio 6에선 기본적으로 문자코드가 multibyte이기 대문에 , lpcwstr 관련 에러 문제가 발생한다면 환경설정에서 unicode로 바꾸면 재대로 컴파일이 될 것이다.(근데 나는 Visual studio 6에서 문자셋을 바꾸는 부분을 찾지 못해서 Visual Studio 2015, 곧 unicode로 설정되어 있는 Studio에서 컴파일을 하였다.)


레지스트리를 이용한 운영체제 버전 판단


레지스트리 정보를 이용하는 경우는 유저모드와 커널모드에서 모두 가능하다.

  • HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\WindowsNT\CureentVersion\CSDVersion 은 서비스 팩 정보 문자열을 포함하고 있다.
  • HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\WindowsNT\CurrentVersion\CurrentBuildNumber는 운영체제의 빌드 번호를 포함하고 있다.
  • HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\WindowsNT\CurrentVersion\CurrentVersion 은 커널의 Major, Minor 버전 정보를 포함하고 있다.


(Windows 10을 대상으로 보게 되면 아래 이미지와 같다. HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\WindowsNT\CurrentVersion)

Windows XP SP3은 아래와 같은 레지스트리를 갖는다.



유저모드에서는 RegQueryValue와 RegQueryValueEx 함수를 이용해서 레지스트리 키 안의 정보를 얻을 수 있다.

디바이스 드라이브에서 레지스트리 키 안의 정보를 구하는 방법은 아래와 같다.

댓글 없음:

댓글 쓰기