Skip to main content

Attack Vector That Triggered By Risk Board Game

· 13 min read
Mert Degirmenci


Albert Lamorisse invented Risk game in 1957. According to Wikipedia,

Risk is a strategy board game of diplomacy, conflict and conquest for two to six players. The standard version is played on a board depicting a political map of Earth, divided into forty-two territories, which are grouped into six continents. Turn rotates among players who control armies of playing pieces with which they attempt to capture territories from other players, with results determined by dice rolls. Players may form and dissolve alliances during the course of the game. The goal of the game is to occupy every territory on the board and in doing so, eliminate the other players.

During the early stages of the analysis of suspicious files, the abovementioned rules and goals of the game were observed. The code, the strings, the images all seem to form the digital version of the game.

Some strings about the game inside the files

At first glance, there was no malicious indicator at all. In contrast, on Virustotal, the files have a very bad reputation. After digging beneath the surface, the findings lead to a Github account and then a repository which is greatly matched with the files except for the sizes. The comparison results lighting up a complex attack vector that is constructed by various stages and also utilizes steganography-like technique in order to trigger the next step in one point of the execution. The attack vectors are ended with Agent-Tesla and Nano Core Client RATs. Agent-Tesla is a spyware that is active since 2014 and one Agent-Tesla variant in-depth analysis is available on

Nano Core Client RAT

This particular remote access trojan has been discovered in 2013 and since then multiple versions have been all around and used by various threat actors. The capability of the malware is extended by the plugins. The analyzed sample's overall code quality takes attention especially when combines with exception handling and logging features.

The Attack Vector

Stage1: Risk

The analyzed samples are based on .Net Framework PE executable files. After glance their code, resources, and other contents, even all 7 files have various names about payment, booking offers, BRITISH PETROLEUM, etc. the thing is crystal clear that the files are about Risk board game. Code, strings that represent rules, image files in resources section all suggest this. These contents create an illusion for the analyst, it seems to be a game sample. And during the early stages of the dynamic analysis session, they don't reveal any [spoiler alert] malicious behavior [/spoiler alert]. On the other hand, during the early stages of the static analysis, the flow starts and continues to configure Forms. Later, dissecting the contents piece by piece, a string glance behind from the screen: the name that looks like the creator of the something.

The string that mentions a name as 'Creator'

By using this little information, a profile on Github and by then a repository is discovered. The name of the repository is Risk-Game. The language of the repository C#. Bingo!

Risk-Game project's repository on Github

This project has been added to the analysis, and all the signs that are observed apply to this file as well. The major differences are, on disk, the executable file of the project is much bigger than the suspicious samples.

Size differences

A plausible scenario is that the open-source project can be used to hide malicious behavior beneath the Risk board game. It also clarifies the size difference, reducing the size might be a plus by shrinking undesired parts. With this thought in mind, one of the suspicious files and the project file are compared side by side according to the flow and before long, during one of the Form sequences, an additional code block draws the attention.

Side-by-side comparison

At the basic level, the injected code block is loading a file named 'CassaPub2' ('CassaPub4' is also observed) that located in the resources section to the process by using 'Assembly.Load' function. Then it triggers this file with a parameter that it prepares by merging hard-coded Arabic strings dynamically.

The string of the one sample, that is going to be merged

The loaded file appears to be a DLL file, named GuitarLibX, based on .Net, and 'Hide_GuitarX' class is triggered.


Constructor of the Hide_GuitarX class takes the merged string as a parameter and using this value it reads a PNG file stored inside the resources section of the Risk-like file. Then the PNG file is subject to a decryption algorithm. The algorithm:

  • Reads pixel by pixel and filter out those RGBA(0, 0, 0, 0)
  • Separates R, G and B values and stores them in a new array
  • The first 16 values of the array used as XOR key array and the rest of the values XORed one by one
  • Decrypted data is loaded to the process and executed

A part of the routine that decrypts the image inside the resources section

GuitarLibX file triggers the next step of the attack vector by decrypting an image file located at the resources section. In order to hijack and grab the decrypted data, a new C# project is created by patching the code, instead of executing decrypted data, writes to the disk.


The file GuitarLibX has an image file inside its resources.

The unused image inside GuitarLibX file

Corresponding image file is used by another code block that isn't triggered and the type of the code is Form. A new C# project has been created in order to run this code block as standalone.

The unused image inside GuitarLibX file

Stage2: CyaX-Sharp

Basic Concepts

The decrypted data from the image file appears to be a PE file based on .Net. After a glance, it can be observed that this stage uses intense obfuscation techniques. One of them is Control Flow Flattening and the other one is that the symbols inside the file are obfuscated. All the 7 files that analyzed uses the abovementioned obfuscation techniques, but just one of them additionally keeps the strings in encrypted form and it resolves dynamically.

C# code is compiled into a special form, Intermediate Language (IL), and when executed Common Language Runtime (CLR) performs Just In Time (JIT) compilation to convert the IL code to native machine instructions. DnSpy is a tool that represents the IL in higher-level form. The other feature of this tool is to capable to modify the IL of a file. By using this feature, the suspicious file's IL is patched to decrypt encrypted strings and write to the disk. It can be much more plausible to pop up decrypted values one by one but required libraries don't available in this situation, so this isn't an option. Fortunately, writing disk is possible.

Patching the IL in order to reveal encrypted strings

The corresponding IL is as following:

0000    ldc.i4  -0x4E75C93B
0005 call !!0 [CssYlNN4An3ch7]'<Module>'::smethod_12<string>(uint32)
000A stsfld string [CssYlNN4An3ch7]Class8::string_0
000F nop
0010 nop
0011 ldstr "%path%"
0016 ldsfld string Class8::string_0
001B call void [mscorlib]System.IO.File::WriteAllText(string, string)
0020 nop
0021 ret

The Flow

The malware sleeps immediately after starting its execution, between 45 and 60 seconds long that it determines randomly. Then it begins to take actions according to the hard-coded configuration values inside it. Corresponding data comes as a string and it contains various configuration values separated by '||'. It dynamically splits this string.

One of the configuration string

The meaning of indexes of the array which is formed by splitting corresponding data, in sequence concerning the flow, is as follows:

  • 9th value determines whether disables Microsoft Windows Defender protection

Code block that disables Microsoft Windows Defender protection

  • 7th value determines whether stops the execution according to the artifacts of the virtualization software

Code block that searches virtualization software artifacts

  • 8th value determines whether stops the execution according to the artifacts of the malware analysis

Code block that searches malware analysis artifacts

  • 4th value determines whether downloads a file to '%temp%' from the internet and execute it

Code block that downloads and executes according to configuration values

  • 5th value holds the file's URL to use according to 4th value
  • 6th value holds a name to use as file's name while storing at '%temp%' path according to 4h value
  • 1st value determines whether there is a file named match with hard-coded value inside the malware and if it doesn't find, copy the file the process launch from to '%appdata%' folder with the hard-coded name and schedule a task for the file in '%appdata%'

Code block that makes ready the file and schedules a task

  • 0th value determines the way this step would trigger the next step.
    • If the value is 4, then it triggers directly after decryption routine
    • If the value is other than 4, then it does base64 decode and loads resultant data to the process and call the function 'Kurd' inside it. The path that is chosen according to 0th value and the file that was executed if the value was 4 passes as parameters.

2 function that triggered according to 0th value

4th value for all 7 analyzed samples is inactive so 5th and 6th values are empty. Also, for all 7 analyzed samples, there is a file as 'XML' stored inside the resources section. This is used as a scheduled task configuration file.

The XML file inside resources section

'[USERID]' and '[LOCATION]' fields are updated automatically by the malware.

Base64 encoded data that stored as 'CyaX-Sharp', when the 0th configuration value is other than 4, is decoded and loaded then the attack vector's execution continues from there. Decoded data is a DLL file named 'CyaX.dll' based on .Net. This file is the same for all of the analyzed samples. 'Kurd' function inside the Dll is triggered and it calls another function within it. The important thing; instead of using a dynamically chosen path concerning the 0th value, it passes the path of the file the process launch from, as a parameter. After this point, the malware creates a suspended process from the abovementioned path and then it injects the data block passes as a parameter to the process. After a successful injection routine, the execution passed to the injected data.

Totally 7 files are been analyzed. 6 of them try to inject 'Agent.Tesla' variant and only one sample try to inject 'Nano Core Client RAT'.

Stage3: Nano Core Client RAT

Basic Concepts

The analyzed sample of the NanoCore handles its execution according to configurations that they are stored as a dictionary object. It has a special class for these purposes. This class works like 'if the key exists then return its value, else return default value'. Additionally, with plugins, it can expend key-value storage. For the sample, configuration keys are as following:

  • BuildTime
  • Version
  • Mutex
  • DefaultGroup
  • PrimaryConnectionHost
  • BackupConnectionHost
  • ConnectionPort
  • RunOnStartup
  • RequestElevation
  • BypassUserAccountControl
  • BypassUserAccountControlData
  • ClearZoneIdentifier
  • ClearAccessControl
  • SetCriticalProcess
  • PreventSystemSleep
  • ActivateAwayMode
  • EnableDebugMode
  • RunDelay
  • ConnectDelay
  • RestartDelay
  • TimeoutInterval
  • KeepAliveTimeout
  • MutexTimeout
  • LanTimeout
  • WanTimeout
  • BufferSize
  • MaxPacketSize
  • GCThreshold
  • UseCustomDnsServer
  • PrimaryDnsServer
  • BackupDnsServer
  • ShowInstallationDialog
  • InstallationDialogTitle
  • InstallationDialogMessage
  • InstallationDialogIcon
  • KeyboardLogging

At the starting of execution, a file within the resources section is read and firstly the file used to initialize required components. The process can be summarized as:

  • Reads first 4 bytes and according to the value, it reads that amount of bytes
  • Takes GUID of the file
  • Applies Rijndael decryption to the bytes, uses GUID as Key and IV
  • Initialize DES algorithm, uses the decrypted data as Key and IV

Subsequently, including the rest of the data block of the file from the resources section, all plugins and configuration data are subject to the DES decryption routine firstly. Then the malware parses resultant data. The malware uses custom data structures during the parsing routine.

public struct GStruct2
public byte byte_0;
public byte byte_1;
public Guid guid_0;
public object[] object_0;

It begins assigning 'byte_0', 'byte_1' and 'guid_0' variables. Then a list object is used in the sequel and in the end it creates a new array from the list object and assigns it to the 'object_0' variable. The whole routine in detail is as:

  • Reads a byte and if it is true, reads 4 bytes and allocates that amount of bytes for a byte array and then decompress rest of the data and store it in the new array
  • Reads a byte and assigns to the 'byte_0'
  • Reads a byte and assigns to the 'byte_1'
  • Reads a byte and if it is true, reads 16 bytes and assigns to the 'guid_0'
  • From this byte to the last byte, it reads one by one and according to the value, a Case block is executed to form a list object
  • Creates a new array from the list (by calling list.ToArray) and assigns to the 'object_0'

According to 'EnableDebugMode' value, it tries to log to console, a file named 'client.log' at the location the process launched from, or to both of them. The logging is detailed and well structured. The corresponding value is actually 'false', but it is altered manually.

Friday, December 13, 2019

4:04 PM: Builder settings loaded..
4:04 PM: KeyboardLogging = True
4:04 PM: BuildTime = 9/2/2019 6:55:15 AM
4:04 PM: Version =
4:04 PM: Mutex = fb03f1b7-c3cb-4a68-8d5a-68180ad51d86
4:04 PM: DefaultGroup = NewDNS
4:04 PM: PrimaryConnectionHost =
4:04 PM: BackupConnectionHost =
4:04 PM: ConnectionPort = 54900
4:04 PM: RunOnStartup = True
4:04 PM: RequestElevation = False
4:04 PM: BypassUserAccountControl = False
4:04 PM: ClearZoneIdentifier = True
4:05 PM: ClearAccessControl = False
4:05 PM: SetCriticalProcess = False
4:05 PM: PreventSystemSleep = True
4:05 PM: ActivateAwayMode = False
4:05 PM: EnableDebugMode = False
4:05 PM: RunDelay = 0
4:05 PM: ConnectDelay = 4000
4:05 PM: RestartDelay = 5000
4:05 PM: TimeoutInterval = 5000
4:05 PM: KeepAliveTimeout = 30000
4:05 PM: MutexTimeout = 5000
4:05 PM: LanTimeout = 2500
4:05 PM: WanTimeout = 8000
4:05 PM: BufferSize = 65535
4:05 PM: MaxPacketSize = 10485760
4:05 PM: GCThreshold = 10485760
4:06 PM: UseCustomDnsServer = True
4:06 PM: PrimaryDnsServer =
4:06 PM: BackupDnsServer =
4:13 PM: Reading client settings from 'settings.bin'..
4:13 PM:
4:13 PM: Client Exception (LoadSettings):
4:13 PM: Settings file 'settings.bin' could not be found. at Class8.smethod_93(String string_4)
4:13 PM:
4:13 PM: Reading client settings from 'settings.bak'..
4:13 PM:
4:13 PM: Client Exception (LoadSettings):
4:13 PM: Settings file 'settings.bak' could not be found. at Class8.smethod_93(String string_4)
4:13 PM:
4:13 PM: Initializing cached plugins..
4:13 PM: Plugin: SurveillanceEx Plugin, Cache: True
4:13 PM: Rebuilding host cache..
4:13 PM: Host:
4:14 PM: Connecting to

It relies on the 'PrimaryConnectionHost' configuration value for connection host. If the 'UseCustomDnsServer' value is 'True', then in order to obtain the IP address of the corresponding domain, it uses 'PrimaryDnsServer' and 'BackupDnsServer' values. In a situation that DNS check results as a failure for both of the servers, it uses the system's DNS server.

All the communication through the C&C server is DES encrypted. After successful connection; the GUID of the machine, the machine name + '' + username, 'DefaultGroup' configuration value and the version of the Nano Core Client is sent to the server.

Then it beacons in certain intervals.

The Flow

The malware starts a routine at the beginning of the execution. First of all, it reads a file that is located inside the resources section. Then this data is decrypted and it separates these to 2 arrays as plugins and configuration variables. 'dictionary_1', used to track configuration values, is updated or, if the key does not exist, added according to configuration array. After parsing the other array, it is added to 'dictionary_0' which is used for plugins. At the end of this routine; configuration variables, plugins, and all the other required elements become ready to use. After that, it takes action according to configuration values. For the analyzed sample, those actions are as follows:

  • Creates Mutex,
  • Creates a folder under '%appdata%' by using MachineGuid of the system,
  • Creates a file at '%appdata%' + GUID + '\' in order to track first run time,
  • Adds an entry to the 'run keys'. According to the privilege level of the process, it chooses between 2 separate capabilities. If it is administrator:
    • Adds an entry named 'NTFS Monitor' to the 'run keys' for HKLM and the file is at '%programfiles%\NTFS Monitor\ntfsmon.exe',
    • Checks the md5 of that file with itself,
    • Deletes 'NTFS Monitor' at HKCU, if it exists,
    • Deletes the file at '%appdata%' + GUID + '\NTFS Monitor\ntfsmon.exe', if it exists,
  • If it is not administrator:
    • Adds an entry named 'NTFS Monitor' to the 'run keys' for HKCU and the file is at '%appdata%' + GUID + '\NTFS Monitor\ntfsmon.exe',
    • Checks the md5 of that file with itself,
  • Clears zone identifiers of the file the process is launched from,
  • Creates a thread that calls SetThreadExecutionState in a certain interval,
  • Triggers SurveillanceEx plugin,
  • Connects to newapa123[.]ddns[.]net


The plugin is designed to provide keylogging capability to the malware. It uses the 'RawInput' technique and besides that, it also intercepts Clipboard changes. The file for logging purpose is located at '%appdata%\Logs' + Username + '\KB' + TickCount '.dat'. There is a data structure that defines data types. The logging process uses this structure to separate different types. It appends a byte corresponding to each type. It starts with Unix Timestamp, and also for each delay that is greater than 1 minute, it appends Timestamp again.

public enum KeyboardType : byte

A sample keylogger data:

Sample keylog data that contains logs of various kinds like Time, Window, Char and Clipboard


It is ironic that an attack vector is constructed as it will trigger from a point, a game, that at the core it is designed to bring fun. But when one look through the cyber dynamics of the decade, it isn't that much ironic though.


rule Risk {

author = "Mert Degirmenci"
description = "YARA rule for the files whose hash is one of the below"
date = "12.11.2019"
hash1 = "c40d59f85e1b4bacf10643b535da804af2e99caba91ab860b221121e24a2a9bb"
hash2 = "11455bc66548fd161362d300d24c6539c36c7b236aafd4f457d8ee2d8b6c9262"
hash3 = "29659dd2cd05d0e3c97c2fd3687644a78622ad487178901cb67f14be314c168b"
hash4 = "3c3b311505b8a3b280024d05017ff9edcb19e193c1760cac099d09fb165e93d7"
hash5 = "6822a44b8ae526747479d59ea775b7dc5758880469f802caa9ad4ceade2218df"
hash6 = "b0a8c2cb1e0afb0cdef74f983c4f16be2bcd87a93b3d3aa8cad21ec85d29153e"
hash7 = "f7c2cd67d1a009454facf8ab9b0cbee0c9a53644cae7bbd4bc952917ec19522b"

$s_guitar = "Hide_GuitarX" ascii

$sv_PA = { da af 37 db 8e d9 88 34 d8 a6 d9 88 d9 be da a4 }

$sv_PA_GLV = { 33 da a4 30 35 db 8e d8 a6 35 da a4 da a4 34 da }

$sv_F7 = { 34 37 da b5 da 98 da 95 d9 88 33 36 30 36 da 98 }

$sv_B0 = { d8 ab db 86 da a4 da b5 32 db 8e 37 36 da 95 d9 }

$sv_68 = { 30 35 da 95 31 d8 ab 32 db 8e 36 da 86 da b5 32 }

$sv_3C = { 38 da 95 38 31 32 da af d9 88 36 34 da af da 98 }

$sv_29 = { 30 38 32 d9 be 31 31 da 98 d9 be d9 88 db 95 da }

//484 05E8 call uint8[] Risk.Properties.pivXzWdzeJWjeaqOGHdveAHWAfZOfnJDIK::wjllPrhevNrbhVfoxikTPfvSRFDqBJfKVfax()
//485 05ED call class [mscorlib]System.Reflection.Assembly [mscorlib]System.Reflection.Assembly::Load(uint8[])
//486 05F2 stloc.0
//487 05F3 ldloc.0
//488 05F4 ldstr "GuitarLibX.Hide_GuitarX"
//489 05F9 callvirt instance class [mscorlib]System.Type [mscorlib]System.Reflection.Assembly::GetType(string)
//490 05FE stloc.1
//491 05FF newobj instance void Risk.rqshchHfcppuYqLlgwoXsYYTEvaNyXyVr::.ctor()
//492 0604 stloc.2
$s_loadSeq = { 28 A4 00 00 06 28 A9 00 00 0A 0A 06 72 BF 23 00 70 6F AA 00 00 0A 0B 73 01 00 00 06 0C }

uint16(0) == 0x5a4d and $s_guitar and $s_loadSeq and any of ($sv_*)

rule nanoCore {

author = "Mert Degirmenci"
description = "Nano Core Client RAT variant"
date = "25.12.2019"
hash1 = "8d68e9e02e2289e0cc49f7b1dfe678a8b49ed4f02f31103907ec57ad3ecf59a1"

// Deobfucated form:
// private static void smethod_21()
// {
// int num = 0;
// int num2 = Class24.smethod_22();
// for (int i = num; i <= num2; i += 250)
// {
// bool flag;
// Class8.mutex_0 = new Mutex(true, string.Format("Global\\{{{0}}}", Class24.smethod_2()), ref flag);
// if (flag)
// {
// return;
// }
// Thread.Sleep(250);
// }
// Class8.smethod_42();
// }
$s_mutex = { 16 28 46 01 00 06 18 2D 07 26 1B 2D 06 26 2B 4A 0C 2B F7 0B 2B F8 17 20 67 22 D0 1E 28 FF 00 00 06 28 32 01 00 06 8C 48 00 00 01 28 5C 00 00 0A 12 00 73 DD 00 00 0A 1A 2D 06 26 06 2C 0A 2B 07 80 35 00 00 04 2B F4 2A 20 FA 00 00 00 28 DE 00 00 0A 07 20 FA 00 00 00 58 0B 07 08 31 B8 28 88 00 00 06 }

$s_res = { 10 00 00 00 E8 99 3F 18 32 75 76 2F 58 EE CA 83 35 F6 61 35 18 5D 01 00 78 1E 89 C0 2B 22 B3 76 }

uint16(0) == 0x5a4d and all of them


  • newapa123[.]ddns[.]net
  • \BaseNamedObjects{fb03f1b7-c3cb-4a68-8d5a-68180ad51d86}
  • %appdata%\tDNlhP.exe
  • %appdata%\ImDdQPOzyrjI.exe
  • %appdata%\ZOxeRuBzJmpNJp.exe
  • %appdata%\JYBEcxnaL.exe
  • %appdata%\xaHinrL.exe
  • %appdata%\AFTppCr.exe
  • %appdata%\IZVyyrlfEctu.exe
  • %systemroot%\System32\Tasks\Updates\tDNlhP
  • %systemroot%\System32\Tasks\Updates\ImDdQPOzyrjI
  • %systemroot%\System32\Tasks\Updates\ZOxeRuBzJmpNJp
  • %systemroot%\System32\Tasks\Updates\JYBEcxnaL
  • %systemroot%\System32\Tasks\Updates\xaHinrL
  • %systemroot%\System32\Tasks\Updates\AFTppCr
  • %systemroot%\System32\Tasks\Updates\IZVyyrlfEctu
  • %appdata% + GUID + \run.dat
  • %appdata% + GUID + \Exceptions\
  • %appdata% + GUID + \Logs\ + UserName + \KB_ + TickCount + .dat
  • %appdata% + GUID + \NTFS Monitor\ntfsmon.exe
  • %programfiles%\NTFS Monitor\ntfsmon.exe
  • c40d59f85e1b4bacf10643b535da804af2e99caba91ab860b221121e24a2a9bb
  • 11455bc66548fd161362d300d24c6539c36c7b236aafd4f457d8ee2d8b6c9262
  • 29659dd2cd05d0e3c97c2fd3687644a78622ad487178901cb67f14be314c168b
  • 3c3b311505b8a3b280024d05017ff9edcb19e193c1760cac099d09fb165e93d7
  • 6822a44b8ae526747479d59ea775b7dc5758880469f802caa9ad4ceade2218df
  • b0a8c2cb1e0afb0cdef74f983c4f16be2bcd87a93b3d3aa8cad21ec85d29153e
  • f7c2cd67d1a009454facf8ab9b0cbee0c9a53644cae7bbd4bc952917ec19522b
  • 666bf6411729fa410c75bcdc6d09630c1b68c5b90827595b0fc7d022812aee8e
  • 8d68e9e02e2289e0cc49f7b1dfe678a8b49ed4f02f31103907ec57ad3ecf59a1
  • 283524aa6cfe0e44cc0010347157f218d929afe1ad2dc1377f8a00830f0c3c40
  • 8c519c1a6be92305e2418b6bc477f0fd45c4371e16de8eaa726c6a818bb79fc1
  • 277c66c0399e8da87d31461bde4229d69325d2bb5cba769be982228c213c3b2b
  • 2565961dda75679a16247d7b56f85e1cf16c88ee4643e584b1902830deb4287e