Flare-On 8th两道题目复现

 

Flare-On8由FireEye公司于今年9月份至10月份期间举办,共10道题目。笔者从中选取了自己感兴趣的三道题目进行复现,下文是前两道题目复现过程中所作笔记,第三道题目涉及到的技术点及分析过程笔者会单独写一篇文章。

 

0x01 Challenge 5:Flare Linux VM

题目描述如下:

压缩包中文件:

使用VMWare导入FLARE Linux VM.ovf文件,在打开虚拟机之前将网络连接修改为”桥接模式”,方便后续通过scp复制文件:

root身份登录,密码为flare。进入到Documents目录下查看:

新建一TXT文件,过一段时间查看发现其扩展名由.txt变为.txt.broken。使用crontab -l命令列出计划任务(若读者之前未接触过,可翻阅《鸟哥的Linux私房菜》第15章或是crontab(5) — Linux manual page):

在另一Linux虚拟机中使用scp命令将该文件复制出来,查看其详细信息:

getenv函数返回值与”/Documents”字符串拼接成绝对路径传递给opendir函数,调用readdir函数遍历该目录下文件。 将d_name字段值与...进行比较,之后判断后缀是否为.broken

如果上述条件均不满足,则进行加密:

加密函数只对原文件前0x400字节进行加密并写入.broken文件(若不足0x400字节,最后.broken文件亦是0x400字节大小,具体见下面对encrypt函数的分析),之后调用remove函数来删除原文件。

可以看到其加密函数采用变形RC4算法,区别在于最后的异或运算。使用crontab -r命令删除计划任务,将Documents目录下所有文件的.broken扩展名去掉:

#!/bin/bash

for name in `ls *.broken`
do
    mv $name ${name%.broken}
done

再执行一次/usr/lib/zyppe即可完成解密。逐一查看解密后文件,发现下面四个文件内容是未加密的:

按照ugali.txt文件给出提示,将Sausages.txtSpaghetti.txt拖入CyberChef,执行Arithmetic/Logic中的Rotate Left运算:

“c3BhZ2hldHRp”是”spaghetti”的Base64编码:

按照shopping_list.txt文件给出提示,进入/usr/bin目录,发现存在dot文件:

使用IDA打开:

计算输入的SHA256值,与b3c20caa9a1a82add9503e0eac43f741793d2031eb1c6e830274ed5ea36238bf进行比较,相等才会中止循环。按照shopping_list.txt文件给出顺序,查看reeses.txt

笔者一开始按照提示使用Reese's作为Key去解密ice_cream.txt,尝试数次结果均为乱码。按shopping_list.txt文件给出顺序,下一文件应为banana_chips.txt,结果如下:

其他以B开头文件通过异或运算解码出内容如下:

其他以R开头文件亦可使用Base64解码出内容:

笔者起初以为ENCODED_BYTE + 27 + NUMBER1 * NUMBER2 - NUMBER3公式中3个NUMBER是前边解码出的三个字节,但尝试后发现并不是,而是环境变量:

代入三个环境变量,公式化简为ENCODED_BYTE-4。笔者同时查看了.bashrc文件:

使用公式解密ice_cream.txticed_coffee.txtinstant_noodles.txt

笔者在解码出ice_cream.txt结果时,不知道其内容有何作用,等解码出instant_noodles.txt结果时回看,发现每个数字对应字母各不相同,那么0xMS——0x64,iced_coffee.txt结果中给出的SREFBE——493513。以493513作为RC4算法的Key去解密nachos.txtnatillas.txtnutella.txt

根据提示进行搜索,算法应使用Bifid Cipher:

Key应使用eggs

解密以D开头文件:

根据提示,于Documents目录下看到隐藏文件.daiquiris.txt,使用Bifid Cipher解密:

搜索Giovan Battista Bellaso相关,确定下一步应使用维吉尼亚密码(Key是microwaves):

解密以O开头文件:

根据文件给出的推特账号进行搜索:

从中提取出AES解密所需Key及IV:

解密以T开头文件:

/etc/Quijote.txt中内容来自《堂吉诃德》,使用在线西班牙语词频分析工具分析其中出现的独特单词个数:

将所有十六进制ASCII码转换成字符:

输入dot,得到Flag:

这道题目前面部分对勒索软件zyppe的分析是很有意思的,笔者之前未接触过Linux平台的恶意软件分析。后面部分环环相扣,梳理清楚逻辑之后按部就班使用CyberChef解密即可得出Flag,难度偏易。

 

0x02 Challenge 7:spel

题目只给了一个PE文件,查看基本信息:

拖入IDA查看,分析了很长一段时间才完成,其函数数量非常多:

放入沙箱中,没有检测出有效信息:

运行界面:

关闭之后,可以看到其仍在后台运行:

看到官方WriteUp上提到capa,之前一直没有使用过该工具。按照capa explorer documentation给出步骤搭建好环境,capa rules下载链接文中已经给出,下载到本地后于Settings——capa rules path一栏中填写即可。capa.exe spel.exe部分输出结果:

将上面结果与IDA插件capa explorer分析结果结合,在Search一栏中输入”stackstring”,定位到相关函数后勾选”Limit results to current function”:

切换模式查看,发现是很长一段向栈中写值指令,直接跳转到0x14017973B处向上回溯:

可以看到总长度为0x2ED2D,之后调用VirtualAllocExNuma函数申请同样大小且具有PAGE_EXECUTE_READWRITE权限的一块内存,并将内容复制到新内存块中,最终跳转到新内存块执行:

初始化部分寄存器之后跳转到Offset 0x40处执行:

以往笔者遇到下图向栈中写字符串操作,是通过动调在合适指令处设断点后观察内存:

在看官方WriteUp时,看到其提及FLOSS与Ironstrings两个工具:

关于Ironstrings的安装可以参考FLARE Script Series: Recovering Stackstrings Using Emulation with ironstrings一文。

--no-static-strings参数运行FLOSS:

执行ironstrings.py脚本:

之后通过RCX传递Hash值给sub_A1C函数获取LdrLoadDllLdrGetProcedureAddress调用地址:

将stackstring传递给上述两个函数获取地址并调用之,Offset 0xB28处存储一PE文件。GetNativeSystemInfo判断当前运行环境,获取PE文件Image Optional Header中ImageBase及SizeOfImage字段值后调用VirtualAlloc函数申请内存空间(第一次以ImageBase作为lpAddress,申请失败则置为NULL)。接下来根据各区段VirtualAddress,PointerToRawData及SizeOfRawData加载区段至申请内存空间中,根据重定位表进行重定位。调用VirtualProtect设置各区段flNewProtect值,通过RtlAddFunctionTable函数设置异常,最终通过PE文件Image Optional Header中AddressOfEntryPoint字段定位入口点完成加载。

关于以上描述过程使用的Reflective DLL Injection技术可参阅DOUBLEPULSAR Usermode Analysis: Generic Reflective DLL Loader一文。

将其加载DLL Dump出来之后,capa检测到其.data区段中存有另一PE文件:

从EntryPoint执行到DllMain,传递PE文件存储地址给加载函数进行加载:

之后调用sub_27327D0获取其导出函数Start地址进行调用:

首先是异或解密stackstring:

其流程是申请一块内存—>向栈中写值—>XOR解密—>复制至申请内存空间,官方WriteUp中给出了解密IDAPython脚本,笔者分析时直接在函数结束处设置断点,观察内存内容:

官方WriteUp中提到一个IDA Plugin——Shellcode Hashes,笔者觉得很好用,可以提高静态分析的效率和体验。该插件与上文提及的Ironstrings都位于flare-ida中,将shellcode_hashes_search_plugin.py与flare目录一同复制到IDA的Plugins目录之后即可使用,选择\flare-ida\shellcode_hashes目录下的sc_hashes.db数据库文件即可:

前者是上文提及sub_A1C函数,后者是最后Dump出来的DLL中函数。

接下来调用sub_180001A40sub_180001990会调用该函数两次——第一次传递给它的第二个参数值为1,第二次传递有两种情况:2或是8,若Filename为”Spell.EXE”则传递2,否则传递8。第一次调用会解密一串字符串,获取Filename及加载名为PNG的资源:

sub_180001A40保存获取到的相关信息时结构如下(后面还有一串字符inactive,没有放在图中):

sub_180002E60函数判断Filename是否等于”Spell.EXE”:

若不等返回0,那么传递给sub_180001A40函数第二个参数值为8:

直接退出:

将程序命名为”Spell.EXE”之后再次调试,便可进入到sub_180001A40函数处理第二个参数为2的情形:

第二个参数为2时会调用sub_180001F80,该函数会向inactive[.]flare-on[.]com发起连接,根据接收到的不同命令执行不同的操作。后续在看官方WriteUp时,其提到FakeNet-NG工具,笔者在虚拟机里按照FakeNet Genie: Improving Dynamic Malware Analysis with Cheat Codes for FakeNet-NG一文进行了配置,之后再次进行调试,分析出sub_180002070函数(由sub_180001F80调用)会处理三种命令:

  • exe:调用sub_180002410
  • run:调用sub_180002590
  • flare-on.com:返回1

sample_custom_response.ini中TcpRawFile字段为同目录下文件,该文件存储要返回的命令:

当该函数返回1时,会进入到之后的sub_180002A20函数,设置注册表键值。接下来调用sub_180002F70,若返回1则进入sub_180002730设置另一注册表键值。第一个设置的键值:

该结果由”flare-on.com”与0x1B8A7E991DC19F1415891D8A异或而来:

sub_180002730通过switch将Flag与0xFAE58ED80D859C9B8D87ACD7A7B7A4E2C3C1A806C29633进行异或:

之后再次调用sub_180002A20设置第二个键值:

这道题目很贴合实际的样本分析,官方WriteUp中有这样一段话可以概括之:This challenge was inspired by multiple malware samples we’ve analyzed over the last year。其使用的Reflective DLL Injection技术,stackstring,API Hashes,混淆字符串直到使用时才解密,C2等笔者在之前的样本分析过程都曾遇到过,而此题将其都融合在一个里面,是很有意思的一道题目。在分析过程中,结合官方WriteUp学习了几个新工具或是IDA Plugin(capa,FLOSS,Ironstrings,shellcode_hashes,FakeNet-NG)的使用,方便以后的样本分析。

 

0x03 参阅链接

(完)