Computer Security

#16 cr4 overwrite 기법 본문

리눅스 커널 해킹

#16 cr4 overwrite 기법

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

cr4 overwrite 기법

 

kernel ROP 에서 파생된 기법으로, cr4 레지스터의 SMEP 제어 비트를 제거해서 SMEP 보호 기법을 비활성화 하는 기법이다.

 

BOF 상황에서 overflow 할 수 있는 크기가 작거나, 마땅한 ROP 가젯을 찾기 어려울 때 시도해볼만한 기법이다.

 

제한적인 상황에서 SMAP 제어 비트를 제거하여 SMAP도 우회가 가능하다.

 

 


 

cr4 register

cr4 레지스터

  • control 레지스터 중 하나로, 프로세서에서 지원하는 다양한 기능에 대한 제어를 담당하는 레지스터이다.
  • 20번째 SMEP 제어 비트가 있으며, 이 비트를 제거할 경우 SMEP를 비활성화 할 수 있다.

 


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

cr4_overwrite

start.sh : qemu script

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

cr4_check.c : 커널 패닉을 일으켜 cr4 레지스터의 값을 확인하는 code

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

 


1. start.sh 를 살펴보자.

cat start.sh

KASLR : 적용 X

SMEP : 적용 O
SMAP : 적용 X

 

 

 


2.BOF 취약점을 이용해 커널의 흐름을 원하는 대로 조작할 수 있는 디바이스 드라이버 예제인 test.c를 살펴보자.

test.c

 

test_write()함수

 

 

copy_from_user 함수를 이용해 유저로부터 원하는 크기의 데이터를 전달 받은 뒤, 지역변수 arr에 복사하는 역할을 한다.

이로인해 BOF 취약점이 터지게된다.

 

kbuild 옵션을 통해 SSP(canary) 보호 기법을 제외한 뒤 컴파일 한 예제 드라이버다.

 

 

 

 


3. cr4_check.c 를 살펴보자.

cr4_check.c

커널 패닉을 일으켜 cr4 레지스터의 값을 확인하는 코드이다.

 

write()를 이용해 test 드라이버에 dummy 값 40바이트를 전달한다.

 

커널 스택의 return address 부분을 dummy 값이 덮게 되고, 커널 패닉이 발생하게된다.

 

 

 

 


4. ./start.sh 로 qemu를 실행한후, cr4_cehck를 실행해보자.

cr4_check

RIP가 0x414141...로 변조되어 kernel panic이 발생하고, 패닉 로그에서 cr4레지스터의 값을 알 수 있다.

 

cr4레지스터의 초기값은 0x1006f0 이다.

 

 

 

 


5.exp.c 의 main()함수 부분

main()

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

 

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

 

3. cr4 레지스터를 덮어쓰는 가젯과 ret2usr기법으로 작성한 payload()함수의 주소를 이용해서 ROP payload를 작성한다.

 

4. write()함수를 이용해서 test 드라이버에 ROP payload를 전달한다.

 

 

SMEP가 걸려있음에도 불구하고 ret2usr를 사용할 수  있는 이유는 cr4 레지스터의 SMEP제어비트를 제거 해서 SMEP를 비활성화 했기 때문이다.

 

 

 

 


6. payload 부분을 분석해 보자.

 

AAAAAAAA...
pop rax; ret;
0x6f0
mov cr4, rax; ret;
payload()

 

 

1. dummy  (AAAAAAAAAA...)

  • BOF 가 터지는 상황에서 커널 스택의 return address 부분에 payload를 맞추기 위해 dummy값을 삽입한다.
  • "A"의 개수는 총 32개. 즉 dummy 값은 32byte이다.

 

 

2. cr4 overwrite  [ pop rax; ret;  ,  0x6f0  ,  mov cr4,rax; ret; ] 

  • cr4 레지스터를 SMEP 제어 비트를 제거한 값으로 덮는 부분이다.
  • pop rax; ret; 어셈블리는 rax에 0x6f0을 넣기 위한 가젯이다.
  • 0x6f0은 초기의 cr4 레지스터 값인 0x1006f0에 SMEP 제어 비트를 제거한 값이다.
  • mov cr4, rax; ret; 어셈블리는 cr4 레지스터를 0x6f0으로 덮기 위한 가젯이다.

 

 

3. payload()

  • ret2usr 기법으로 작성한 payload 함수를 호출한다.
  • payload() 함수는 commit_creds(pre... -> swapgs -> context준비 -> iretq 순서로 구성되어 있다.

 

 

 


7. ./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, rop, sizeof(rop))   --> 커널공간 test_write() 

--> 커널공간 copy_from_user(ptr, buf, count)  --> 커널공간 memcpy(arr, ptr, count)

 

 

 

 


cr4 overwrite 최종 정리

 

 

이 기법은 kernel ROP와 같이 SMEP를 우회하는 기법이며, 제한적인 상황에서 21번째의 SMAP 제어 비트를 제거하여 SMAP도 우회가 가능하다.

 

커널 취약점을 이용해 rip control이 가능할 때, ROP payload를 구성한 뒤 해당 ROP payload로 rip를 제거하면 권한 상승이 가능하다.

 

만약 BOF와 같이 payload를 삽입한 후 rsp가 자동으로 맞춰지는 상황이 아닌, 단순히 rip control만 가능한 상황에서는 kernel stack pivotin 기법을 추가해야 한다.

 

반응형

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

#18 struct cred overwrite 기법  (2) 2022.08.26
#17 kernel stack pivoting 기법  (0) 2022.08.25
#15 kernel ROP 기법  (0) 2022.08.23
#14 ret2usr 기법  (0) 2022.08.22
#13 KPTI 우회  (0) 2022.08.21
Comments