2015-12-06 102 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 –