This Week In Security: Npm Timing Leak, Siemens Universal Key, And PHP In PNG

First up is some clever wizardry from the [Aqua Nautilus] research team, who discovered a timing attack that leaks information about private npm packages. The setup is this, npm hosts both public and private node.js packages. The public ones are available to everyone, but the private packages are “scoped”, meaning they live within a private namespace, “@owner/packagename” and are inaccessible to the general public. Trying to access the package results in an HTTP 404 error — the same error as trying to pull a package that doesn’t exist.


The clever bit is to keep trying, and really pay attention to the responses. Use npm’s API to request info on your target package, five times in a row. If the package name isn’t in use, all five requests will take the expected amount of time. That request lands at the service’s backend, a lookup is performed, and you get the response. On the flipside if your target package does exist, but is privately scoped, the first request returns with the expected delay, and the other four requests return immediately. It appears that npm has front-end that can cache a 404 response for a private package. That response time discrepancy means you can map out the private package names used by a given organization in their private scope.

Now this is all very interesting, but it turns into a plausible attack when combined with typosquatting and dependency confusion issues. Those attacks are two approaches to the same goal, get a node.js deployment to run a malicious package instead of the legitimate one the developer intended. One depends on typos, but dependency confusion just relies on a developer not explicitly defining the scope of a package.

Siemens Left the Keys in the Ignition

Siemens released version 12 of their TIA portal nearly 10 years ago, and with this update added asymmetric cryptography between the portal and their SIMATIC S7-1200 and S7-1500 products. To put that in plain English, their industrial controllers started using HTTPS to talk to the controller software. This was a good thing. Unfortunately, the private key for that HTTPS connection lives on the controller hardware, and every unit shipped had the same key.

The real fun is how the team at Claroty discovered all this. Industrial controllers get programmed in a specific, high-level language, that is strictly for automation logic. Pointers, memory management, and the rest of our normal vulnerable vectors don’t show up here. Those programs get compiled to a custom bytecode that runs in a controlled environment on the controller. So naturally, our researchers reverse engineered the bytecode and wrote their own compiler, to have access to those under-the-hood features. It was still a challenge to defeat the security controls built-in to that environment, but they eventually found a function that could set a pointer to an arbitrary value, allowing kernel reads and writes. Including reading the universal key.

And that brings us to the first real attack that having this secret-but-shared key enables. Depending on the configuration, it’s sometimes possible to download the configuration blob without authentication. One of the items contained in that dataset is the encrypted password hash, which was encrypted using — you guessed it — that universal key. With the key in hand, an attacker can download the hash, decrypt, and then authenticate using the hash.

And then, having the secret key to an HTTPS certificate allows all the normal shenanigans one would think of: capturing traffic and decrypting, or performing a man-in-the-middle attack. The issues have been fixed with the latest firmware and portal updates, and Siemens has issued an advisory owning up to the problems. See the video below for the first-hand story of escaping The Matrix and getting to real code execution on these machines.

(Hackaday’s parent company, Supplyframe, is owned by Siemens.)

Valid PNG, Valid PHP

There’s always something weirdly fun about a file that is valid as multiple, wildly different file formats. In this case, it’s the PNG file that is also valid PHP. The security angle here is that many websites allow you to upload PNGs and then view them. If that PNG could actually, sneakily be a PHP file too, you have an instant webshell. Now there are likely some insecure sites where it’s just as simple as uploading a script, but many uploader libraries will at least check that the file is valid for the specified mimetype. Simply, it has to be a valid PNGif set to image/png. But is that enough?

PNG files can contain comments. What does a web server do when it serves a .php file that also contains binary PNG data? In many cases, it treats it like any other file, sending the raw data until it finds a <?php tag, where it might just start executing PHP script. The next question is how does one create such a file that the PHP script persists through compression, resizing, and other sanitizing steps? The first approach discussed is using tEXt chunks, which are usually used for storing title, author, etc. In many cases these bits of embedded text will persist through any modifications.

The other, harder approach, is to embed text as image data directly. There is the PLTE chunk, where custom palette entries can be defined. These can have any value, but must have a multiple-of-three length, and maximum 768 characters. The even harder one is to use the actual IDAT chunks, AKA actual valid pixel data. This is deep magic indeed.

Zoneminder — It Could Have Been Worse

This one hits close to home, as it’s a trio of vulnerabilities in a project I recommend and occasionally sling code for. [Trenches of IT] contacted the project on the 30th with a trio of vulnerabilities that had the potential to be really ugly when put together. Up first is a Log Injection flaw, where a web user can push arbitrary data into the ZM logs, with no rate limiting. Need the cameras to stop recording? Fill the drive up with log messages. Both the message itself and the component that sent it can be set arbitrarily.

Up next is a CSRF bypass. Cross-Site Request Forgery is an attack where an end user’s browser takes an action the user didn’t intend, just by making an HTTP request. ZM uses CSRF tokens to protect against such issues, which is a random token, supplied by the web service, that must be included in any POST requests. The bypass in the case of ZM is that some actions, like deleting a recording, can be made as GET requests, which don’t require a token. Whoops.

The last issue has the potential to be the worst, as it’s a Cross-Site Scripting (XSS) issue. That log injection issue also enables this one, as the “file” field can contain arbitrary HTML code, including a script tag. Put the three issues together and a user with view-only privileges can inject a delete or disable command that will trigger when an admin views the logs. That’s bad, but at least it’s not a pre-auth vulnerability. It was fixed in 1.36.27, released on the 7th. If you happen to be stuck in the 1.34 series of releases, this a few other issues are outstanding and no further releases are planned for that deprecated version. Thanks to [Trenches of IT] for finding and reporting!

Microsoft’s Gift That Keeps Giving

Remember the Exchange 0-day, the one that was sort of a workaround of an older problem with the autodiscover endpoint? Well it still hasn’t been patched, and the recommended workarounds have been updated multiple times, as they’ve been trivially bypassed. It might just be time to just pull the plug on autodiscover, and just block all outside access to IIS while you’re at it.

Python and Userland Execution

Finally a red-team quick-tip. You’ve popped shell on a server, and you want to pull some tools in to start exploring the environment. Root is mounted read-only, and your temp directories are all mounted noexec. How do you get a binary on to the system and run it? If Python is installed, then you could use ulexecve. [Vincent Berg] wrote the tool and has the story. How it works is equally impressive, as it downloads and parses a given binary, manually loading it into memory and generating the jump buffer. Finally, it jumps code execution into the new binary, which never needs to be written to disk. Tricky.

12 thoughts on “This Week In Security: Npm Timing Leak, Siemens Universal Key, And PHP In PNG

  1. Microsoft thing: who still buys and operates Megashaft systems that store confidential data after seeing the summary as “and block all outside access to IIS is reliable for all consequences from data breaches because of intentionally using a faulty system.
    Of course the M$ kickbacks to corporate IT management and employees make sure this will not change.

  2. That php one appears nasty, but relies on a badly written application to allow the user to upload arbitrary filenames, which is the stupid mistake.

    Everyone should know that mine type checks can be fooled – modern file formats which are actually zips already make this abundantly clear.

    1. The actual stupid mistake is to allow arbitrary data uploaded by users to run, for any definition of “arbitrary”, “data”, “upload”, “user” and “run”. Concept applies not only to web servers.

  3. It is not that difficult. Source and endpoint.. i.e. regulation of code that is allowed to run. It should be considered a “bug” just as Linux does! The psychology of modern hacking (read as phishing etc) is not impossible to defeat, it is just that Microsoft and Apple do very little to diminish it (maybe because they have a master?)

  4. As someone who needs (some) security from Siemens TIAportal, I REALLY enjoyed the linked claroty video: adonis kernel, MC7+ bytecode, great stuff. But it did not talk about the https private key flaw, or glossed over it.

  5. correct me if i’m wrong, but would the PNG “vulnerability” only exist if the Web server ran the PHP preprocessor over the PNG image?

    I mean, if the server sends the raw PNG out to the browser without actually interpreting it first as PHP, there is no vulnerability, correct? Are most servers that badly configured that they would allow arbitrary execution of a non-PHP file?

    The way I see it, two things can render this useless: 1. Only execute *.php files as PHP, and 2. Prevent user-uploaded files from having a .php extension.

Leave a Reply

Please be kind and respectful to help make the comments section excellent. (Comment Policy)

This site uses Akismet to reduce spam. Learn how your comment data is processed.