{
	"id": "490eaebb-8ab6-40ec-96fc-570fcbaedab5",
	"created_at": "2026-04-10T03:19:55.511128Z",
	"updated_at": "2026-04-10T13:11:53.383611Z",
	"deleted_at": null,
	"sha1_hash": "26f5213bbc6976551117eb1b6ba0941c1b17dbc9",
	"title": "Uncovering Tetris – a Full Surveillance Kit Running in your Browser",
	"llm_title": "",
	"authors": "",
	"file_creation_date": "0001-01-01T00:00:00Z",
	"file_modification_date": "0001-01-01T00:00:00Z",
	"file_size": 1517569,
	"plain_text": "Uncovering Tetris – a Full Surveillance Kit Running in your\r\nBrowser\r\nPublished: 2021-08-12 · Archived: 2026-04-10 02:20:07 UTC\r\nExecutive Summary\r\nA Chinese state sponsored threat actor is targeting Chinese-speaking opposition through waterholed\r\nwebsites.\r\nThe Campaign uses a modular and custom JS surveillance framework, dubbed “Tetris”, implementing a\r\nwide range of browser feature.\r\nAlmost all of Tetris’ components have zero AV detections.\r\nTetris exploits vulnerabilities is 58 widely used websites, including Aliexpress, Baidu, QQ and Tmall.\r\nThree different waterholed websites have been found, there are indications to at least 5 more.\r\nIntroduction\r\nThis report is based on exemplary work by @felixaime, who found 2 waterholed websites which triggered all this\r\nresearch.\r\nAs of the time of this writing, all the components of the framework are undetected by AV, except a 2nd stage\r\ndetected by “Ikarus”. This report includes several detection and prevention ideas and indicators, for the web users\r\nand for developers.\r\nUpdate 22/08/21 – Added 3rd wateholed site, additional web users mitigations.\r\nTetris Attack Chain\r\nhttps://imp0rtp3.wordpress.com/2021/08/12/tetris/\r\nPage 1 of 20\n\nWaterholed sites\r\nFelix has found two sites containing links to the malicious domain googledrivers[.]com. The sites both appear to\r\nbe independent newsblogs. Both are focused on China, one site on its actions against Taiwan and Hong-Kong\r\nwritten in Chinese and still updated and the other about general atrocities done by the Chinese government,\r\nwritten in Swedish and last updated 2016.\r\nUpdate 22/08/21 – @k3yp0d Found a third waterholed site, the site is the Chinese language subdomain of an\r\norganization doing artificial intelligence research and consultation but also reports on Chinese aggressive actions,\r\ne.g. indirect support to the Taliban. Interestingly, the English-language site was not infected, although it appears to\r\nbe hosted on the same WordPress instance.\r\n1st site waterhole link  \r\n2nd site waterhole script\r\nAs seen in the code snippets, the waterhole is embedded differently in each site. Moreover, while the first site has\r\nevery page infected with the script, The second has the waterhole only on its homepage. I believe this difference\r\nhttps://imp0rtp3.wordpress.com/2021/08/12/tetris/\r\nPage 2 of 20\n\nstems from the first site being managed by WordPress and thus enabling the attackers to inject their script tag in\r\nthe default heading.\r\n301 redirection response to /s/02Bl\r\nBoth links redirect to a second path in the same domain (Status 301 redirection). The path is the same except the\r\nvalue of ‘ver’ GET argument, which I later discovered is called Project ID by the Tetris developers.\r\nJetriz\r\nJetriz is a Javascript script which has undergone massive obfuscation. After deobfuscation(see Appendix D), it\r\nturns out most of the script is an obfuscated version of the known JS frameworks “fetch.js” and “core.js”. Each\r\ntime the script is requested from the server a different uid variable is set for it, so there is no common hash.\r\nUpdate 13/08/21 – Arkbird introduced me to a public obfuscation framework named plainly “Javascript\r\nobfuscator” available here. The framework has different options which allow the attacker to choose the\r\nsophistication of the obfuscated script. It is highly likely this framework was used to obfuscate the Tetris scripts .\r\nThe custom functions of the script are simple:\r\n1. Anti-debugging (the script detects if the developer tools sidebar is opened).\r\n2. Basic browser information extraction.\r\n3. Sending of the browser information, the current time and the sid back to the server.\r\n1\r\n2\r\n3\r\n4\r\n{\r\ndevice: \"PC\" ,\r\nlanguage: \"zh_CN\" ,\r\nengine: \"Blink\" ,\r\nhttps://imp0rtp3.wordpress.com/2021/08/12/tetris/\r\nPage 3 of 20\n\n5\r\n6\r\n7\r\n8\r\n9\r\nbrowser: \"Chrome\" ,\r\nos: \"Windows\" ,\r\nosVersion: \"10.0\" ,\r\nversion: \"91.0.4472.124\"\r\n}\r\nJetriz before deobfuscation, not much fun to read:(\r\nThe response to the request depends on whether the browsers’ language is Chinese. If it’s not then “\u003ch1\u003eNot\r\nFound\u003c/h1\u003e” is returned. If it is Chinese then the server responses with Swid.\r\nSwid\r\nOn First sight, Swid looks exactly like Jetriz – same obfuscation, similar size and it even shared functionality. A\r\ncloser look reveals that although it shares the anti-debug and redirection functions of Jetriz, its main logic is\r\ndifferent. Moreover, it depends on environment variables set in Jetriz – the browser information object and the\r\nprojId. Interestingly, the sid is no longer regarded.\r\nThe Script has two main functions:\r\n1. Injecting itself to any new page opened\r\n2. Loading, managing and running plugins\r\nLink Hijacker\r\nThe mechanism used by the script is pretty simple: it registers a callback for every link of the same domain\r\nclicked. Once a user clicks a link the callback neutralizes the original browser event that should have occurred\r\n(redirecting the user to a new path) and instead performs the same mechanism itself. Before loading the next page,\r\nhttps://imp0rtp3.wordpress.com/2021/08/12/tetris/\r\nPage 4 of 20\n\nit appends to it a \u003cscript\u003e tag with Jetriz’s url as source. That way, as long as the user stays in the same website,\r\nthe attacker can run its code.\r\nLink hijacking mechanism\r\nOf course, if it were up to the attackers, they would have hijacked all links, and not just links to the same website.\r\nUnfortunately for them, CORS prevents that. Cross-Origin Resource Sharing is a mechanism implemented in\r\nevery browser and enables servers to decide which (if any) other domains can access their content. This way, the\r\nattacker cannot implant a script in a web page in which he wasn’t given access to.\r\nPlugin Manager\r\nSwid contains a quite impressive plugin manager, built in a modular way and even giving an API for the plugins to\r\nuse. Although very easy to implement, the manager can’t run the plugins periodically, and they only run once.\r\ncommunications\r\nThe plugin manager initiates a websocket connection to the server using the public socket.io framework ver. 2.2.0.\r\nThe client also uses a specific namespace in the socket named “/zSocket”. The websocket connection is based on\r\nthe current http(s) connection – so a long as the http connection to the server is encrypted so is the websocket.\r\nOnce connected, the client sends every 5 seconds a “heartbeat” message, which contains the projId and the\r\nbrowser information collected by Jetriz. Because websockets are asynchronous the client doesn’t have to wait for\r\nany response and can send a message while still handling the other.\r\nPlugin Loading\r\nThe main client message callback is “task”. A “task” message contains a plugin that the plugin manager should\r\nrun. Each task contains:\r\npluginId – 24 characters long hex string\r\ndata – javascript code of the plugin\r\npluginType – always 0\r\nhttps://imp0rtp3.wordpress.com/2021/08/12/tetris/\r\nPage 5 of 20\n\nrun – always empty\r\nInterestingly, “data” is run immediately when getting a new task. it does not run the plugin itself but rather returns\r\na function which is called to run the plugin. The function is called with 3 parameters – The plugin managers’\r\ncontext, the “run” argument and a dictionary containing the pluginId and pluginType.\r\n“task” message parsing and running\r\nPlugin API\r\nThe plugin managers create a dictionary of 29 functions to be used by the plugins easily by referencing the plugin\r\nmanagers’ context. Many of the functions are not used by any of the plugins I found. Please See Appendix C for\r\nthe complete function list.\r\nMoreover, the manager enables the different plugins to use a unified way to send information back to the server.\r\nBy calling the “callback” function the plugins can send back the data they collected to the server. The callback\r\nmessage contains 6 fields:\r\n1. userSocketId (internal ID of socket.io, doesn’t work in version 2.2.0)\r\n2. data – response data\r\n3. msg – always empty\r\n4. status – always true\r\n5. type – type of data, “string” (for json) or “object”\r\n6. save – always true\r\nPlugins\r\nOnce the server gets the first heartbeat, it sends between 11 to 15 different plugins at once.\r\nThe plugins are generally much lighter obfuscated but the degree of obfuscation varies. All plugin have the same\r\nclass creation mechanism. This plugin class has always at least 2 functions: “run” which runs the main logic of the\r\nplugin and “callback” or “report” which, well, report back to the server. The numbering of the plugins was done\r\nby me randomly, and doesn’t have to do with the order of arrival (which wasn’t consistent since the protocol is\r\nasynchronous).\r\nPlugins 0-7\r\nThese plugins use a known but not a widely used technique called JSONP-hijacking. The technique enables\r\nexfiltrating the logged-in user account information from vulnerable sites. While it doesn’t give the attacker a\r\npassword or any authentication token, it enables him to identify the victims and to assess his interest in them.\r\nhttps://imp0rtp3.wordpress.com/2021/08/12/tetris/\r\nPage 6 of 20\n\nThe Implementation is quite easy – the attacker needs to load the relevant JSONP address as a script\r\n($.getScript()) and to set the name of the callback function inside the url of the JSONP. The callback function will\r\nbe called once the JSONP is loaded and will get as argument the user data.\r\nPlugin 0 gathers information from 58 different sites. 57 of those sites are very popular Chinese sites, like qq and\r\nbaidu. There are approximately 30 different attributes the attacker tries to exfiltrate, which differ from site to site.\r\nThe common attributes are userid, real name and phone number. A complete list of the sites and attributes is\r\navailable in APPENDIX C.\r\nNYT JSONP callback function\r\nA site that stands out is the New York Times. The JSONP vulnerability look like it enables the attacker to get the\r\nuser id and the name of the logged-in reader.\r\nUpdate 16/08/21 – After though examination by the NYT security team it turns out the name of the user cannot\r\nbe accessed via this request, but solely its uid and subscriptions.\r\nPlugins 1-7 are used to exfiltrate user data specifically from one specific website each, using the same technique.\r\nWhile all the domains in those plugins appear and are already queried in plugin 0, the plugins use more\r\ncomplicated techniques and site-specific vulnerabilities to access more comprehensive user data.\r\nThe sites queried by the plugins are:\r\nP1 – 163.com basic user info query\r\nP2 – employer.58.com – get “enterpriseinfo“\r\nP3 – jd.com JSONP request embedded in iframe\r\nP4 – sohu.com JSONP request embedded in iframe\r\nP5 – hupu.com JSONP request embedded in iframe\r\nP6 – qq.com – JSONP exploiting music access API of qq that leaks comprehensive user data.\r\nP7 – baidu.com – complicated JSONP request utilizing a vulnerability enabling the attacker to run code in\r\nthe context of the iframe. The plugin had also additional obfuscation (possibly because it used a newer\r\nversion of the obfuscator).\r\nPlugin 8\r\nhttps://imp0rtp3.wordpress.com/2021/08/12/tetris/\r\nPage 7 of 20\n\nThe plugin collects geolocation data. The collection happens through regular browser query, so the accuracy can\r\nvary depending on the type of network access and whether the device has GPS. The browser gives some value\r\nrepresenting accuracy.\r\nIt is worth noting that this plugin would cause the browser to request permission from the victim unless the\r\nvictim has granted the waterholed website that permission before.\r\nPlugin 9\r\nThe plugin gets the internal IP(s) of the victim through the use of WebRTC api.\r\nPlugin 10\r\nThe plugin attempts to take one photo of the victim using the webcam of the device, if present. Similarly to plugin\r\n8, this could make the browser request permission from the victim.\r\nPlugin 11\r\nThe plugin uses the public javascript library fingerprint2. The result, excluding pixel ration, memory information\r\nand devices information is hashed and sent back to the server. Additionally, it loads icons of 11 Chinese security\r\nresearch sites, the purpose of that is unclear.\r\nPlugin 12\r\nThe plugin is used to capture anything the user types in the waterholed domain.\r\nThe plugin does that by registering a callback on any \u003cinput\u003e and \u003ctextarea\u003e tags in the document and reports\r\ntheir textual data back to the server.\r\nPlugin 13\r\nThe plugin  checks if the victim is using TOR by trying to access a favicon with an onion address. It is worth\r\nmentioning that on a victim not running TOR this could trigger a DNS request to an onion address (see detection).\r\nPlugin 14\r\nhttps://imp0rtp3.wordpress.com/2021/08/12/tetris/\r\nPage 8 of 20\n\nThe plugin tries to connect to websockets at localhost. If the connection succeeds all data transferred through the\r\nsocket is forwarded to the attackers’ server. This known but relatively new technique allows Tetris to exfiltrate\r\ndeveloper information and even API secrets. This article is an excellent explanation of the technique.\r\nThe Following table shows the ports tried by the plugin and their default use:\r\nPort Service\r\n3000 webpack-dev server, core component in React.js development\r\n3001 socket.io secure websocket common port\r\n7000 Used in eventlet examples, Default in RSocket – binary protocol able to run on WS\r\n8000 Used in many examples, likely to be used by several frameworks\r\n9856 reload (node module)\r\nPlugin 15\r\nThe plugin collects very comprehensive OS information, including battery status, ad blocker status, hardware\r\nconcurrency support and browser plugins. Additionally, it requests the localstorage for the current site.\r\nAdditional Attack chains\r\nDiscovery\r\nThe two links used in the waterholed sites originally found were very similar: /s/02Bl \u0026 /s/02Bn. This prompted\r\nme to try similar combinations. Through this basic approach I was able to find 7 additional redirection URIs\r\n(/s/02Bj was also found later in the 3rd waterholed site).\r\noriginal URI Redirected path\r\n/s/02Bi /public/jquery.min.js?ver=607fd694d0dfb600379f3bb9\r\n/s/02Bj /public/jquery.min.js?ver=6085111875349500318504f6\r\n/s/02Bk /public/x/jquery.min.js?ver=6085111875349500318504f6\r\n/s/02Bl /public/jquery.min.js?ver=60851543c3baea002ff24ff4\r\n/s/02Bm /public/x/jquery.min.js?ver=60851543c3baea002ff24ff4\r\n/s/02Bn /public/jquery.min.js?ver=60878220c25fbf0035f9876c\r\n/s/02Bo /public/x/jquery.min.js?ver=60878220c25fbf0035f9876c\r\n/s/02Bp public/jquery.min.js?ver=609351de045c15003a22361c\r\nhttps://imp0rtp3.wordpress.com/2021/08/12/tetris/\r\nPage 9 of 20\n\n/s/02Bq /public/x/jquery.min.js?ver=609351de045c15003a22361c\r\nIn bold – URIs used in the waterholed sites.\r\nAs you can see, the redirection links alternate between public/x/jquery and public/jquery, and keep the same\r\nprojId between them. while all the public/jquery links lead to exactly the same Jetriz script, the public/x/jquery\r\nlead to a different script, which I named Jineva.\r\nJineva\r\nJineva is a weird combination of Jetriz and Swid. Judging by its design, shared code and obfuscation it was\r\ndeveloped by the same team. It has 2 main differences:\r\n1. No link hijacking logic\r\n2. No dynamic Plugin manager, but rather a websocket client with 3 functions.\r\nWebsocket Client\r\nCommunications\r\nThe Client uses the same socket.io version as Swid. Unlike Swid, its namespace is “/sSocket“.\r\nThe connection request contains 4 parametrs: projId, baseurl (current URL base64 encoded), cookie\r\n(document.cookie), isRender (boolean argument, purpose unclear).\r\nOnce connected, the client sends a heartbeat containing the projId every 5 seconds (unlike Swid which also\r\nincludes device information and language).\r\nFunctionality\r\nThere are 3 functions the server can execute on the client :\r\n– processGET: performs a GET request to a url given by the server using the native JS Fetch call (or the fetchjs\r\npolyfill if the native is not available). The response is sent back to the server. The request to the url includes\r\ncredentials. in this way, the attacker can steal NTLM credentials, cookies and authorization headers of the victim.\r\n– processPOST: Same as processGET but sends a POST fetch request, with parameters set by the server.\r\n– setLS : Gets a dictionary from the server and sets Items in the locastorage according to it.\r\nAdditionally, without regards to server request, the client sends a copy of the localstorage of the current website\r\n(window.localStorage) every 5 seconds (independently of the heartbeat)\r\nWhy A Parallel attack chain?\r\nThere are several possible explanations for the use of different chains:\r\nhttps://imp0rtp3.wordpress.com/2021/08/12/tetris/\r\nPage 10 of 20\n\n1. Different Targets – Jineva is ideal for exfiltration of data from on-premise web servers and credential\r\nstealing, While Jetriz and Swid serve more for surveillance of individuals\r\n2. Different stages of attack – It is possible the TA uses Jineva as a second stage designed to be used in case\r\nit deems Swid’s victim interesting. It is possible that the Jineva link is injected into subpages of the\r\nwatehole so to infect only more “interested users”. Unfortunately I have not found any indication of that in\r\nthe 2 waterholed sites I know. I think this is less likely that Swid redirects to Jineva using the plugins,\r\nbecause Jineva is accessible via a short link, which was used by the TA only for the waterholed sites.\r\nThe use of the same projID for different attack chains is also interesting, as the projID looked at first like a unique\r\nID per waterholed site. I see two possible explanations:\r\n1. The TA has a number conversion system like “1” -\u003e “60851…”. “2” -\u003e”60935…” etc. This hypothesis is\r\nstrengthened by the fact that the projIDs all start with “60” and move up from “607” to “609”. It could\r\nexplain why the attacker would have the same IDs, as the same ID can mean “2nd Jetriz site” and “2nd\r\nJineva site” depending on the path.\r\n2. Each time the attacker creates a new wateholed website instance the server automatically creates two links,\r\nfor Jetriz and Jineva, regardless what the attacker chooses.\r\nBased on these hypotheses, I assess with medium confidence that there are at least 3 more infected domains we\r\ndon’t know about.\r\nInfrastructure\r\nI am only aware of one domain used by the group. The domain and the HTTPS certificate were bought in April.\r\nThe certificate (by “Let’s Encrypt”) was valid only for 3 months from April 20th until July 19th, was not updated\r\nand is still the server’s certificate. The attackers used the common “openresty” web server.\r\nWhile it makes sense For a TA to change domains frequently, not taking it down and leaving all scripts there is\r\nquite surprising. Moreover, the waterholed websites are not highly visited and thus the short term benefit from the\r\nwaterhole doesn’t seem substantial.\r\nDetection \u0026 prevention\r\nDetection\r\nSOC \u0026 Security Researchers\r\n1. In some browsers, plugin 13 would cause a DNS request for an onion address. This can be easily detected\r\nif DNS is monitored.\r\n2. Please See Appendix B for YARA rules.\r\nPrevention\u0026mitigation\r\nWeb Users\r\nhttps://imp0rtp3.wordpress.com/2021/08/12/tetris/\r\nPage 11 of 20\n\n1. Noscript is an excellent add-on which would have prevented a user visiting such waterholed site prevent\r\ninfection. This method comes with its problems, as it can prevent legitimate sites from loading correctly.\r\n2. Update 22/08/21 – Using Firefox with strict tracking protection or the latest Chromium (see referrer\r\npolicy default) based browsers (Chrome, Edge, Opera, Brave etc.) can prevent some of plugins (mainly\r\nthose using JSONP) from runnning correctly. This would mitigate the effect of Tetris, but would not\r\nprevent it.\r\n3. Visiting less-known or less-trusted sites in incognito mode can mitigate the effect an infection has and the\r\namount of data it can harvest, but would not prevent it.\r\n4. Using proxy, VPN or TOR can also make it harder for the threat actor to target or identify you, but would\r\nnot prevent an infection.\r\nWeb Developers\r\n1. The TA was able to use the waterholed sites only because their Access-control list was set to “*”. Changing\r\nthat setting and verifying it periodically would prevent that. This is a great resource containing\r\nexplanations about it.\r\nAttribution\r\nI asses with high confidence that the TA is working on behalf of the Chinese government. This assessment is based\r\non several reasons:\r\n1. Victimology – Based on the type of waterholed websites and the fact that the attackers search for Chinese\r\nkeyboard it is reasonable that the TA is interested in Chinese opposition movements, activists and\r\nsupporters. Naturally, this interest is almost exclusive to China.\r\n2. Language – There are several occurrences of short sentences written in Chinese in the plugins. While this\r\ncould be a false flag, its presence specifically in the plugins, where there is also no complicated\r\nobfuscation, raises doubts about that, as it looks like the TA did not foresee any researcher accessing these\r\nscripts. Moreover, there are several places with bad English – sometimes in a way that is unlikely to be\r\nintentional – instead of accessing the “dependencies” folder, the server has a “dependence” folder. More\r\nsimilar errors are seen in the plugins.\r\n3. Similarity – plugin 0 used by the TA has a strong resemblance to a report published by AlienVault in 2015\r\n. While the report doesn’t include samples, the use of wide JSONP-hijacking against a subset of the\r\nChinese sites used in plugin 0 hints at some connection between both operations. The report attributes this\r\nattack to china.\r\nConclusion\r\nAn Analysis and comparison of the different techniques used by the actor lead to 3 interesting conclusions:\r\n1. Separation between teams – Some parts of the attack chain are done quite professionally – several stages,\r\nobfuscation anti-debugging, generic URL path with a unique GET argument and a modular plugin\r\nmanager. Other parts seem to be done unprofessionally – “dependece” path, huge dead code, invalid\r\ncertificate, the sending of 15 plugins at once, plugins that cause permission requests from the user and\r\nhttps://imp0rtp3.wordpress.com/2021/08/12/tetris/\r\nPage 12 of 20\n\nredirection links that enable brute forcing. I believe these inconsistencies show us that there is a strong\r\nseparation between the team developing the code infrastructure (Jetriz and Swid) and the team operating\r\nthe specific server and writing some of the plugins.\r\n2. Experience with public discoveries – The obfuscation used by the TA, randomization of some paths and\r\nmulti-stage design hint that the TA had several encounters with AV detections or publications in the past. It\r\nis possible that the TA learnt from mistakes of colleagues or reports by the cybersecurity industry alone.\r\n3. Type of use – It is unclear why the TA chose to keep the server running with an invalid certificate. I see 2\r\npossible explanations:\r\na) The TA had been denied access by the cloud provider but the provider didn’t care to take down its\r\nserver.\r\nb) This specific campaign wasn’t effective and thus the team didn’t actively continue it. They did not take\r\ndown the server because they either did not care for the code to be found (because it was written by another\r\nteam, or didn’t see this as a risk), or that they thought that it still could have some value in the future.\r\nSummary\r\nTetris accomplishes to take the most out of the browser sandbox, and illustrates its almost inherent vulnerability.\r\nAs browser implement more and more capabilities, which were reserved for executables, It’s likely we will see\r\nmore similar frameworks.\r\nA state spying on its citizens and dissidents is not new – for some states that is even their top priority. Still, the\r\namount of such cyber-espionage campaigns published is relatively low. From lack of telemetry, to the nonexistent\r\nincentive of most of the private and public sector to prevent it, many campaigns remain hidden and serve as a\r\npowerful tool for authoritarian governments.\r\nThis research is based alone on the finding of the two waterholed sites by Felix. There are still several open\r\nquestions: How widespread are infections? Are there more sophisticated plugins? Does the actor utilize a sanbdox-escape exploit at some point? What are the other waterholed sites?\r\nI believe that by collaboration we can answer some of these questions. As cybersecurity experts, we have the\r\nability to contribute to those who do not have the privilege to live in a democratic and liberal state, and providing\r\nthem with a little more freedom.\r\nYou are welcome contact me if you have any new finding or questions regarding Tetris.\r\nAppendix A – Mitre ATT\u0026CK® Techniques\r\nMatrix\r\nhttps://imp0rtp3.wordpress.com/2021/08/12/tetris/\r\nPage 13 of 20\n\nThe Techniques are also available as JSON and Excel in my git repository.\r\nNotable Techniques\r\nHide Atrifacts (T1564)\r\nNetwork Service Scanning (T1046) – plugin 14 Tries to connect to 5 different ports of the host to\r\ndiscover services and exfiltrate their traffiic.\r\nSoftware Discovery (T1518) – Plugin 15 discovers browser plugins and adblockers installed by the user.\r\nSystem Network Configuration Discovery (T1016) – Plugin 13 checks whether the system is configured\r\nto connect through TOR, Plugin 9 discovers the internal IP.\r\nData From local System (T1005) – Plugin 15 exfiltrates localstorage and cookies of the waterholed\r\nwebsite from the browser.\r\nAppendix B – Detection\r\nYara Rules\r\nRules detecting Tetris components.\r\nRule detecting the fingerprint2 library – can be used for legitimate purposes..\r\nIOCs\r\ngoogledrivers[.]com\r\n45.77.103[.]201\r\nhttps://imp0rtp3.wordpress.com/2021/08/12/tetris/\r\nPage 14 of 20\n\nSamples \u0026 Hashes\r\nThe hashes of the various components of the framework all depend on projId and some on sid, except the plugins.\r\nI have uploaded the raw scripts to virustotal and to my repository both the raw and deobfuscated versions of them\r\n(with some of my comments and more readable variables).\r\nI have not uploaded plugins 0-7 to any platform, as I believe their value for more threat actors is bigger than their\r\nvalue for security researchers.\r\nAny company that was targeted by the plugins can contact me directly and once verified I would send the relevant\r\ncode used to exploit their site.\r\nVirusTotal Links\r\nJetriz\r\nSwid\r\nJeniva\r\nPlugins Hashes\r\n0e10230dacf24c762c5b931fbb9d7f810b3761cacc06823b0422338f818235b4 – plugin 0\r\n22a36d03806d4db34654aba285585e1a76459cd41e3c109a9f24738533710634 – plugin 1\r\nced981f8f9b321949d880df65142d7a6931ed862b02b72ffe36b1ebed4c848a2 – plugin 2\r\n1491de46915a6781a3fe82b371d3236a616d89da213f77e2d07c780ca7e65da5 – plugin 3\r\nd1b87b6de14091a70291e04541ecb07a0b6ca4cb848cb8906fcf6059a0ae15e4 – plugin 4\r\n6ea2189452b9fcb072bd2d09c9a03ba3c43118382b5687c010783defc27f4b62 – plugin 5\r\ncd2795f34c37ff5b7dac60e8f618631bdf14f88d017f0073eb8133068e21d150 – plugin 6\r\n78a0b96ca39944a04a7981a13cff76a9f9a3bc285f347ebeae1274c128358ea7 – plugin 7\r\nb1b50a18e8a166f47416a73a5e19351ea042bf2c7fb4e3088a5e457d7b8ff05b – plugin 8\r\nf3ab3203289c30e4e137f73696ab46d7434769c6965583d69b8b297845f9aefc – plugin 9\r\n8b623691edc5ba724405acac4e2f446c977670dca4488b6526852101dca76e52 – plugin 10\r\n4dfa39a06ea81d0a80df2002c643ae07f1bb8a4c608133741d972589a9f874f0 – plugin 11\r\ncae143b302ce23c361bc6cb0ff612ad44cb47e1d15fadc64991d3cec89e42892 – plugin 12\r\n46e47db6175296c2768d13779173684d742a702caa7e71d7bb998f5ef1f29467 – plugin 13\r\nc7653aa63e5c1723c4bd63b7a78f2219e84495502c97313b287f95877064df96 – plugin 14\r\n88f45be2b5117e8d554261e31e02c0e5812c87cfa664472fd43558c3f5603258 – plugin 15\r\nURIs\r\n/public/jquery.min.js?ver=607fd694d0dfb600379f3bb9\r\n/public/jquery.min.js?ver=6085111875349500318504f6\r\n/public/jquery.min.js?ver=60878220c25fbf0035f9876c\r\n/public/jquery.min.js?ver=609351de045c15003a22361c\r\n/public/jquery.min.js?ver=60851543c3baea002ff24ff4\r\n/public/x/jquery.min.js?ver=6085111875349500318504f6\r\n/public/x/jquery.min.js?ver=60851543c3baea002ff24ff4\r\nhttps://imp0rtp3.wordpress.com/2021/08/12/tetris/\r\nPage 15 of 20\n\n/public/x/jquery.min.js?ver=60878220c25fbf0035f9876c\r\n/public/x/jquery.min.js?ver=609351de045c15003a22361c\r\n/s/02Bi\r\n/s/02Bj\r\n/s/02Bk\r\n/s/02Bl\r\n/s/02Bm\r\n/s/02Bn\r\n/s/02Bo\r\n/s/02Bp\r\n/s/02Bq\r\n/zSocket \r\n/sSocket\r\n/public/dependence/jquery/3.1.1/jquery.min.js\r\n/public/dependence/fingerprint2.min.js\r\n/public/dependence/jquery/1.12.4/jquery.min.js\r\nAppendix C – Plugins\r\nPlugins API calls\r\naddIEMeta – Add an Internet Explorer Compatible Meta tag.\r\naddNoRefererMeta – Set any page request or redirection to be without Referer.\r\najaxPromise – Perform basic Ajax request.\r\nbase64Decode – Decode buffer from base64 to string.\r\nbase64Encode – Encode buffer to base64.\r\ncreateElement – Create a DOM element in the \u003cbody\u003e of a document of the attackers choosing.\r\ncreateHiddenElement – Create element with no visibility and 0 dimensions.\r\ncrossOriginJsonp – See noRefererJsonp.\r\ndebounce – Common function used in JS to prevent fast numerous repetitious running of same function.\r\nSwidIframe – Create an Iframe with the dimensions of the windows, overshadowing any other element\r\ngetHighestZindex – Get highest Z-Index in the document, used to calculate how to create an element in the\r\nforeground.\r\ngetLang – Get browser language the function distinguishes between two “types” of Chinese – mainland\r\nChinese and Hong Kong, Taiwan or Mongol Chinese\r\nhasJquery – Check whether window has jquery with Minor version above 8. (Maybe used when older\r\njquery ver. 1 were used by the TA).\r\nhiddenIframe – Create invisible iframe with zero dimensions.\r\nhiddenImg – Create invisible img with zero dimensions.\r\niframe – Create an iframe element with attacker controlled parameters.\r\nimg – Create an img element with attacker controlled parameters. if projId is not present in the img URL\r\nthe function appends it as ?ver=\u003cprojId\u003e.\r\nipec – See xsrf.\r\nhttps://imp0rtp3.wordpress.com/2021/08/12/tetris/\r\nPage 16 of 20\n\nisIE – Check for ActiveXObject in the windows.\r\nloadCSS – Load a css file.\r\nloadJS – Load a JS file.\r\nnoRefererJsonp – Create hiddenIframe and loads a script URl in it. crossOriginJsonp does the same\r\nexcept it sets the iframe‘s referrerPolicy as ‘origin‘.\r\nrandom – Return random number.\r\nremoveCSS – Remove all CSS from windows.\r\nrewriteLink – Rewrite all links in the document to a URL of the attackers’ choosing.\r\nscriptViaIframe – Embed a script in a an Iframe of the attackers’ choosing. if projId is not present in the\r\nimg URL the function appends it as ?ver=\u003cprojId\u003e.\r\nscriptViaWindow – Same as scriptViaIframe but the script is embedded in a windows of the attackers\r\nchoosing.\r\nxsrf – Perform a CSRF\\XSRF attack by submitting an invisible form with attacker controlled parameters.\r\nipec does the same except it uses textarea instead of input and works only with POST requests.\r\n*Calls in bold are used directly or indirectly by the plugins I know.\r\nJSONP-vulnerable Sites Accessed by Plugin 0\r\nSites in bold are also queried by Plugin 1-7.\r\nDomain Attributes\r\nGlobal\r\nAlexa\r\nRank\r\nChinese\r\nRank\r\ntmall.com isLogin 3 1\r\nqq.com userId,nickName,headURL,userHome 4 2\r\nbaidu.com userId,userName 5 3\r\nsohu.com nickName,headURL,userHome,profile,userName 6 4\r\ntaobao.com isLogin 8 5\r\njd.com userName,headURL 10 7\r\nweibo.com userId 14 8\r\ntianya.cn userName 42 17\r\naliexpress.com isLogin 44 –\r\ngome.com.cn userId,nickName,headURL 89 26\r\n163.com nickName,headURL 97 27\r\nnytimes.com uid,subscriptions 113 –\r\nhttps://imp0rtp3.wordpress.com/2021/08/12/tetris/\r\nPage 17 of 20\n\nzol.com.cn userId 310 50\r\niqiyi.com userinfo,qiyi_vip_info 390 53\r\noutbrain.com userName 419 –\r\n58.com userName,userId,phone 468 58\r\nzhibo8.cc userId,nickName,background,headURL 482 69\r\ndianping.com userId,nickName 619 93\r\nrenren.com userId,nickName,userName,headURL,birth 696 94\r\nyouku.com userId,userName,sex,headURL 710 104\r\ndangdang.com ddoy,loginTime 799 109\r\nanjuke.com userId,userName,lastUser,profileURL 844 119\r\nsmzdm.com userId,nickName,headURL 1489 207\r\nifeng.com isLogin,isLogin 1607 218\r\n7k7k.com userId,userName,nickName,headURL,level 1902 216\r\nzhaopin.com userName 2587 289\r\n4399.com isLogin,gameInfos 2764 254\r\nctrip.com userName,level 3185 346\r\n10086.cn userName 4047 383\r\nhupu.com userId,userName 4440 543\r\nvip.com level,lastLogin 6074 1519\r\npconline.com.cn userId,nickName 7303 773\r\nxunlei.com nickName,payName,userName 8680 2126\r\nxcar.com.cn headURL,userName,userName 10868 1157\r\nqunar.com isLogin 11185 1708\r\npcauto.com.cn userId 11410 2117\r\njumei.com nickName,userId 14264 1726\r\n37.com userName,lastLoginIP,lastLoginTime 14905 1548\r\nhexun.com userId,userName,headURL,sex 20653 2480\r\nhttps://imp0rtp3.wordpress.com/2021/08/12/tetris/\r\nPage 18 of 20\n\nsuning.com phone,headURL,level 28883 2845\r\nlu.com userId,sex,realName,userName,mobile 29184 2985\r\ntiexue.net userId,userName 31430 3235\r\nbaihe.com userId,nickName,gender,age,headURL,cityID 36791 –\r\nbbs.360safe.com userName,userId,email,adminId,lastVisit,group 39660 –\r\nqyer.com username,userid 43347 –\r\n56.com userHome 48982 –\r\nzongheng.com level,headURL 59346 –\r\nziroom.com userName 74364 3702\r\nbitauto.com userId,userName 84849 –\r\nchinaiiss.com userName 119808 –\r\n2144.cn userId,userName,nickName 199953 –\r\nyhd.com userName,headURL 343737 –\r\nletv.com userId 671069 –\r\nreadnovel.com userName,headURL 1167917 –\r\nduoshuo.com userId,userName,userHome,headURL,social_uid,email – –\r\naliyun.com userId – –\r\nhuihui.com uid,userName – –\r\ndaijun.com userName – –\r\nIcons loaded by plugin 11\r\nhttps[:]//www.seebug[.]org/static/images/favicon.ico\r\nhttps[:]//www.vulbox[.]com/static/web/img/favicon.ico\r\nhttps[:]//www.secfree[.]com/favicon.ico\r\nhttps[:]//www.secpulse[.]com/favicon.ico\r\nhttps[:]//zhongce.360[.]cn/favicon.ico\r\nhttps[:]//bbs.ichunqiu[.]com/favicon.ico\r\nhttps[:]//www.cnvd.org[.]cn/favicon.ico\r\nhttp[:]//cnnvd.org[.]cn/favicon.ico\r\nhttps[:]//xz.aliyun[.]com/static/icon/favicon.ico\r\nhttps[:]//www.t00ls.net/favicon.ico\r\nhttps://imp0rtp3.wordpress.com/2021/08/12/tetris/\r\nPage 19 of 20\n\nhttps[:]//bbs.pediy[.]com/view/img/favicon.ico\r\nhttps[:]//www.freebuf[.]com/favicon.ico\r\nhttps[:]//www.zoomeye[.]org/favicon.ico\r\nhttps[:]//fofa[.]so/favicon.ico\r\nTOR URL Accessed by Plugin 13\r\nhttp[:]//bn6kma5cpxill4pe[.]onion/static/images/tor-logo1x.png – Legitimate official TOR browser website for\r\nonion v2 (Deprecated).\r\nAPPENDIX D  — Deobfuscation\r\nEach obfuscated script starts with setting an array which consists of base64 encoded strings. The array is then\r\nrotated. Next, a string access function is initialized, which serves throughout the script for any string used.\r\nI wrote a python script to automatically deobfuscate scripts obfuscated in that way. \r\nSource: https://imp0rtp3.wordpress.com/2021/08/12/tetris/\r\nhttps://imp0rtp3.wordpress.com/2021/08/12/tetris/\r\nPage 20 of 20",
	"extraction_quality": 1,
	"language": "EN",
	"sources": [
		"Malpedia"
	],
	"origins": [
		"web"
	],
	"references": [
		"https://imp0rtp3.wordpress.com/2021/08/12/tetris/"
	],
	"report_names": [
		"tetris"
	],
	"threat_actors": [],
	"ts_created_at": 1775791195,
	"ts_updated_at": 1775826713,
	"ts_creation_date": 0,
	"ts_modification_date": 0,
	"files": {
		"pdf": "https://archive.orkl.eu/26f5213bbc6976551117eb1b6ba0941c1b17dbc9.pdf",
		"text": "https://archive.orkl.eu/26f5213bbc6976551117eb1b6ba0941c1b17dbc9.txt",
		"img": "https://archive.orkl.eu/26f5213bbc6976551117eb1b6ba0941c1b17dbc9.jpg"
	}
}