Overview

The sample originated as a message through wechat. The mawlare is currently unknown. Submissions to VirusTotal indicate that the original file name was 申博公司服务器采购表.exe which roughly translates to Shenbo company server purchase form.exe

Sample: 104bd2d33c119d007df2adbc571a3e8cfac722cf1f0b6156ba211f413905e9f4

When executed the sample downloads a polyglot jpg as a second stage from http://43.129.168.248/xlb.jpg

Second Stage: xlb.jpg - 32fb33a87f5123e919eb416b2c95a98b2f4b367812a51758bb1daeaf114b6b50

Related samples on VirusTotal that download the same second stage.

References:

Stage 1

Download http://43.129.168.248/xlb.jpg -> C:\\ProgramData\\xlb.jpg

Decrypt jpg starting at offset 83877 using -6 ^ 0x78 for range 7176 then directly execute!

import sys
import os

JPG_FILEPATH = r'/tmp/work/xlb.jpg'
OUT_SHELLCODE_FILEPATH = r'/tmp/work/shellcode.bin'


jpg_data = open(JPG_FILEPATH, 'rb').read()

jpg_offset = 83877

out = []
for i in range(0,7176):
    out.append(((jpg_data[jpg_offset+i] - 6) & 0xff) ^ 0x78)

open(OUT_SHELLCODE_FILEPATH, 'wb').write(bytes(out))
7176

Stage 2

Check mutex ozhpanvityfxknsr to ensure we are only running once.

Check for a list of process names.

proc_names = ['rr','471','tphpv','rjejbo','ufmfhsbn','hpphmf','xfdibu','gmzwqo','fu/fyf','xqt','ntfehf','fydfm','xpse','qpjou','usbz','gjsfgpy','thuppm','dmpve','opufqbe','dbmd','{ivepohgbohzv','mjof','rvjdlr']

for n in proc_names: out = '' for i in n: out += chr((ord(i) -1)&0xff) print(out)

C2 Comms

The malware connect to the C2 via a TCP socket using a hardcoded IP and port 43.129.168.248:16166

The malware sendd the C2 the it's current module name and waits to receive data.

The c2 return data is composed of a structure including a flag, length, xor key, data.

// DWORD flag
// DWORD length
// BYTE xor_key[32]
// Data ...

The C2 data contains a stage3 PE file that is reflectivly loaded into memory by the malware and executed via the export PluginMe

Stage 3

Stage3 was not directly recovered from the download chain but was recovered as an artifact from the infected host. An assumption was made that this was stage3 based on the unique export PluginMe.

Sample: 7d47e5871efc4c079531513f29926d394922d7954701f34dc6244ea311d20969

Reversing Tips

The binary is witten in C++ with STL using MSVC 6.0 (very old). The STL types cause all kinds of pain but we can using Lumina and FLIRT to identify most of the functions. Rolf has a nice IDA script that will add some STL structs to IDA for us.

One STL type the pops up is the List. To use the script to add this struct simply run it in IDA then use MakeListTypes(DWORD) in the Python CLI to define the structs.

We also had trouble with the string object. This was resolved on stream.

General

Mutex name: db38wzikd

Store data in registry under key HKEY_CURRENT_USER\Software\2345.com\Mini

  • logname

The logname is composed of the hostname username and timestamp likes so hostname-username-timestamp

"%d%02d%02d%02d%02d%02d",
    SystemTime.wYear,
    SystemTime.wMonth,
    SystemTime.wDay,
    SystemTime.wHour,
    SystemTime.wMinute,
    SystemTime.wSecond
  • group
  • host
  • install

C2 Comms

C2 host: tesla.tomcat.buzz port 16333 -> used to resolve to 43.129.168.248 (same as stage 1,2 C2)

The sample connects to the C2 and immediatly expects to recieve commands, no data is sent initially.

The C2 recv data is encrypted with ^ 0x33 - 103

C2 command xlbfdc might cause the RAT to upload its accumulated data.