Skip to content

Instantly share code, notes, and snippets.

@Reelix
Created July 16, 2025 18:27
Show Gist options
  • Save Reelix/d47762822b65f5a4518dcd1fd0c80aef to your computer and use it in GitHub Desktop.
Save Reelix/d47762822b65f5a4518dcd1fd0c80aef to your computer and use it in GitHub Desktop.
RoundCube Session Password Decryptor
#!/usr/bin/env python3
# Thanks Gemini!
import re
import base64
# The 'cryptography' library is required to run this code.
# You can install it in your local Python environment with:
# pip install cryptography
from cryptography.hazmat.primitives.ciphers import Cipher, algorithms, modes
from cryptography.hazmat.backends import default_backend
def unpad_pkcs7(data):
"""Removes PKCS#7 padding from a byte string."""
if not data:
return data
padding_len = data[-1]
if padding_len > len(data):
return data
return data[:-padding_len]
def decrypt_roundcube_session_password(session_data, des_key):
"""
Decrypts the user password stored in a RoundCube session using 3DES.
Args:
session_data: The serialized PHP session string.
des_key: The value of $config['des_key'] from RoundCube's config.
Returns:
The decrypted plaintext password, or an error message.
"""
# 1. Extract the encrypted password from the session string
match = re.search(r'password\|s:32:"([^"]+)"', session_data)
if not match:
return "Error: Encrypted password not found in session data."
encrypted_password_b64 = match.group(1)
try:
# 2. Base64 decode the data
encrypted_data = base64.b64decode(encrypted_password_b64)
# 3. The first 8 bytes are the IV, the rest is the ciphertext, as per RoundCube's method
iv = encrypted_data[:8]
ciphertext = encrypted_data[8:]
# 4. Set up the 3DES CBC cipher. The key must be 24 bytes.
cipher = Cipher(
algorithms.TripleDES(des_key.encode('utf-8')),
mode=modes.CBC(iv),
backend=default_backend()
)
decryptor = cipher.decryptor()
# 5. Decrypt and remove PKCS#7 padding
decrypted_padded = decryptor.update(ciphertext) + decryptor.finalize()
plaintext = unpad_pkcs7(decrypted_padded)
return plaintext.decode('utf-8')
except ImportError:
return "Error: The 'cryptography' library is not installed. Please run 'pip install cryptography'."
except Exception as e:
return f"An error occurred during decryption: {e}"
def main():
"""
Main function to run the decryption process.
"""
# session_data_string: The serialized PHP session string. (From sessions in Database)
session_data_string = r'language|s:5:"en_US";imap_namespace|a:4:{s:8:....."maxuid";i:3;}}list_mod_seq|s:2:"10";'
# des_key: The value of $config['des_key'] from RoundCube's config.
des_key = 'rcconfig-Pass123'
username_match = re.search(r'username\|s:\d+:"([^"]+)"', session_data_string)
username = username_match.group(1) if username_match else "Unknown"
decrypted_password = decrypt_roundcube_session_password(session_data_string, des_key)
print("--- RoundCube Session Password Decryptor ---")
print(f"Username: {username}")
print(f"Decrypted Password: {decrypted_password}")
if __name__ == '__main__':
main()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment