透明部落样本payload分析

阅读量316508

|

发布时间 : 2020-11-10 15:30:56

透明部落”APT组织携新型武器—USB,向政府和军队发起新一轮攻击- 安全客,安全资讯平台

 

背景信息

“透明部落”是一个南亚(可能是巴基斯坦)来源具有政府背景的APT组织,其长期针对周边国家和地区的军队和政府机构实施定向攻击,其和南亚“响尾蛇”APT组织属于两个相互 “敌对”的APT组织。
样本信息

由于没有找到docx的md5所以也无法获取到样本只能从宏样本释放的payload进行分析。

• 档案名称:TrayIcos.exe
• 文件类型:适用于MS Windows(GUI)Intel 80386 32位的PE32可执行文件
• 档案大小:2.4 MB(2519552位元组)
• MD5:18ACD5EBED316061F885F54F82F00017
• 签名:Microsoft Visual C ++ 8

 

静态分析

初步先使用ida打开观看下大体的内容,下图展示的大概就是获取资源然后进行解密等操作

下面这张图如果有经验的话可以发现这是利用了CLR进行内存中加载.NET程序,没有经验也没有关系后面也都会提到。

下面就是实现C++运行donet的代码

#include <windows.h>
#include <oleauto.h>
#include <mscoree.h>
#include <comdef.h>
#include <cstdio>
#include <cstdint>
#include <cstring>
#include <cstdlib>
#include <sys/stat.h>
#import "mscorlib.tlb" raw_interfaces_only
void rundotnet(void *code, size_t len) {
    HRESULT                  hr;
    ICorRuntimeHost          *icrh;
    IUnknownPtr              iu;
    mscorlib::_AppDomainPtr  ad;
    mscorlib::_AssemblyPtr   as;
    mscorlib::_MethodInfoPtr mi;
    VARIANT                  v1, v2;
    SAFEARRAY                *sa;
    SAFEARRAYBOUND           sab;
    printf("CoCreateInstance(ICorRuntimeHost).n");
    hr = CoInitializeEx(NULL, COINIT_MULTITHREADED);
    hr = CoCreateInstance(
      CLSID_CorRuntimeHost, 
      NULL, 
      CLSCTX_ALL,
      IID_ICorRuntimeHost, 
      (LPVOID*)&icrh);
    if(FAILED(hr)) return;
    printf("ICorRuntimeHost::Start()n");
    hr = icrh->Start();
    if(SUCCEEDED(hr)) {
      printf("ICorRuntimeHost::GetDefaultDomain()n");
      hr = icrh->GetDefaultDomain(&iu);
      if(SUCCEEDED(hr)) {
        printf("IUnknown::QueryInterface()n");
        hr = iu->QueryInterface(IID_PPV_ARGS(&ad));
        if(SUCCEEDED(hr)) {
          sab.lLbound   = 0;
          sab.cElements = len;
          printf("SafeArrayCreate()n");
          sa = SafeArrayCreate(VT_UI1, 1, &sab);
          if(sa != NULL) {
            CopyMemory(sa->pvData, code, len);
            printf("AppDomain::Load_3()n");
            hr = ad->Load_3(sa, &as);
            if(SUCCEEDED(hr)) {
              printf("Assembly::get_EntryPoint()n");
              hr = as->get_EntryPoint(&mi);
              if(SUCCEEDED(hr)) {
                v1.vt    = VT_NULL;
                v1.plVal = NULL;
                printf("MethodInfo::Invoke_3()n");
                hr = mi->Invoke_3(v1, NULL, &v2);
                mi->Release();
              }
              as->Release();
            }
            SafeArrayDestroy(sa);
          }
          ad->Release();
        }
        iu->Release();
      }
      icrh->Stop();
    }
    icrh->Release();
}
int main(int argc, char *argv[])
{
    void *mem;
    struct stat fs;
    FILE *fd;
    if(argc != 2) {
      printf("usage: rundotnet <.NET assembly>n");
      return 0;
    }
    // 1. get the size of file
    stat(argv[1], &fs);
    if(fs.st_size == 0) {
      printf("file is empty.n");
      return 0;
    }
    // 2. try open assembly
    fd = fopen(argv[1], "rb");
    if(fd == NULL) {
      printf("unable to open "%s".n", argv[1]);
      return 0;
    }
    // 3. allocate memory 
    mem = malloc(fs.st_size);
    if(mem != NULL) {
      // 4. read file into memory
      fread(mem, 1, fs.st_size, fd);
      // 5. run the program from memory
      rundotnet(mem, fs.st_size);
      // 6. free memory
      free(mem);
    }
    // 7. close assembly
    fclose(fd);
    return 0;
}

 

动态调试

有了大体的认识之后我们可以开始用OD调试看看里面具体的细节,首先我们可以来到程序的入口点,不是VC的入口点,而是进入main函数里面的代码。发现调用了OleInitialize这个函数,这个函数的作用是初始化COM库。所以后面肯定使用到了COM库。

下面是这种操作mov了一大堆的指令然后再调用了一个call

进入这个call里面观看,这个函数就是取到了之前mov的数组进行解密了

那么我们直接来到return 看看返回值,可以很明显发现这解密出了字符串

所以我把这个函数命名为DecString

下面是获取环境变量Cor_Enable_Profiling的值如果和0x41B2A0做比较如果不等于则会继续走下面,等于则跳转走另一分支,另一分支就是直接结束程序。所以我们走遍历模块的。

下面的api就是在创建快照

遍历模块和解密字符串

解密出来mscorjit.dll,这个dll是donet的,所以遍历模块应该是为了找到这个dll

这一段汇编就是strcmp,不熟悉的可以多看看

如果找到一样的则关闭句柄,并且return

然后下面又在找这个dll clrjit.dll

下面的代码就是一直循环在找那两个dll

当最后没有找到的话就会来到后面的解析资源的操作
遍历模块没看懂的话可以看看MSDN遍历模块

这里是在找资源了

然后先malloc一个资源大小 然后又new了一个0x40022的大小

很明显下面是个if else 就是下面这样的汇编格式,到这里内存空间就申请完了,下面就是拷贝资源了吧

cmp
jxx
ELSE_BEGIN:

jmp ELSE_END
….
ELSE_END:

这个函数主要做的就是把资源拷贝到new出来的空间

这个是按照1024个字节拷贝到malloc这个内存中

这里在取模sizeofRes也就是拷贝不足1024个字节的资源到malloc申请的空间中

释放资源后,malloc了一个空间,这个空间就是放解密后的资源数据

看看下面解密函数栈,第一个是刚刚malloc的空间,也就是解密数据要放的空间。第二个是之前malloc的大小。第三个是之前mallco空间的地址(加密的数据),最后一个是资源的大小。

解密后的资源不难看出有一个PE

再后面也没啥看的大概就是准备donet的环境,把该有的dll加载起来然后用C++调用这个PE文件,有兴趣的可以看看

现在我把那个PE给dump出来看看

使用PE解析工具看看发现资源里面还藏了个PE

既然这样这个dll就没啥必要看了大概功能就是释放执行里面的PE还是个Loader,用dnspy把资源保存出来

一看就是被混淆了的使用工具de4dot.exe去除试试

去完混淆后基本能很好的看懂了

这里就是远控的的代码地方了 donet的感兴趣的自己可以看看还是比较简单的

VT查了下最里层的Payload还没有被查

 

样本来源

cyberstanc

本文由NATIVE原创发布

转载,请参考转载声明,注明出处: https://www.anquanke.com/post/id/221906

安全客 - 有思想的安全新媒体

分享到:微信
+15赞
收藏
NATIVE
分享到:微信

发表评论

内容需知
合作单位
  • 安全客
  • 安全客
Copyright © 北京奇虎科技有限公司 三六零数字安全科技集团有限公司 安全客 All Rights Reserved 京ICP备08010314号-66