Ivy Fan-Chiang - Reversing Synasploit.exe
  • Home
  • About
  • Projects
  • Blog
  • Misc
  • Contact
  • Reversing Synasploit.exe


    Posted 2021/06/28

    A few months ago an unknown user joined our school’s cubing club’s Discord server and dropped a piece of malware in one of the text channels. The user was quickly banned but I downloaded a copy of the malware for future analysis (VirusTotal). This was my first dive into malware analysis and reverse engineering as I have always focused on forensics and some cryptography in CTFs.

    Basic Analysis

    Looking through strings of the file I found many references to Python so I thought this executable may have been created by PyInstaller.

    image-20210626104239710

    Running pyinstxtractor extracted .pyc files from the executable and .pyd files containing the Python modules the program used. With many of the other .pyc files being standard modules it became clear that CloudBot.pyc contained the compiled Python bytecode for the malware.

    image-20210626105400636

    Reversing the Bytecode

    I have decompiled a few .pyc files in the past using the uncompyle6 decompiler but running file on CloudBot.pyc revealed that it was compiled using Python 3.9 which uncompyle6 does not support currently.

    image-20210626105318342

    I tried using dis to disassemble the bytecode but was met with an IndexError from an invalid opcode.

    image-20210628111320107

    I switched to using Decompyle++‘s disassembler (I have since switched to xdis which has better formatting) which gave me the full bytecode for the program and functions. With no available decompilers I translated the bytecode to equivalent Python source code.

     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
    import os
    if os != 'nt':
        exit()
    
    from re import findall
    from json import loads, dumps
    from base64 import b64decode
    from subprocess import Popen, PIPE
    from urllib.request import Request, urlopen
    from datetime import datetime
    from threading import Thread
    from time import sleep
    from sys import argv
    
    LOCAL = os.getenv('LOCALAPPDATA')
    ROAMING = os.getenv('APPDATA')
    PATHS = {
        'Discord':ROAMING+'\\Discord',
        'Discord Canary':ROAMING+'\\discordptb',
        'Discord PTB':ROAMING+'\\discordptb',
        'Google Chrome':LOCAL+'\\Google\\Chrome\\User Data\\Default',
        'Opera':ROAMING+'\\Opera Software\\Opera Stable',
        'Brave':LOCAL+'\\BraveSoftware\\Brave-Browser\\User Data\\Default',
        'Yandex':LOCAL+'\\Yandex\\YandexBrowser\\User Data\\Default'
    }
    
    def getheaders(token, content_type=(None, 'application/json')):
    
    def getuserdata(token):
    
    def gettokens(path):
    
    def getdeveloper():
    
    def getip():
    
    def getavatar(uid, aid):
    
    def gethwid():
    
    def getchat(token, uid):
    
    def has_payment_methods(token):
    
    def main():
    
    try:
        main()
    except Exception as e:
        print(e)
        exit()
    

    The bytecode for the program was pretty simple to reverse but the bulk of the program lies in the main() function. Things to note from this code is that the malware only runs on Windows and it targets the storage locations of Discord, Chrome, Opera, Brave, and Yandex browsers. Not all the translated code will be included in this post, I do not wish to share functional malware code on this site, just a breakdown on how scrapers like these work

    getheaders()

    1
    2
    3
    4
    5
    6
    7
    8
    def getheaders(token, content_type=(None, 'application/json')):
        headers = {
            'Content-Type': content_type,
            'User-Agent': 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.11 (KHTML, like Gecko) Chrome/23.0.1271.64 Safari/537.11'
        }
        if token:
            headers.update({'Authorization': token})
        return headers
    

    Simple method that generates headers for the malware’s API requests

    getuserdata()

    Retrieves the username, user ID, avatar, email, and phone number

    gettokens()

    Finds Discord authentication tokens from the local storage of browsers and Discord client

    getdeveloper()

    Gets the author of the program who is wodx. Tries to retrieve more information about the author from a pastebin that was taken down

    getip()

    Gets the IP address of the device

    getavatar()

    Finds the avatar URL

    gethwid()

    Calls wmic csproduct get uuid to get the HWID

    getfriends()

    Gets a list of all of the infected user’s friends

    getchat()

    Gets a list of all channels the infected user is in

    has_payment_methods()

    Finds if there are payment methods associated with the infected account

    send_message()

    Function to send messages using the Discord API

    spread()

    Sends a copy of the malware to all of the infected user’s Discord friends

    main()

    This function contains the bulk of the program. The function starts by getting the target IP, Windows username, and hostname. It then proceeds to look through the local storage of all the browsers mentioned above looking for discord tokens using the gettokens() function. If a valid token is found then it finds information about that user using the getuserdata(), getavatar(), and has_payment_methods() functions. This data is then sent in an embed to a hardcoded Discord webhook address. If the constant self_spread is set to True then the malware also runs the spread() method.

    Conclusions

    From this analysis I learnt how to reverse Python bytecode and executables. The spread of Discord token scrapers like this program is concerning especially since the source code of many of these pieces of malware can be found on GitHub for script kiddies to use. Steven also managed to find a repo with a variant using the same webhook address as the executable that I analysed. I think this goes without saying but don’t run suspicious executables that get sent over messages.