[t:/]$ 지식_

linux kernel 2.6.38.8 system call wrapping

2011/09/30

시스템 콜 후킹은 해킹 위험 때문에 맨날 막히는데 구글로 찾아보고 하니 뚫린다.

사실 뚫었다고 하긴 뭐하지만..

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

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

원래 참고한 블로그 글 (감사합니다!)
http://blog.naver.com/PostView.nhn?blogId=passket&logNo=100111928670

시스템 콜 하이재킹
http://securex0.tistory.com/entry/linux-kernel-26x-%EC%97%90%EC%84%9C-%EC%9E%91%EB%8F%99%ED%95%98%EB%8A%94-%EC%8B%9C%EC%8A%A4%ED%85%9C-%EC%BD%9C-%ED%95%98%EC%9D%B4%EC%9E%AC%ED%82%B9-%EB%A3%A8%ED%8A%B8%ED%82%B7

하이재킹의 방법은 여러가지가 있는데 보통 sys_call_table 내용을 엎어치기 하는 트릭이다. 최근 커널에는 cr0 트릭이 먹힌다.
http://www.troot.co.kr/tc/2644

뭐 커널 소스 직접 건든다면 바로 익스포트
http://blog.naver.com/parkys1982?Redirect=Log&logNo=30003953701

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

비슷한 글
http://www.mareq.com/2008/05/linux-unix-system-calls-wrapping.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 을 하든지 해서 붙임.

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

시스템 콜 후킹 하는 커널 모듈을 만들자.

#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/proc_fs.h>
#include <linux/syscalls.h>
#include <linux/kallsyms.h>
#include <linux/sched.h>
#include <asm/uaccess.h>
#include <asm/unistd.h>

// 익스포트 안 했다면 알아서 대충 변수명 정해서 아까 얻은 주소 쓰면 됨.
// 위에 링크 글 보면 테이블 주소 찾는 법이 있는데.. 요즘은 또 바뀌었음..;; 
// void **syscccc = (void *)c011111...... 
extern void *sys_call_table[];

// asmlinkage int (*orig_setuid)( uid_t ruid );  
// 이 포인터는 뭐 복구용으로 알아서 잘 쓰시고..

asmlinkage int new_syscall(void)
{
        printk("dawnsea!!!\n" );

        return 0;
}

int __init m_init( void )

{

//      orig_setuid = sys_call_table[__NR_dawnsea_1];

        write_cr0( read_cr0( ) & ( ~0x10000 ) );  // 이게 중요한 부분

        sys_call_table[__NR_dawnsea_1] = new_syscall;

        write_cr0( read_cr0( ) | 0x10000 );

        printk("Module init, %lx, %lx\n", (unsigned long)sys_call_table, sys_call_table[__NR_dawnsea_1] );

        return 0;
}

void __exit m_exit( void )
{
        printk( KERN_ALERT "Module exit\n" );
}

module_init( m_init );
module_exit( m_exit );

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

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

PWD = $(shell pwd)

obj-m += dawnsea3.o

all:
        make -C /lib/modules/$(shell uname -r)/build M=$(PWD) modules

clean:
        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 추가하면 끝.

#include <linux/kernel.h>
#include <linux/sched.h>
#include <asm/types.h>
#include <asm/thread_info.h>
#include <asm/unistd_32.h>
#include <asm/syscalls.h>
#include <asm/cacheflush.h>

asmlinkage int sys_dawnsea_1(void)
{

        printk("dawnsea org syscall\n");
        return 0;
}

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

시스템 콜 넘버 선언 추가하려면 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에서 찾아온다.

...

asmlinkage int sys_dawnsea_1(void);
#endif /* _ASM_X86_SYSCALLS_H */

시스템콜이 호출이 되어야 하니까 어플도 하나 대충 만듬ㅋㅋ

#include <linux/unistd.h>
#include <stdio.h>
main()
// main (int argc, char *argv[])
{
        int i;

        i = syscall(341); // 아까 추가한 콜 번호.. include.. asm/syscalls.h 하면 NR... 아 귀찮다..

        printf("i = %d\n", i);
        return 0;
}

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

dmesg | tail 로 보면?

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

바꼈네?!! 굿!

나중에 cflush 관련 함수랑 set_memory_rw 등등 함수 안짝좀 찾아봅시다.

/arch/x86/mm/pageattr.c 등등에 있음.

setuid 공부도 좀 하자. 왤케 무식하니.









[t:/] is not "technology - root". dawnsea, rss