Summary
We observed a threat actor leveraging GitHub repositories to execute Braodo Stealer a Sophisticated Python based Stealer. The Author hosted all the necessary python packages to run the stealer within the GitHub repository. The infection layers included a Byte Order Marker (BOM)
, a type of obfuscator designed to make the victim believe it is a Chinese file. The BOM then renders the content in Chinese. Even Google translates the content into what appears to be a legitimate file containing seemingly random statements. The main difference we can see here is the Version 2.0 employs AES encryption followed by BOM & pyobfuscate obfuscation
method which makes the Researchers difficult to Analyze further
Infection Chain

Fig 1: Infection Killchain
Technical Analysis
GitHub Repository serving malicious files
As our automated threat Intelligence platform continuously crawls the internet, including GitHub Repositories, some of our entries show us suspicious files such as bat, python packages. These were present in a repository that belonged to the same GitHub User. This prompted us to dive into the repository and conduct an Investigation, which led to the discovery of the Braodo stealer being served from GitHub containing multi-stage obfuscation methods.

Fig 2: GitHub Page Inspection
Obfuscated Batch script
The initial Bat script contains Chinese strings that can be translated to normal English statements without any errors. This leads the victim to run the file without hesitation. But investigating further reveals that it employs a BOM (Byte Order Marker) obfuscation technique, which deceives text editors and other command-line tools to interpret the script as UTF-8. This tactic makes the script appear to be gibberish or some random statements in Chinese, effectively making it harder to analyse further.
Fig 3: Obfuscated Batch Script (BOM)
The system interprets the commands as gibberish as threat actor embedded “FF FE” in the beginning of the file, The above decoded content has been revealed by removing the bytes of “FF FE” from the beginning
Code
if content.startswith(b'\xff\xfe'):
content = content[2:]
Python script (Obfuscated)
Lib\prt.py
contains obfuscated code that employs the popular obfuscation method pyobfuscate
, which is available in open source. In addition to AES encryption, the decryption key was revealed within the obfuscated code itself. We used a de-obfuscation tool shared by pyobfuscate.com/pyd
by ‘pyobfuscate‘ and tweaked it slightly to print to the console. This revealed the AES encryption in place for hardcoded encrypted values from pyc and pye
with the key IlllIllllllllIlIllIIlIIIllIlIIlIlII
. We spent some time to extract the script manually and executed it by feeding the required fields. The final payload of the Braodo stealer was decrypted.
Fig 4: De-Obfuscation of Python Snippet
Code for Deobfuscation
import warnings
warnings.filterwarnings("ignore", category=DeprecationWarning)
class compile:
def __init__(self):
try:
__import__('builtins').? = __import__('builtins').exec.?[0]
except:
__import__('builtins').? = __import__('builtins').exec
for ? in dir(__import__('builtins').compile):
try:
__import__('builtins').?("self.{0} = __import__('builtins').compile.{0}".format(str(?)), {'self': self})
except AttributeError:
pass
self.? = [vars(__import__('builtins')).copy()['compile'], 0]
self.__dir__ = self.?[0].__dir__
try:
del __import__('builtins').?
except:
pass
return None
def __repr__(self):
return str(self.?[0])
def __call__(self, *args, **kwargs):
#print(eval(__import__('ast').unparse(args[0])[4:]))
print(__import__('ast').unparse(args[0]))
exit(0)
@property
def __dict__(self):
return self.?[0].__dict__
@property
def __class__(self):
return self.?[0].__class__
compile = compile()
__import__('builtins').compile = compile
file = open(input(">> input file path: "), 'rb').read()
print('>> source code: ')
exec(file)
Braodo Layer decoder
from Crypto.Cipher import AES
from Crypto.Random import get_random_bytes
from Crypto.Protocol.KDF import PBKDF2
from Crypto.Util.Padding import unpad
import hashlib
from base64 import b85decode as b85
#Key
httpspyobfuscatecom = "KEY"
#Main Braodo script
pyc = """Obfuscated Code"""
pye = """Obfuscated Code"""
try:
def d(b, p):
c = b85(b.encode('utf-8'))
r = AES.new(PBKDF2(p, c[:16], dkLen=32, count=1000000), AES.MODE_GCM, nonce=c[16:32])
return r.decrypt_and_verify(c[48:], c[32:48]).decode('utf-8')
fo = open("braodo.py", "w", encoding="utf-8")
fo.write(d(pyc + pye, httpspyobfuscatecom))
#print(d(pyc + pye, httpspyobfuscatecom))
except:
def a(i):
return unpad(AES.new(hashlib.sha256(str(list(pyobfuscate)[0][0] + list(pyobfuscate)[1][0][:-1]).encode()).digest()[:24], AES.MODE_CBC, i[:AES.block_size]).decrypt(i[AES.block_size:]), AES.block_size).decode()
print(a(pyobfuscate[1][2]))
Braodo Stealer (Python)
The de-obfuscated Python code, which is the core payload of Braodo stealer, reveals that it also drops a web browser extension. This extension is later used to collect cookie information and post it to the URL chinaischo.in/upload.php
, allowing the collected cookies to be handled separately.
Fig 5: Extension downloaded & Steals
Exfiltration
Below are the details it looks for and sent to Telegram bot by encrypting all the information into Base64.
- Computer Name
-
IP Information (using
ipinfo.io
) -
Browsers User data (Typical path:
browser_name\User Data\\
) - Facebook session & Other Facebook details
- Credit card details (All payment methods)
- logins.json & hostname
-
Passwords (
SELECT a11, a102 FROM nssPrivate WHERE a102 = ?;
) -
Login Data (
SELECT action_url, username_value, password_value FROM logins from login_db
) -
Cookies (
in the name of edge_Cookies_Fb_*, chrome_Cookies_Fb_*, brave_Cookies_Fb_*, Cookies_Fb_* from extension
)cookies.zip/background.js
-
Exfiltrate information from Cookies (
SELECT host_key, name, path, encrypted_value, expires_utc, is_secure, is_httponly FROM cookies
)
List of Browsers it looks for,
Chromium | Thorium | 7Star | Cent Browser |
Iridium | Vivaldi | Coowon | Epic Privacy Browser |
Catalina | Liebao | QIP | Comodo Dragon |
Orbitum | Sputnik | Brave Browser | Slimjet |
Yandex | Sogou | Discord | Speed360 |
All these information was archived and sent to Telegram Bot
and will be deleted from the victim machine immediately.
Fig 6: Data Exfiltration
Fig 7: Facebook cookie and other information
The archive will get deleted once the zipped file sent to Telegram Bot contains all the exfiltrated information.
Fig 8: Data sent to Telegram Bot & Deleted
Indicator of Compromise (IOCs)
# | Type/ Filename | IOCs |
---|---|---|
1 | zip | 801016eff72de82ecbb575793c45a9f0c9c830d0afc3282b31e55fa5f7736242 |
2 | Stage #1 BAT | 54cac2be9f051e300436c8cec8c6186182e551e50a95d77822f96869a37e6408 |
3 | Stage #1 BAT | cf138624ea870a821742b55d764da16a720ae9c0ace7cc00bc5ae85e66563d46 |
4 | Python | ea68356bf6e9c23ebe0ebf05a39f8bc5b8c27a9515c45aae0769e6905373e0df |
5 | Python (AES decrypted layer) | 5335158b14e4e5e980d397f6ca0ae5b7c8b4790da9e4d3d245f3e70674c87bc3 |
6 | Python (Braodo) | 6403092566f0ce88db552cd8fd5931c06eb8d173c09dd88a5b7d98734a9add3e |
7 | Python (Braodo) | ecd08093eae07e239b70d3d00b90c139173e548c3ec6e39462e93f4aef101de9 |
8 | Zip | 8d9f58762885b3befce4d0bf7103f9c3d2f3b0ed45cc4e500fe78614e60aef64 |
9 | Zip | 5256649361bd2f5be074f5fccfd937e89b4ee946b3aafb0cc5fb146b2a4a63c4 |
10 | Zip | 7ba5790ff595c852fa45c02fcf40f8118c6584e7382e2bed1357e9efedcb2866 |
GitHub Pages
- github[.]com/bvit17
- github[.]com/KevinDark5
- github[.]com/abarekl1
- github[.]com/eed8989
- github[.]com/eggege342358
Telegram BOTS
- 7686322208:AAEqS0m2oyvfjVi6gZg3MeY_KouflxGZcok
- 7520995374:AAHV5sS_YzF3rpMs6aKTnl2ErTX0DxANoqw
Domain & C2C
- chinaischo.in/upload.php
- nonever.net/uploads
You be the first comment