返回资讯中心
外部精选
软件工程
#开发者实时流

We used RCE on 3M PCs to prevent a botnet

Between November 2025 and March 2026, Eye Research actively disabled the vulnerable update mechanism used by the popular download client Popcorn Time (Time4Popcorn). This involved executing code on systems running the v…

Hacker News 最新6467543752026/10/22 · 23 天前30 分钟阅读

以下正文同步自 Hacker News 最新,版权归原站所有,已转换为易读排版。

Oct 22, 2026

By: Niels Teusink

-->

-->

Between November 2025 and March 2026, Eye Research actively disabled the vulnerable update mechanism used by the popular download client Popcorn Time (Time4Popcorn). This involved executing code on systems running the vulnerable software. This is the story of how we got here and why we took the unprecedented decision of taking matters into our own hands. The vulnerability was assigned CVE-2026-30612, about which we published an advisory in June 2026.

It all started with a normal threat hunt. As an MSSP, we have lots of telemetry from our clients and we use this data to search for known and unknown threats. We noticed a process called “Updater.exe” that was running on a laptop at one of our clients. This process was attempting to connect to a domain that wasn’t registered anymore: popcorntimeupd.xyz. It was also connecting to several other domains, some of which are marked as malicious on VirusTotal, so we thought it was worth investigating further.

Looking at the file path and VirusTotal, it quickly became clear that this file was part of Popcorn Time. Popcorn Time is a BitTorrent client that allows users to view movies downloaded from the internet. It was very popular around ten years ago, but the original version was shut down in 2014. This inspired several forks of the software, including one called Time4Popcorn. Confusingly, these forks (including Time4Popcorn) commonly used the Popcorn Time name when distributing the software. This means that it wasn’t always clear to users what version of the software they had installed. The ‘Updater.exe’ we found is part of the Time4Popcorn fork. This is a closed-source variant of the software, so no source code was available.

None of our clients were actively using the software. Most had installed it years ago and probably forgotten about it. The Updater program was still running in the background, however, regularly checking if any updates were available.

Since early 2025, a new project started using the Popcorn Time name and is building a legal alternative. This research does not apply to that software.

This software wasn’t all that common among our clients. Only a handful of them had it running. We run an MSSP for businesses, so people don’t usually run software that lets them illegally stream copyrighted material (although you’d be surprised how often detections result from end-users trying to install cracked software). Intrigued, we decided to register the domain and see what kind of requests were coming in.

We were a bit shocked to see the web server log growing and growing. About 50 requests per second were coming in, mostly looking like this:

GET /?app_id=T4PSEC&hid=0a62d1fbddf387e1b37b5034f21049f6&ver=6.1.0.0&os=WIN060200

The ‘hid’ parameter seemed to contain a hardware ID, supposedly uniquely identifying the client. Over the next six months, we saw over 3.8 million of these IDs. Half of them were running on Windows, with the rest running macOS (~45%) and Android (<5%).

Later, we would learn that counting clients based on hardware ID was not as reliable as we had hoped and we were underestimating the number of Windows systems and overestimating the ones running macOS.

So now what? All we knew at that point was that this software was connecting to the domain and sending requests. All this was happening over unencrypted HTTP connections. Everything suggested that it was trying to fetch an update from the server, but we didn’t know if we could let the software execute one. Simply serving an executable didn’t seem to do anything. Even if we figured out how the process works, the software may check digital signatures, preventing abuse by third parties.

If we were able to send an update, we could potentially get code execution on millions of systems. Ransomware operators often use infected clients in a botnet to gain an initial foothold in corporate networks. Password-stealing malware also loves taking those passwords stored on devices, especially if companies allow end-users to log into corporate systems from personal devices. In other words: the impact would be severe if this were to fall into the wrong hands.

We could see the Updater.exe program was trying to connect to several other domains. At the time, we only owned one of them; the others were all registered by third parties. They all seemed to be claimed by bulk domain buyers and parked or for sale for thousands of dollars. None of the domains offered updates to connecting clients, so to determine how the process works, we had to reverse engineer the binary. The other platforms (Android, macOS) turned out to use different domains as well. Many of these domains were still unregistered.

The Updater executable was written using C++ and Boost 1.55 (released in 2013). C++ executables can be a bit annoying to reverse, especially if they use Boost, so it took us a while to figure out it was expecting a JSON response (probably could have guessed that). All we needed to do was supply a link to an executable and the program would download it and then execute it with high privileges (NT AUTHORITY\SYSTEM). There was no code signing and this process was all happening over HTTP.

On macOS, things were pretty much the same. We could push an update that would execute as root. The executable differs a lot from the Windows one though, and as I did not have any prior macOS-reversing experience, this took a while to figure out. For some reason, the author decided to obfuscate a lot of strings, and I may or may not have spent half a day reverse engineering a base64 implementation. The expected JSON was very different on the macOS version, but the result was the same: code execution with high privileges.

On both platforms, this was all happening in the background as the program started automatically. Many users had probably forgotten about the software years ago and weren’t actively using it.

On Android, things are slightly different: there is no background process. The application checks for updates when it is opened by the user. The end-user is then asked if they want to install an APK.

So, we have millions of hosts that are connecting to different domains trying to get updates. How do we make them safe again? Normally, when finding vulnerabilities, we would contact the vendor, they would release a patch, and most people hopefully install this. In this case, the ‘vendor’ was a bunch of pirates (arrr). Even if we could contact them, what were they going to do about it? They seemed to have lost control of the domains and would not have been able to push an update to clients anyway. The site that used to distribute the software hasn’t been active in years.

We thought about trying to get control of all the domains. Looking at the landing pages, they seemed to be owned by several different people. One of the domains was hosting a personal blog. Some were selling the domains for thousands of dollars. We figured that, by spending a lot of money, we could probably get control of most of the domains, which could be worth it. However, if we were unable to buy one of the domains, the plan would not be very effective. Also, as updates were happening over unencrypted HTTP, end-users would still be at risk from attackers that could manipulate their internet traffic. In some countries, governments have used insecure update processes to install spyware on dissident PCs. For other users, simply connecting to an unencrypted Wi-Fi network could put them at risk.

Given the nature of the software, most of these clients will be home users. We mapped a sample of the IP addresses using kepler.gl and they were everywhere:

Most clients are connecting from end-user ISPs spread across the world, but we’re also seeing connections from various government and military networks around the world. We’re also seeing a lot of clients connecting from corporate networks. It’s hard to draw conclusions from this, but we think it’s safe to say criminals would be very interested in many of these systems.

Can we disable the updater remotely on connecting systems? Sure, we can offer an update to the clients that instructs the updater to disable itself. But is this ethical? Could we get into legal trouble? When systems are asking you for an update, can you give them one? Thankfully, our legal team enjoys a good challenge and was able to provide some advice.

The only real alternative we had was to do nothing, and this didn’t seem like it would make the world a better place. The update process wasn’t doing anything functional anyway, it was only creating risk for users. A somewhat similar case was Operation Ladybird, where the Dutch police deployed a software update to clients that were part of the Emotet botnet, neutralising the infections. Of course, those clients never intentionally became part of a botnet, while these users presumably voluntarily installed the software.

But while these users chose to install Popcorn Time, none of them chose to have a forgotten updater running in the background for years, ready to run any code with full privileges for whoever controlled one of its domains. With millions of systems affected and the software long abandoned, there was no vendor to fix this and no patch on the way: if we didn’t act, nobody would.

To mitigate the risks, we did extensive tests of the update and ran a small-scale test first. For our full-scale deployment, we made sure we were able to deploy updates on both Mac and Windows systems. We also built a system that granularly allowed us to deploy the update to specific systems.

On Windows systems, our update simply stops and disables the service via the Service Control Manager. That’s all it does, so no telemetry, no file deletion, nothing. You could achieve the same manually via the command line by executing these two commands:

sc.exe config "Update service" start= disabled

On Mac systems, we use a shell script and execute this command:

launchctl unload -w /Library/LaunchDaemons/PT.updd.plist

This stops and disables the launch daemon that would start the PT.updd process when the system boots.

We also didn’t want bad actors to start doing the same thing. To prevent this, we initially only offered the update to hardware IDs we had seen before. This made it harder to investigate how the update process worked by setting up a test system. Each ID would only be served the update a single time. We also redirected clients to HTTPS where possible. After a few weeks we relaxed all of these restrictions to get our update to as many systems as possible. Some hosts weren’t following our HTTPS redirects, and, as we later learned, relying on hardware IDs to uniquely identify clients wasn’t ideal.

In our small-scale tests, we noticed some peculiarities. The Windows devices we were updating were getting the update more than once. This was the trigger we used to determine if our update was failing and it seemed to be failing a lot. Did our code suck? Did we have some endpoint protection product blocking it?

When we looked closer, we saw devices with the same ‘hid’ requesting the update multiple times a day. However, the requests almost always came from different IP addresses, all over the globe. Also, some clients were reporting several different operating system and application versions. This led us to believe that at least on Windows, large numbers of systems were using the same ‘hid’.

When looking at the generation of the ‘hid’ value by Updater.exe, in our reversing we had seen that the software created an MD5 hash of three combined elements:

This didn’t sound too bad. It’s not

正文由 探How 从来源站点 RSS 同步,内容未经改写;遇到排版缺失或需要图片、视频时请以原文为准。

打开原文
去社区讨论 →