NodeJS
The backend for running JavaScript as a server or application
Last updated
The backend for running JavaScript as a server or application
Last updated
Similar to sqlmap, there is tplmap which aims to automate template injections by testing various templating engines, as many exist for NodeJS. Here is a simple example:
The tool also allows you to exploit the injection using arguments such as --os-shell
.
See the --help
page for more useful arguments.
package.json
)In every NodeJS project, there is a package.json
file which contains a lot of metadata information about the project, such as where the main file is, some description, and the dependencies. These are external pieces of code with a version number attached that are used throughout the project.
A possible problem is when these dependencies aren't regularly updated, and vulnerabilities might be found in those dependencies and be fixed in later versions. If the code keeps using the older version it may become vulnerable because of those dependencies.
A simple way to check for known vulnerabilities is by uploading the package.json
file to Snyk checker:
For attackers, this can give an idea of what vulnerabilities there might be. Of course, not all vulnerabilities this checker finds are actually exploitable, but you should find what parts/functions of the vulnerable code are used to see if it is.
mysqljs/mysql
library (latest) - SQL Injection using ObjectsThis popular npm
library uses prepared statements to prevent SQL Injection using regular strings, but a code example like the following is surprisingly still vulnerable:
In this case the username
and password
variables are directly passed into the SQL query, but using prepared statements with ?
question marks as placeholders. Normally this would not be vulnerable to SQL Injection as the library handles separating code and data for you, which would be true if the variables were strings.
If the variables are objects, however, weird things start to happen. With web endpoints in Express like the above, you can use the Content-Type: application/json
to use JSON for your body, which may contain a more complex Object
like the following:
This is not a string anymore and mysql
will have to put it into the query somehow. Instead of simply stringifying the object, it does something unexpected where key-value pairs become key=value
pairs inside of the final query:
To understand what this weird new query does, we follow the code from left to right. The WHERE
clause makes sure username
is equal to 'admin'
, and then comes the messed-up syntax. What actually happens here is that the first part password = password
means "the password column equals the password column", which is always true! Then the last = 1
simply tests if the previous expression is equal to one. Due to type coercion, TRUE
is the same as 1
, so this condition will also be true.
This results in only the username being checked, which in theory could also be injected in the same way by providing an object for the username, if the administrator username is not known and we want to simply log in as the first user.
Tip: JSON is not the only way to create an Object
instead of a String
, as some frameworks also accept the ?name[key]=value
syntax in query or body parameters. The above login bypass would look like this with the new syntax:
Successful protections against this technique are:
The alternative mysql2
library
Wrapping parameters in String(...)
to stringify them
The stringifyObjects: true
option while setting up with createConnection
:
Bun is an alternative JavaScript runtime just like NodeJS, but has some more native packages. One such API is the $ Shell API that allows running shell commands safely with Tagged templates. User input as a string will be escaped properly to prevent injection of more commands.
Take a look at the following example:
Running this, we can try to access /?dir=$(id)
in hopes of command substitution, but we get an error instead:
The same will happen for any command injection attempt. There are however, edge cases where this is exploitable, and the example above is surprisingly one of them. The problem lies in an obscure functionality that disables the escaping of arguments: $.escape
(escape strings)
In that section of the documentation an interesting example is shown:
If you do not want your string to be escaped, wrap it in a
{ raw: 'str' }
object:
If the value in the tagged template is an object with a raw
key, the value is not escaped. If we are able to abuse any functionality to make our input into an object, we can include this raw:
key ourselves to bypass the filtering. In Express, this is possible by using a more complex query string that can create objects like ?dir[raw]=$(id)
becoming { raw: "$(id)" }
. This works!
Many other frameworks allow creating an object like this from a query string, or even directly from JSON input in a request body.
One more interesting functionality in Bun is that globbing is partially implemented for filename expansion. This allows inputs like *
to match all files, and more specific patterns like *.txt
to match only files ending in .txt
. Take the following example:
The above code should directly echo back your input, but natively it allows wildcards to match any local filenames, even in different directories:
Note that depending on the filenames matched, this can even inject multiple arguments into a place where normally only one argument should be. The following Python script can be used to test this:
The above will generate multiple arguments in the place of ${string}
, and if you have control over the filenames matched, it may allow you to perform some more complex attacks: