1/19 By oR10n oR10n Labs or10nlabs.tech/reverse-engineering-the-new-mustang-panda-plugx-downloader/ 2020-07-20 HomeReverse EngineeringReverse Engineering the New Mustang Panda PlugX Downloader Reverse Engineering the New Mustang Panda PlugX Downloader Hello everyone! Recently, I came across this tweet by a security researcher known as @Arkbird_SOLG mentioning a targeted campaign using a Vatican themed lures by an APT group known as Mustang Panda. Note: For those of you who are not yet familiar with Mustang Panda, security vendors like Crowdstrike, Avira, and Anomali have released detailed reports about this threat group in the past. You can also check some of my earlier blog posts about reverse engineering the loader and parts of the actual RAT. [TLP:White] The #APT Mustang Panda group targets the Vatican state with lures. This uses the TTPs already used for pushing the payloads as vulnerable Word version (office 2007) by side-loading method for execute a dll. pic.twitter.com/48ScU5hfu0 — Arkbird (@Arkbird_SOLG) July 14, 2020 Note: More IOCs related to the campaign are published on this GIthub repo. The tweet mentioned the use of vulnerable version of Microsoft word and a malicious DLL that gets executed via DLL side-loading. Based from this ANY.RUN task posted by @Arkbird_SOLG, it seems like the malicious DLL file has a downloader functionality and fetches a .dat file from hxxp://103.85.24[.]190/qum.dat, which in turn leads to the delivery of PlugX on the target system. So for this post, we will take a look into the inner workings of this new downloader to further understand how this campaign works. Sample Details Filename MD5 Description QUM, IL VATICANO DELL’ISLAM.exe ceaa5817a65e914aa178b28f12359a46 Legitimate MS Word executable https://or10nlabs.tech/reverse-engineering-the-new-mustang-panda-plugx-downloader/ https://or10nlabs.tech/ https://or10nlabs.tech/category/re/ https://www.crowdstrike.com/blog/meet-crowdstrikes-adversary-of-the-month-for-june-mustang-panda/ https://insights.oem.avira.com/new-wave-of-plugx-targets-hong-kong/ https://www.anomali.com/blog/china-based-apt-mustang-panda-targets-minority-groups-public-and-private-sector-organizations https://or10nlabs.tech/reverse-engineering-the-mustang-panda-plugx-loader/ https://or10nlabs.tech/reverse-engineering-the-mustang-panda-plugx-rat-extracting-the-config/ https://twitter.com/hashtag/APT?src=hash&ref_src=twsrc%5Etfw https://t.co/48ScU5hfu0 https://twitter.com/Arkbird_SOLG/status/1283000270151208960?ref_src=twsrc%5Etfw https://github.com/StrangerealIntel/DailyIOC/blob/master/2020-07-14/Mustang%20Panda/IOC-Mustang-Panda-2020-07-14.csvhttp:// https://app.any.run/tasks/6c5cff49-df4e-4edf-86bc-b68ae8cd507b/ 2/19 Filename MD5 Description wwlib.dll c6206b8eacabc1dc3578cec2b91c949a Malicious DLL Static Analysis Tossing the DLL file to DiE, we can immediately note down some important details like: – Export Names – Imports indicating that this sample dynamically resolves addresses of Win32 API functions at runtime via LoadLibrary and GetProcAddress – Presence of PE resources named SCRDLL and SCRDAT – No packer signature identified and low file entropy which indicates that this file is likely not packed https://github.com/horsicq/Detect-It-Easy 3/19 DW) Detect It Easy 2.05 File name: (Cr \Users user Desktop wwib.dll Type: PE Export EntryPoant: 00003330 NumberOfections: 0005 Entropy SizeOfimage: patcher simple patch({-)[-] Microsoft Linker(6.0) (DLL 32) Dil Name OriginalFirstThunk TimeDateStamp ns Ordinal Hint Olc2 Ole 01236 oo7d Ols ForwarderChain LoadLibraryA LocalFree GetModuleHandleA ExitProcess (GetProcAddress 10000000 oooorOOd PE 3/19 4/19 [DR Detect tt Easy 2.05 File name: C:\Users user Desktop wwib.dl Type: PE : 3248 Entropy Export Import Resource 10002 * ‘SRODAT 10001 4/19 5/19 Checking the PE resources and extracing SCRDLL shows us that the DLL file contains a .docx file as it resource. 6/19 Running FLOSS on the sample shows us some interesting strings that indicates potential capabilities such as: – Communicating via HTTP – Utilizing the embedded resource – Executing OS commands – Loading something in memory for execution https://github.com/fireeye/flare-floss 7/19 wininet ConnectA InternetOpenA InternetConnectA InternetSetOptionA HttpOpenRequestA HttpQueryInfoA HttpSendRequestA InternetCrackUrlA InternetCloseHandle Mozilla/5.0 (compatible; MSIE 6.0; Windows NT 10.1); Microsoft Internet Explorer FindResourceA LoadResource SizeofResource LocalAlloc LocaRtlDecompressBuffer VirtualProtect SetFileAttributesA ShellExecuteA lstrlenA Additionally, we can see a big blob with repeating pattern of “123456789“. If you’ve seen my partial analysis of Mustang Panda’s PlugX RAT, you can immediately tell that this probably contains some malware configuration. Now, to confirm some of this hypothesis we can use the newly released open-source tool by FireEye’s FLARE team called capa. As a short overview, capa recognize capabilities of programs from repetitive patterns of API calls, strings, constants, and other features. In basic terms, you can simply run it against a sample and it will tell you the capabilities based on rules crafted by RE experts from the FLARE team. The best thing about this is now that it’s open-sourced, anyone can contribute on crafting rules and extending the capability of the capa itself. For a detailed overview of capa, you can check out this blog post released by FIreEye. https://or10nlabs.tech/reverse-engineering-the-mustang-panda-plugx-rat-extracting-the-config/ https://github.com/fireeye/capa https://www.fireeye.com/blog/threat-research/2020/07/capa-automatically-identify-malware-capabilities.html 8/19 Running capa on the sample tells us that it: – contains obfuscated stackstrings – encodes data using XOR – contains a resource section – link functions at runtime Tip: You can utilize -v or -vv argument in capa to see specific offsets where a rule matched. This is extremely helpful when disassembling and labeling functions with IDA. Dynamic Analysis Running this sample on a VM with monitoring tools and proper setup will give us a ton of useful information. Note: I downloaded hxxp://103.85.24[.]190/qum.dat and placed it on C:\Python27\Lib\site- packages\fakenet\defaultFiles\ in order to allow Fakenet to serve this file and fully simulate the infection chain. https://github.com/fireeye/flare-fakenet-ng 9/19 As you can see from the ProcMon and Fakenet outputs above, the infection chain looks like this: – Sample drops a .docx file in the current directory. This is the same .docx file in the resource section – Sample sets the file attributes of the .docx file to HN (Hidden / Not Indexed) – Sample opens the .docx file. I took a quick look on this .docx file and it seems that this is just a decoy file to masquerade the true purpose of the sample – Sample connects to hxxp://103.85.24[.]190/qum.dat to fetch a next stage payload. This doesn’t seem to create a new file on disk so this is probably executed in memory – Sample creates qum.exe, hex.dll, and adobeupdate.dat on %temp%. These are PlugX components – Sample executes qum.exe – qum.exe creates a copy of the PlugX components (AAM Updates.exe, hex.dll, nad adobeupdate.dat) to %programdata%\AAM UpdatesmKD\ – qum.exe obtains persistence for AAM Updates.exe on the system via the registry Run key – qum.exe executes AAM Updates.exe – AAM Updates.exe periodically connects to www.systeminfor[.]com using various ports for C2 Now that we have these information, we can use these as a guide while doing in-depth analysis on the sample. In-depth Analysis Since we almost have a full picture of the infection chain, I will breeze through some of the tedious parts of the disassembly and focus on important ones. Dropping the decoy .docx file As we’ve seen on our earlier analysis, we know that the sample has a decoy .docx file on the resource section and is dropped at the current directory upon execution. We also know that the file attribute of decoy .docx file is set to hidden and that the file is opened afterwards to fool the users into thinking that executed file is just a normal .docx file. This is achieved via a series of calls to LocalAlloc, FindResourceA, LoadResource, SizeofResource, CreateFile, WriteFile, GetCurrentDirectoryA, SetFileAttribute, and ShellExecuteA. As expected from Mustang Panda, these Win32 API functions are stored in the sample as stackstrings and the address of the functions are dynamically resolved at runtime via LoadLibrary and GetProcAddress. 10/19 This is a recurring technique through out the disassembly and the following snippet is a good example: Decrypting the malware config After dropping and opening the decoy .docx file, the sample proceeds to decrypt the malware configuration. The function responsible for this is called on offset 10002EAD. As you can the following values were pushed onto the stack before the function is called – an offset unk_10005000, 1002h (4098), an address pointing to the string “123456789”, and result of strlen(“123456789”).These are the adrress for the encrypted config, the length of the encrypted config, the address for the key, and the length of key respectively. 11/19 If we check unk_10005000, we can see that it points to offset 0 of the .data section. Taking a closer look on the decryption function (sub_10001450), we can immediately determine that it implements XOR decryption with multi-byte key. 12/19 eee eee ee 0000000010001450 func decrypt config proc near 0000000010001450 0000000010001450 arg 0= 0000000010001450 arg 4= 0000000010001450 arg 8= 0000000010001450 arg c= 0000000010001450 0000000010001450 push 0000000010001451 push 0000000010001452 mov 0000000010001456 xor 0000000010001458 test 000000001000145A mov 000000001000145¢C jle dword ptr 4 dword ptr 8 dword ptr 0Ch dword ptr 10h ebx edi edi, [espt8targ 4] ecx, ecx edi, edi bl, 9Fh short loc_10001484 (al ca 000000001000145E push 000000001000145F mov 0000000010001463 push 0000000010001464 mov ebp ebp, [espt+0Chtarg 8] esi esi, [esp+l10ht+arg 0] vy [al can 0000000010001468 0000000010001468 mov 000000001000146A or 000000001000146D cdq 0000000010001472 mov 0000000010001475 mov 0000000010001478 xor 000000001000147A mov 000000001000147D inc 000000001000147E cmp 0000000010001480 jl 0000000010001468 loc_ 10001468: 000000001000146E idiv eax, ecx bl, OF2h [esp+l10h+arg C] al, [edx+ebp] dl, [ecx+esi] dl, al [ecxtesi], dl ecx ecx, edi short loc_10001468 Gus 0000000010001482 pop esi 0000000010001483 pop ebp (al ca = 0000000010001484 0000000010001486 0000000010001484 loc 10001484: 0000000010001484 pop 0000000010001485 pop 0000000010001486 retn 0000000010001486 func _decrypt_config endp edi ebx 12/19 13/19 This is very similar to how the configuration for the PlugX RAT is stored. Here’s how the decrypted configuration looks like: The URL for the next stage payload is located at offset 0 of the config file. Which allows us to do a quick-and-dirty python script to decrypt the config and extract the URL for the next stage payload: Fetching the next stage payload After decrypting the config file, the sample proceeds to fetch the next stage payload. This is achieved through a series of calls to InternetCrackUrlA, InternetOpenA, InternetOpenUrlA, HttpQueryInfoA, and InternetReadFileA located in the function sub_100020F0. The payload is stored directly to a memory buffer initiated through a call to LocalAlloc. https://or10nlabs.tech/reverse-engineering-the-mustang-panda-plugx-rat-extracting-the-config/ 14/19 The following is a sample HTTP request used to fetch the next stage payload: It’s also worth noting that there is a backup function at sub_10001490 used to fetch the next stage payload with a slightly different implementation. One of the glaring difference noticeable in a network packet capture is the use of a different user agent string “Mozilla/5.0 (compatible; MSIE 6.0; Windows NT 10.1);” as opposed to “Microsoft Internet Explorer”. 15/19 Decrypting and executing the next stage payload After successfully fetching the payload, the sample proceeds to decrypt and execute the next stage payload. The call to the responsible function (sub_10001110) can be found at offset 1000269D. Looking closer at the function, we can see a series of call to LocalAlloc, RtlDecompressBuffer, the multi-byte XOR function (sub_10001450), and VirtualProtect prior to a call to the next stage payload. Looking closer at the call to RtlDecompressBuffer, we can see a PUSH 2 prior to the call which indicates that the next stage payload is compressed with LZNT1 algorithm aside from being encrypted with XOR using a multi-byte key. https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-xca/5655f4a3-6ba4-489b-959f-e1f407c52f15 16/19 Looking closer at the call to the multi-byte XOR function (10001372), we can see that the XOR key is actually the first string in the decompressed payload itself. This is something similar to what we observed previously, on how the PlugX loader decrypts the encrypted payload. Again, we can create a quick-and-dirty python script to automate the decryption of the next stage payload. The next stage payload is actually never created on disk but is directly loaded into a memory buffer initiated through LocalAlloc. https://or10nlabs.tech/reverse-engineering-the-mustang-panda-plugx-loader/ 17/19 Several lines of disassembly after the call to the multi-byte XOR function, we can see a call to VirtualProtect to change the access protection of the memory buffer containing the decrypted next stage payload to 0x40 (PAGE_EXECUTE_READWRITE). Immediately after, a CALL ESI is made to execute it. Following the call on a debugger, we can see a small shellcode right after 0x5a4d which will effectively call an Export function on the next stage payload named Loader. For the sake of brevity, we won’t go through the next stage payload in detail but it’s essentially a dropper responsible for dropping and executing the PlugX components on the system.The components are actually embedded as PE resources. 18/19 To quickly extract the PlugX indicators, we can dump the encrypted payload from the PE resource of the dropper and use the scripts mentioned on my earlier blog posts about reverse engineering the loader and extracting the config from the PlugX RAT. $ plugx_decrypt.py plugx_payload Identified Key: 454f4961444d71716941 Payload decrypted at plugx_payload-decrypted! $ plugx_extract_config.py plugx_payload-decrypted File: plugx_payload-decrypted XOR key: 313233343536373839 Folder name: AAM UpdatesmKD Mutex name: KvcpmvXXtltWtOLoYreI C2 servers: www.systeminfor.com:110 www.systeminfor.com:995 www.systeminfor.com:25 Config extraction successful!!! https://or10nlabs.tech/reverse-engineering-the-mustang-panda-plugx-loader/ https://or10nlabs.tech/reverse-engineering-the-mustang-panda-plugx-rat-extracting-the-config/ 19/19 There you have it folks! I really hope this blog post helps the community in further understanding this malware and the associated TTPs of the Mustang Panda group. As always, thank you for taking the time to read my blog and I hope you can re-share this to the community for awareness. Tags:Downloader, Malware, Mustang Panda, PlugX, Reverse Engineering https://or10nlabs.tech/tag/downloader/ https://or10nlabs.tech/tag/malware/ https://or10nlabs.tech/tag/mustang-panda/ https://or10nlabs.tech/tag/plugx/ https://or10nlabs.tech/tag/reverse-engineering/