{
	"id": "2566ea61-b18b-4c39-9276-2d5e96637a1d",
	"created_at": "2026-04-06T00:07:26.321875Z",
	"updated_at": "2026-04-10T13:11:57.88721Z",
	"deleted_at": null,
	"sha1_hash": "1231fb95ec01f6ab4a1f255723c57d0ee0c91e53",
	"title": "GTPDOOR - A novel backdoor tailored for covert access over the roaming exchange",
	"llm_title": "",
	"authors": "",
	"file_creation_date": "0001-01-01T00:00:00Z",
	"file_modification_date": "0001-01-01T00:00:00Z",
	"file_size": 1455905,
	"plain_text": "GTPDOOR - A novel backdoor tailored for covert access over the\r\nroaming exchange\r\nBy haxrob\r\nPublished: 2024-02-27 · Archived: 2026-04-05 21:04:58 UTC\r\nThis page was updated on the 8th of June, 2025 with an update on attribution.\r\nIntroduction\r\nGTPDOOR is the name of Linux based malware that is intended to be deployed on systems in telco networks\r\nadjacent to the GRX (GRPS eXchange Network) with the novel feature of communicating C2 traffic over GTP-C\r\n(GPRS Tunnelling Protocol - Control Plane) signalling messages. This allows the C2 traffic to blend in with normal\r\ntraffic and to reuse already permitted ports that maybe open and exposed to the GRX network.\r\nThe following diagram illustrates a foreseen use of GTPDOOR. Here the actor already has established persistence\r\non the roaming exchange network and access a compromised host by sending GTP-C Echo Request messages with a\r\nmalicious payload:\r\nIn addition to remote code execution capability, GTPDOOR can be beaconed by sending arbitrary TCP packets to a\r\nhost the implant resides on. Supporting it’s stealth capability, the beacon response message hides particular\r\ninformation in a TCP header flag.\r\nNaming\r\nI have given this malware the name GTPDOOR as it uses a similar “port knocking / magic packet” technique as\r\nBPFDOOR as described here and here. Both use raw sockets to intercept packets on the network interface. Unlike\r\nBPDDOOR, GTPDOOR explicitly uses GTP-C echo request/response messages and does not utilize BFP / pcap\r\nfilters, but rather filters on UDP and GTP header values through simple  cmp  instructions. At the time of writing, I\r\nam not aware of this malware being documented anywhere else.\r\nhttps://doubleagent.net/telecommunications/backdoor/gtp/2024/02/27/GTPDOOR-COVERT-TELCO-BACKDOOR\r\nPage 1 of 18\n\nAttribution\r\nGTPDOOR is attributed to LIMINAL PANDA.\r\nGTPDOOR is likely attributed to UNC1945 (Mandiant) / LightBasin (CrowdStrike)\r\nAs described in the CrowdStrike article this threat actor has been documented to use the GTP protocol for\r\nencapsulating tinyshell traffic in a valid PDP context session by employing an SGSN emulator to tunnel traffic to an\r\nexternal GGSN in another operator network. Here, GTPDOOR is leveraging not off a PDP context (GTP-U,\r\nuserplane) but specific GTP-C signalling messages with it’s own extended message structure.\r\nAs we will see below, both binaries contain the name of the original c source file,  dnsd.c . A google search links to\r\na presentation by CrowdStrike about this threat actor that contains text from a process listing originating from what\r\nlooks like a Solaris machine. In that listing is a process with the name  dnsd :\r\nIf the attribution is correct, then given the discovery of this screenshot, it is likely that in addition to the two Linux\r\nbinaries documented in this blog post, a third version exists which targets Sun Solaris systems.\r\nBackground information\r\nIn order to provide connectivity between telecommunication network operators around the globe, a “closed” network\r\nexists that provides interconnectivity between various systems. These network elements / functions need to have\r\ndirect connectivity to the GRX network in order to route / forward roaming related signaling and user plane traffic.\r\nExamples of these systems are:\r\neDNS - External DNS to resolve APN names, select packet gateway for routing the subscribers traffic\r\nSGSN, GGSN - 2G/3G packet core network elements for packet switched data\r\nP-GW (Packet Data Network Gateway) - 4G version of the GGSN\r\nSTP - Signalling gateways for circuit switched routing (e.g. authentication to HLR/HSS) - specifically for\r\nSS7 signaling.\r\nDRA (Diameter Routing Agent) - 4G version of the STP, rather then SS7, the signaling traffic is over\r\ndiameter.\r\nThese functions are listed as to give examples of where GTPDOOR could be placed as they may require direct\r\nconnectivity to the GRX network. That is - providing opportunity for direct access into a telco’s core network. It is\r\nmore likely that it would be placed on systems that support GTP-C over GRX, such as SGSN, GGSN, PGW (which\r\ndon’t run some esoteric operating system). That said, if the GRX firewall is not configured right, there would be\r\nopportunities to place this type of implant elsewhere, or even within the internal core network.\r\n💡\r\nA GSMA document called the  IR.21  is used for network providers to publish the details of these systems such as\r\nthe GT (global titles), IP addresses, APNs etc. This list is used for other companies that have roaming agreements to\r\nhttps://doubleagent.net/telecommunications/backdoor/gtp/2024/02/27/GTPDOOR-COVERT-TELCO-BACKDOOR\r\nPage 2 of 18\n\nconfigure their network accordingly. Alternatively, they may exchange this information directly.\r\nSummary of functionality\r\nGTPDOOR supports the following:\r\nListens for “magic” wakeup packet, a GTP-C echo request message (GTP type  0x01 ). The host does not\r\nneed to have a listening sockets / listening services active, as all UDP packets are received into the user space\r\nvia opening a raw socket\r\nExecutes a command on the host which is specified in the magic packet and returns the output to the remote\r\nhost, supporting a “reverse shell” type functionality. Both request/responses\r\nare  GTP_ECHO_REQUEST  /  GTP_ECHO_RESPONSE  messages accordingly.\r\nCan be covertly probed from an external network to illicit a response by sending a TCP packet to any port\r\nnumber. If the implant is active a crafted empty TCP packet is returned along with information if the\r\ndestination port was open/responding on the host.\r\nAuthenticates and encrypts contents of magic GTP packet messages using a simple XOR cipher.\r\nAt runtime can be instructed to change it’s authentication + encryption key (rekeying). This prevents the\r\ndefault key hardcoded in the binary to be used by other actors\r\nBlend in to environment by changing it’s process name to look like syslog process invoked as a kernel thread\r\nDoes not require ingress firewall changes if the target host is allowed to communicate over the GTP-C port.\r\nVersions\r\nAt the time of writing two versions have been identified on Virus Total:\r\nVersion Filename Architecture Hash\r\n1\r\ndbus-echo\r\nx86-64 827f41fc1a6f8a4c8a8575b3e2349aeaba0dfc2c9390ef1cceeef1bb85c34161\r\n2 pickup i386 5cbafa2d562be0f5fa690f8d551cdb0bee9fc299959b749b99d44ae3fda782e4\r\npickup  has additional enhancements/features to  dbus-echo , and hence is assigned a higher version number.\r\nAt the time of writing, both samples have been uploaded to Virus Total in late 2023.\r\nVersion 1 - 1 detection\r\nhttps://doubleagent.net/telecommunications/backdoor/gtp/2024/02/27/GTPDOOR-COVERT-TELCO-BACKDOOR\r\nPage 3 of 18\n\nVersion 2 - 0 detections\r\nNote: as of the 17th of March, 2024, there is now 37 detections\r\nBoth binaries were targeted for a particularly old Linux distribution, “Red Hat Linux 4.1”. This is the equivalent to\r\nRHEL 5.x. The GCC date is marked 2008. It is quite likely the target network operator of this implant had quite poor\r\npatch / lifecycle management.\r\n2024-03-17  - for maximum ABI compatibility, compiling against old glibc versions increases the chance of\r\nbinaries working in newer releases, so the targetted version may not be exact, although it would be expected to be\r\nwithin proximity to ensure stability.\r\nhttps://doubleagent.net/telecommunications/backdoor/gtp/2024/02/27/GTPDOOR-COVERT-TELCO-BACKDOOR\r\nPage 4 of 18\n\nAs the binaries are not stripped, source code’s original filename was likely  dnsd.c :\r\nTechnical Details\r\nGTP magic packet message types\r\nThe command instruction is sent in the GTP Echo Request message along with the associated data. As summarized:\r\nGTPDOOR v1\r\nMessage Type Function Payload\r\n0x01 Set new encryption key New key\r\n0x02 Write data to system.conf File content\r\n0x03 - 0xFF Execute command and return output Shell command to run\r\nGTPDOOR v2\r\nMessage Type Function Payload\r\n0x01 Set new encryption key New key value\r\n0x02\r\nWrite arbitrary data to\r\nsystem.conf\r\nFile content\r\n0x03 , 0x04 , 0x08 - 0xFF\r\nExecute command and\r\nreturn output\r\nShell command to run\r\n0x05\r\nIP address or subnet to\r\naccess control list.\r\nMultiple subnets or single IPs (/32) can be\r\nseparated by a comma, e.g. 192.168.0.1/24,10.0.0.1\r\n0x06 Return ACL list\r\n0x07 Clear ACL\r\nMagic packet format\r\nThe packet can be visually represented as followed: \r\nhttps://doubleagent.net/telecommunications/backdoor/gtp/2024/02/27/GTPDOOR-COVERT-TELCO-BACKDOOR\r\nPage 5 of 18\n\nAs a “c-like struct”:\r\nstruct gtp_header\r\n{\r\n uint8_t flags;\r\n uint8_t type;\r\nhttps://doubleagent.net/telecommunications/backdoor/gtp/2024/02/27/GTPDOOR-COVERT-TELCO-BACKDOOR\r\nPage 6 of 18\n\nuint16_t length;\r\n uint32_t tei; // technically labelled spare if type == GTP_ECHO\r\n};\r\nstruct gtpdoor_header\r\n{\r\n uint8_t pad[5];\r\n int32_t key1;\r\n uint8_t cmdMsgType;\r\n uint16_t cmdLength;\r\n};\r\nstruct gtpdoor_packet\r\n{\r\n ip_header iph;\r\n udp_header udph;\r\n gtp_header gtph;\r\n gtpdoor_header gtpdoorh;\r\n uint8_t payload[2020];\r\n};\r\nOperational detail\r\nVersion 1 + 2:\r\nChecks if the length of it’s filename is greater then 8 characters, and if so, process name stomps itself to\r\nbecome  [syslogd]  by overwriting  argv . The length check is to ensure it does not corrupt the stack.\r\nTells the parent process to ignore signals from it’s child process be setting  SIG_IGN  for the  SIGCHLD  signal\r\nCreates a raw socket listening for UDP packets on port 2123 (GTP-C)\r\nhttps://doubleagent.net/telecommunications/backdoor/gtp/2024/02/27/GTPDOOR-COVERT-TELCO-BACKDOOR\r\nPage 7 of 18\n\nAccepts UDP packets on destination port  2123  with a GTP header field type value of  GTP_ECHO_REQUEST\r\nChecks that the 32 bit symmetric key is correct in order to authenticate the message. The hardcoded value in\r\nthe binary is  135798642 , representative of someone typing odd numbers up the length of a keyboard even\r\nnumbers back down again:\r\nhttps://doubleagent.net/telecommunications/backdoor/gtp/2024/02/27/GTPDOOR-COVERT-TELCO-BACKDOOR\r\nPage 8 of 18\n\nDecrypts payload in GTP message using the same authentication key using a simple XOR at fixed blocks of\r\nthe key size.\r\nAn equivalent implementation of the decryption routine in python:\r\ndef decrypt(key, ciphertext):\r\n key_idx = 0\r\n strlen = len(ciphertext)\r\n plaintext = bytearray(strlen)\r\n for i in range(strlen):\r\n if key_idx \u003e= len(key):\r\n key_idx = 0\r\n plaintext[i] = key[key_idx] ^ ciphertext[i]\r\n key_idx += 1\r\n return plaintext\r\nhttps://doubleagent.net/telecommunications/backdoor/gtp/2024/02/27/GTPDOOR-COVERT-TELCO-BACKDOOR\r\nPage 9 of 18\n\nExecutes a function specified message type with the primary function to execute a shell command and return\r\nthe result to the remote client via a  GTP_ECHO_RESPONSE  message\r\nIf the message type number is not explicitly defined, the action will fall back to the remote code execution function:\r\nThe above image also shows the approximate code for the “rekeying” message type.\r\nCan write arbitrary contents to a file,  system.conf . It’s exact purpose is unknown.\r\nSpecific to version 2:\r\nMultithreaded (GTP magic packet handler and TCP probe beacon handler)\r\nAs the binary was not stripped and debug symbols left in, we can see the original function\r\nnames  tcpMethod  and  gtpMethod  which run in two pthreads:\r\nhttps://doubleagent.net/telecommunications/backdoor/gtp/2024/02/27/GTPDOOR-COVERT-TELCO-BACKDOOR\r\nPage 10 of 18\n\nCreates a mutex  /var/run/daemon.pid  to prevent more then once instance running. The mutex file contains\r\nthe PID of the process\r\nAcknowledge it is alive by responding to any TCP packet on any port number with an empty TCP packet\r\nwith both the  RST  and  ACK  flags set.\r\nOn “remote command execution”, the process is  forked()  and  popen()  is utilized to execute a subprocess on the\r\nhost.\r\nhttps://doubleagent.net/telecommunications/backdoor/gtp/2024/02/27/GTPDOOR-COVERT-TELCO-BACKDOOR\r\nPage 11 of 18\n\nAll printf statements such as those observed above are emitted to  stdout . As such it is likely GTPDOOR would\r\nbe invoked similar to the following (redirecting  stdin  and  stderr  to  /dev/null  and detaching from the parent\r\nprocess):\r\nnohup ./gtpdoor 2\u003e\u00261 2\u003e/dev/null \u0026\r\nMore on the probing feature\r\nThe TCP probe is a feature that allows an external host to probe the GRX listening address for TCP packets. A\r\nsubnet filter is checked against the source IP address of the “client” and if it does NOT match, a reply beacon is sent\r\nto the (scanning) client. A crafted TCP  RST/ACK  response packet with the urgent pointer field set to  0x01  indicates\r\nthe implant is running.\r\nBased on the analysis of the behaviour, it appears that two types of scans are supported:\r\nTCP connect scan (simple TCP three way handshake)\r\nACK scans (client sending an ACK message with no initial SYN)\r\nTCP Connect Scan\r\nhttps://doubleagent.net/telecommunications/backdoor/gtp/2024/02/27/GTPDOOR-COVERT-TELCO-BACKDOOR\r\nPage 12 of 18\n\nFor a TCP connect scan to work, there must be a service listening and port exposed on the host, either from a\r\npermissive firewall or no firewall at all. GTPDOOR will send a “decoy” TCP  ACK/RST  response on the initial\r\nTCP  SYN  from the client but with no identifying information to indicate GTPDOOR is running. It is the second\r\nTCP  ACK/RST  that is sent on the client’s ACK that has the urgent pointer set to signal GTPDOOR is running on the\r\nremote host.\r\nACK Scan\r\nFor an ACK scan to work, the condition would be no firewall or a non stateful firewall (so the TCP  ACK  is not\r\ndropped due to no initial  SYN  packet from the client). No service needs to listen the TCP beaconing port with an\r\nACK scan: as with the GTP message handler, a raw socket is used to “intercept” all TCP packets.\r\nThe beacon response packet that is sent back to the probing host is manually assembled, copying the incoming\r\npacket’s relevant IP and TCP header fields into the outgoing beacon packet.\r\nThe probe response packets will always have the  ACK/RST  flags set and the urgent pointer flags set according to if\r\nan  TCP ACK  was observed. This is a covert way of encoding messages by bit manipulation in the TCP header.\r\nhttps://doubleagent.net/telecommunications/backdoor/gtp/2024/02/27/GTPDOOR-COVERT-TELCO-BACKDOOR\r\nPage 13 of 18\n\nIt is assumed that packets of this combination would be rare or non-existent in normal TCP/IP communication as the\r\nURG flag is set to 0, while the urgent pointer specifies a value. Additionally, this is occurring with the RST flag set.\r\nRFC0793 states that the urgent pointer has no meaning if the URG flag is not set:\r\nWe can observe the differences in a tcpdump. In the following a TCP connect() from the probe “client” on a non\r\nexisting port  22222  has a probe response  RST/ACK  with the urgent pointer flat set to  0 . The assumption here is\r\nthat this is a “decoy” response to blend in  RST/ACK  responses for closed or open ports on the remote host.\r\nhttps://doubleagent.net/telecommunications/backdoor/gtp/2024/02/27/GTPDOOR-COVERT-TELCO-BACKDOOR\r\nPage 14 of 18\n\nOn the other hand, when the client connects to an open port  22 (SSH) , the probe response includes a  RST/ACK  but\r\nthis time with the urgent pointer set to  1\r\nACL functionality\r\nIt is not known if the ACL is intended to be a deny list or allow list - there are pros and cons of explicitly denying IP\r\nsubnets from probing:\r\nAvoid keeping threat actor C2 infrastructure network/IPs resident in memory\r\nSpecify internal victim networks or host IPs to prevent causing traffic disruption from beaconed TCP reset\r\nmessages.\r\nBased on analysis of the samples alone, the author assumes this behaviour is intentional. The threat actor can change\r\ntheir C2 infrastructure or intermediate transit hosts without loosing the ability to send probe messages.\r\nhttps://doubleagent.net/telecommunications/backdoor/gtp/2024/02/27/GTPDOOR-COVERT-TELCO-BACKDOOR\r\nPage 15 of 18\n\nIt is likely that the  RST/ACK  responses from an initial  SYN  packet is there as a decoy - a casual review of a network\r\ncapture would result in one assuming that this is normal behaviour of the firewall or hosts TCP/IP stack. One would\r\nhave to notice that the  RST/ACK  packet has the urgent pointer field set only for incoming  ACK  packets. Tricky\r\nindeed!\r\nAn approximation of the ACL filtering. Note the  !  on line  118 :\r\nNotably one condition before TCP packets are “intercepted” by the process is the global\r\nvariable  local_grx_addr  must be set first. This is set based on the destination IP address in any GTP-C packet that\r\nis received.\r\nAnother condition is that the ACL must have at least one subnet or IP defined for the probe feature to be operational.\r\nDetection\r\nGTPDOOR can be identified by listing raw sockets open on the system, e.g. via  lsof , looking\r\nfor  SOCK_RAW  or  raw .\r\nnetstat -lp --raw  also shows listening sockets:\r\nProcess name stomped files that are disguised as kernel threads can be identified by their parent process not\r\nbeing  kthreadd . In the following screenshot the  PPID  of the backdoor is  1935 , while the other kernel\r\nthread parent IDs are  2 :\r\nhttps://doubleagent.net/telecommunications/backdoor/gtp/2024/02/27/GTPDOOR-COVERT-TELCO-BACKDOOR\r\nPage 16 of 18\n\nThe presence of the mutex  /var/run/daemon.pid  could be an indicator.\r\nThe presence of the file  system.conf  could be an indicator.\r\nYara rule for threat hunting:\r\nrule Linux_Malware_GTPDOOR_v1v2\r\n{\r\nmeta:\r\ndescription = \"Detects GTPDOOR\"\r\nauthor = \"@haxrob\"\r\ndata = \"28/02/2024\"\r\nreference = \"https://doubleagent.net/telecommunications/backdoor/gtp/2024/02/27/GTPDOOR-COVERT-T\r\nhash1 = \"827f41fc1a6f8a4c8a8575b3e2349aeaba0dfc2c9390ef1cceeef1bb85c34161\"\r\nhash2 = \"5cbafa2d562be0f5fa690f8d551cdb0bee9fc299959b749b99d44ae3fda782e4\"\r\nstrings:\r\n$s1 = \"excute result is\" ascii fullword\r\n$s2 = \"idkey not correct\" ascii fullword\r\n$s3 = \"send ret message\" ascii fullword\r\ncondition:\r\nuint16(0) == 0x457f and\r\n2 of them and\r\nfilesize \u003c 20KB\r\n}\r\nDefence\r\nGSMA has released two relevant guidelines:\r\nFS.31 GSMA Baseline Security Controls\r\nIR.77 Inter-Operator IP Backbone Security Requirements For Service Providers and Inter-operator IP\r\nbackbone Providers\r\nGTP Firewall\r\nGPTDOOR handles malformed GTP packets. In the following test, the GTP protocol type of  0  (GTP prime -\r\ncharging related) is set in custom client. GTP’ does not work over the GTP-C port. Additionally the extension header\r\nis corrupt. The GTPDOOR message encrypted payload is appended on the GTP message. As such, a GTP capable\r\nfirewall may detect and drop abnormal packets like this.\r\nhttps://doubleagent.net/telecommunications/backdoor/gtp/2024/02/27/GTPDOOR-COVERT-TELCO-BACKDOOR\r\nPage 17 of 18\n\nFirewalling\r\nThe inbound UDP port is required to be open for systems that require it on the GRX network. Firewall rules\r\nshould be explicit enough to drop these packets inbound for any system that does not use the GTP protocol\r\nAggressive rules to block inbound TCP connections via the GRX - There is not a lot that actually needs to be\r\nopen\r\nProbe TCP packets with RST/ACK flag set could be dropped on the GRX firewall\r\nActive GTPDOOR network scanner\r\nA multithreaded network scanner is available which can be used to scan remotes hosts in attempt to detect the\r\npresence of GTPDOOR:\r\nhttps://github.com/haxrob/gtpdoor-scan/\r\nSource: https://doubleagent.net/telecommunications/backdoor/gtp/2024/02/27/GTPDOOR-COVERT-TELCO-BACKDOOR\r\nhttps://doubleagent.net/telecommunications/backdoor/gtp/2024/02/27/GTPDOOR-COVERT-TELCO-BACKDOOR\r\nPage 18 of 18",
	"extraction_quality": 1,
	"language": "EN",
	"sources": [
		"Malpedia"
	],
	"origins": [
		"web"
	],
	"references": [
		"https://doubleagent.net/telecommunications/backdoor/gtp/2024/02/27/GTPDOOR-COVERT-TELCO-BACKDOOR"
	],
	"report_names": [
		"GTPDOOR-COVERT-TELCO-BACKDOOR"
	],
	"threat_actors": [
		{
			"id": "ece64b74-f887-4d58-9004-2d1406d37337",
			"created_at": "2022-10-25T16:07:23.794442Z",
			"updated_at": "2026-04-10T02:00:04.751764Z",
			"deleted_at": null,
			"main_name": "LightBasin",
			"aliases": [
				"DecisiveArchitect",
				"Luminal Panda",
				"TH-239",
				"UNC1945"
			],
			"source_name": "ETDA:LightBasin",
			"tools": [
				"CordScan",
				"EVILSUN",
				"FRP",
				"Fast Reverse Proxy",
				"Impacket",
				"LEMONSTICK",
				"LOGBLEACH",
				"LOLBAS",
				"LOLBins",
				"Living off the Land",
				"OKSOLO",
				"OPENSHACKLE",
				"ProxyChains",
				"Pupy",
				"PupyRAT",
				"SIGTRANslator",
				"SLAPSTICK",
				"SMBExec",
				"STEELCORGI",
				"Tiny SHell",
				"pupy",
				"tsh"
			],
			"source_id": "ETDA",
			"reports": null
		},
		{
			"id": "c0b06c51-f463-47dc-9b15-1ffa317dbf2c",
			"created_at": "2025-03-04T02:00:02.983311Z",
			"updated_at": "2026-04-10T02:00:03.793603Z",
			"deleted_at": null,
			"main_name": "LIMINAL PANDA",
			"aliases": [],
			"source_name": "MISPGALAXY:LIMINAL PANDA",
			"tools": [],
			"source_id": "MISPGALAXY",
			"reports": null
		},
		{
			"id": "31c0d0e1-f793-4374-90aa-138ea1daea50",
			"created_at": "2023-11-30T02:00:07.29462Z",
			"updated_at": "2026-04-10T02:00:03.482987Z",
			"deleted_at": null,
			"main_name": "LightBasin",
			"aliases": [
				"UNC1945",
				"CL-CRI-0025"
			],
			"source_name": "MISPGALAXY:LightBasin",
			"tools": [],
			"source_id": "MISPGALAXY",
			"reports": null
		}
	],
	"ts_created_at": 1775434046,
	"ts_updated_at": 1775826717,
	"ts_creation_date": 0,
	"ts_modification_date": 0,
	"files": {
		"pdf": "https://archive.orkl.eu/1231fb95ec01f6ab4a1f255723c57d0ee0c91e53.pdf",
		"text": "https://archive.orkl.eu/1231fb95ec01f6ab4a1f255723c57d0ee0c91e53.txt",
		"img": "https://archive.orkl.eu/1231fb95ec01f6ab4a1f255723c57d0ee0c91e53.jpg"
	}
}