2015-12-06 62 views
0

我一直试图拦截连接系统调用,试图重写tcp请求的目标ip地址。我想我成功地从符号表中检索到连接系统调用的地址并拦截它。我的结论是基于我的函数被内核调用的事实。但是,我不太确定我的代码是否实际上拦截了连接系统调用。为了验证我试图打印出源或目的地的IP地址。但每当我尝试访问套接字缓冲区结构时,内核崩溃。您可以在hijackConnect函数中看到该代码段,并将它们注释掉。我想知道我在做什么错误,我如何确保我真的拦截了tcp请求。如果可能,我想知道如何重写目标IP地址,以便我可以将http请求重定向到特定的网站。即使你不知道如何去做,我仍然很欣赏良好的指针和学习资源。访问套接字缓冲区结构时内核崩溃

声明:我不想做任何险恶的事情。这是针对内核黑客学校项目的,它必须在内核空间中完成。我的内核是3.16版,下面的代码是根据我自己的需要调整在线教程的。

#define DISABLE_WRITE_PROTECTION (write_cr0(read_cr0() & (~ 0x10000))) 
#define ENABLE_WRITE_PROTECTION (write_cr0(read_cr0() | 0x10000)) 

static unsigned long **find_sys_call_table(void); 
asmlinkage int hijackConnect(struct sock *sk, struct sockaddr *uaddr,int addr_len); 

asmlinkage int (*original_sys_connect)(struct sock *, struct sockaddr *, int); 
asmlinkage unsigned long **sys_call_table; 

/* Initialisation routine */ 
int init_module(void) 
{ 
    sys_call_table = find_sys_call_table(); 

    if(!sys_call_table) { 
     printk(KERN_ERR "Couldn't find sys_call_table.\n"); 
     return -EPERM; /* operation not permitted; couldn't find general error */ 
    } 

    DISABLE_WRITE_PROTECTION; 
    original_sys_connect = (void *) sys_call_table[SYS_CONNECT]; 
    sys_call_table[SYS_CONNECT] = (unsigned long *) hijackConnect; 
    ENABLE_WRITE_PROTECTION; 

    printk(KERN_INFO "Connect system call is hijacked!\n"); 

    return 0; 
} 

/* Cleanup routine */ 
void cleanup_module(void) 
{ 
    printk(KERN_INFO "Unhook hijacking\n"); 

    /* Restore the original sys_open in the table */ 
    DISABLE_WRITE_PROTECTION; 
    sys_call_table[SYS_CONNECT] = (unsigned long *) original_sys_connect; 
    ENABLE_WRITE_PROTECTION; 
} 

static unsigned long **find_sys_call_table() { 
    unsigned long offset; 
    unsigned long **sct; 

    for(offset = PAGE_OFFSET; offset < ULLONG_MAX; offset += sizeof(void *)) { 
     sct = (unsigned long **) offset; 

     if(sct[__NR_close] == (unsigned long *) sys_close) 
      return sct; 
    } 

    /* 
    * Given the loop limit, it's somewhat unlikely we'll get here. I don't 
    * even know if we can attempt to fetch such high addresses from memory, 
    * and even if you can, it will take a while! 
    */ 
    return NULL; 
} 

asmlinkage int hijackConnect(struct sock *sk, struct sockaddr *uaddr,int  addr_len) 
{ 
    printk(KERN_INFO "Connect is called!\n"); 

    /* struct sockaddr_in *usin = (struct sockaddr_in *)uaddr; 
    struct inet_sock *inet = inet_sk(sk); 
    struct tcp_sock *tp = tcp_sk(sk); 
    __be16 orig_sport, orig_dport; 
    __be32 daddr, nexthop, test; 

    orig_sport = inet->inet_sport; 
    orig_dport = usin->sin_port; 
    test = inet->inet_saddr; 
    //daddr = usin->sin_addr.s_addr; 

    printk(KERN_INFO "ADDRESS - %d", ntohl(test));*/ 
    return (*original_sys_connect)(sk,uaddr,addr_len); 
} 
+1

syscall函数的正确定义是'SYSCALL_DEFINE3(connect,int,fd,struct sockaddr __user *,uservaddr,int,addrlen)'。请注意,它的第二个参数uservaddr具有其__user类型的修饰符。这意味着给定的指针指向*用户地址空间*,并且应该通过特殊函数(如'copy_from_user')来访问。顺便说一句,探索origin系统调用可能会发现,它使用'move_addr_to_kernel'来处理该指针。 – Tsyvarev

回答

0

如果可能的话,我想知道如何重写目的IP地址,这样我可以将HTTP请求重定向到特定的网站。

这是最适合于在Linux的netfilter一个任务(即 iptables的)分组过滤框架。

劫持系统调用不是受支持的技术,会导致系统不稳定。在这种特定情况下,它在32位x86内核上将会失败严重,因为connect()没有自己的系统调用号;相反,socketcall()系统调用与SYS_CONNECT一起用作其第一个参数。您在系统调用表中覆盖的条目完全不相关。 (我相信它实际上是exit()的条目!)

+0

感谢您的回复。我实际上已经尝试过使用Netfilter,并且成功阻止了对静态IP网站的访问(动态IP是另一个问题)。但是,尝试通过更改tcp头的目标IP将网站重定向到另一个站点失败。即使在重新计算校验和之后。客户端(firefox,wget)一直向原始站点请求,就好像它不承认我发生的更改一样。那时候,我认为我可能比我需要的水平低得多,并且决定尝试在更高级别更改IP来连接系统调用。 – user30646

1

该代码显然是错误的,方法也是如此。 这里真正的目标是什么?

您有:

asmlinkage int hijackConnect(struct sock *sk, struct sockaddr *uaddr,int  addr_len) 

,并用它来取代对连接系统调用的条目()。很明显,这不可能是正确的 - 用户空间应该如何将指针传递给套接字?且不说连接系统调用接受不同的参数:

SYSCALL_DEFINE3(connect, int, fd, struct sockaddr __user *, uservaddr, 
       int, addrlen) 

第一个参数是文件描述符,而不是指向一个插座,让不出所料导致坠毁。

但是,这种方法本身存在根本上的缺陷。由于您稍后尝试调用实际的connect(),内核会从用户空间重新获取数据,并且攻击者可以简单地修改它以修复您的代码所做的任何操作。有关更多详情,请参阅http://www.watson.org/~robert/2007woot/

+0

谢谢,但是您能解释SYSCALL_DEFINE3的函数签名吗?因为我很难理解为什么它没有返回类型,但函数体返回的是int值。 – user30646

+0

http://lxr.free-electrons.com/source/include/linux/syscalls.h#L194 –