Computer Security

#25 Double Fetch 본문

리눅스 커널 해킹

#25 Double Fetch

쿠리 Kuri 2022. 9. 2. 18:30
반응형

Double Fetch 

 

 

커널 모드와 사용자 모드 간의 데이터 엑세스 경쟁인 Race Condition 취약점이다.

 

일반적으로 Race Condition 취약점은 주로 같은 공간(커널 <-> 커널, 유저 <-> 유저)의 코드 블럭을 동시에 실행했을 때 발생하지만, Double Fetch 취약점은 서로 다른, 커널 모드와 유저 모드간에서 발생한다는 차이점이 있다.

 

일반적인 Race Condition 취약점도 디버깅하기 까다롭지만, Double Fetch 취약점은 좀 더 까다로운 편이다.

 

 

 

 


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

 

double_fetch

start.sh : qemu script

df.c :  Double Fetch 취약점이 터지는 디바이스 드라이버 예제

exp.c : 취약점을 이용해 권한 상승을 일으키는 exploit code

 

 

 

 


1. cat start.sh 를 이용해 적용된 보호기법을 살펴보자.

cat start.sh

 

KASLR : 적용 X

SMEP : 적용 O

SMAP : 적용 X

KPTI : 적용 X

 

2프로세서 2코어 1스레드를 사용한다.

즉, SMP 시스템에서 2개의 코어를 사용하기 때문에 Race Condition 취약점이 발생할 수 있다.

 

 

 

(1) Race Condition     

Race Condition이란 두 개 이상의 cocurrent한 프로세스(혹은 스레드)들이 하나의 자원(리소스)에 접근하기 위해 경쟁하는 상태를 말한다.

 

 

 

 

 


2. Double Fetch 와 BOF 취약점이 터지는 디바이스 드라이버 예제인 df.c를 살펴보자.

df.c

df_write()

1. count 매개 변수로 전달받은 주소를 역참조한 값이 32보다 크거나 0보다 작은지 검사한다.

 

2. len 변수에 count를 역참조한 값을 저장한뒤, 해당 변수를 기준으로 arr에 데이터 복사 작업을 진행한다.

 

3. 여기서 len 변수에 count를 역참조하는 과정에서 Double Fetch가 발생한다.

 

 

 

 

 


3. exp.c 코드를 살펴보자.

exp.c

 

 

 


4. exp.c 에서 main() 함수 부분을 살펴보자.

main()

 

Step 1

  • rop payload를 준비한다.

 

Step 2

  • len 전역 변수를 반복적으로 수정하는 race 스레드를 생성한다.

 

Step 3

  • rop payload를 전달하고, race 스레드에 의해 바뀐 len 값을 다시 32로 설정하는 작업을 반복한다.
  • 이로인해 BOF가 발생해 root권한을 획득한다.

 

 

 


5. exp.c 에서 race() 함수를 살펴보자.

race()

Double Fetch를 발생시키는 스레드

 

race 스레드에선, len의 값을 240으로 변경하는 작업을 반복한다.

 

main 함수에선, len의 값을 32로 복원하는 작업을 반복한다.

 

즉, 커널의 입장에선 전달된 len의 값이 240과 32로 빠르게, 반복적으로 바뀌는 상황이다.

 

이는 커널로 전달된 인자가 데이터가 아닌 유저 공간을 가리키는 포인터이기 때문이다.

 

 

 


익스플로잇 순서

 

 

1.rop payload 준비

rop payload

BOF를 위한 ROP payload를 준비하는 부분이다.

Stack based BOF 방식과 동일하다.

 

 

 


2. race 스레드 생성

race

Doubl Fetch를 발생시키기 위해 len의 값을 240으로 변경한다.

 

 

 


3. double fetch 발생 및 ROP payload전달

 

 

 

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

 

 

유저공간 main() --> 유저공간 write() --> 커널공간 df_write() -->커널공간 if(*(int*)count >32...

--> 커널공간 len = *(int*)count --> 커널공간 df_write()

 

df.c

정상적인 상황에선 len 변수에 32가 들어가야 하지만, race 스레드에의해 *(int*)count 의 값이 240으로 변경되어 최종적으로 len에 240이 들어가게 된다.

 

취약점에 의해 len의 값이 240이 되었으므로, memcpy()과정에서 BOF가 발생하여 실행 흐름이 ROP payload로 변경된다.

 

 

 

 


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

./start.sh

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

 

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

 

 

 

 

 


Double Fetch 최종 정리

 

 

 

입력 데이터가 복잡해 구조체를 사용할 땐, 커널로 전달되는 인자는 유저 공간을 가리키는 포인터이며, 이 포인터가 가리키는 데이터는 스레드에 의해 변조될 수 있다.

 

이렇게 변조된 데이터가 특정 작업에 사용되는 counter로 이용될 경우, 예제와 같이 커널의 흐름을 변조할 수 있다.

 

이러한 종류의 취약점을 exploit 할 때는 디버깅하기 다소 까다로운편이다. ftrace 등을 사용하면 디버깅에 도움이 된다.

 

반응형

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

#26 Input Test Driver 2  (0) 2022.09.04
#26 Input Test Driver 1  (0) 2022.09.03
#24 Arbitrary Write 2  (0) 2022.09.01
#23 Arbitrary Write 1  (0) 2022.08.31
#22 Kernel Heap Overflow  (0) 2022.08.30
Comments