{
	"id": "22783d9f-ac3e-46e9-bb9c-f3949ce929ef",
	"created_at": "2026-04-06T00:07:26.836221Z",
	"updated_at": "2026-04-10T03:20:49.605679Z",
	"deleted_at": null,
	"sha1_hash": "d994ed6077956fdbeeedba0df4b14ce9433b964b",
	"title": "RotaJakiro: A long live secret backdoor with 0 VT detection",
	"llm_title": "",
	"authors": "",
	"file_creation_date": "0001-01-01T00:00:00Z",
	"file_modification_date": "0001-01-01T00:00:00Z",
	"file_size": 897804,
	"plain_text": "RotaJakiro: A long live secret backdoor with 0 VT detection\r\nBy Alex.Turing\r\nPublished: 2021-04-28 · Archived: 2026-04-05 18:39:54 UTC\r\nOverview\r\nOn March 25, 2021, 360 NETLAB's BotMon system flagged a suspiciousELF file\r\n(MD5=64f6cfe44ba08b0babdd3904233c4857) with 0 VT detection, the sample communicates with 4 domains on\r\nTCP 443 (HTTPS), but the traffic is not of TLS/SSL. A close look at the sample revealed it to be a backdoor\r\ntargeting Linux X64 systems, a family that has been around for at least 3 years.\r\nWe named it RotaJakiro based on the fact that the family uses rotate encryption and behaves differently for\r\nroot/non-root accounts when executing.\r\nRotaJakiro pays quite some attention to hide its trails, using multiple of encryption algorithms, including: the\r\nuse of AES algorithm to encrypt the resource information within the sample; C2 communication using a\r\ncombination of AES, XOR, ROTATE encryption and ZLIB compression .\r\nRotaJakiro supports a total of 12 functions, three of which are related to the execution of specific Plugins.\r\nUnfortunately, we have no visibilityto the plugins, and therefore do not know its true purpose. From a broad\r\nbackdoor perspective, the functions can be grouped into the following four categories.\r\nReporting device information\r\nStealing sensitive information\r\nFile/Plugin management (query, download, delete)\r\nExecution of specific Plugin\r\nAny more out there?\r\nWith the sample we have, we discovered the following 4 samples, all of which have 0 detections on VT, and the\r\nearliest First Seen time on VT is in 2018.\r\nFileName MD5 Detection First Seen in VT\r\nsystemd-daemon 1d45cd2c1283f927940c099b8fab593b 0/61 2018-05-16 04:22:59\r\nsystemd-daemon 11ad1e9b74b144d564825d65d7fb37d6 0/58 2018-12-25 08:02:05\r\nsystemd-daemon 5c0f375e92f551e8f2321b141c15c48f 0/56 2020-05-08 05:50:06\r\ngvfsd-helper 64f6cfe44ba08b0babdd3904233c4857 0/61 2021-01-18 13:13:19\r\nhttps://blog.netlab.360.com/stealth_rotajakiro_backdoor_en/\r\nPage 1 of 18\n\nThese samples all have the following 4 C2s embedded. These 4 C2 domains have very close Crteated,Updated\r\nand Expired time, readers will notice that the crated data was in Dec 2015, 6 years ago.\r\nDomain Detection Created Last Updated Expired\r\nnews.thaprior.net 0/83 2015-12-09 06:24:13 2020-12-03 07:24:33 2021-12-09 06:24:13\r\nblog.eduelects.com 0/83 2015-12-10 13:12:52 2020-12-03 07:24:33 2021-12-10 13:12:52\r\ncdn.mirror-codes.net 0/83 2015-12-09 06:24:19 2020-12-03 07:24:32 2021-12-09 06:24:19\r\nstatus.sublineover.net 0/83 2015-12-09 06:24:24 2020-12-03 07:24:32 2021-12-09 06:24:24\r\nReverse Analysis\r\nThe 4 RotaJakiro samples, with time distribution from 2018 to 2021, are very close to their functions, and the\r\n2021 sample is selected for analysis in this blog, which has the following basic information:\r\nMD5:64f6cfe44ba08b0babdd3904233c4857\r\nELF 64-bit LSB executable, x86-64, version 1 (SYSV), dynamically linked (uses shared libs), for GNU/Linux 2.6.32\r\nPacker:No\r\nAt the coding level , RotaJakiro uses techniques such as dynamic AES, double-layer encrypted communication\r\nprotocols to counteract the binary \u0026 network traffic analysis.\r\nAt the functional level , RotaJakiro first determines whether the user is root or non-root at run time, with\r\ndifferent execution policies for different accounts, then decrypts the relevant sensitive resources using AES\u0026\r\nROTATE for subsequent persistence , process guarding and single instance use, and finally establishes\r\ncommunication with C2 and waits for the execution of commands issued by C2.\r\nThe following will analyze the specific implementation of RotaJakiro from the above perspective.\r\n0x00: Tricks used by the sample\r\n0x01: Encryption algorithm\r\nAll sensitive resources in RotaJakiro are encrypted, and in IDA we can see that the decryption method dec_proc is\r\ncalled 60 times, which is composed of AES and Rotate.\r\nThe AES decryption entry is as follows:\r\nhttps://blog.netlab.360.com/stealth_rotajakiro_backdoor_en/\r\nPage 2 of 18\n\nWhere aes_dec is AES-256, CBC mode, key\u0026iv are hardcoded.\r\nKEY\r\n 14 BA EE 23 8F 72 1A A6 00 00 00 00 00 00 00 00\r\n 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00\r\nIV\r\n 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00\r\nhttps://blog.netlab.360.com/stealth_rotajakiro_backdoor_en/\r\nPage 3 of 18\n\nThe Rotate decryption entry is shown below:\r\nThe so-called Rotate is a cyclic shift, we can see that the number of shifts is determined by the value of\r\nplain_len(length of plaintext) \u00267 .\r\nTake the following C2 cipher text as an example.\r\nff ba a2 3b cd 5b 7b 24 8c 5f e3 4b fc 56 5b 99\r\nac 91 cf e3 9a 27 d4 c9 6b 39 34 ce 69 ce 18 60\r\nThe various parameters related to decryption are shown below, the length of the ciphertext is 32 bytes and the\r\nlength of the plaintext is 26 bytes.\r\nFirst, decrypting with AES, we get the following \"sub-ciphertext\".\r\nThen, the valid ciphertext is extracted from the sub-ciphertext, where the valid ciphertext starts from the 8th byte,\r\nand the length is the plaintext length minus 8, which is 26-8=18 bytes here.\r\n98 1B DB D9 8B 59 19 5D 59 1B 59 D8 1D DC 8B D8\r\nDB 5B\r\nFinally, we can calculate 26(the length of plaintext is 26)\u00267=2, and get the number of shifts, and shift the above\r\nvalid ciphertext byte by byte by 2 bits to get C2 plaintext.\r\nblog.eduelects.com\r\nhttps://blog.netlab.360.com/stealth_rotajakiro_backdoor_en/\r\nPage 4 of 18\n\n0x02: Persistence\r\nRotaJakiro makes a distinction between root/non-root users when implementing persistence features, and\r\ndifferent techniques are used for different accounts.\r\nroot account\r\nDepending on the Linux distribution, create the corresponding self-starting script /etc/init/systemd-agent.conf or /lib/systemd/system/sys-temd-agent.service .\r\nContent of systemd-agent.conf\r\n-----------------------------\r\n#system-daemon - configure for system daemon\r\n#This service causes system have an associated\r\n#kernel object to be started on boot.\r\ndescription \"system daemon\"\r\nstart on filesystem or runlevel [2345]\r\nexec /bin/systemd/systemd-daemon\r\nrespawn\r\nContent of systemd-agent.service\r\n-----------------------------\r\n[Unit]\r\nDescription=System Daemon\r\nWants=network-online.target\r\nAfter=network-online.target\r\n[Service]\r\nExecStart=/usr/lib/systemd/systemd-daemon\r\nRestart=always\r\n[Install]\r\nThe file name used for the disguise is one of the following twos.\r\n/bin/systemd/systemd-daemon\r\n/usr/lib/systemd/systemd-daemon\r\nnon-root account\r\nCreate autostart script $HOME/.config/au-tostart/gnomehelper.desktop for desktop environment\r\n[Desktop Entry]\r\nType=Application\r\nExec=$HOME/.gvfsd/.profile/gvfsd-helper\r\nhttps://blog.netlab.360.com/stealth_rotajakiro_backdoor_en/\r\nPage 5 of 18\n\nModify the .bashrc file to create the autostart script for the shell environment\r\n# Add GNOME's helper designed to work with the I/O abstraction of GIO\r\n# this environment variable is set, gvfsd will not start the fuse filesystem\r\nif [ -d ${HOME} ]; then\r\n ${HOME}/.gvfsd/.profile/gvfsd-helper\r\nfi\r\nThe file name used for the disguise, both of which exist at the same time\r\n$HOME/.dbus/sessions/session-dbus\r\n$HOME/.gvfsd/.profile/gvfsd-helper\r\n0x03:Process guarding\r\nRotaJakiro implements process guarding to protect its own operation, and like persistence, there are different\r\nimplementations for root/non-root users.\r\nroot account\r\nWhen running under the root account, depending on the Linux distribution, a new process is automatically created\r\nwhen the service process is terminated by writing Restart=always or respawn to the service's configuration file.\r\nThe actual result is shown in the figure below, where you can see that a new process is created immediately after\r\nthe systemd-daemon process is terminated.\r\nnon-root account\r\nhttps://blog.netlab.360.com/stealth_rotajakiro_backdoor_en/\r\nPage 6 of 18\n\nWhen running under a non-root account, RotaJakiro generates two processes, session-dbus and gvfsd-helper ,\r\nwhich monitor each other's survival and restore them when one of them is terminated, which is very typical of\r\ndual-process protection.\r\nHow is RotaJakiro's dual-process protection implemented?\r\nFirst, it creates a piece of shared memory with the shmget API , and session-dbus and gvfsd-helper communicate\r\nwith each other through this shared memory, telling each other their PIDs.\r\nThen, dynamically fetching the process survival through the /proc/[PID] directory. When the other process is\r\nfound dead, the process is created by execvp API to help the dead process \"resurrect\", as shown in the following\r\ndiagram.\r\nThe actual effect is shown in the figure below, you can see that after session-dbus and gvfsd-helper are ended by\r\nkill -9, new processes are created right away.\r\nhttps://blog.netlab.360.com/stealth_rotajakiro_backdoor_en/\r\nPage 7 of 18\n\n0x04: Single instance\r\nRotaJakiro implements a single instance by file locking, as shown below.\r\nThe lockfile used in this differs under the root/non-root account.\r\nThe lockfile under root, one will be created.\r\n/usr/lib32/.X11/X0-lock\r\n/bin/lib32/.X11/X0-lock\r\nThe lockfile under non-root, both will be created.\r\n$HOME/.X11/X0-lock\r\n$HOME/.X11/.X11-lock\r\nIn the actual non-root account, for example, the processes and file locks can be matched by /proc/locks , and\r\nthen the corresponding RotaJakiro sample is executed.\r\nhttps://blog.netlab.360.com/stealth_rotajakiro_backdoor_en/\r\nPage 8 of 18\n\n0x05: Network communication\r\nRotaJakiro establishes communication with C2 through the following code snippet, pending the execution of\r\nsubsequent commands.\r\nhttps://blog.netlab.360.com/stealth_rotajakiro_backdoor_en/\r\nPage 9 of 18\n\nThis process can be divided into 2 stages\r\nStage 1, initialization phase\r\nDecrypt the C2 list, establish a connection with C2, send the online information, receive and decrypt the\r\ninformation returned by C2.\r\nStage 2, wait for C2 calls\r\nVerify the information returned by C2, if it passes the verification, execute the subsequent instructions sent\r\nby C2.\r\nStage 1: Initialization\r\nThe C2 list is decrypted by the decryption algorithm described in the previous section, and the following four C2s\r\nare built into the sample at present.\r\nnews.thaprior.net\r\nblog.eduelects.com\r\nhttps://blog.netlab.360.com/stealth_rotajakiro_backdoor_en/\r\nPage 10 of 18\n\ncdn.mirror-codes.net\r\nstatus.sublineover.net\r\nRotaJakiro will first try to establish a connection with them, and then construct the golive message by the\r\nfollowing code snippet.\r\nThen it encrypts the golive information and sends it to the C2s\r\nFinally, it receives the packet back from the C2, decrypts it and checks its legitimacy, and if it passes the check, it\r\nhttps://blog.netlab.360.com/stealth_rotajakiro_backdoor_en/\r\nPage 11 of 18\n\ngoes to Stage 2.\r\nStage 2: Specific operations\r\nReceive and execute the command from C2 through the following codesnippet.\r\nAt present, RotaJakiro supports a total of 12 instructions, and the correspondence between the instruction code\r\nand the function is shown in the following table.\r\nCmdId Function\r\n0x138E3E6 Exit\r\n0x208307A Test\r\n0x5CCA727 Heartbeat\r\n0x17B1CC4 Set C2 timeout time\r\n0x25360EA Steal Senstive Info\r\n0x18320e0 Upload Device Info\r\n0x2E25992 Deliver File/Plugin\r\nhttps://blog.netlab.360.com/stealth_rotajakiro_backdoor_en/\r\nPage 12 of 18\n\nCmdId Function\r\n0x2CD9070\r\nQuery File/Plugin\r\nStatus\r\n0x12B3629\r\nDelete File/Plugin Or\r\nDir\r\n0x1B25503\r\nRun\r\nPlugin_0x39C93E\r\n0x1532E65\r\nRun\r\nPlugin_0x75A7A2\r\n0x25D5082\r\nRun\r\nPlugin_0x536D01\r\nThe Run Plugin function reuses the same code and implements the function call\r\nthrough the following logic.\r\nWe are currently not capturing such payloads, so we use the Plugin_\"parameter\"\r\nform to represent different tasks.\r\n0x06 Packet analysis\r\nThe network communication packet of RotaJakiro consists of three parts: Head, Key, Payload .\r\nHead is mandatory and 82 bytes long, and the Key \u0026 Payload parts are optional.\r\nHead \u0026 Key are encrypted with XOR \u0026 Rotate, and Payload is encrypted with AES \u0026 ZLIB Compression.\r\nhttps://blog.netlab.360.com/stealth_rotajakiro_backdoor_en/\r\nPage 13 of 18\n\nIn the following, we will illustrate the composition of network traffic head\u0026key\u0026payload and the decryption\r\nprocess through a round of interaction between Bot and C2.\r\nC2 -\u003e Bot\r\nThe first 0x52 bytes are the content of the Head. How to decrypt the head? Very simple, shift 3 bits left byte\r\nby byte, and then XOR with 0x1b . After decryption, we can get the following content.\r\n00000000 16 11 10 b9 03 b1 0c fb 04 20 00 00 00 08 00 e0 |...¹.±.û. .....à|\r\n00000010 20 83 01 c2 20 64 20 01 e2 00 00 00 00 c2 0c 00 | ..Â d .â....Â..|\r\n00000020 00 00 32 42 36 39 33 33 34 46 38 34 31 44 30 44 |..2B69334F841D0D|\r\n00000030 39 46 41 30 36 35 38 45 43 33 45 32 39 46 41 44 |9FA0658EC3E29FAD|\r\n00000040 34 39 c8 53 e6 9c 48 c4 8b 77 24 2e 02 1c 96 d9 |49ÈSæ.HÄ.w$....Ù|\r\n00000050 81 28\r\n------------filed parse------------------\r\noffset 0x09, 4 bytes---\u003epayload length\r\noffset 0x0d, 2 bytes---\u003ebody length\r\noffset ox0f, 4 bytes---\u003ecmdid\r\nThrough the field parsing, we can know that the length of key is 0x8 bytes, the length of payload is 0x20 bytes,\r\nand the instruction code to be executed is 0x18320e0, that is, the report device information .Reading 8 bytes\r\nfrom offset 0x52 gives the Key ea 9a 1a 18 18 44 26 a0 , and using the same decryption method as head, we\r\nget 4c cf cb dbdb 39 2a 1e , which is used as the AES key to decrypt the Payload.\r\nReading 32 bytes from offset 0x5a gives us the following Payload.\r\n54 c1 c3 69 00 18 31 e4 a2 5b 10 7f 67 ab d1 4b\r\nb2 7b 3d 3f b3 bc 66 6a 26 f6 f6 b3 f7 2e 66 6d\r\nUsing the decrypted key as the AES-256 key, decrypt the above data in CBC mode to get the following content.\r\n3b c7 f8 9b 73 2b d1 04 78 9c e3 60 60 60 d8 df d9 c1 71 56 f7 6f 00 00 13 80 04 28\r\nThe 8th byte onwards is ZLIB compressed data, decompressed to get the following content.\r\nhttps://blog.netlab.360.com/stealth_rotajakiro_backdoor_en/\r\nPage 14 of 18\n\n08 00 00 00 bf 89 88 08 cd 2d fd 50\r\n------------filed parse------------------\r\noffset 0, 4 bytes---\u003elength\r\nWhat is the use of the decompressed Payload( bf 89 88 08 cd 2d fd 50 )? It is used as a new AES key to\r\ndecrypt some sensitive resource information.\r\nFor example, when Bot collects device information, one of the information is the current OS distribution, which is\r\nimplemented by the cat /etc/*release | uniq command.\r\nroot@debian:~# cat /etc/*release | uniq\r\nPRETTY_NAME=\"Debian GNU/Linux 9 (stretch)\"\r\nNAME=\"Debian GNU/Linux\"\r\nVERSION_ID=\"9\"\r\nVERSION=\"9 (stretch)\"\r\nID=debian\r\nHOME_URL=\"https://www.debian.org/\"\r\nSUPPORT_URL=\"https://www.debian.org/support\"\r\nBUG_REPORT_URL=\"https://bugs.debian.org/\"\r\nThe cat /etc/*release | uniq command is the result of the following cipher text\r\n\"cat /etc/*release | uniq\" cmd_ciphertxt\r\n---------------------------\r\n74 00 dd 79 e6 1e aa bb 99 81 7e ca d9 21 6b 81\r\n6b d9 9d 14 45 73 6a 1c 61 cc 28 a3 0f 2b 41 5a\r\n6b 33 8c 37 25 89 47 05 44 7e f0 6b 17 70 d8 ca\r\ndecrypted with the new AES key and the parameters in the following figure.\r\nBot -\u003e C2\r\nWhen BOT receives C2's \"report device information\" command, it will send the following data to C2, and you can\r\nsee that the value of the key part is still ea 9a 1a 18 18 44 26 a0 .\r\nhttps://blog.netlab.360.com/stealth_rotajakiro_backdoor_en/\r\nPage 15 of 18\n\nThe decrypted key value is 4c cf cb db db 39 2a 1e . After decrypting and decompressing the payload sent by\r\nBot to C2, we get the following data, which is the various information of the device, including the information\r\nobtained by cat /etc/*release | uniq mentioned before, which verifies that our analysis is correct.\r\nRelationship with the Torii Botnet\r\nThe Torii botnet was exposed by Avast on September 20, 2018, and we noticed that there are some the similarities\r\nbetween the twos,for example:\r\nhttps://blog.netlab.360.com/stealth_rotajakiro_backdoor_en/\r\nPage 16 of 18\n\n1: String similarity\r\nAfter decrypting the sensitive resources of RotaJakiro \u0026 Torii, we found that they reuse a lot of the same\r\ncommands.\r\n1：semanage fcontext -a -t bin_t '%s' \u0026\u0026 restorecon '%s'\r\n2：which semanage\r\n3：cat /etc/*release\r\n4：cat /etc/issue\r\n5：systemctl enable\r\n6：initctl start\r\n...\r\n2: Traffic similarity\r\nIn the process of constructing the flow, a large number of constants are used and the construction methods are very\r\nclose.\r\n3: Functional similarity\r\nFrom the perspective of reverse engineering, RotaJakiro \u0026 Torii share similar styles: the use of encryption\r\nalgorithms to hide sensitive resources, the implementation of a rather old-school style of persistence,structured\r\nnetwork traffic, etc.\r\nhttps://blog.netlab.360.com/stealth_rotajakiro_backdoor_en/\r\nPage 17 of 18\n\nWe don’t exactly know the answer, but it seems that RotaJakiro and Torii have some connections.\r\nThe tip of the iceberg\r\nWhile this concludes our analysis of RotaJakiro, the real work is far from over, and many questions remain\r\nunanswered: \"How did RotaJakiro spread, and what was its purpose?\" , \"Does RotaJakiro have a specific target?”,\r\nWe would love to know if the community has relevant leads.\r\nReaders are always welcomed to reach us on twitter, or email to netlabat[at]360.cn.\r\nIOC\r\nSample MD5\r\n1d45cd2c1283f927940c099b8fab593b\r\n11ad1e9b74b144d564825d65d7fb37d6\r\n5c0f375e92f551e8f2321b141c15c48f\r\n64f6cfe44ba08b0babdd3904233c4857\r\nC2\r\nnews.thaprior.net:443\r\nblog.eduelects.com:443\r\ncdn.mirror-codes.net:443\r\nstatus.sublineover.net:443\r\nIP\r\n176.107.176.16 Ukraine|Kiev|Unknown 42331|PE_Freehost\r\nSource: https://blog.netlab.360.com/stealth_rotajakiro_backdoor_en/\r\nhttps://blog.netlab.360.com/stealth_rotajakiro_backdoor_en/\r\nPage 18 of 18",
	"extraction_quality": 1,
	"language": "EN",
	"sources": [
		"MITRE",
		"Malpedia"
	],
	"references": [
		"https://blog.netlab.360.com/stealth_rotajakiro_backdoor_en/"
	],
	"report_names": [
		"stealth_rotajakiro_backdoor_en"
	],
	"threat_actors": [],
	"ts_created_at": 1775434046,
	"ts_updated_at": 1775791249,
	"ts_creation_date": 0,
	"ts_modification_date": 0,
	"files": {
		"pdf": "https://archive.orkl.eu/d994ed6077956fdbeeedba0df4b14ce9433b964b.pdf",
		"text": "https://archive.orkl.eu/d994ed6077956fdbeeedba0df4b14ce9433b964b.txt",
		"img": "https://archive.orkl.eu/d994ed6077956fdbeeedba0df4b14ce9433b964b.jpg"
	}
}