본문 바로가기
【Fundamental Tech】/Linux

linux kernel 2.6.38.8 system call wrapping

반응형
◈ 원문 출처: http://www.troot.co.kr/tc/2649


Exploiting races in system call wrappers
http://lwn.net/Articles/245630/

뭐 대충 시스템 콜 상속에 관한 논문.
http://www.seclab.cs.sunysb.edu/anupam ··· erit.pdf

원래 참고한 블로그 글 (감사합니다!)
http://blog.naver.com/postview.nhn?blo ··· 11928670

시스템 콜 하이재킹
http://securex0.tistory.com/entry/linu ··· 582%25b7

하이재킹은 여러 가지 방법으로 시도했지만.. sys_call_table 내용을 엎어치기 하는 트릭으로.. 
최근 커널에는 cr0 트릭이 먹힌다.
http://www.troot.co.kr/tc/2644

뭐 커널 소스 직접 건든다면 바로 익스포트
http://blog.naver.com/parkys1982?redir ··· 03953701

이렇게 테이블 위치를 찾을 수도 있다. 
http://teamcrak.tistory.com/50

비슷한 글 마구 레퍼런스
http://www.mareq.com/2008/05/linux-uni ··· ing.html

이건 libc 레벨에서의 꼼수. 그러니까 libc를 preload 하고 심볼 찾아서 내 함수로 대치하면 libc에서 커널 쪽으로 안 보내고 내 함수를 부른다.

http://kldp.org/node/83447
물론 시스템 병신 만들기 싫으면 내 함수 호출 후 원래 함수도 호출해야 함 (래핑)

사실 libc 래핑도 할 수 있음. gcc 기능으로.
http://www.troot.co.kr/tc/2641


해킹하려고 찾은게 아니라서.. 
시스템 콜 실험을 할 때 매번 재빌드 하기 귀찮아서 디벼봤음;;

해킹 기법이 아니라 슈퍼유저 권한을 사용한다.
뭐... 사용하지 않고도 할 수 있음. 하지만 보통 상용 서버라면 중요 툴 실행 권한을 안 줌;

진짜 해킹을 해서 루트킷을 심고 싶다면.. 피싱 홈페이지나 dns 스푸핑으로 최신 (가짜) 디바이스 드라이버 설치하도록 삥쳐야 함.


sys_call_table은 정의된 부분은.
arch/x86/kernel/syscall_table_32.S 

이걸 딴 데서 가져다 써야하므로, EXPORT 해야 한다. 파일 찾아서 추가.
kernel/i386_ksyms_32.c:EXPORT_SYMBOL(sys_call_table);

extern void *sys_call_table; 도 써줘야 한다. void **가 맞겠군. 아무렇게나 써도 됨.

하지만 이건 어디까지나 슈퍼유저의 방법이므로..
아까 본 sys_call_table_32.S의 맨 앞 함수를 찾는다.

cat /proc/kallsyms > ddd 한 후 ddd 파일에서 sys_restart를 찾는다.
어라 .. 사용자 계정으로 보니까 주소가 모두 000 이네?


그렇다면 방법이 또 있다.
grep sys_restart /boot/System... 뒤에 버전은 uname -r 을 하든지 해서 붙임.

여긴 제대로 나옴 ㅋㅋㅋㅋㅋ
이 주소를 직빵 지정하면 됨.



시스템 콜 후킹 하는 커널 모듈을 만들자.
  1. #include <linux/init.h>  
  2. #include <linux/kernel.h>  
  3. #include <linux/module.h>  
  4. #include <linux/proc_fs.h>  
  5. #include <linux/syscalls.h>  
  6. #include <linux/kallsyms.h>  
  7. #include <linux/sched.h>  
  8. #include <asm/uaccess.h>  
  9. #include <asm/unistd.h>  
  10.   
  11. // 익스포트 안 했다면 알아서 대충 변수명 정해서 아까 얻은 주소 쓰면 됨.  
  12. // 위에 링크 글 보면 테이블 주소 찾는 법이 있는데.. 요즘은 또 바뀌었음..;;   
  13. // void **syscccc = (void *)c011111......   
  14. extern void *sys_call_table[];  
  15.   
  16.   
  17. // asmlinkage int (*orig_setuid)( uid_t ruid );    
  18. // 이 포인터는 뭐 복구용으로 알아서 잘 쓰시고..  
  19.   
  20.   
  21. asmlinkage int new_syscall(void)  
  22. {  
  23.         printk("dawnsea!!!\n" );  
  24.   
  25.         return 0;  
  26. }  
  27.   
  28. int __init m_init( void )  
  29.   
  30. {  
  31.   
  32. //      orig_setuid = sys_call_table[__NR_dawnsea_1];  
  33.   
  34.         write_cr0( read_cr0( ) & ( ~0x10000 ) );  // 이게 중요한 부분  
  35.   
  36.   
  37.         sys_call_table[__NR_dawnsea_1] = new_syscall;  
  38.   
  39.         write_cr0( read_cr0( ) | 0x10000 );  
  40.   
  41.         printk("Module init, %lx, %lx\n", (unsigned long)sys_call_table, sys_call_table[__NR_dawnsea_1] );  
  42.   
  43.         return 0;  
  44. }  
  45.   
  46. void __exit m_exit( void )  
  47. {  
  48.         printk( KERN_ALERT "Module exit\n" );  
  49. }  
  50.   
  51. module_init( m_init );  
  52. module_exit( m_exit );  

커널 모듈로 빌드하니까 빨라서 좋다. 
모듈로 빌드하자고!
http://www.troot.co.kr/tc/2591


대충 디렉토리 하나 만들고 위에 소스 때려넣고 Makefile을 만들자.

  1. PWD = $(shell pwd)  
  2.   
  3. obj-m += dawnsea3.o  
  4.   
  5. all:  
  6.         make -C /lib/modules/$(shell uname -r)/build M=$(PWD) modules  
  7.   
  8. clean:  
  9.         make -C /lib/modules/$(shell uname -r)/build M=$(PWD) clean  

빌드 3초!                                                                   

아차.. 커널에 빈 시스템 콜을 하나 넣어두자.
http://www.troot.co.kr/tc/2559


빈 시스템 콜에 연결할 함수 본체는. 아래처럼 야메로 짬.

/kernel/dawnsea.c 로 만들고.
/kernel Makefile 에 
obj-y += dawnsea.o 추가하면 댐.

  1. </span></font>  
  2. <font face="'맑은 고딕'">#include <linux/kernel.h>  
  3. #include <linux/sched.h>  
  4. #include <asm/types.h>  
  5. #include <asm/thread_info.h>  
  6. #include <asm/unistd_32.h>  
  7. #include <asm/syscalls.h>  
  8. #include <asm/cacheflush.h>  
  9.   
  10. asmlinkage int sys_dawnsea_1(void)  
  11. {  
  12.   
  13.         printk("dawnsea org syscall\n");  
  14.         return 0;  
  15. }</font></font>  
  16. <font size="2" color="#000000"><span style="font-family: '맑은 고딕'; line-height: 22px; ">  

인클루드가 많은 건 이런 저런 실험하다 남은 찌꺼기 ㅋㅋㅋ


시스템 콜 넘버 선언 추가하려면
arch/x86/include/asm/unistd_32.h 까보면 됨.


뭐 대충 커널을 빌드하자.
make-kpkg --initrd --append-to-version=dawnseahw1 kernel-image kernel-headers -j 4


arch/x86/include/asm/syscalls.h 에 미리 선언도 해둬야.. 나중에 어플 빌드할 때 asm에서 찾아온다.

  1. ...  
  2.   
  3. asmlinkage int sys_dawnsea_1(void);  
  4. #endif /* _ASM_X86_SYSCALLS_H */  

asm 심볼릭 링크도 잘 해두잡. 즉.. arch/x86/include/asm 은 include/asm에 잘 연결되어 있어야 함..
/usr/include/asm 도 저기서 긁어오게 해둘 것~


시스템콜이 호출이 되어야 하니까 어플도 하나 대충 만듬ㅋㅋ
  1. </span></font>  
  2.   
  3. <font face="'맑은 고딕'">#include <linux/unistd.h>  
  4. #include <stdio.h>  
  5. main()  
  6. // main (int argc, char *argv[])  
  7. {  
  8.         int i;  
  9.   
  10.         i = syscall(341); // 아까 추가한 콜 번호.. include.. asm/syscalls.h 하면 NR... 아 귀찮다..  
  11.   
  12.         printf("i = %d\n", i);  
  13.         return 0;</font><span style="font-family: '맑은 고딕'; line-height: 22px; ">                    </span><font face="'맑은 고딕'">  
  14. }  
  15.                                                                                      </font>  
  16. <font face="'맑은 고딕'">  


insmod dawnsea3.ko 하면 시스템 콜이 바뀐 상태. 
즉 sys_dawnsea_1 함수가 new_syscall 로 바뀜


dmesg | tail 로 보면?


[   71.177668] dawnsea org syscall
[   80.422611] Module init, c152b220, f8d46020
[   86.237055] dawnsea!!!

바꼈네?!! 굿!
반응형