{
	"id": "4ee41b45-429c-453f-9fb7-5d26d76cb435",
	"created_at": "2026-04-06T00:19:51.207877Z",
	"updated_at": "2026-04-10T03:32:21.49303Z",
	"deleted_at": null,
	"sha1_hash": "a88d221c105c0640a7664d1d3e92236268e1b23b",
	"title": "Gh0stKCP Protocol",
	"llm_title": "",
	"authors": "",
	"file_creation_date": "0001-01-01T00:00:00Z",
	"file_modification_date": "0001-01-01T00:00:00Z",
	"file_size": 405951,
	"plain_text": "Gh0stKCP Protocol\r\nBy Erik Hjelmvik\r\nPublished: 2025-09-24 · Archived: 2026-04-05 13:43:01 UTC\r\n, \r\nWednesday, 24 September 2025 09:40:00 (UTC/GMT)\r\nGh0stKCP is a transport protocol based on KCP, which runs on top of UDP. Gh0stKCP has been used to carry\r\ncommand-and-control (C2) traffic by malware families such as PseudoManuscrypt and ValleyRAT/Winos4.0.\r\n@Jane_0sint recently tweeted about ValleyRAT using a new UDP based C2 protocol. I wanted to take a closer\r\nlook at the protocol, so I downloaded the PCAP from any.run and opened it with CapLoader. To my surprise\r\nCapLoader claimed that the C2 traffic was using a known protocol called “KCP”.\r\nhttps://www.netresec.com/?page=Blog\u0026month=2025-09\u0026post=Gh0stKCP-Protocol\r\nPage 1 of 8\n\nThe protocol detection feature in CapLoader compares traffic in TCP and UDP sessions to statistical models of\r\nknown protocols. This means that no protocol specification or RFC is required to identify a protocol. All that is\r\nneeded is some example traffic to build a protocol model from (see this XenoRAT detection video for a\r\ndemonstration of this feature). In this case CapLoader’s KCP protocol model was built from UDP based C2 traffic\r\nfrom PseudoManuscrypt, which was reported to have been using KCP.\r\nWhat is KCP?\r\nKCP is a UDP based protocol designed as a low-latency alternative to TCP. The protocol was created by Lin Wei\r\nin the early 2010s, primarily to transport p2p voice chat audio in games. The protocol is, however, very generic\r\nand can be used to transport basically any type of data. The KCP protocol specification includes the following\r\npacket structure:\r\nhttps://www.netresec.com/?page=Blog\u0026month=2025-09\u0026post=Gh0stKCP-Protocol\r\nPage 2 of 8\n\nThe first field “conv” is a 32 bit (4 byte) unique ID for a KCP session. This conversation ID is used to uniquely\r\nidentify a connection and will remain constant throughout the connection. KCP doesn’t include any handshake\r\nmechanism for establishing new sessions, which means that KCP endpoints typically start transmitting payload\r\ndata already in the first KCP packet.\r\nThe Gh0stKcp Protocol\r\nThe UDP based KCP C2 protocol used by PseudoManuscrypt as well as the ValleyRAT C2 traffic that CapLoader\r\nreported being “KCP” both deviated from the original KCP specification in several ways. For instance, KCP\r\npackets have a 24 byte header, which means that packets shorter than 24 bytes can’t be KCP. In fact, the KCP\r\nsource code actually ignores UDP packets that carry less than 24 bytes of payload. Yet, both the\r\nPseudoManuscrypt and ValleyRAT UDP C2 traffic initially transmit several 12-byte packets.\r\nhttps://www.netresec.com/?page=Blog\u0026month=2025-09\u0026post=Gh0stKCP-Protocol\r\nPage 3 of 8\n\nImage:Flow transcript of Gh0stKCP traffic in CapLoader\r\nThese 12-byte Gh0stKCP handshake packets are generated by an open source library called HP-Socket, which\r\nincludes a custom Automatic Repeat reQuest (ARQ) handshake mechanism.\r\nThe following behavior can be deduced by examining UDP traffic from Valley RAT or by analyzing the UDP\r\nhandshake mechanism in HP-Socket's ArqHelper.h.\r\nThe client (bot) starts by sending an empty UDP packet to the C2 server, followed by a UDP packet carrying a 12\r\nbyte payload structured like this:\r\n4f bb 01 00 xx xx xx xx 00 00 00 00\r\nThe first four bytes can be decoded as follows:\r\n4f bb = Magic bytes\r\n01 = Handshake command\r\n00 = Handshake is not completed\r\nThe “xx” bytes represent a KCP conversation ID (conv) proposed by the bot. This initial handshake packet can\r\neasily be detected and alerted on with the following Suricata IDS signature:\r\nalert udp $HOME_NET any -\u003e $EXTERNAL_NET any (msg:\"Gh0stKCP handshake\"; dsize:12; content:\"|4f bb\r\n01 00|\"; offset:0; depth:4; content:\"|00 00 00 00|\"; within:8; distance:4; classtype:trojan-activity;\r\nreference:url,https://netresec.com/?b=259a5af; sid:1471101; rev:1;)\r\nThe C2 server also transmits a UDP packet containing a 12 byte handshake using the exact same structure as the\r\nclient. However, the C2 server proposes a 32 bit conversation ID of its own. In “normal” KCP implementations\r\nthe client and server agree on a single shared conversation ID, but Gh0stKCP actually uses one separate ID for\r\neach direction. This allows the server to transmit its handshake packet without having seen the client’s handshake.\r\nhttps://www.netresec.com/?page=Blog\u0026month=2025-09\u0026post=Gh0stKCP-Protocol\r\nPage 4 of 8\n\n4f bb 01 00 yy yy yy yy 00 00 00 00\r\nThe “yy” bytes represent the C2 server’s 32-bit conversation ID (conv).\r\nThe communicating parties frequently re-transmit this initial handshake packet until they have received a\r\nhandshake from the other end.\r\nUpon receiving the other end’s handshake both the bot and C2 server acknowledge the other end’s conversation\r\nID with a UDP packet carrying the following 12 byte payload:\r\n4f bb 01 00 xx xx xx xx yy yy yy yy\r\nWhere “xx” is the sender’s conversation ID and “yy” is the other end’s conversation ID. After having received the\r\nother end’s acknowledgment packet both parties additionally transmit a final ack packet, indicating that the\r\nhandshake is completed and they will start communicating using KCP. This final ack packet is identical to the\r\nprevious one, except the fourth byte (handshake complete flag) has changed from 0x00 to 0x01.\r\n4f bb 01 01 xx xx xx xx yy yy yy yy\r\nFrom this point on Gh0stKCP communicates using the KCP protocol, with the exception that each end transmits\r\npackets using their own conversation ID rather than a common ID. The KCP traffic that follows can therefore be\r\nparsed and inspected in Wireshark with help of a KCP Lua parser, such as CandyMi’s kcp_dissector.lua.\r\nhttps://www.netresec.com/?page=Blog\u0026month=2025-09\u0026post=Gh0stKCP-Protocol\r\nPage 5 of 8\n\nImage: KCP traffic from ValleyRAT sample any.run in Wireshark\r\nFinally, the Gh0stKCP session is terminated by sending a UDP packet containing the following hard coded 16\r\nbytes:\r\nbe b6 1f eb da 52 46 ba 92 33 59 db bf e6 c8 e4\r\nThis unique byte sequence is defined in HP-Socket as s_szUdpCloseNotify, which can be detected with the\r\nfollowing Suricata IDS signature:\r\nhttps://www.netresec.com/?page=Blog\u0026month=2025-09\u0026post=Gh0stKCP-Protocol\r\nPage 6 of 8\n\nalert udp any any -\u003e any any (msg:\"Gh0stKCP close\"; dsize:16; content:\"|be b6 1f eb da 52 46 ba 92 33 59 db bf\r\ne6 c8 e4|\"; offset:0; depth:16; classtype:trojan-activity; reference:url,https://netresec.com/?b=259a5af;\r\nsid:1471102; rev:1;)\r\nHole Punching in NAT Firewalls\r\nThe elaborate handshake procedure used by Gh0stKCP introduces a significant delay before the C2 session is\r\nestablished. The handshake takes up to 500ms to complete, which is much slower than a normal TCP 3-way\r\nhandshake. KCP is typically used because of its low-latency properties, but the handshake routine ruins any\r\nchance for quick establishment of Gh0stKCP sessions.\r\nThe intricate ARQ handshake routine does, however, allow for hole punching in firewalls, aka “NAT traversal”,\r\nwhich enables the protocol to be used for peer-to-peer communication. This p2p-enabling property could\r\npotentially be used to relay C2 communication through one or several bots, even if those bots are behind separate\r\nNAT firewalls.\r\nDetecting Gh0stKCP with Snort and YARA\r\nCapLoader can detect when the KCP protocol is used. However, only a few security analysts have a CapLoader\r\nlicense. We have therefore decided to release Surucata signatures and a YARA rule that can be used to detect\r\nGh0stKCP.\r\nThe Suricata signatures included in this blog post can also be downloaded from here:\r\nhttps://github.com/Netresec/Suricata/blob/main/netresec.rules\r\nOur Gh0stKCP YARA rule is based on Steve Miller’s “RareEquities_KCP” rule, from Mandiant’s 2020 blog post\r\nAPT41 Initiates Global Intrusion Campaign Using Multiple Exploits. Steve’s original YARA rule provides generic\r\ndetection of software that uses the original KCP library. We’ve extended that rule to also look for HP-Socket’s\r\ncharacteristic 16-byte close command.\r\nhttps://github.com/Netresec/YARA/blob/main/Gh0stKCP.yar\r\nIOC List\r\nMany of the IOCs in the list below are old, which is why you might not want to use them for alerting. They are\r\nincluded here primarily for researchers and analysts who wish to perform retrohunting to discover malware\r\nsamples that use GhostKCP.\r\n2021 (PseudoManuscrypt)\r\nUDP 34.64.183.91:53\r\nUDP 34.97.69.225:53\r\nUDP 160.16.200.77:53\r\nUDP 167.179.89.78:53\r\nUDP 185.116.193.219:53\r\nUDP 198.13.62.186:53\r\nUDP email.yg9[.]me:53\r\nhttps://www.netresec.com/?page=Blog\u0026month=2025-09\u0026post=Gh0stKCP-Protocol\r\nPage 7 of 8\n\nUDP facebook.websmails[.]com:53\r\nUDP google.vrthcobj[.]com:53\r\n2022 (PseudoManuscrypt)\r\nUDP 34.142.181.181:53\r\n2025 (ValleyRAT / Winos4.0)\r\nUDP 27.124.3.234:8443\r\nUDP 43.133.39.217:80\r\nUDP al17[.]tk:80\r\nUDP xiaoxiao.fenghua678.eu[.]cc:8443\r\nAttribution\r\nUse of ValleyRAT is often attributed to the APT group Silver Fox (银狐), but ValleyRAT and Gh0stKCP could be\r\nused by other threat actors as well.\r\nPosted by Erik Hjelmvik on Wednesday, 24 September 2025 09:40:00 (UTC/GMT)\r\nTags: #CapLoader#Suricata\r\nSource: https://www.netresec.com/?page=Blog\u0026month=2025-09\u0026post=Gh0stKCP-Protocol\r\nhttps://www.netresec.com/?page=Blog\u0026month=2025-09\u0026post=Gh0stKCP-Protocol\r\nPage 8 of 8",
	"extraction_quality": 1,
	"language": "EN",
	"sources": [
		"Malpedia"
	],
	"references": [
		"https://www.netresec.com/?page=Blog\u0026month=2025-09\u0026post=Gh0stKCP-Protocol"
	],
	"report_names": [
		"?page=Blog\u0026month=2025-09\u0026post=Gh0stKCP-Protocol"
	],
	"threat_actors": [
		{
			"id": "8f68387a-aced-4c99-b2a6-aa85071a0ca3",
			"created_at": "2024-06-25T02:00:05.030976Z",
			"updated_at": "2026-04-10T02:00:03.656871Z",
			"deleted_at": null,
			"main_name": "Void Arachne",
			"aliases": [
				"Silver Fox"
			],
			"source_name": "MISPGALAXY:Void Arachne",
			"tools": [],
			"source_id": "MISPGALAXY",
			"reports": null
		},
		{
			"id": "a7805d1a-b8d0-4a42-ae86-1d8711e0b2b9",
			"created_at": "2024-08-28T02:02:09.729503Z",
			"updated_at": "2026-04-10T02:00:04.967533Z",
			"deleted_at": null,
			"main_name": "Void Arachne",
			"aliases": [
				"Silver Fox"
			],
			"source_name": "ETDA:Void Arachne",
			"tools": [
				"Gh0stBins",
				"Gh0stCringe",
				"HoldingHands RAT",
				"Winos"
			],
			"source_id": "ETDA",
			"reports": null
		},
		{
			"id": "4d5f939b-aea9-4a0e-8bff-003079a261ea",
			"created_at": "2023-01-06T13:46:39.04841Z",
			"updated_at": "2026-04-10T02:00:03.196806Z",
			"deleted_at": null,
			"main_name": "APT41",
			"aliases": [
				"WICKED PANDA",
				"BRONZE EXPORT",
				"Brass Typhoon",
				"TG-2633",
				"Leopard Typhoon",
				"G0096",
				"Grayfly",
				"BARIUM",
				"BRONZE ATLAS",
				"Red Kelpie",
				"G0044",
				"Earth Baku",
				"TA415",
				"WICKED SPIDER",
				"HOODOO",
				"Winnti",
				"Double Dragon"
			],
			"source_name": "MISPGALAXY:APT41",
			"tools": [],
			"source_id": "MISPGALAXY",
			"reports": null
		},
		{
			"id": "e698860d-57e8-4780-b7c3-41e5a8314ec0",
			"created_at": "2022-10-25T15:50:23.287929Z",
			"updated_at": "2026-04-10T02:00:05.329769Z",
			"deleted_at": null,
			"main_name": "APT41",
			"aliases": [
				"APT41",
				"Wicked Panda",
				"Brass Typhoon",
				"BARIUM"
			],
			"source_name": "MITRE:APT41",
			"tools": [
				"ASPXSpy",
				"BITSAdmin",
				"PlugX",
				"Impacket",
				"gh0st RAT",
				"netstat",
				"PowerSploit",
				"ZxShell",
				"KEYPLUG",
				"LightSpy",
				"ipconfig",
				"sqlmap",
				"China Chopper",
				"ShadowPad",
				"MESSAGETAP",
				"Mimikatz",
				"certutil",
				"njRAT",
				"Cobalt Strike",
				"pwdump",
				"BLACKCOFFEE",
				"MOPSLED",
				"ROCKBOOT",
				"dsquery",
				"Winnti for Linux",
				"DUSTTRAP",
				"Derusbi",
				"ftp"
			],
			"source_id": "MITRE",
			"reports": null
		},
		{
			"id": "2a24d664-6a72-4b4c-9f54-1553b64c453c",
			"created_at": "2025-08-07T02:03:24.553048Z",
			"updated_at": "2026-04-10T02:00:03.787296Z",
			"deleted_at": null,
			"main_name": "BRONZE ATLAS",
			"aliases": [
				"APT41 ",
				"BARIUM ",
				"Blackfly ",
				"Brass Typhoon",
				"CTG-2633",
				"Earth Baku ",
				"GREF",
				"Group 72 ",
				"Red Kelpie ",
				"TA415 ",
				"TG-2633 ",
				"Wicked Panda ",
				"Winnti"
			],
			"source_name": "Secureworks:BRONZE ATLAS",
			"tools": [
				"Acehash",
				"CCleaner v5.33 backdoor",
				"ChinaChopper",
				"Cobalt Strike",
				"DUSTPAN",
				"Dicey MSDN",
				"Dodgebox",
				"ForkPlayground",
				"HUC Proxy Malware (Htran)"
			],
			"source_id": "Secureworks",
			"reports": null
		}
	],
	"ts_created_at": 1775434791,
	"ts_updated_at": 1775791941,
	"ts_creation_date": 0,
	"ts_modification_date": 0,
	"files": {
		"pdf": "https://archive.orkl.eu/a88d221c105c0640a7664d1d3e92236268e1b23b.pdf",
		"text": "https://archive.orkl.eu/a88d221c105c0640a7664d1d3e92236268e1b23b.txt",
		"img": "https://archive.orkl.eu/a88d221c105c0640a7664d1d3e92236268e1b23b.jpg"
	}
}