InfoSec Write-ups

A collection of write-ups from the best hackers in the world on topics ranging from bug bounties and CTFs to vulnhub machines, hardware challenges and real life encounters. Subscribe to our weekly newsletter for the coolest infosec updates: https://weekly.infosecwriteups.com/

Follow publication

Decrypting Zoom Team Chat: Forensic Analysis of Encrypted Chat Databases

Muhammad Haidar Akita Tresnadi
InfoSec Write-ups
Published in
8 min readMar 17, 2025

--

Src: https://pin.it/4Rv2KEaYc

Introduction

Zoom Team Chat is becoming a common communication tool in many organizations, but digital forensic analysis of its artifacts is rarely discussed. Beyond meetings and calls, chat messages, shared files, and conversation metadata stored by Zoom Team Chat can reveal important traces about user activities and interactions.

In this article, I’ll explore what kind of evidence can be recovered from Zoom Team Chat, based on a real CTF challenge I created. I’ll also include a short walkthrough of the overall challenge flow, leading up to the discovery of Zoom Team Chat artifacts, for those interested in the full picture.

If you’re interested in the full challenge background, scenario, and attachments, you can read the detailed description here

If you’re only interested in Zoom Team Chat analysis, feel free to skip ahead to Zoom Team Chat Artifact Discovery and Analysis.

Analyzing the Disk Image and Identifying the Ransomware

We were given a disk image (.ad file) to analyze. After loading it into FTK Imager, the first thing we noticed was that a lot of files were encrypted. It was clear that the system had been hit by ransomware.

When looking for program execution artifacts, we also found that registry data was broken or incomplete, making it difficult to trace what had been run on the system. Since common artifacts were either encrypted or damaged, we had to look for alternatives. One of the artifacts that still existed was Windows jumplists, which record data about programs recently executed or files opened.

C:\Users\xxx\AppData\Roaming\Microsoft\Windows\Recent\CustomDestinations

Using eric zimmerman’s jump list explorer tool, we can see that there is a suspicious hta file in the user data folder, and we know that chromesetup should use exe not hta.

Jumplist Artifact

I won’t go too deep into the encryption logic, the point is that there is obfuscated javascript that can be deobfuscated with online tools, and the full decryptor is included here.

Tracing User Activity: Chrome and Discord

While exploring the Documents folder, we found a file named “My todo list.pdf”, which contained a list of tasks. One of the entries mentioned:

Hint that state the current windows password is weak

This line suggested that the current Windows password might still be weak or unchanged, which could become useful later.

According to the challenge description, the user was last seen spending time on Google Chrome. So from there, we moved on to analyzing Chrome’s browsing history to look for more evidence of user activity.

C:\Users\xxx\AppData\Local\Google\Chrome\User Data\Default\History

With sqllite viewer, we can check the history in the url table and also see that the user accessed discord from chrome browser.

discord in chrome history database

To recover messages on discord accessed with a browser, we can try analyzing the cache of chrome and parsing it with chromecacheview.

C:\Users\xxx\AppData\Local\Google\Chrome\User Data\Default\History\Cache\Cache_Data

discord message in chromecacheview

There are 2 discord chats that lead us to analyze the zoom chat artifact which is the main point of this challenge.

parsed discord chat message

Zoom Team Chat Artifact Discovery and Analysis

After following the trail from Chrome and Discord, we turned our attention to Zoom, suspecting that important evidence might be stored there. Specifically, we were looking for traces of Zoom Team Chat, which could reveal user communications and shared files. Zoom stores its application data under:

C:\Users\xxx\AppData\Roaming\Zoom\data\

Inside this data folder, we found two important files:

  • Main database directly under the data folder, used to store general Zoom account and session information (zoomus.enc.db).
  • User specific database inside a subfolder named with the user's XMPP JID, which contains the Zoom Team Chat data (zoomus.async.enksdb).

C:\Users\xxx\AppData\Roaming\Zoom\data\<XMPP JID>\

Here’s where it gets interesting:

  • Both databases are encrypted using SQLCipher with custom parameters, page size 1024 and KDF iterations set to 4000.
  • Zoom uses different keys to encrypt each one.
  • The user_key needed to decrypt the user specific database can only be derived after obtaining the main_key linked to the main database in the data folder.

This layered key setup makes analyzing Zoom Team Chat data more complex than typical app data.

Finding the main_key

In the Zoom data folder, there’s a file named zoom.us.ini that contains the key to decrypt the main database. But this key is encrypted with DPAPI.

The key is stored as a base64-encoded string under the variable name win_osencrypt_key, and it starts with the marker ZWOSKEY. To extract the actual encrypted key, it’s necessary to parse the value of win_osencrypt_key and strip the ZWOSKEY prefix, leaving only the base64-encoded DPAPI blob.

Zoom.us.ini file

Noticing a reference to a weak Windows password in the PDF, cracking it became the next step. The encrypted master key needed for DPAPI decryption is stored in:

C:\Users\xxx\AppData\Roaming\Microsoft\Protect\<SID>\

Using dpapimk2john, the master key was converted to a hash and cracked with John the Ripper and the rockyou wordlist.

DPAPImk2john --sid="S-1-5-21-676146416-2632849227-3912224545-1000" --masterkey="883366a6-1eea-45de-b0b4-37c38ada44f6" --context="local" > hash.txt
john hash.txt --wordlist=/usr/share/wordlists/rockyou.txt
Now we know the windows local password is chizuru

After cracking the Windows local password, the next step is to decrypt the DPAPI-encrypted master key. This can be done using Mimikatz, which allows us to recover the master key needed to decrypt DPAPI-protected data. Once the master key is decrypted, it can be used to decrypt the win_osencrypt_key value extracted from zoom.us.ini.

dpapi::masterkey /in:dbb54711-8c3e-4a0a-b585-cfae51bbe54d /sid:S-1-5-21-676146416-2632849227-3912224545-1000 /password:chizuru /protected
dpapi::blob /masterkey:a77bac8f85212e3e1bdcc7f9bcb97776ca5d4458aaa4b498664abfa7b4c3ca967931949074118ffde80f31e69623b270457029c988fc8e8cdb44819376130085 /in:"keyblob" /out:keyblob.txt
L4jYqZnRF/ZrwJuMcVvPOFqklFzqtMPj554VF82B9g0= is the main_key

Decrypting main database

Although the goal is to obtain the key to decrypt the user specific database, decrypting the main database isn’t required. However, to solve the challenge, there is one important piece of information inside the main database which is the email address used for the Zoom account (If you want to know all tables and fields, you can check this link).
The email is stored in the zoom_user_account_enc table, under the uid column.

kevmann7@bookwormsboutiques.com is the email used

All other fields in that table are encrypted. Decrypting those fields is not necessary to solve the challenge, but it is possible. If you want to decrypt other fields such as uname or zoom_uid, you can use the script provided below:

from Crypto.Cipher import AES
from Crypto.Hash import SHA256
from base64 import b64decode

main_key = ""
key = SHA256.new(main_key).digest() # Derive AES key from main_key

raw = b64decode("encrypted_field_value")

iv, tag, data = raw[1:13], raw[-16:], raw[19:-16] # Extract IV, authentication tag, and ciphertext

plaintext = AES.new(key, AES.MODE_GCM, iv).decrypt_and_verify(data, tag) # Decrypt and verify

print(plaintext.decode('utf-8'))

Decrypting user specific database

To decrypt the user-specific database, you need the user’s Zoom credentials both email and password — or an active user session tied to the Zoom account. Unfortunately, this is a major limitation when analyzing Zoom Team Chat artifacts. Unlike other apps that store everything locally, Zoom does not store all the required keys on disk. Instead, it relies on a key called kwk (Key Wrapping Key), which is:

  • Unique for each user.
  • Stored securely on Zoom’s server, not saved in any local file.

To obtain the kwk, Zoom requests it dynamically during login or session refresh. To obtain the kwk, Zoom requests it dynamically during login or session refresh. Session refresh happens when Zoom re-establishes its session with the server — for example, when the app is reopened while the user is still logged in but hasn’t entered credentials again.

This means capturing kwk requires monitoring the Zoom application at runtime, while it’s actively communicating with Zoom servers. For this purpose, RhobitoB API monitoring can be used to intercept and log API calls made by Windows applications, including Zoom. This allows capturing the moment kwk is fetched from the server and extracting it for later use in decrypting the user-specific database.

How user_key is Derived

Once both main_key and kwk are available, Zoom performs the following steps to derive the user_key used to decrypt the user specific database:

  1. Take the first 42 bytes of the main_key, then calculate its SHA256 hash.
  2. Calculate SHA256 hash of kwk.
  3. Concatenate both SHA256 hashes (as hex strings), then convert the concatenated string from hex to bytes.
  4. SHA256 hash the resulting byte data.
  5. Base64 encode the final SHA256 hash

Recap on This Challenge’s Case

In this challenge, we already obtained:

  • The Zoom email address from the zoom_user_account_enc table in the main database.
  • The Zoom password, which was found in Discord chat logs, described as a combination of the Windows local password plus _Arkavidia_1337!!!.

So, for this specific scenario, we had everything needed to proceed — except for the kwk.

Capturing kwk

To capture kwk, Zoom’s external DLL responsible for cryptographic operations must be monitored. Zoom uses libcrypto-3-zm.dll to handle SHA256 calculations.The simplest way is to hook the SHA256 API and inspect the data passed to it. This DLL is located at:

C:\Users\xxx\AppData\Roaming\Zoom\bin_00\libcrypto-3-zm.dll

nB9oO3Kg8XA+gzd6O+k8YMq+iGCpDmHAe9m0iqtJY3w= is the kwk key

Profit

With all the required elements — main_key and kwk — collected, we can now derive the user_key and decrypt the Team Chat database. The following Python script calculates the user_key:

import hashlib, base64

main_key = b'L4jYqZnRF/ZrwJuMcVvPOFqklFzqtMPj554VF82B9g' # First 42 bytes of main_key
kwk = b'nB9oO3Kg8XA+gzd6O+k8YMq+iGCpDmHAe9m0iqtJY3w='

h1 = hashlib.sha256(main_key).hexdigest()
h2 = hashlib.sha256(kwk).hexdigest()
final = hashlib.sha256(bytes.fromhex(h1 + h2)).digest()
print(base64.b64encode(final).decode())

Once we have the user_key, the Zoom Team Chat database can be decrypted, and here is a sample of the recovered chat data (If you want to know all tables and fields, you can check this link):

Example of decrypted Zoom Team Chat messages: sql cipher raw database entries (top) and parsed conversation output (bottom).

Conclusion

Analyzing Zoom Team Chat artifacts is not straightforward — it requires both local keys and the server-side kwk, which makes full decryption challenging. In this case, we managed to recover all required data by combining forensic analysis and API monitoring. Note that this article focused on Team Chat artifacts — other encrypted databases, meeting records, call logs, and local configurations are also part of Zoom’s ecosystem but were not covered here.

Thank you for reading, and I hope this write-up was useful. Feel free to share any thoughts or feedback.

Reference

Sign up to discover human stories that deepen your understanding of the world.

Free

Distraction-free reading. No ads.

Organize your knowledge with lists and highlights.

Tell your story. Find your audience.

Membership

Read member-only stories

Support writers you read most

Earn money for your writing

Listen to audio narrations

Read offline with the Medium app

--

--

Published in InfoSec Write-ups

A collection of write-ups from the best hackers in the world on topics ranging from bug bounties and CTFs to vulnhub machines, hardware challenges and real life encounters. Subscribe to our weekly newsletter for the coolest infosec updates: https://weekly.infosecwriteups.com/

No responses yet

Write a response