{
	"id": "75b8ef23-613f-4847-9b70-00f8e978100c",
	"created_at": "2026-04-06T00:13:53.169922Z",
	"updated_at": "2026-04-10T13:12:06.305771Z",
	"deleted_at": null,
	"sha1_hash": "4a7ea9604eab9e1454de8b777e296984616474b1",
	"title": "Tofsee – modular spambot",
	"llm_title": "",
	"authors": "",
	"file_creation_date": "0001-01-01T00:00:00Z",
	"file_modification_date": "0001-01-01T00:00:00Z",
	"file_size": 154739,
	"plain_text": "Tofsee – modular spambot\r\nArchived: 2026-04-05 16:21:15 UTC\r\nTofsee, also known as Gheg, is another botnet analyzed by CERT Polska. Its main job is to send\r\nspam, but it is able to do other tasks as well. It is possible thanks to the modular design of this\r\nmalware – it consists of the main binary (the one user downloads and infects with), which later\r\ndownloads several additional modules from the C2 server – they modify code by overwriting some\r\nof the called functions with their own. An example of some actions these modules perform is\r\nspreading by posting click-bait messages on Facebook and VKontakte (Russian social network).\r\nBot communicates with the botmaster using non-standard protocol built on top of TCP. The first\r\nmessage after establishing the connection is always sent by the server – the most important thing it\r\ncontains is a random 128-byte key used for encrypting further communication. It is therefore\r\nimpossible to decode the communication if one wasn’t listening right from its beginning.\r\nAt all times, bot keeps a list of resources (in the form of linked list) in memory. Just after bot starts,\r\nthe list is almost empty and contains only basic information, such as bot ID, but it is quickly filled\r\nby data received from the server in further messages. Resources can take different forms – for\r\nexample, it might be a list of mail subjects to be used in spam, but DLL libraries extending bot\r\ncapabilities are treated as named resources as well. Additionally, one of resources – work_srv –\r\ncontains a list of C2 IP addresses. It is one of the first messages sent by server and, interestingly,\r\nmay not contain itself – in this case, connection is soon terminated and a random server from the\r\nnewly received list is chosen as communication partner. This usually happens during connection to\r\none of C2s hardcoded in the binary – effectively, they act as “pointer” to real servers.\r\nAll sent emails are randomized – for this purpose, Tofsee uses a special script language (an example\r\nfile is in technical analysis section). Its body contains macros, which will be replaced randomly by\r\ncertain strings of characters during parsing – for example %RND_SMILE will be substituted by one\r\nof several emoticons. Thanks to this randomization, simpler spam filters might pass these messages\r\nthrough.\r\nTechnical analysis\r\nThe C2 IP address list is hardcoded in the binary in an encrypted form. The algorithm used for\r\nobfuscation is very simple – it XORs the message with the hardcoded key.\r\nhttps://www.cert.pl/en/news/single/tofsee-en/\r\nPage 1 of 13\n\nData decrypts to three IP+port pairs – at least in the analyzed sample, the port was equal to 443 for\r\nall of them. The probable reason is to conceal communication by using port dedicated for SSL\r\ntraffic.\r\nCommunication protocol\r\nAfter establishing TCP connection the first message is sent by the server. Its size is always 200\r\nbytes long (though not all bytes are used – the final ones seem to be reserved, perhaps for future\r\nexpansion of the protocol). This message is also obfuscated by simple bitwise operations:\r\ndef greetingXor(data):\r\ndec=\"\"\r\nhttps://www.cert.pl/en/news/single/tofsee-en/\r\nPage 2 of 13\n\nres=198\r\nfor c in data:\r\ndec+=chr((res^(32*ord(c)|(ord(c)\u003e\u003e3)))\u00260xFF)\r\nres=ord(c)^0xc6\r\nreturn dec, res\r\nDecrypted data form the following structure (we were not able to find the meaning of some of the\r\nfields):\r\nstruct greeting{\r\nuint8_t key[128];\r\nuint8_t unk1[16];\r\nuint32_t bot_IP;\r\nuint32_t srv_time;\r\nuint8_t unk2[48];\r\n};\r\nFrom this point on all traffic (both incoming and outgoing) is encrypted using the the 128-byte key\r\nreceived in the first message. The key is modified after every sent or received byte, so it is\r\nimpossible to decrypt the transmission without listening to it from the beginning. XORing is used in\r\nsuch a way, that a single function can both encrypt and decrypt messages:\r\ndef xorStream(data, key, main_key, it):\r\nres=\"\"\r\nfor c in data:\r\nkey[it%7]+=main_key[it%128]\r\nkey[it%7]\u0026=0xFF\r\nres+=chr(ord(c)^(key[it%7]))\r\nit+=1\r\nreturn res\r\nParameters:\r\nhttps://www.cert.pl/en/news/single/tofsee-en/\r\nPage 3 of 13\n\ndata – raw data\r\nkey – short, 7-byte key, initialized by “abcdefg” bytes before the first message\r\nmain_key – 128-byte key from the greeting message\r\nit – number of bytes sent/received till now\r\nAll messages (except the greeting) consist of header and payload. The header is represented by the\r\nfollowing structure:\r\nThe protocol supports data compression, but it is only used for bigger messages. Fields op, subop1\r\nand subop2 are certain constants defining message type. The binary contains code handling a large\r\nnumber of types, but in practice, only a fraction of them is used.\r\nPayload is sent after the header. Its exact structure and contents depend on message type – some of\r\nthem will be described in details below.\r\nThe first message sent by the bot has types {1,0,0} (op, subop1 and subop2, respectively) and is a\r\nquite big structure:\r\nstruct botdata{\r\nuint32_t flags_upd;\r\nuint64_t botID;\r\nuint32_t unk1;\r\nuint32_t net_type;\r\nuint32_t net_flags;\r\nuint32_t vm_flags;\r\nuint32_t unk2;\r\nuint32_t unk3;\r\nuint32_t lid_file_upd;\r\nuint32_t ticks;\r\nuint32_t tick_delta;\r\nuint32_t born_date;\r\nuint32_t IP;\r\nuint32_t unk4;\r\nuint32_t unk5;\r\nhttps://www.cert.pl/en/news/single/tofsee-en/\r\nPage 4 of 13\n\nuint8_t unk6;\r\nuint8_t OS;\r\nuint8_t unk[46];\r\n};\r\nSome of the field names (such as lid_file_upd) we got for free – we did not have to reverse them by\r\nanalyzing their usage, since bot saved them under those exact indices to internal data structure,\r\nmapping variable names to their contents.\r\nServer response can have different forms as well. The simplest one – op=0 – means an empty\r\nresponse (or end of transmission consisting of multiple messages). If op=2, the server sends us a\r\nnew resource – the message payload is in this case of the following structure:\r\nstruct resource{\r\nuint32_t type; // Small integer.\r\nchar name[16];\r\nuint32_t unk;\r\nuint32_t length;\r\nuint8_t contents[]; // Size=length.\r\n};\r\nUsually after connecting to C2 server hardcoded in the binary the first message (after greeting)\r\nreceived by the bot is a single resource named work_srv, which contains a list of a couple of IP\r\naddresses and ports (this time different than 443), on which true C2 servers are listening. The bot\r\nthen disconnects from the current server and, after a while, starts the communication over with one\r\nof the freshly obtained IPs.\r\nIf op=1, the message’s meaning depends on subop2 and, additionally, first four bytes of payload\r\n(which are apparently used as flags in this case). For example, if these conditions are met: op=1,\r\nsubop2\u00261=0, flags=4, the message is a C2 request for all resources the bot has. The bot’s response\r\nis then a concatenated list of resources in a form similar to the showed above, after which server\r\nsends tens or hundreds type 2 messages (containing resources) – resources, which bot does not have\r\nyet.\r\nResources\r\nEvery resource is identified by its type – a small integer (up to 40, but most of them are below 10)\r\nand a short name, such as “priority”. Some of the most interesting types include:\r\nhttps://www.cert.pl/en/news/single/tofsee-en/\r\nPage 5 of 13\n\nType 5\r\nContains plugin DLLs. Since they don’t have all of their symbols stripped, we could quickly guess\r\nplugins’ tasks. As of today, Tofsee downloads the following plugins:\r\nName of resource – number 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 spread1.dll 227ec327fe7544f04ce07023ebe816d5\r\n17 spread2.dll 90a7f97c02d5f15801f7449cdf35cd2d\r\n18 sys.dll 70dbbaba56a58775658d74cdddc56d05\r\n19 webb.dll 8a3d2ae32b894624b090ff7a36da2db4\r\n20 p2pR.dll e0061dce024cca457457d217c9905358\r\nJudging by these names, apart from spamming, Tofsee also has other functions, such as coordinated\r\nDDoS, or cryptocurrency mining (as it turns out, one of the resources being downloaded is a\r\nLitecoin miner).\r\nType 11\r\nContains periodically updated scripts in an atypical language, which are used to send spam.\r\nExample script:\r\nhttps://www.cert.pl/en/news/single/tofsee-en/\r\nPage 6 of 13\n\nFrom: \"%NAME\" \u003c%FROM_EMAIL\u003e\r\nTo: %TO_EMAIL\r\nSubject: %SUBJ\r\nDate: %DATE\r\nMIME-Version: 1.0\r\nContent-Type: multipart/mixed;\r\nboundary=\"%BOUNDARY1\"\r\n--%BOUNDARY1\r\nContent-Type: multipart/alternative;\r\nboundary=\"%BOUNDARY2\"\r\n--%BOUNDARY2\r\nContent-Type: text/plain;\r\ncharset=\"%CHARSET\"\r\nContent-Transfer-Encoding: quoted-printable\r\n{qp1-}%GI_SLAWIK{/qp}\r\n--%BOUNDARY2\r\nContent-Type: text/html;\r\ncharset=\"%CHARSET\"\r\nContent-Transfer-Encoding: quoted-printable\r\n{qp0+}%GI_SLAWIK{/qp}\r\n--%BOUNDARY2--\r\n--%BOUNDARY1\r\nContent-Type: application/zip;\r\nname=\"%ATTNAME1.zip\"\r\nhttps://www.cert.pl/en/news/single/tofsee-en/\r\nPage 7 of 13\n\nContent-Transfer-Encoding: base64\r\nContent-Disposition: attachment;\r\nfilename=\"%ATTNAME1.zip\"\r\n%JS_EXPLOIT\r\n--%BOUNDARY1--\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-\r\n4].%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\nW \"\"\"MAIL From:\u003c__M(%FROM_EMAIL)__\u003e\\r\\n\"\"\"\r\nR\r\nS mx_smtp_03.txt\r\nhttps://www.cert.pl/en/news/single/tofsee-en/\r\nPage 8 of 13\n\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\r\nL_NOEMAILS 0 __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\nhttps://www.cert.pl/en/news/single/tofsee-en/\r\nPage 9 of 13\n\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\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\nThe language is slightly similar to assembly – for example “J” as the first character in line means\r\njump, and “L” – defines label. Script contains macros, which are substituted into other text at\r\nruntime – for example %ATTNAME1.\r\nType 7\r\nContains general purpose macros. The name of these resources is the same as macro’s they describe,\r\nfor example %DATE_RAN_SUB (likely abbreviation of DATE RANDOM SUBJECT). The resource\r\ncontent is a newline-separated list of substitutions, for example:\r\nhttps://www.cert.pl/en/news/single/tofsee-en/\r\nPage 10 of 13\n\n%NAME posted something on your wall\r\nNewsletter from %NAME\r\n%NAME changed her status\r\nUser %NAME is available to chat\r\n%NAME answered your message\r\nNew message from %NAME\r\n%NAME requested to be your friends\r\nUser %NAME sent you a message\r\n%NAME likes your status\r\nDo you know %NAME?\r\n%NAME sent you invitation\r\nNew friendship request from %NAME\r\n%NAME is your friend now\r\nSince some of the variables need to contain literal newline character, several macros are hardcoded\r\nin binary for that very purpose, for example %SYS_N.\r\nType 8\r\nContains local macros. Since different email scripts might want to use macros with the same name,\r\nbut different content, some of the macros are local. The resource names are of NUM%VAR form, for\r\nexample 1819%TO_NAME, where 1819 is number of the script being the scope of macro\r\n%TO_NAME.\r\nVariable substitutions are recursive, as seen on aforementioned example of %DATE_RAN_SUB –\r\nmacros can contain other macros. The script language also allows for more complicated constructs,\r\nsuch as %RND_DIGIT[3], meaning three random digits (often used in color’s hexadecimal\r\ndescription), or %{%RND_DEXL}{ %RND_SMILE}{}, meaning a random choice between\r\n%RND_DEXL, %RND_SMILE and an empty string. As we can see the language is quite flexible.\r\nRest of the types contain only a handful of resources and are less interesting from our perspective,\r\nso we will skip their description in this article.\r\nHash of the analyzed binary and YARA rules matching this malware family will conclude this\r\nanalysis.\r\nhttps://www.cert.pl/en/news/single/tofsee-en/\r\nPage 11 of 13\n\nHash:\r\nae0d32e51f36ce6e6e8c5ccdc3d253a0 - analyzed sample (main binary, before unpacking)\r\nYARA rules:\r\nrule tofsee\r\n{\r\nmeta:\r\nauthor=\"akrasuski1\"\r\nstrings:\r\n$decryptStr = {32 55 14 88 10 8A D1 02 55 18 F6 D9 00 55 14}\r\n$xorGreet = {C1 EB 03 C0 E1 05 0A D9 32 DA 34 C6 88 1E}\r\n$xorCrypt = {F7 FB 8A 44 0A 04 30 06 FF 41 0C}\r\n$string_res1 = \"loader_id\"\r\n$string_res2 = \"born_date\"\r\n$string_res3 = \"work_srv\"\r\n$string_res4 = \"flags_upd\"\r\n$string_res5 = \"lid_file_upd\"\r\n$string_res6 = \"localcfg\"\r\n$string_var0 = \"%RND_NUM\"\r\n$string_var1 = \"%SYS_JR\"\r\n$string_var2 = \"%SYS_N\"\r\n$string_var3 = \"%SYS_RN\"\r\n$string_var4 = \"%RND_SPACE\"\r\n$string_var5 = \"%RND_DIGIT\"\r\n$string_var6 = \"%RND_HEX\"\r\n$string_var7 = \"%RND_hex\"\r\n$string_var8 = \"%RND_char\"\r\nhttps://www.cert.pl/en/news/single/tofsee-en/\r\nPage 12 of 13\n\n$string_var9 = \"%RND_CHAR\"\r\ncondition:\r\n(7 of ($string_var*) and 4 of ($string_res*))\r\nor\r\n(7 of ($string_var*) and 2 of ($decryptStr, $xorGreet, $xorCrypt))\r\nor\r\n(4 of ($string_res*) and 2 of ($decryptStr, $xorGreet, $xorCrypt))\r\n}\r\nSource: https://www.cert.pl/en/news/single/tofsee-en/\r\nhttps://www.cert.pl/en/news/single/tofsee-en/\r\nPage 13 of 13",
	"extraction_quality": 1,
	"language": "EN",
	"sources": [
		"Malpedia"
	],
	"origins": [
		"web"
	],
	"references": [
		"https://www.cert.pl/en/news/single/tofsee-en/"
	],
	"report_names": [
		"tofsee-en"
	],
	"threat_actors": [
		{
			"id": "f8dddd06-da24-4184-9e24-4c22bdd1cbbf",
			"created_at": "2023-01-06T13:46:38.626906Z",
			"updated_at": "2026-04-10T02:00:03.043681Z",
			"deleted_at": null,
			"main_name": "Tick",
			"aliases": [
				"G0060",
				"Stalker Taurus",
				"PLA Unit 61419",
				"Swirl Typhoon",
				"Nian",
				"BRONZE BUTLER",
				"REDBALDKNIGHT",
				"STALKER PANDA"
			],
			"source_name": "MISPGALAXY:Tick",
			"tools": [],
			"source_id": "MISPGALAXY",
			"reports": null
		},
		{
			"id": "54e55585-1025-49d2-9de8-90fc7a631f45",
			"created_at": "2025-08-07T02:03:24.563488Z",
			"updated_at": "2026-04-10T02:00:03.715427Z",
			"deleted_at": null,
			"main_name": "BRONZE BUTLER",
			"aliases": [
				"CTG-2006 ",
				"Daserf",
				"Stalker Panda ",
				"Swirl Typhoon ",
				"Tick "
			],
			"source_name": "Secureworks:BRONZE BUTLER",
			"tools": [
				"ABK",
				"BBK",
				"Casper",
				"DGet",
				"Daserf",
				"Datper",
				"Ghostdown",
				"Gofarer",
				"MSGet",
				"Mimikatz",
				"Netboy",
				"RarStar",
				"Screen Capture Tool",
				"ShadowPad",
				"ShadowPy",
				"T-SMB",
				"down_new",
				"gsecdump"
			],
			"source_id": "Secureworks",
			"reports": null
		},
		{
			"id": "d4e7cd9a-2290-4f89-a645-85b9a46d004b",
			"created_at": "2022-10-25T16:07:23.419513Z",
			"updated_at": "2026-04-10T02:00:04.591062Z",
			"deleted_at": null,
			"main_name": "Bronze Butler",
			"aliases": [
				"Bronze Butler",
				"CTG-2006",
				"G0060",
				"Operation ENDTRADE",
				"RedBaldNight",
				"Stalker Panda",
				"Stalker Taurus",
				"Swirl Typhoon",
				"TEMP.Tick",
				"Tick"
			],
			"source_name": "ETDA:Bronze Butler",
			"tools": [
				"8.t Dropper",
				"8.t RTF exploit builder",
				"8t_dropper",
				"9002 RAT",
				"AngryRebel",
				"Blogspot",
				"Daserf",
				"Datper",
				"Elirks",
				"Farfli",
				"Gh0st RAT",
				"Ghost RAT",
				"HOMEUNIX",
				"HidraQ",
				"HomamDownloader",
				"Homux",
				"Hydraq",
				"Lilith",
				"Lilith RAT",
				"McRAT",
				"MdmBot",
				"Mimikatz",
				"Minzen",
				"Moudour",
				"Muirim",
				"Mydoor",
				"Nioupale",
				"PCRat",
				"POISONPLUG.SHADOW",
				"Roarur",
				"RoyalRoad",
				"ShadowPad Winnti",
				"ShadowWali",
				"ShadowWalker",
				"SymonLoader",
				"WCE",
				"Wali",
				"Windows Credential Editor",
				"Windows Credentials Editor",
				"XShellGhost",
				"XXMM",
				"gsecdump",
				"rarstar"
			],
			"source_id": "ETDA",
			"reports": null
		}
	],
	"ts_created_at": 1775434433,
	"ts_updated_at": 1775826726,
	"ts_creation_date": 0,
	"ts_modification_date": 0,
	"files": {
		"pdf": "https://archive.orkl.eu/4a7ea9604eab9e1454de8b777e296984616474b1.pdf",
		"text": "https://archive.orkl.eu/4a7ea9604eab9e1454de8b777e296984616474b1.txt",
		"img": "https://archive.orkl.eu/4a7ea9604eab9e1454de8b777e296984616474b1.jpg"
	}
}