-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathpayload_decrypter.py
More file actions
143 lines (107 loc) · 4.89 KB
/
payload_decrypter.py
File metadata and controls
143 lines (107 loc) · 4.89 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
from cryptography.hazmat.backends import default_backend
from cryptography.hazmat.primitives.ciphers import Cipher, algorithms, modes
import base64
from hashlib import pbkdf2_hmac
# Fixed IVs used by Bubble.io (obtained through JS debugging)
FIXED_IV_Y = 'po9'
FIXED_IV_X = 'fl1'
def decrypt_aes_cbc(ciphertext, key, iv):
"""Decrypt data using AES-CBC mode"""
cipher = Cipher(algorithms.AES(key), modes.CBC(iv), backend=default_backend())
decryptor = cipher.decryptor()
return decryptor.update(ciphertext) + decryptor.finalize()
def unpad_pkcs7(data):
"""Remove PKCS7 padding from decrypted data"""
return data[:-data[-1]]
def decrypt_with_fixed_iv(appname, encrypted_b64, fixed_iv):
"""Decrypt x or y values using fixed IV
Args:
appname: Application name from X-Bubble-Appname header
encrypted_b64: Base64 encoded encrypted data
fixed_iv: Fixed IV string ('po9' for y, 'fl1' for x)
Returns:
Decrypted bytes (with PKCS7 padding removed)
"""
ciphertext = base64.b64decode(encrypted_b64)
# Derive key and IV using PBKDF2-MD5
derived_iv = pbkdf2_hmac('md5', fixed_iv.encode('utf-8'), appname.encode('utf-8'), 7, dklen=16)
derived_key = pbkdf2_hmac('md5', appname.encode('utf-8'), appname.encode('utf-8'), 7, dklen=32)
decrypted = decrypt_aes_cbc(ciphertext, derived_key, derived_iv)
# Remove PKCS7 padding
return unpad_pkcs7(decrypted)
def decrypt_payload(appname, timestamp, iv_bytes, encrypted_b64):
"""Decrypt main payload (z) using timestamp and IV
Args:
appname: Application name
timestamp: Decrypted timestamp string
iv_bytes: Decrypted IV bytes
encrypted_b64: Base64 encoded encrypted payload
Returns:
Decrypted payload bytes
"""
ciphertext = base64.b64decode(encrypted_b64)
# Derive key from appname + timestamp
key_material = f"{appname}{timestamp}".encode('utf-8').replace(b'\x01', b'')
derived_key = pbkdf2_hmac('md5', key_material, appname.encode('utf-8'), 7, dklen=32)
# Derive IV
derived_iv = pbkdf2_hmac('md5', iv_bytes, appname.encode('utf-8'), 7, dklen=16)
# Decrypt and remove padding
decrypted = decrypt_aes_cbc(ciphertext, derived_key, derived_iv)
return unpad_pkcs7(decrypted)
def decrypt_bubble_payload(appname, x_encrypted, y_encrypted, z_encrypted):
"""Main decryption function for Bubble.io payloads
Args:
appname: Application name from X-Bubble-Appname header
x_encrypted: Encrypted IV (base64)
y_encrypted: Encrypted timestamp (base64)
z_encrypted: Encrypted payload (base64)
Returns:
tuple: (timestamp, iv, decrypted_payload)
"""
# Step 1: Decrypt timestamp (y)
decoded_y_raw = decrypt_with_fixed_iv(appname, y_encrypted, FIXED_IV_Y)
decoded_y_str = decoded_y_raw.decode('utf-8')
# Remove suffix _1 if present (added during encryption)
if decoded_y_str.endswith('_1'):
decoded_y = decoded_y_str[:-2]
else:
# For backward compatibility with old data
decoded_y = decoded_y_str.replace('_1', '')
# Step 2: Decrypt IV (x)
decoded_x = decrypt_with_fixed_iv(appname, x_encrypted, FIXED_IV_X)
# Remove padding bytes if present (for backward compatibility)
# New encryption adds b'\x0e' at end, but after PKCS7 removal it should be clean
# Old data might have multiple padding bytes manually added
if b'\x0e' in decoded_x or b'\r' in decoded_x or b'\x0f' in decoded_x:
decoded_x = decoded_x.replace(b'\x0e', b'').replace(b'\r', b'').replace(b'\x0f', b'')
# Step 3: Decrypt payload (z)
decrypted_payload = decrypt_payload(appname, decoded_y, decoded_x, z_encrypted)
return decoded_y, decoded_x, decrypted_payload
if __name__ == "__main__":
# Input values
appname = input("Enter AppName (from X-Bubble-Appname header): ").strip()
if not appname:
print("Error: AppName is required!")
exit(1)
ciphertext_x = input("Enter encrypted IV (x): ").strip()
ciphertext_y = input("Enter encrypted timestamp (y): ").strip()
ciphertext_z = input("Enter encrypted payload (z): ").strip()
try:
# Decrypt
timestamp, iv, payload = decrypt_bubble_payload(appname, ciphertext_x, ciphertext_y, ciphertext_z)
# Display results
print("\n" + "=" * 80)
print("DECRYPTION RESULTS")
print("=" * 80)
print(f"Timestamp (y): {timestamp}")
print(f"IV (x): {iv.hex()}")
print("\nDecrypted Payload (z):")
print("-" * 80)
print(payload.decode('utf-8'))
print("=" * 80)
except Exception as e:
print(f"\nError during decryption: {e}")
print("\nPossible reasons:")
print(" - Incorrect AppName")
print(" - Corrupted encrypted data")
print(" - Invalid base64 encoding")