Computer Security

#15 kernel ROP 기법 본문

리눅스 커널 해킹

#15 kernel ROP 기법

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

kernel ROP

 

SMEP 보호 기법을 우회하기 위한 기법으로, 커널 공간의 주소들로 ROP payload를 작성하여 권한상승을 일으키는 기법이다.

 

SMEP 보호 기법은 커널 공간에서 유저 공간과 관련된 코드의 실행을 막는 기법이기 때문에, 실행되는 대상이 커널 공간의 주소일 경우 SMEP를 우회할 수 있다.

 

가장 많이 사용되는 보편적인 커널 공격 테크닉이다.

 

 


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

kernel_ROP

start.sh : qemu script

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

exp.c : kernel ROP 기법을 이용해 권한 상승을 일으키는 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.exp.c 의 main()함수 부분

main()

/dev/test 장치를 open()

 

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

 

권한 상승을 일으키는 commit_creds() 코드 및 필요한 명령과 저장한 context를 이용해서 ROP payload를 구성

 

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

 

commit_creds() 함수와 prepare_kernel_cred() 함수의 주소는 KADR 우회 방식으로 구한다.

 

 

 


4.  ROP payload를 자세히 분석해보자.

AAAAAAAAAAAAAAAAAA....
pop rdi; ret;
0
prepare_kernel_cred
pop rcx; ret;
0
mov rdi, rax; rep...; ret;
commit_creds
swapgs; ret;
iretq; ret;
context

 

1. dummy  (AAAAAAAAAA...)

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

 

 

 

2.prepare_kernel_cred(0)  [ pop rdi;ret;  ,   0  ,  prepare_kernel_cred ] 

  • 권한 상승을 일으키는 commit_creds(pre...코드 중에서 prepare_kernel_cred(0) 을 호출하는 부분이다.
  • pop rdi; ret 어셈블리는 prepare_kernel_cred() 함수의 인자로 0을 주기 위한 가젯이다.
  • 0은 pop rdi를 통해 rdi 레지스터를 0으로 설정하기 위한 값이다.
  • 설정된 rdi 레지스터를 인자로 prepare_kernel_cred()함수를 호출한다.

 

 

3.commit_creds() [pop rcx; ret; ,  0  ,  mov rdi; rep...;ret; ,  commit_creds]

  • 권한 상승을 일으키는 commit_creds(pre... 코드 중에서 commit_creds()를 호출하는 부분이다.
  • pop rcx; ret; 와 0은 이후 다음 가젯의 rep... 부분을 스킾하기 위한 가젯이다.
  • mov rdi; rax; rep..; ret;는  prepare_kernel_cred(0)의 반환값을 rdi 레지스터로 설정하기 위한 가젯이다.
  • 설정된 rdi 레지스터를 인자로 commit_creds()함수를 호출한다.

 

 

4. swapgs & iretq

swapgs 와 iretq 명령을 통해 유저 공간으로 전환한다.

 

 

 

5. context 

backup_rv() 함수를 이용해 저장한 context 를 준비한다.

이중 RIP 레지스터는 /bin/sh를 실행하는 shell() 함수의 주소로 설정한다.

RIP
CS
RFLAGS
RSP
SS

 

 

 


5. ./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)

 

 

 


kernel ROP 최종 정리

 

 

이 기법은 SMEP를 우회하는 기법이며, 제한적인 상황에서 SMAP도 우회가 가능하다.

 

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

 

ROP payload는 commit_creds(pre... -> swapgs -> context 준비 -> iretq순서대로 구성되어야 한다.

 

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

 

 

반응형

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

#17 kernel stack pivoting 기법  (0) 2022.08.25
#16 cr4 overwrite 기법  (0) 2022.08.24
#14 ret2usr 기법  (0) 2022.08.22
#13 KPTI 우회  (0) 2022.08.21
#12 SSP 우회  (0) 2022.08.20
Comments