Video Summary and Transcription
The Node.js security team is responsible for addressing vulnerabilities and receives reports through HackerOne. The Talk discusses various hacking techniques, including DLL injections and DNS rebinding attacks. It also highlights Node.js security vulnerabilities such as HTTP request smuggling and certification validation. The importance of using HTTP proxy tunneling and the experimental permission model in Node.js 20 is emphasized. NearForm, a company specializing in Node.js, offers services for scaling and improving security.
1. Introduction to Node.js Security Team
Hello, everybody. My name is Rafael Gonzaga. I'm a staff engineer at Neo4m. I'm a member of a few organizations in the open source, and I'm a Node.js DSC member, a security working group lead. Recently, I started live coding on Twitch. So first of all, all the CVs mentioned here were addressed. Make sure you are using a safe version of Node.js. The Node.js security team consists of the Node.js triage team and the security working group. Did you find a potential security vulnerability? Please do not open a public issue. The process of submitting Node.js vulnerabilities is fairly straightforward. You find a potential vulnerability and you go to the hacker one. The Node.js three-edge team receives your report and assesses it against our threat model.
Hello, everybody. My name is Rafael Gonzaga. I'm a staff engineer at Neo4m. I'm from Brazil. I'm a member of a few organizations in the open source, and I'm a Node.js DSC member, a security working group lead. I'm a Node.js releaser, so if any of Node.js builds break you, probably it was on me, OK?
So recently, I started live coding on Twitch. So if you like this kind of content, follow me there as well. I'm mostly available in all the social medias.
So, OK, first of all, before showing the bad parts of Node.js, I would like to give a disclaimer telling that all languages have it and introduced a concept of security in programming language. So for instance, first of all, all the CVs mentioned here were addressed, OK? Make sure you are using a safe version of Node.js. For instance, I wrote a package called IsMyNodeVulnerable. If you would just call npx is my node vulnerable, you'll be able to see if you are using a vulnerable version of Node.js. If you are, please update, OK?
So first of all, I will present the Node.js security team. Basically, the Node.js security team consists in two groups. The first one is the Node.js triage team. It consists of the Node.js Technical Steering Committee, specific contributors of Node.js with security expertise, the Node.js release team, and the build team, OK? And the second group is the security working group. It's a community working group. We work on several security initiatives, and the experimental permission or the permission model is just one of them. So you can be part of it. Just ping me, send me a message, you can go to the repository, and you'll be able to see it, OK?
So let's go to what matters. Did you find the potential security vulnerability? Please do not open a public issue. You will be disclosing the vulnerability, and that's crucial. That's very bad for maintainers, because we need to hurry. We need to do a lot of things in a short period of time, and it's eventually very bad, actually. So usually, see the security.md in the Node.js file, you'll be able to see it. If you go to the hacker one, you'll be able to see it, as well. So the process of submitting Node.js vulnerabilities is fairly straightforward, okay? You find a potential vulnerability and you go to the hacker one. Hacker one is a platform where you can submit any potential vulnerability and you assess it. And then you fill the form, and the Node.js three-edge team receives your report. And we assess it against our threat model.
2. Hacking Node.js: DLL Injections
And if that gets accepted, we will prepare a security fix and a security release. You can make money from it through bug abating programs. I will be presenting five ways you could have hacked Node.js. The first one is DLL injections, a technique used by hackers to inject malicious dynamic link library files into a running process. Let's take this example: you are on Windows, you install a game, and a malicious package containing a providers.dll is installed. This package requires crypto, and when it is initialized, it will search for providers.dll in the current working directory.
And if that gets accepted, we will prepare a security fix and a security release. Okay? So, well, you can make money from it through bug abating programs. Okay?
So, in this talk, I will be presenting five ways you could have hacked Node.js. However, it's important to mention that all the vulnerabilities were a threat. So don't worry.
The first one is DLL injections, okay? Hello, Windows users. DLL injection is a technique used by hackers to inject malicious dynamic link library files into a running process, thereby modifying its behavior or gaining unauthorized access to its resources.
So let's take this example, okay? You are on Windows. Again, sorry, Windows users. Then let's say that you install any kind of game. You install most of the games nowadays need to open SSL. So you have opened SSL in your machine. And then you are following a blog post, but you mistyped Fastify. And then you install Fastify, okay? And then this package, this is a malicious package that contains a providers.dll. And the content of this dll is basically the most dangerous thing you can do on Windows, that is, to open the calculator, okay? And then, okay, this package requires crypto, actually, in the beginning. Whenever you require crypto, HTTPS or TLS module on Node.js, we'll initialize open SSL. And when it is initialized, it will search for providers.dll in the current working directory. And for instance, if the package, malicious package, contains just a post-install script that calls NPM versions that, under the hood, require crypto, it will initialize open SSL and will load the providers.dll and then the attack happens. Now it thinks that it doesn't load providers.dll in the current working directory anymore.
3. DNS Rebinding Attack
Let's talk about DNS rebinding. DNS rebinding is a technique used to trick users into visiting a bad website instead of the intended one. An attacker can use DNS rebinding to redirect users to an invalid IP address. The attacker can then exploit the DNS server, which is not protected by SSL or TLS, to perform a man-in-the-middle attack. By mapping the request to their attacker IP with a short time to live, the attacker can intercept the page's request and load malicious content. The time to live ensures that messages don't get stuck in a loop and works like a timer for message delivery.
So let's go to the second one. Let's talk about DNS rebinding. So when you want to visit a website like xample.com or jsnation.com, your computer needs to know the IP address of that website. So the DNS is like a phone book. For the internet that helps your computer to find the right IP address to the DNS.
So imagine that someone wants to trick you into visiting a bad website instead of the one that you intended to go to. They could use something called DNS rebinding attack to do this. So let's assume that there's a user using node-inspect. This will open the Node.js debugger. And then you access the attacker.com. And the attacker.com redirects you to an invalid IP address. So the Node.js was not validating that IP address correctly. So it was going to the browser. And then the browser says, OK, this is not a real IP address, I will ask to the DNS server. The DNS server goes to a DNS server with a compromised connection, which means, OK, I want the DNS or the IP address for the 10.0.2.555 in the port 9229. And then, well, you may think, OK, the attacker would need to get access to the DNS server and that's hard, actually not. DNS is not protected by SSL or TLS. So if you are in the same network, it can just perform a man-in-the-middle attack.
So OK. Let's assume the attacker now has access to the DNS server. And then, when you require, when you request the IP address for that invalid IP address, it maps the request to their attacker IP with a short time to live. OK? And then the page tries to load a slash JSON. The time to live is basically a special number that is used to make sure that the message sent over the Internet don't get stuck in a loop or keep going forever. It works like a timer that tells the computer in charge of sending the message when to stop, try to deliver it if it takes too long. OK? So, for instance, I request to the web server the IP address of axample.com, and I receive a time to live, a time to live of, I don't know, 60 seconds. And then if I request the IP address of that DNS in that short period of time, before 60 seconds, I receive the same IP. If I request the IP address after the 60 seconds, it will perform another DNS call. OK? So, OK. Then it's loading the SlashJSON under attack IP, and then the tll expires. And this time, it requires the DNS server again, and the attacker sends it to the local host.
4. Node.js Security Vulnerabilities
So it will expose the SlashJSON under your local host to the attacker IP, which means that it will show the WebSocketDebugger URL, and then the attacker will get access to your machine. And well, it can run whatever you want, or she wants in your compromised Node.js instance. The third one is 80PS request smuggling. Let's do an analogy here. Imagine you are in a restaurant, and you want to order a burger. But now imagine that someone else at the table wants to order a soda. So they write a note with the soda order and hide it inside your burger order, like a secret message. Let's do it in a technical way now. Let's assume you just request and then you have a CDN. And then you have a private network under, let's say that I have a microservice called users. And to make it happen in the Node.js vulnerability, basically the transfer encoding was a header required to exploit it. Imagine there is a malicious user sends a request with the following content, post today slash. And then one of the headers is the X semicolon slash n. That is the new line. But an invalid header is sent using only LF, the slash n. But it is still being processed by Node.js, OK? So what was happening behind the scene is that, this request goes to the CDN, the CDN sends it to the server, the server interprets it as two requests, a POST to the slash and a GET to the admin stuff, even though I sent just one request.
So it will expose the SlashJSON under your local host to the attacker IP, which means that it will show the WebSocketDebugger URL, and then the attacker will get access to your machine. And well, it can run whatever you want, or she wants in your compromised Node.js instance. So that's very bad. It's difficult to replicate, OK? But it's still a good attack. And after solving this, we received another report that, OK, DNS rebinding was fixed, but there's an Edge case on Apple, and then we fixed it again. It happens.
The third one is 80PS request smuggling. So let's do an analogy here. Imagine you are in a restaurant, and you want to order a burger. You give your order to the waiter, who takes it to the kitchen. But now imagine that someone else at the table wants to order a soda. And they want to do it in a sneaky way. So you don't not see. So they write a note with the soda order and hide it inside your burger order, like a secret message, OK? So the waiter takes your burger's order and sees the note for the soda hidden inside. But because the note is hidden, the waiter does not realize that there's two separate orders. And then the waiter brings you a burger and a soda, even though you only ordered a burger, OK? Let's do that. Let's do it in a technical way now, OK? Let's assume you just request and then you have a CDN. And then you have a private network under, let's say that I have a microservice called users, OK? And then you can have, I don't know, several servers. You have a load balancer, reverse, proxy. It really doesn't matter. And to make it happen in the Node.js vulnerability, basically the transfer encoding was a header required to exploit it. So basically, transfer encoding is a header that serves to tell the server how to interpret the bytes on the header request, OK, on the header body as well. So imagine there is a malicious user sends a request with the following content, post today slash. And then one of the headers is the X semicolon slash n. That is the new line. This was by passing the Node.js LLTP validation. So, Node.js was expecting a CLLF, that is carry-return-line-feed, to properly separate the headers. But an invalid header is sent using only LF, the slash n. But it is still being processed by Node.js, OK? So what was happening behind the scene is that, this request goes to the CDN, the CDN sends it to the server, the server interprets it as two requests, a POST to the slash and a GET to the admin stuff, even though I sent just one request.
5. Navigating Node.js Security Vulnerabilities
But it is still being processed by Node.js, OK? So what was happening behind the scene is that, this request goes to the CDN, the CDN sends it to the server, the server interprets it as two requests, a POST to the slash and a GET to the admin stuff, even though I sent just one request. So maybe the admin stuff was not exposed to the network, to the web, even though I could make this request. So that's terrible, okay? The other one is attempt read from arbitrary paths. Let's assume you are on a Linux based host with multiple users and one of the users is a malicious one. A malicious user creates a fake openSSL.cnf file containing the malicious configuration. The attacker can modify the key generator, alter the default settings, and more. Node.js in the startup was trying to read a file called openSSL.cnf in that specific location. The attacker could figure it out using Linux utility tools like strace. We have addressed this issue and created a test to solve it. The last one is certification validation. Let's assume you perform a GET request to the server with a client IP address that is different, like a PROC server. You can use a man-in-the-middle proxy tool like HTTP Toolkit Proxy to intercept debugger requests.
But it is still being processed by Node.js, OK? So what was happening behind the scene is that, this request goes to the CDN, the CDN sends it to the server, the server interprets it as two requests, a POST to the slash and a GET to the admin stuff, even though I sent just one request.
So maybe the admin stuff was not exposed to the network, to the web, even though I could make this request. So that's terrible, okay?
So well, the other one is attempt read from arbitrary paths. Basically, let's assume you are on a Linux based host with multiple users and one of the users is a malicious one, okay? It happens very often in universities, okay? So let's assume that a malicious user creates a fake openSSL file, openSSL.cnf file configuration containing the malicious configuration. The openSSL.cnf is just a file containing the security configuration for the openSSL, okay? So the attacker can do a lot of things like modify the key generator, alter the default settings, and so on. And then the malicious user create this fake openSSL.cnf at this specific file, io.js build ws.out.release and so on and go to that long file. And then Node.js in the startup was trying to read a file called openSSL.cnf in that specific location. It was a mistake from our side. So the attacker could figure out it using the Linux utility tools like strace. It used it to trace system calls, OK, so it just called a strace and then it was able to see, OK, this is the open calls that this program specific does. And then I create this file because it will try to read this file specific and then I can hack it. OK, so we have addressed it, as I said, and I have created a test addressing this problem. So if you want to see the PR 46150, you'll be able to see how I solve it.
So OK and then OK, once the node.js loads it, the attacker will get access to that open ssl and with a custom configuration. So the attacker now controls it. And OK, that's bad. OK, it's very hard to explain, but that's bad.
The last one, certification validation. Personally, I did this mistake and I fixed it, but it was hard. So let's assume that you do a normal request. You perform a GET request to the server and the client IP is xsx because it's your IP address. But then you want to use a PROC server. It's fairly common because let's say that you want to intercept a request, normally a PROC server, a PROC ATP debugger, is good to do that. And then the client IP address is like different, is the III, the PROC server one. You can use it for a man-in-the-middle proxies. There is another tool called HTTP Toolkit Proxy. You can intercept debugger requests. That's very useful for developers. This is just an example of the man-in-the-middle proxy. And then let's say that you are in an interview, and the interviewer asks you to implement an HTTP proxy client, okay? And you end up with the following example.
6. HTTP Proxy Tunneling and Permission Model
Performing HTTP requests through a proxy without TLS encryption can expose your data to network sniffing. HTTP PROXY tunneling creates a secure SSL tunnel between the proxy and the server, protecting your data. Use a good HTTP client library like Onduchi. Node.js 20 introduces the experimental permission model, which allows fine-grained control over file access. An example demonstrates how the permission model can prevent unauthorized access to sensitive files.
I have the HTTP GET and the hostname is basically the PROC's URL. And the request of the server is the server I want to perform the request under the PROC's client. Basically in a query request, it's basically like this. The local host is my PROC's server. However, don't do that. I did that for Undici, one of the Node.js backers. And that's, how can I say that, is dramatic.
Okay, let me explain the problem. When you perform that kind of approach, all the HTTP connection is, all the connection, all the server, all the data you want to send to the server, will send first to the PROC's server on the other HTTP connection without TLS. So when there's no TLS, it means that anyone in your network, in your local network, will be able to sniff the network and read all the traffic without any encryption, regardless if your requested server is HTTPS or not. And that's very bad, because in that case, for instance, in that case of the UNDG. It was using the PROXY agent, ok? And whenever you send a request to the XSample.com using the PROXY URL as a localhost HTTP, it's like a default address for AmandaMiddleProx or HTTP2Kit, if someone goes to your network and sniffs using Wireshark, for instance, as you can see in the blue line, it is displaying my user and my password under the network, even though the XSample.com is a TLS ender server. That's bad. That's why HTTP PROXY tunneling comes in. Basically you create a PROXY, SSL tunnel between the PROXY and the server. So it means that the PROXY won't be able to read your data. It will only create the tunnel to you between the server and the PROXY. So that's the safer approach.
So I know that most of you won't pass by something related because I don't think that interviewers will ask you to do that. So make sure to use a good HTTP client library. Onduchi is now safe. So what do we learn from all this? The target is often you. And the Node.js 20 comes with an exciting feature called permission model, dash, dash experimental permission. Just a final example. Let's assume that there is a humble dev trying to solve a problem. It goes to the tutorial, it finds a problem solver package. The problem solver package looks like this. It was trying to read the etc.passwd that is basically the password file. But this humble dev decides to be cautious and use the experimental permission to allow read only in the files he wants. And then the humble dev got saved by the permission model, because it was trying to access the etc.passwd and it was denied because this permission was not explicitly granted to the process.
7. NearForm and Experimental Feature
This is a good feature, please make use of it. It is experimental, so you might expect some bugs for now. Don't use it in production until it gets stable, considering that a security feature. NearForm is a professional service company with core contributions to Node.js. They can help your business scale under Node.js infrastructure, covering security, performance, and more.
This is a good feature, please make use of it. It is experimental, so you might expect some bugs for now. Don't use it in production until it gets stable, considering that a security feature. So there is a lot of other flags like AllowRead, Write, Child Process, Worker, and a lot of things.
And well, that's it from my side. A bit about NearForm. NearForm is a professional service company. We are distributed worldwide. We have core contribution to Node.js. I'm a member of the Node.js TSE, but we have two other folks on the Node.js core team as well. So we can certainly help your business scale under Node.js infrastructure. Regardless, security, performance, a lot of things we cover.
And that's it from me.
Comments