윈도우 커널 권한상승(LPE)
해당 실습은 익스 코드를 짜는게 아닌 윈도우 커널의 어떤 부분을 이용해야지 시스템 권한으로 권한상승 되는지 알 수 있는 실습이다.
처음에 윈도우 커널 익스를 할 때 어떤 부분을 건드려야하는지 감이 안왔다. 하지만 해당 실습을 통해 대략 어떻게 시스템 권한을 얻게 되고, 또 어떤 부분을 건드리면 해당 권한에 대한 모든 기능을 사용할 수 있는지 또한 알게되었다.
실습 환경:
OS: Windows 10 22H2
실습의 목적은 토큰을 악용해 권한상승을 파악하는 것이다.
두가지 기법에 대해 실습할 것이다.
- Token stealing/replacement - 낮은 권한의 토큰을 높은 권한의 토큰으로 변경
- Token privilege adjustment - 기존 토큰에 더 많은 권한 추가 및 사용 가능
_EPROCESS
프로세스 이름, 실행중인 데스크탑 세션, 액세스 토큰 및 기타 프로세스에 대한 여러 정보를 포함하고 있다. 즉, 시스템에서 실행중인 각 프로세스는 커널 메모리에 해당하는 _EPROCESS 개체를 가지고 있다.
_dt eprocess로 구조를 확인할 수 있다.
_Token
프로세스의 보안 컨텍스트를 설명하는 커널 메모리 구조로 프로세스 토큰 권한, 로그온 ID, 세션 ID, 토큰 유형 등의 정보를 포함한다.
windbg에서 dt _token으로 구조를 볼 수 있다.
이제 프로세스 및 토큰에 대한 위의 정보를 사용하여 커널이 공격하는 방식으로 낮은 권한의 프로세스를 높은 권한의 프로세스로 권한 상승하는걸 해볼것이다.
권한 상승의 한가지 방법은 낮은 권한의 토큰을 높은 권한의 토큰으로 바꾸는 것이다. 다음은 권한 상승을 하기 위한 시나리오이다.
- 시스템에서 실행되는 프로세스에 대한 _EPROCESS를 찾는다.
- EPROCESS는 _TOKEN 메모리 구조에 대한 포인터를 포함하고 있고, 권한이 낮은 프로세스의 _TOKEN 구조의 주소를 찾는다.
- 그리고 NT\SYSTEM으로 실행되는 권한 있는 프로세스의 _TOKEN 구조의 주소를 찾는다.
- 낮은 권한으로 실행되는 프로세스의 토큰을 높은 권한으로 실행되는 토큰으로 바꾼다.
실습할 프로그램은 Powershell이며 권한 상승을 통해 SYSTEM 권한으로 바꿔볼 것이다.
먼저 windbg로 해당 pc에서 실행되는 모든 프로세스를 나열한다.
이렇게 프로세스에 대한 정보가 나오고, PROCESS 뒤에 나오는 주소가 _EPROCESS구조에 대한 주소이다.
다음으로 Powershell에서 프로세스 ID를 알아낸다.
그리고 pid 189C(6300)에 대한 프로세스 정보를 확인한다. 그러면 해당 프로세스에 대한 _EPROCESS 주소를 알아낼 수 있다.
토큰 교환이 목적이기 때문에 핵심 멤버는 0x4b8에 위치한 Token이다.
_EPROCESS.TOKEN이 가리키는 메모리 구조를 읽는다.
해당 명령을 사용해서 메모리 구조를 보려고 하는데, windbg에서 이 주소가 토큰 개체를 가리키지 않는다는 오류 메시지를 출력했다.
왜냐하면 해당 주소는 _EPROCESS.TOKEN을 가리키는 것이지 _Token을 가지고 있는 _EX_FAST_REF 구조를 가리키는 것이 아니기 때문이다.
그래서 EPROCESS.Token에 저장된 주소를 _EX_FAST_REF 구조와 오버레이해 내부 구조를 본다.
세 멤버의 오프셋이 모두 같고, Object와 Value가 동일한 주소를 가리키고 있고, RefCnt는 2비트만 켜져있다. 해당 값은 5이고 Object와 Value 값의 끝자리인 0x5와 같다.
RefCnt는 토큰 주소의 일부가 아니라 커널 객체에 대한 참조 횟수를 나타낸다고 한다. 즉 해당 값을 0으로 만든 후에야 _TOKEN 주소를 얻을 수 있다.
0xffffb3026e9350a5인 경우 5를 0으로 만들어야 _TOKEN주소가 나온다.
powershell 프로세스의 TOKEN주소를 보면 마지막이 0으로 되어있는걸 확인할 수 있다. 즉, _EX_FAST_REF가 가리키는 값의 마지막 숫자를 0으로 만들면 리얼 _TOKEN 구조 주소를 얻을 수 있다.
이제 !token 명령을 사용하여 해당 주소가 속한 사용자 그룹 등의 실제 토큰 세부 정보를 볼 수 있다.
SID를 보면 토큰에서 보이는 SID값과 일치하는걸 볼 수 있다.
낮은 권한의 토큰 주소를 찾았으니 이제 SYSTEM권한의 토큰을 찾을것이다.
System 프로세스의 토큰주소를 볼 수 있고, 주소는 ffffb30267246800이다.
이제 powershell프로세스의 토큰 주소를 System프로세스의 토큰 주소로 덮어씌우면 System으로 권한 상승이 된다.
powershell의 eprocess구조체의 Token주소를 System의 Token주소로 바꿨더니 권한 상승이 일어나면서 일반 사용자에서 system사용자가 됐다.
SID값도 바뀐걸 볼 수 있다.
권한상승을 했지만 아직 사용할 수 있는 권한이 많이 없는걸 볼 수 있다. 사실 아직까지 권한 상승을 했다고 할 수 없다. 지금까지 한거는 일반 토큰을 system 토큰으로 바꾼것 밖에 없다. 즉, 토큰이란건 사용자에 대한 인증 정보이다. 이름만 system으로 변경된것이지 권한까지 받은것은 아니다. 회장님이 됐지만, 아직 직무 권한이라던가 이런 세세한 부분이 아직 결제가 안난것이다. 뭐 대충 설명하면 이렇다..
그래서 다음에 할것은 토큰 권한 수정이다. 아까 봤던 _TOKEN 구조체의 0x40 offset에는 _SEP_TOKEN_PRIVILEGES라는 멤버가 있다.
해당 부분도 권한상승에 사용되며, 이 부분은 아까 whoami /all로 봤던 권한을 담당하는 부분이다.
지금 보이는 것은 powershell의 토큰이 가지는 권한이다. 각 필드는 다음을 나타낸다.
Present: 프로세스가 가질 수 있는 모든 특권 목록
Enabled: 현재 프로세스에게 부여된 특권 목록
EnabledByDefault: 프로세스가 처음 생성될 때 기본적으로 부여된 특권 목록
만약 Present의 값을 Enabled에 복사하면 프로세스가 가질 수 있는 모든 특권 목록을 가질 수 있게 된다.
방금까지는 기존에 있는 권한을 활성화 한것이고, 더 많은 권한을 추가하려면 System프로세스의 토큰을 이용하면 된다.
지금은 System 토큰을 가지고 있고, 해당 명령을 이용해 System 토큰의 권한을 모두 활성화 시킨것이다.
일반 사용자일 경우에는 가지고 있는 권한이 많지 않다.
가지고 있는 특권을 모두 활성화하려면 아까 했던것처럼 Present값을 Enabled에 복사하면 된다.
만약 더 많은 특권을 추가 하고 싶다면, System 토큰의 권한 값을 일반사용자 토큰의 Present, Enabled 필드에 모두 덮어씌우면 된다.
이런식으로 덮어씌워주게 되면
일반 사용자임에도 불구하고, 더 많은 특권을 가지게되고, 모두 활성되있게 된다.
내가 이번 실습을 하게된 계기는 처음에 LPE라고 했을 때 권한 상승이고, 권한 상승을 하면 더 많은 권한을 누릴 수 있겠지 정도만 알았지 어떻게 이루어지는지 알 수 없었다. 하지만 인터넷을 통해 많이 검색해보니 우연히 익스 코드를 안짜고, 권한 상승이 이루어지는 방법에 대해 보게되었고, 해당 실습을 통해 조금이나마 권한 상승이 이루어지는 방법에 대해 알게되었다.
물론 실전 익스는 훨씬 더 복잡한 과정을 거치겠지만, 대략적인 프로세스의 구조, 권한을 관리하는 곳 등을 알게돼서 너무 좋았다.