前言

最近项目上收到了许多钓鱼邮件,部门大佬对其进行分析后,本文是对部门大佬的分析进行一个复现。从中学习到了很多。这里团队的Snab师傅就带大家一起学习一下golang字符串拼接,如若有错请指正,一起学习进步。

一共分为两篇:

针对于钓鱼邮件当中的原文件进行分析—上

针对释放后的木马文件进行分析—下

思路

1、先将其解压,上传沙箱帮助分析

2、通过ida、xdebug进行分析

3、首先判断其语言

4、分析其所调用的api函数

5、分析应用行为

6、找到外联地址

沙箱分析

在线沙箱地址

–微步

js字符串变量拼接技巧_stringbuffer拼接字符_golang字符串拼接

可以看到该exe释放了3个文件

分别是:

Bplnfg.exe

xxxx.pdf

wsqmcons.exe

其中 使用了Bplnfg.exe 调用了wsqmcons.exe 和 ping.exe

看一下微步沙箱的进程分析

stringbuffer拼接字符_js字符串变量拼接技巧_golang字符串拼接

该钓鱼文件执行了以下步骤

1、利用释放的Bplnfg.exe 运行了 释放的 xxx.pdf

2、Bplnfg.exe 运行了 释放的wsqmcons.exe

3、ping -5 8.8.8.8 并删除了自生

通过 BpLnfg.exe /c start、BpLnfg.exe /c ping、del 等命令

可以大致猜测BpLnfg.exe 大概率是一个类似commond.exe的东西

而沙箱没有分析出来外联的地址

则可能存在以下情况:

1、反沙箱

通过检测当前运行环境是否正常,如果不正常则直接结束线程

调用sleep函数进行延时,沙箱的分析是有时间限制的,sleep延时个30分钟就能过沙箱检测

2、该初始的钓鱼文件并不是藏有shellcode的文件

而其释放的wsqmcons.exe可能才是最终的木马文件

判断该木马所使用的语言

使用工具:

ExeinfoPe、idea、CFF exploer等

ExeinfoPe

golang字符串拼接_js字符串变量拼接技巧_stringbuffer拼接字符

可以看到其是使用 Golang语言编写的 一个exe

Ida

stringbuffer拼接字符_golang字符串拼接_js字符串变量拼接技巧

js字符串变量拼接技巧_stringbuffer拼接字符_golang字符串拼接

通过idea反编译的到的符号表可以看到 有很多 golang的特征

可以完全确定其使用的语言就是golang

静态分析

以下是通过ida对木马进行 反编译得到的代码进行大致的猜测

一个程序需要运行起来都必须需要一个 主函数入口

一般都为main函数

该木马没有混淆可以直接通过反编译看到其使用的函数

js字符串变量拼接技巧_golang字符串拼接_stringbuffer拼接字符

Main()main_Hvdf_HCzKr() –隐藏窗口

先从 main函数入手

打开看到其main函数的内容长这样

void __cdecl main_main(){  main_Hvdf_HCzKr();  main_Start_Func_HCzKr((__int64)&byte_55859B, 40LL, (__int64)&byte_54F93F, 6LL, 0LL, 0LL, 30LL, 60LL, 10LL);  从第一个main_Hvdf_Hczkr() 开始void main_Hvdf_HCzKr(){  main_ShowConsoleAsync(0LL);}ShowConsoleAsync是golang里面隐藏/显示windows系统下的黑色命令窗口

以下是钓鱼文件中 main_ShowConsoleAsync 具体的实现方法

但他要怎么做 做什么我们只需要知道 他是为了隐藏窗口就足够了,我们的目的不在这里

void __golang main_ShowConsoleAsync(__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);                  }

main_Start_Func_HCzKr() –核心

js字符串变量拼接技巧_stringbuffer拼接字符_golang字符串拼接

Copy_cmd_pLTZN() –复制cmd

可以看到这个函数前面声明了很多变量 做了一些判断

我们可以很清楚的看到图里有一个函数

Copy_cmd_pLTZN();                                    __int128 main_Copy_cmd_pLTZN()                  {                    main_Get_Home_pLTZN();                    v5 = v1;                    v7 = v0;                    v2 = main_RandStringBytesRmndr_pLTZN(6LL);                     v6 = runtime_concatstring4(0LL, v7, v5, (__int64)&byte_55204B, 17LL, v2, v3, (__int64)&byte_54F497, 4LL);                    main_CopyFileddd_pLTZN(v6, v4, (__int64)&dword_5551A4, 27LL);                    *(_QWORD *)&result = v6;                    *((_QWORD *)&result + 1) = v4;                    return result;                  }                                   main_Get_Home_pLTZN --获取环境变量当中的值                  {                    v6 = os_Getenv((__int64)&byte_5500E5, 9LL);                    v2 = os_Getenv((__int64)&byte_54FD9B, 8LL);                    v0 = runtime_concatstring2(0LL, v6, v3, v2, v3);                    v1 = v5;                    if ( !v5 )                    {                      v0 = os_Getenv((__int64)&word_55084A, 11LL);                      v1 = v4;                    }                    *(_QWORD *)&result = v0;                    *((_QWORD *)&result + 1) = v1;                    return result;                  }     

RandStringBytesRmndr_pLTZN –生成一个随机字符串

runtime_concatstring–将生成的随机字符串与其他进行拼接

CopyFileddd_pLTZN–将文件复制文件

结合反编译代码和其函数名字 Copy_cmd可以大致猜测:

生成一串随机字符串xxx,并将cmd复制到某个目录下重命名为xxx.exe

GetCurrentAbPathByExecutable() –读取文件路径目录遍历

回到main_Start_Func_HCzKr()当中 来看这个函数

main_GetCurrentAbPathByExecutable_pLTZN();                  {                    os_Executable(); --获取当前运行环境的路径                    v6 = v2;                    v7 = v1;                    if ( v3 )                    {                      v8[0] = *(_QWORD *)(v3 + 8);                      v8[1] = v5;                      v5 = log_Fatal((__int64)v8, 1LL, 1LL);                    }                    v4 = path_filepath_Dir(v7, v6); --获取当前运行环境的上级目录                    path_filepath_EvalSymlinks(v4, v5); --获取所执行的文件的绝对路径                    return v6;                  }                  

通过几个golang当中”path/filepath”包下的函数 os.Executable()、filepath.Dir()、filepath.EvalSymlinks()

大致可以猜测其是在读取文件路径目录遍历

main_Run_normal_file_HCzK() –写文件->打开文件

 {                    v9 = runtime_concatstring2(0LL, (__int64)&byte_54F873, 6LL, a5, a6); --字符串拼接                    v6 = HCzKr_Asset(v9, v10);                    io_ioutil_WriteFile(a3, a4, v6, v7, v8, 493);                    main_Open_normal_file_pLTZN(a1, a2, a3, a4, 0LL, 0LL);                   }

HCzKr_Asset –暂时没看懂

js字符串变量拼接技巧_stringbuffer拼接字符_golang字符串拼接

io_ioutil_WriteFile –创建文件写入数据

js字符串变量拼接技巧_stringbuffer拼接字符_golang字符串拼接

main_Open_normal_file_pLTZN –打开创建的文件

golang字符串拼接_js字符串变量拼接技巧_stringbuffer拼接字符

main_Run_and_Task_HCzKr –释放木马文件并执行

{                    random_path_HCzKr = main_Get_random_path_HCzKr((__int64)&dword_55300C, 20LL, 0LL, 0LL);                    main_Get_muma_file_HCzKr(a1, a2, random_path_HCzKr);                    main_Update_task_HCzKr(random_path_HCzKr);                  }
main_Get_random_path_HCzKr
main_Get_Home_HCzKr(); v4 = runtime_concatstring2(0LL, v8, v10, a1, a2); if ( !a4 ) { main_Get_random_name_HCzKr(); } *(_QWORD *)&result = path_filepath_Join((__int64)v15, 2LL, 2LL); *((_QWORD *)&result + 1) = v12; main_Get_Home_HCzKr 与上面的GetCurrentAbPathByExecutable.Get_Home大致一样 main_Get_random_name_HCzKr 与GetCurrentAbPathByExecutable.RandStringBytesRmndr大致一样 path_filepath_Join golang当中"path/filepath"的函数 用于路径拼接
main_Get_muma_file_HCzKr --创建木马文件
{ v11 = runtime_concatstring2(0LL, (__int64)&byte_54F873, 6LL, a5, a6); HCzKr_Asset(v11, v12); io_ioutil_WriteFile(a3, a4, v8, v9, v10, 493); if ( a8 ) main_Open_normal_file_pLTZN(a1, a2, a3, a4, a7, a8); else main_Open_normal_file_pLTZN(a1, a2, a3, a4, 0LL, 0LL); }
main_Update_task_HCzKr --创建计划任务

stringbuffer拼接字符_golang字符串拼接_js字符串变量拼接技巧

可以看到Update_task_HCzKr当中多处引用了来自github上面的函数

github_com_capnspacehook_taskmaster_Connect                      // Connect connects to the local Task Scheduler service, using the current                      连接到本地任务计划程序服务                      // token for authentication. This function must run before any other functions                      用于身份验证的令牌                                   github_com_capnspacehook_taskmaster__ptr_TaskService_GetRegisteredTasks                            // GetRegisteredTasks enumerates the Task Scheduler database for all currently                     registered tasks.                            所有当前注册的任务枚举任务计划程序数据库                                   github_com_capnspacehook_taskmaster_TaskService_NewTaskDefinition                            // NewTaskDefinition returns a new task definition that can be used to register a new task.                            返回可用于注册新任务的新任务定义                            // Task settings and properties are set to Task Scheduler default values.                            任务设置和属性设置为“任务计划程序”默认值                                              github_com_capnspacehook_taskmaster__ptr_TaskService_UpdateTask                            //UpdateTask updates a registered task.                            更新注册表                                   github_com_capnspacehook_taskmaster__ptr_TaskService_CreateTask                            //CreateTask creates a registered task on the connected computer.                            在连接的计算机上创建一个已注册的任务

具体做了什么事情,还是得通过调试去看

main_Hide_clean_pLTZN –执行命令

 {                    v6 = os_exec_Command(a1, a2, (__int64)v7, 10LL, 10LL);                    v4 = (_BYTE *)runtime_newobject((__int64)&RTYPE_syscall_SysProcAttr);                    *v4 = 1;                    v5 = v6;                    if ( dword_7B7D70 )                      runtime_gcWriteBarrier();                    else                      *(_QWORD *)(v6 + 152) = v4;                    os_exec__ptr_Cmd_Start(v5);                    }

动态调试

隐藏窗口

可以看到当我们将木马文件丢到 x64dbg里面的时候他有一个窗口

stringbuffer拼接字符_golang字符串拼接_js字符串变量拼接技巧

在任意一处下断点后运行后 窗口不见了

但是程序还在运行

那么则证实了对静态分析当中的 main_Hvdf_HCzKr 将窗口进行了隐藏

stringbuffer拼接字符_js字符串变量拼接技巧_golang字符串拼接

按照反编译出来得到的地址,这里就是木马文件主函数的入口地点

stringbuffer拼接字符_js字符串变量拼接技巧_golang字符串拼接

获取计算机当前用户目录

stringbuffer拼接字符_golang字符串拼接_js字符串变量拼接技巧

复制CMD.exe

获取了一个字符串

将其释放到 C:UserswowfkAppDataRoaming 下面

stringbuffer拼接字符_js字符串变量拼接技巧_golang字符串拼接

将Cwindowssystem32cmd.exe复制到C:UserswowfkAppDataRoamingBpLnfg.exe

golang字符串拼接_stringbuffer拼接字符_js字符串变量拼接技巧

往下走可以看到此处调用了 readfile和writeFile

读取cmd.exe,将内容写进BpLnfg.exe

在 Win64 里使用下面寄存器来传递参数:

rcx – 第 1 个参数

rdx – 第 2 个参数

r8 – 第 3 个参数

r9 – 第 4 个参数

js字符串变量拼接技巧_golang字符串拼接_stringbuffer拼接字符

js字符串变量拼接技巧_stringbuffer拼接字符_golang字符串拼接

golang字符串拼接_js字符串变量拼接技巧_stringbuffer拼接字符

创建xxx.PDF文件

js字符串变量拼接技巧_stringbuffer拼接字符_golang字符串拼接

js字符串变量拼接技巧_golang字符串拼接_stringbuffer拼接字符

通过复制cmd后得到的BpLnfg.exe 打开该pdf文件

golang字符串拼接_stringbuffer拼接字符_js字符串变量拼接技巧

创建木马文件

js字符串变量拼接技巧_stringbuffer拼接字符_golang字符串拼接

stringbuffer拼接字符_js字符串变量拼接技巧_golang字符串拼接

启动木马文件

js字符串变量拼接技巧_golang字符串拼接_stringbuffer拼接字符

查看该环境是否联网并删除自身

golang字符串拼接_js字符串变量拼接技巧_stringbuffer拼接字符

总结

本次对这个释放文件的木马也就是出售的木马的分析到这也就结束了,如果要说这个木马文件有什么缺点的话:就是太过明显了,释放出来的pdf文件和原来的文件名称都不一致。下篇文章会对初始木马释放的shellcode木马进行分析。如果在日常防护当中,有人中了钓鱼邮件并点击了,请第一时间进行断网处理(断开互联网,有插入网线的也拔了)!!!

资源下载

1、公众号后台回复:jboss,获取jboss综合利用工具网盘下载链接。

2、公众号后台回复:ruoyi,获取ruoyi综合利用工具网盘下载链接。

3、公众号后台回复:postgresql,获取postgresql综合利用工具网盘下载链接

4、公众号后台回复:ecologySessiongolang字符串拼接,获取ecology任意用户登录小工具网盘下载链接

5、公众号回复:资料,获取代码审计,红队,物联网安全,漏洞挖掘相关整合资料。

限时特惠:本站每日持续更新海量设计资源,一年会员只需29.9元,全站资源免费下载
站长微信:ziyuanshu688