최근 워게임을 풀다가 RootKit이라는 개념을 접하게 되었다.
RootKit...
이름은 많이 들어본것 같이 익숙한듯 낯설다.

그리하여, RootKit에 대해 알아보았다.

RootKit
- 특정 시스템을 해킹 한 후 시스템의 제어권을 획득할 목적으로 설치하는 악성 프로그램.
(Post Exploit에 해당한다.)

Rootkit의 성능 지표
1) 원하는 대로 제어권을 획득 할 수 있는지
2) 탐지 되지 않는지

이 조건을 높은 수준으로 충족시키기 위해서는 커널 모드에서 동작하는 RootKit을 작성하여야 한다.

...!
....!
RootKit을 한번 제작해보고 싶어졌다. (아주 간단한 옛날 버전의 리눅스더라도...!)
그래서 나의 프로젝트에 RootKit 제작이 추가되었다.

현재, 학교의 엄청난 과제양과 이미 벌려놓은 수많은 프로젝트들이 있지만,
그래도 정말 하고싶다.! 그래서 시작!!!

(성능좋은) RootKit을 제작하기 위해서는 커널 영역에서 놀 줄 알아야한다.

그러한 의미로 LKM을 공부해보았다.
LKM 입문? 정도다.

LKM은 Loadable Kernel Module 이다.

- 커널영역은 유저영역에서 직접 접근할 수 없다. 커널영역을 사용해야할 때는 system call을 이용하여 커널영역을 사용하게 된다.

- 커널 모듈은 커널에 올라가는 모듈이다. 운영체제 리눅스는 커널 모듈들의 모음이라고 할 수 있다. 다양한 커널모듈들이 있고 각각의 모듈들이 디바이스를 관리하는 역할을 한다. 우리는 LKM을 간단히 만들어 커널영역에 올리는 작업을 해볼 것이다.

그러기 위해 필요한 것이 있다. 바로 linux 헤더이다.


(linux-headers)


자기 운영체제 버전에 맞는 것을 설치해야한다.
먼저 search로 검색을 한 후,

알맞은 운영체제 버전을 선택해서 설치하면 된다.


(설치)


그렇게 되면 준비는 끝난다.

간단한 LKM 을 만들기 위해

hello.c 파일을 작성하였다.


(hello.c)


MODULE 로 시작한 코드들은 해당 모듈에 관한 정보를 적는 것이다.

그 아래 static으로 변수를 만들어 주었다.
주의할 점은 이러한 모듈을 만들 때 전역변수를 함부로 사용하면 안된다. 이유는 이 모듈은 커널에 올라가게 되는데, 전역변수를 사용하게 되면 이곳저곳의 프로세스에 영향을 줄 수 있기 때문이다. 그렇기에 static으로 하여 해당 모듈에서만 영향력있게 만든다. 전역변수를 썼다가 혹여나 다른 프로세스에서 겹치는 변수가 있게 되어 꼬여버릴 수 있기 때문이다.

그 아래 module_param 함수는 변수에 관한 설정을 해주는 것이다. 첫번째는 변수 이름이고, 두번째는 type이다. 여기서는 char pointer 이므로 charp 라고 적어준 것이다. 마지막은 접근 권한이다.

그 아래 init과 exit 함수가 있다. init 함수는 모듈이 올라갈 때 실행되며, exit 함수는 모듈이 해제될 때 실행되는 함수이다. 여기서는 printk를 이용하여 커널 로그에다가 print하는 코드를 넣었다.

맨 마지막에 module_init과 module_exit함수로 init함수와 exit 함수를 지정해준다.

이 파일을 컴파일 하기 위하여 Makefile을 만든다.


(Makefile)


현재 로컬 머신의 버전과 일치하는 컴파일을 하기 위하여 -C 옵션을 주어 경로를 변경한 후 M 모듈은 현재 경로에다가 컴파일 하도록 한다.

make 를 입력하여 컴파일한다.


(컴파일 완료)


그러면 hello.ko 가 생기게 된다. 이 커널 오브젝트 파일은 모듈인데 이 모듈을 올려보도록 할 것이다.


(커널 모듈 올리기)


insmod 명령어로 커널모듈을 올릴 수 있다.

올라간 모듈은 lsmod를 통하여 확인 할 수 있다.


(올라간 모듈 확인)


올라간 모듈을 해제하는 법은 rmmod 이다.


(모듈 해제)


모듈을 해제하고 확인해보니 올라간 모듈 리스트에 없는 것을 확인 할 수 있다.

커널 로그를 확인해보겠다.

아까 우리가 init과 exit 에 printk를 넣었으니, 모듈이 올라갈 때 내려갈 때 로그가 찍혔을 것이다.


(로그 확인)


커널 로그의 위치는 /var/log/kern.log 이다.

이번에는 아까 만든 변수에 값을 넘겨주며 올려보겠다.


(인자 넘기기)


인자는 위와같이 넘길 수 있다.

이 올라간 모듈에 대한 정보는 어디있을까?
/sys/module에 들어가본다.

(모듈 확인)


올라간 모듈 hello에 들어가본다.


(모듈 정보)


모듈 정보들이 보인다.

여기서 우리는 parameters를 확인해 볼 것이다.



(변수 확인)


우리의 변수인 name이 보이고 안을 열어보니 Normaltic이라고 아까 우리가 입력한 값이 저장되어있는 것을 확인 할 수 있다.

이 값을 수정할 수 있을까 했더니


(파일 권한)


파일 권한은 읽기 권한으로만 되어있었다.

마지막으로 인자를 넘긴 모듈을 해제해보겠다.



(모듈 해제)


모듈 해제는 rmmod 로 같다.

그렇다면 kern.log는?


(커널 로그)


커널 로그에는 내가 넘겨준 인자와 함께 문구가 잘 찍힌 것을 확인 할 수 있었다.

LKM에 대해 간단히 이해를 해보았다.
RootKit을 만들고, 이해하는데 커널영역을 더 공부할 필요가 있을 것 같다.

참조
- http://derekmolloy.ie/writing-a-linux-kernel-module-part-1-introduction/

'Hacking > System Hacking' 카테고리의 다른 글

(RootKit) Simple Rootkit  (0) 2018.04.12
malloc에서 사용하는 syscall  (0) 2018.02.21
System Hacking - jmp (반복문)  (0) 2017.04.19
System Hacking - jmp (분기문)  (0) 2017.04.18
System Hacking - 어셈블리어(사칙연산)  (0) 2017.04.14

System call을 이용해 커널모드로 전환되었을 때 root권한으로 상승시켜야 하는 문제이다.
커널 exploit을 맛볼 수 있는 기회가 되었다.



(문제화면)


커널 exploit에서는 시원하게 uid 0으로 만들어버리는 방법을 사용한다그 후 shell을 실행시키면 root권한의 쉘을 얻을 수 있는 것이다.



(시스템 확인)



접속해보았더니 시스템이 arm 시스템이었다.




(커널모듈)


시스템을 확인해보니 m.ko 커널 오브젝트 파일이 있었다m.ko 모듈을 insmod 했을 거라는 예상을 해본다
 
커널 모듈 소스코드를 문제에서 주었다.



(커널 모듈 소스코드)


확인해보면 system call을 하나 만들어서 등록해두었다입력을 통해 out으로 문자열을 소문자면 대문자로 바꾸어주어 보내는 함수이다. printk를 통해 함수가 등록된 것을 알려준다.



(dmesg 확인)



dmesg를 통해서 확인해보니 모듈이 등록되어있는 것을 확인했다.
 
위에서 정의한 system_call은 입력포인터출력포인터에 대한 범위 검사가 없다그렇기에 원하는 곳에 원하는 값을 적을 수 있다는 이야기이다.
시스템콜이 동작할 때는 커널모드로 전환되므로 메모리에서 커널영역 또한 참조하고 수정할 수 있다위 시스템콜의 취약점을 이용하면 커널영역을 마음대로 수정할 수 있다는 이야기가 된다.
나는 system call table의 주소를 내가 원하는 함수로 덮어 쓰므로써 원하는 함수를 실행하기로 계획했다
 
커널 exploit 할 때는 uid 0으로 만들어버린다고 했었는데 방법은 이렇다.
commit_creds(prepare_kernel_cred (0));
 
위 주소는 cat /proc/kallsyms | grep @@ 을 통해 찾을 수 있다
그 후 table의 원하는 주소를 찾아 그 주소를 위 함수가 실행될 수 있도록 덮어쓰고 실행하면 된다.
 

나는 getuid geteuid를 덮어썼다.



(내 exploit코드)



Exploit 코드이다.
 

여기서 주의할 점은 영어 소문자의 범위가 되면 -0x20이 된다는 점이다그렇기에 60까지 쓸 수 있는데 그러면 geteuid를 실행하게 되면 0x8003f560으로 넘어 가게 될텐데, 6c 까지 슬라이딩해서 넘어가야한다. nop으로 깔아주려 했으나 arm 계열에서 nop의 코드는 0x00이다.




(nop 코드)



그렇기에 nop의 기능과 같게 의미없는 코드로 채워야했다. 12바이트를!



(mov r1, r1)


이 코드를 컴파일 한 후 실행해보면



(권한상승)


권한이 상승된 것을 확인할 수 있고 flag까지 안전하게 확인할 수 있었다.

'WarGame > 500 Project' 카테고리의 다른 글

(65/500) pwnable.kr - echo2  (0) 2018.03.08
(64/500) backdoor - Enter the matrix  (0) 2017.10.31
(62/500) NOE.systems - BURYBURY  (0) 2017.10.01
(61/500) NOE.systems - double_input  (0) 2017.09.17
(60/500) pwnable.kr - crypto1  (0) 2017.08.27

+ Recent posts