{
	"id": "7b6543b1-81d4-4ecf-b97a-4965d8624e61",
	"created_at": "2026-04-06T00:19:23.648629Z",
	"updated_at": "2026-04-10T03:28:24.283285Z",
	"deleted_at": null,
	"sha1_hash": "2eec4030c34d5d18701d9b5c3139e4e4bc6d441e",
	"title": "ATT\u0026CK T1501: Understanding Systemd Service Persistence",
	"llm_title": "",
	"authors": "",
	"file_creation_date": "0001-01-01T00:00:00Z",
	"file_modification_date": "0001-01-01T00:00:00Z",
	"file_size": 70987,
	"plain_text": "ATT\u0026CK T1501: Understanding Systemd Service Persistence\r\nBy Dominic Heidt\r\nArchived: 2026-04-05 15:18:23 UTC\r\nThe Red Canary intel team has spent a lot of time researching the endpoint threat landscape and related detection\r\npossibilities for Linux systems. While examining one particularly interesting persistence strategy, we were\r\nsomewhat surprised to learn that the technique didn’t already exist in the ATT\u0026CK™ Framework. While\r\nmalicious use of systemd services isn’t necessarily new to Linux systems, there is little public research or\r\ndocumentation about how adversaries leverage it for persistence.\r\nWhat are systemd services?\r\nPut succinctly (and derived largely from the systemd manual page), systemd is a system and service manager for\r\nLinux distributions. From the Windows perspective, this process fulfills the duties of wininit.exe and services.exe\r\ncombined. At the risk of simplifying the functionality of systemd, it initializes a Linux system and starts relevant\r\nservices that are defined in service unit files. These unit files may define the execution of binaries like httpd or the\r\nexecution of scripts with command lines similar to bash -c scriptedService.sh .\r\nOlder Linux distributions have used different initialization systems in the past, usually SysVInit. This system\r\nleveraged shell scripts that would execute the relevant components needed to provide a service. For several years\r\nnow, modern Linux systems have adopted systemd to define services, deprecating the init scripts of yesteryear.\r\nMany people didn’t greet this decision with open arms, but it seems to be here to stay.\r\nWhat makes up a systemd service?\r\nA service unit file defines a structure similar to this:\r\n[Unit]\r\nDescription=Atomic Red Team Service\r\n[Service]\r\nType=simple\r\nExecStart=/bin/touch /tmp/art-systemd-execstart-marker\r\n[Install]\r\nWantedBy=default.target\r\nLet’s break this down in pieces.\r\nUnit\r\nThe description provides an understandable name for the defined service.\r\nhttps://redcanary.com/blog/attck-t1501-understanding-systemd-service-persistence/\r\nPage 1 of 4\n\nService\r\nTo specify service execution information, you can use several directives:\r\nExecStart: commands executed when the specified service starts\r\nExecStartPre: commands executed before ExecStart\r\nExecStartPost: commands executed after ExecStart\r\nExecStop: commands executed when the specified service stops\r\nExecStopPre: commands executed before ExecStop\r\nExecStopPost: commands executed after ExecStop\r\nExecReload: commands to trigger configuration reload of a service\r\nInstall\r\nFinally, the unit file specifies a WantedBy directive. If you’re a veteran of SysVinit systems, you’ll remember\r\nrunlevels and how each init script existed under a folder numbered to coincide with the relevant runlevel. This let\r\nsystems determine which services would execute based on how the host booted or changed modes. In the world of\r\nsystemd, targets replace runlevels. Each target roughly corresponds to a runlevel from SysVinit, and, in this\r\ncase, our target is the default target. It specifies that this service should execute for whatever target is currently set,\r\nensuring it will execute at the next boot.\r\nOf course it’s more complicated than that…\r\nThere are many places where administrators and adversaries may stash systemd service files. For systemd services\r\nexecuting at the system-level, you can place service files in these folders:\r\n/lib/systemd/system\r\n/usr/lib/systemd/system\r\n/etc/systemd/system\r\n/run/systemd/system\r\nFor systemd services executing in a single user’s context, you can place service files in these folders:\r\n/etc/systemd/user\r\n~/.config/systemd/user\r\n~/.local/share/systemd/user\r\n/run/systemd/user\r\n/usr/lib/systemd/user\r\nIn many cases, software installations will place symbolic links (like Windows shortcuts) in these folders, allowing\r\nthem to place their own service file anywhere on the filesystem while allowing systemd to discover it.\r\nWhat does normal look like?\r\nhttps://redcanary.com/blog/attck-t1501-understanding-systemd-service-persistence/\r\nPage 2 of 4\n\nWhen executing, commands specified by a systemd service should always have a parent process of systemd . In\r\nmost cases, the parent systemd process should have a process ID of 1, but there are edge-cases when it may not.\r\nBy default, system-level services will execute as the root user. This would be equivalent to the Windows\r\nAdministrator account. If desired, you may specify an additional configuration directive, User= , to allow system-level services to impersonate another user. User-level services that are not in the security context of root  cannot\r\nimpersonate another user, however.\r\nFinally, when managing systemd services, you must use the systemctl utility to perform some tasks. After\r\nsomething writes a unit file to disk, systemctl enable \u003cname\u003e allows systemd to load it as a service at boot, and\r\nsystemctl start \u003cname\u003e  executes the commands specified by the service file on demand.\r\nAdversary use of systemd services\r\nSystemd services are an awesome artifact for adversaries to leverage for persistence. With the proper privileges,\r\nadversaries can create a malicious service (just like in Windows) that will allow them to persist between reboots,\r\npotentially as root.\r\nThe most notable reported use of systemd services for persistence involved the compromise of orphaned software\r\npackages no longer maintained by the “acroread” software package for Arch Linux in 2018. Unsuspecting users\r\ndownloaded acroread, allowing the malicious script within to create persistence via a systemd service. Once\r\ndiscovered by users, maintainers of the Arch User Repository reverted those packages to benign versions. Here,\r\nthe adversary was stopped before they could do much damage, in large part because one payload didn’t execute as\r\ndesigned.\r\nAt least one major threat actor, Rocke, has used this persistence technique in opportunistic attacks on Linux\r\nservers. When they evolved their payloads away from simple scripts to leverage Golang binaries, Rocke also\r\nincluded a Systemd service to ensure their payload would execute on boot.\r\nThe Metasploit Framework has already incorporated this persistence technique into its functionality. By using the\r\nservice persistence exploit module, adversaries may create service files on disk to execute as either a system-level\r\nservice or a user-level service. This functionality has been part of the tool since around December 2018. To\r\nleverage this, adversaries can specify their own payload for execution, and Metasploit can handle the details of\r\nwriting the payload to disk, writing the service file to disk and scheduling it for execution at the next boot.\r\nIf you want to test this out in your environment without setting up Metasploit, you can do so with Atomic Red\r\nTeam. We have an Atomic Test that guides you through creating a simple systemd service and scheduling it for\r\nexecution at boot.\r\nHunting for malicious systemd services\r\nAs mentioned before, systemd service files can live in multiple places on disk. When hunting with EDR\r\ntechnology, you can check out suspicious file modifications of those folders. By default, the processes that\r\ntypically write these files are Python because of package management via Yum on CentOS/RHEL, dpkg because\r\nof package management via apt on Debian derivatives, and systemctl itself to enable and disable services. Bash\r\nhttps://redcanary.com/blog/attck-t1501-understanding-systemd-service-persistence/\r\nPage 3 of 4\n\nshell scripts and processes other than those mentioned touch these files less often, so they’ll be more suspect while\r\nhunting.\r\nIf you don’t have EDR tools and you want to hunt for malicious persistence via the Linux command line, you can\r\ndo so with these commands:\r\nfind / -path \"*/systemd/system/*.service\" -exec grep -H -E \"ExecStart|ExecStop|ExecReload\" {} \\;\r\n2\u003e/dev/null\r\nfind / -path \"*/systemd/user/*.service\" -exec grep -H -E \"ExecStart|ExecStop|ExecReload\" {} \\;\r\n2\u003e/dev/null\r\nThese commands will enumerate all the commands specified by system and user systemd services on a host. If\r\nyou’re daring, you might combine these commands with ssh commands to execute them on remote hosts, saving\r\nthe output to files for hunting and processing later. Pay particular attention to service files corresponding to\r\nservices you don’t recognize and execution commands that contain bash , python , or sh .\r\nWhen hunting on EDR platforms, be aware of process ancestry involving systemd. On modern Linux systems, the\r\nsystemd process should start all services, operating as the root of all process trees. Most of the time, systemd will\r\nspawn daemon processes, such as httpd or mysqld. When it spawns shell processes such as bash, this definitively\r\nshows that bash was specified as a service execution. Legitimate user instances of bash shells that occur after\r\nlogon do not spawn as direct children of systemd, and they exist further down the ancestry chain. While a systemd\r\n-\u003e bash ancestry is not certainly evil, it’s a good place to start when hunting in your own environment.\r\nConclusion\r\nBy understanding a bit of Linux system internals, we can hunt down adversaries and remove their footholds.\r\nMalicious persistence takes many forms and, like with Windows, knowing the capabilities of the operating system\r\nmakes all the difference.\r\nSource: https://redcanary.com/blog/attck-t1501-understanding-systemd-service-persistence/\r\nhttps://redcanary.com/blog/attck-t1501-understanding-systemd-service-persistence/\r\nPage 4 of 4",
	"extraction_quality": 1,
	"language": "EN",
	"sources": [
		"MITRE"
	],
	"references": [
		"https://redcanary.com/blog/attck-t1501-understanding-systemd-service-persistence/"
	],
	"report_names": [
		"attck-t1501-understanding-systemd-service-persistence"
	],
	"threat_actors": [
		{
			"id": "7c053836-8f50-4d40-bc5c-7088967e1b57",
			"created_at": "2022-10-25T16:07:24.549525Z",
			"updated_at": "2026-04-10T02:00:05.03048Z",
			"deleted_at": null,
			"main_name": "Rocke",
			"aliases": [
				"Aged Libra",
				"G0106",
				"Iron Group",
				"Rocke"
			],
			"source_name": "ETDA:Rocke",
			"tools": [
				"Godlua",
				"Kerberods",
				"LSD",
				"Pro-Ocean",
				"Xbash"
			],
			"source_id": "ETDA",
			"reports": null
		},
		{
			"id": "905eabd9-2b7f-483d-86bd-0c72f96b4162",
			"created_at": "2023-01-06T13:46:39.02749Z",
			"updated_at": "2026-04-10T02:00:03.185957Z",
			"deleted_at": null,
			"main_name": "Rocke",
			"aliases": [
				"Aged Libra"
			],
			"source_name": "MISPGALAXY:Rocke",
			"tools": [],
			"source_id": "MISPGALAXY",
			"reports": null
		},
		{
			"id": "0b02af5f-2027-42b7-a6f2-51e2fd49ba7f",
			"created_at": "2022-10-25T15:50:23.360509Z",
			"updated_at": "2026-04-10T02:00:05.337702Z",
			"deleted_at": null,
			"main_name": "Rocke",
			"aliases": [
				"Rocke"
			],
			"source_name": "MITRE:Rocke",
			"tools": null,
			"source_id": "MITRE",
			"reports": null
		}
	],
	"ts_created_at": 1775434763,
	"ts_updated_at": 1775791704,
	"ts_creation_date": 0,
	"ts_modification_date": 0,
	"files": {
		"pdf": "https://archive.orkl.eu/2eec4030c34d5d18701d9b5c3139e4e4bc6d441e.pdf",
		"text": "https://archive.orkl.eu/2eec4030c34d5d18701d9b5c3139e4e4bc6d441e.txt",
		"img": "https://archive.orkl.eu/2eec4030c34d5d18701d9b5c3139e4e4bc6d441e.jpg"
	}
}