Computer Security

#17 kernel stack pivoting 기법 본문

리눅스 커널 해킹

#17 kernel stack pivoting 기법

쿠리 Kuri 2022. 8. 25. 18:30
반응형

kernel stack pivoting 기법

 

 

 

함수 포인터를 덮을 수 있는 취약점과 같이 rip control만 가능하고 rsp control이 불가능한 상황에서, kernel ROP로 실행 흐름을 변경하기 위해 kernel stack을 pivoting 하는 기법이다.

 

xchg eax, esp 어셈블리 가젯과 mmap()함수를 이용한다.

 

SMEP보호 기법을 우회할 수 있지만, SMAP도 걸려 있는 상황에선 좀 더 복잡한 과정이 필요하다.

 

 

 


rsp control이 불가능한 상황

 

 

 

스택 버퍼 오버플로우 취약점 같은 경우, 스택의 return address 부분을 ROP payload로 덮으면 별도의 rsp control 작업이 필요 없다.

 

만약 함수 포인터를 덮은 뒤, 그 함수 포인터를 실행하는 취약점의 경우, 단순히 포인터 주소로 jmp하기 때문에 rsp는 별도로 맞추어 줘야 한다.

 

별도로 rsp를 맞추는 방법 중 가장 기본적인 방법이 kernel stack pivoting 기법이다.

 

 

 

 


우리는 아래의 파일들로 실습 할 것이다.

kernel_stack_pivoting

 

start.sh : qemu script

test.c : 간단한 취약점이 터지는 디바이스 드라이버 예제

exp.c : kernel stack pivoting 기법을 이용해 권한 상승을 일으키는 exploit code

 

 

 

 


1. start.sh 를 살펴보자.

cat start.sh

KASLR : 적용 X

SMEP : 적용 O

SMAP : 적용 X

 

 

 

 


2. 커널의 흐름을 원하는 대로 조작할 수 있는 디바이스 드라이버 예제인 test.c 파일을 살펴보자.

vi test.c

test_init() 함수에서 misc 디바이스를 등록하여 /dev 경로에 test라는 디바이스가 생성되는 것을 알 수 있다.

 

test_write() 함수에서 copy_from_user 함수를 이용해 유저로부터 주소를 전달 받아, 그 주소를 실행하는 것을 볼 수 있다.

 

 

 

 


3.exp.c 코드의 main() 함수 부분을 살펴보자.

main()

1. /dev/test 장치를 open()한다.

 

2. pivoting할 fake stack을 준비하는 set_fake_stack()함수를 호출한다.

 

3. write() 함수를 이용해 test 드라이버에 xchg 가젯의 주소를 전달한다.

 

 

 


4.exp.c 코드의 set_fake_stack() 함수부분을 살펴보자.

set_fake_stack()

1. stack pivoting을 일으킬 xchg 가젯의 하위 4byte를 인자로 mmap() 할당

 

2. 현재의 context를 저장하는 backup_rv()함수를 호출한다.

 

3.mmap()을 이용해 할당한 xchg_32 주소에 권한 상승을 일으키는 commit_creds(pre... 코드 및 필요한 명령과 저장한 context를 이용해서 ROP payload를 구성한다.

 

 


조금 더 자세히 알아보자.

 

 

 

 

xchg 가젯 실행 전

rip 0xffffffff8176b4fd<xchg esp, eax>
rax 0xffffffff8176b4fd<xchg esp, eax>
rsp ...

 

xchg 가젯 실행 후

rip 0xffffffff8176b4fe <ret>
rax ...
rsp 0x8176b4fd
 

 

xchg esp, eax 어셈블리는 esp와 eax 레지스터를 서로 바꾸는 명령이다.

 

rax에 xchg 가젯의 주소가 들어 있는 이유는, 커널에서는 함수 포인터를 실행할 때 rax 레지스터에 주소를 저장한 뒤에 jmp rax를 하기 때문(r12일 때도 있다.)

 

위와 같이 stack pivoting을 할 경우 xchg 가젯의 하위 4byte 값으로 rsp가 변경된다.

 
 
 

5. ROP payload흐름을 단계별로 살펴보자.

 

xchg eax, esp
ret
 

 

1. xchg eax, esp

  • eax와 esp 레지스터의 값을 바꾸는 부분이다.
  • 이 가젯으로 인해 kernel stack pivoting이 일어나게 되고, rsp 레지스터가 xchg 가젯의 주소 0xffffffff8176b4fd의 하위 4byte인 0x8176b4fd로 변경된다.

 

 

2. ret

  • ret 명령이 실행되는부분이다. ret 어셈블리는 pop rip; jmp rip를 의미한다.
  • 정상적인 상황이라면, kernel stack으로 부터 pop해야 하지만, xchg가젯으로 인해 rsp가 0x8176b4fd로 pivoting 되었기 때문에 유저 공간에 존재하는 fake stack으로부터 pop하게 된다.
  • 즉, 커널의 실행 흐름이 fake stack으로 바뀌게 된 것이다.

 

 

 

pop rdi; ret;
0
prepare_kernel_cred
pop rcx; ret;
...

3. fake stack(ROP payload)

  • mmap()을 이용해 ROP payload가 등록된 fake stack 부분이다.
  • ROP payload는 commit_creds(pre... -> swapgs -> context 준비 -> rietq 순서대로 구성된다.
  • 구체적인 구성방법은 kernel ROP방식과 같다.

 

 

 

 


6. ./start.sh 를 실행해보자.

./start.sh

 

start.sh를 실행한 후, exp를 실행한 결과이다.

 

user권한에서 root권한을 획득 한 것을 볼 수 있다.

 

 

 

 


전체적인 흐름

 

 

커널공간 : test.c     ,      유저공간 : exp.c

 

 

커널 공간 misc_register(&test_driver)   -->  유저공간 fd=open("/dev/test", O_RDWR) 

--> 유저공간 write(fd, &ptr, sizeof(ptr))   --> 커널공간 test_write() 

--> 커널공간 copy_from_user(&fp_exec, ...)  --> 커널공간 fp_exec()

 

 

 

 


kernel stack pivoting 최종 정리

 

 

 

 

UAF 등의 취약점을 통해 함수 포인터를 덮을 수 있을 때, ROP를 이어나가기 위해 사용하는 기법이다.

 

많은 경우의 커널 취약점이 rip control만 가능한 취약점이기 때문에 이 kernel stack pivoting 기법은 매우 중요하다.

 

하지만, mmap()을 이용하기 때문에 유저 공간에 대한 엑세스를 막는 SMAP가 걸려 있을 경우 사용하기 까다로울 수 있다.

 

xchg eax, esp 가젯이 없을 경우 mov esp, 0x~~~가젯도 사용할 수 있다.

 

반응형

'리눅스 커널 해킹' 카테고리의 다른 글

#19 Stack based BOF  (1) 2022.08.27
#18 struct cred overwrite 기법  (2) 2022.08.26
#16 cr4 overwrite 기법  (0) 2022.08.24
#15 kernel ROP 기법  (0) 2022.08.23
#14 ret2usr 기법  (0) 2022.08.22
Comments