Deep Dive Injection Vulnerability
Injection Vulnerability
Introduction to Injection Flaws
What are injection flaws?
- Injection Flaws: They allow attackers to relay malicious code through the vulnerable application to another system (OS, Database server, LDAP server, etc.)
- They are extremely dangerous, and may allow full takeover of the vulnerable system.
- Injection flaws appear internally and externally as a Top Issue.
OS Command Injection
What is OS Command Injection?
- Abuse of vulnerable application functionality that causes execution of attacker-specified OS commands.
- Applies to all OSes – Linux, Windows, macOS.
- Made possible by lack of sufficient input sanitization, and by unsafe execution of OS commands.
What is the Worst That Could Happen?
- Attacker can replace file to be deleted – BAD:
1
/bin/sh -c "/bin/rm /var/app/logs/../../lib/libc.so.6"
- Attacker can inject arbitrary malicious OS command – MUCH WORSE:
1
/bin/sh -c "/bin/rm /var/app/logs/x;rm -rf /"
- OS command injection can lead to:
- Full system takeover
- Denial of service
- Stolen sensitive information (passwords, crypto keys, sensitive personal info, business confidential data)
- Lateral movement on the network, launching pad for attacks on other systems
- Use of system for botnets or cryptomining
- This is as bad as it gets, a “GAME OVER” event.
How to Prevent OS Command Injection?
Recommendation #1 – don’t execute OS commands
- Sometimes OS command execution is introduced as a quick fix, to let the command or group of commands do the heavy lifting.
- This is dangerous, because insufficient input checks may let a destructive OS command slip in.
- Resist the temptation to run OS commands and use built-in or 3rd party libraries instead:
- Instead of
rm
usejava.nio.file.Files.deleteIfExists(file)
- Instead of
cp
usejava.nio.file.Files.copy(source, destination)
… and so on.
- Instead of
- Use of library functions significantly reduces the attack surface.
Recommendation #2 – Run at the least possible privilege level
- It is a good idea to run under a user account with the least required rights.
- The more restricted the privilege level is, the less damage can be done.
- If an attacker is able to sneak in an OS command (e.g.,
rm -rf /
) he can do much less damage when the application is running astomcat
user vs. running asroot
user. - This helps in case of many vulnerabilities, not just injection.
Recommendation #3 – Don’t run commands through shell interpreters
- When you run shell interpreters like
sh, bash, cmd.exe, powershell.exe
it is much easier to inject commands. - The following command allows injection of an extra
rm
:1
/bin/sh -c "/bin/rm /var/app/logs/x;rm -rf /"
- … but in this case injection will not work, the whole command will fail:
1
/bin/rm /var/app/logs/x;rm -rf/
- Running a single command directly executes just that command.
- Note that it is still possible to influence the behavior of a single command (e.g., for
nmap
the part on the right, when injected, could overwrite a vital system file):1
/usr/bin/nmap 1.2.3.4 -oX /lib/libc.so.6
- Also note that the parameters that you pass to a script may still result in command injection:
1
processfile.sh "x;rm -rf /"
Recommendation #4 – Use explicit paths when running executables
- Applications are found and executed based on system path settings.
- If a writable folder is referenced in the path before the folder containing the valid executable, an attacker may install a malicious version of the application there.
- In this case, the following command will cause execution of the malicious application:
1
/usr/bin/nmap 123.45.67.89
- The same considerations apply to shared libraries, explicit references help avoid
DLL
hijacking.
Recommendation #5 – Use safer functions when running system commands
- If available, use functionality that helps prevent command injection.
- For example, the following function call is vulnerable to new parameter injection (one could include more parameters, separated by spaces, in
ipAddress
):1
Runtime.getRuntime().exec("/user/bin/nmap " + ipAddress) ;
- … but this call is not vulnerable:
1
Runtime.getRuntime().exec(new String[]{"/usr/bin/nmap",ipAddress});
Recommendation #6 – if possible, don’t let user input reach command execution unchanged
- Modifying user input, or replacing user-specified values with others (e.g., using translation tables) helps protect against injection.
- For example, instead of allowing a user to specify a file to delete, let them select a unique file ID:
1
action=delete&file=457
- When submitted, translate that ID into a real file name:
1 2
realName= getRealFileName(fileID); Runtime.getRuntime().exec(newString[]{"/bin/rm","/var/app/logs/"+realName});
Recommendation #7 – Sanitize user input with strict whitelist (not blacklists!)
- In products, we often see blacklists used for parameter sanitization; some of them are incorrect.
- It is hard to build a successful blacklist – hackers are very inventive.
- Suppose we want to blacklist characters used in a file name for command,
rm /var/app/logs/file
- A more robust and simpler solution is to whitelist file name as
[A-Za-z0-9.]+
What is SQL Injection?
- Abuse of vulnerable application functionality that causes execution of attacker-specified SQL queries.
- It is possible in any SQL database.
Made possible by lack of sufficient input sanitization.
Example
Dangers of SQL Injection
- Consequences of SQL injection:
- Bypassing of authentication mechanisms
- Data exfiltration
- Execution of OS commands, e.g., in Postgres:
1
COPY (SELECT 1) TO PROGRAM 'rm -rf /'
- Vandalism/DoS (e.g.,
DROP TABLE sales
) – injected statements may sometimes be chained1
SELECT * FROM users WHERE user='' ;DROP TABLE sales; --' AND pass=''
Common Types of SQL injection
- Error based
- Attacker may tailor his actions based on the database errors the application displays.
- UNION-based
- May be used for data exfiltration, for example:
SELECT name, text FROM log WHERE data='2018-04-01' UNION SELECT user, password FROM users --'
- May be used for data exfiltration, for example:
- Blind Injection
- The query may not return the data directly, but it can be inferred by executing many queries whose behavior presents one of two outcomes.
- Can be Boolean-based (one of two possible responses), and Time-based (immediate vs delayed execution).
- For example, the following expression, when injected, indicates if the first letter of the password is
a
:1
IF(password LIKE 'a%', sleep(10), 'false')
- Out of Band
- Data exfiltration is done through a separate channel (e.g., by sending an HTTP request).
How to Prevent SQL Injection?
Recommendation #1 – Use prepared statements
- Most SQL injection happens because queries are pieced together as text.
- Use of prepared statements separates the query structure from query parameters.
- Instead of this pattern:
1
stmt.executeQuery("SELECT * FROM users WHERE user='"+user+"' AND pass='"pass+"'")
- … use this:
1
PreparedStatement ps = conn.preparedStatement("SELECT * FROM users WHERE user = ? AND pass = ?"); ps.setString(1, user);ps.setString(2, pass);
- SQL injection risk now mitigated.
- Note that prepared statements must be used properly, we occasionally see bad examples like:
1
conn.preparedStatement("SELECT * FROM users WHERE user = ? AND pass = ? ORDER BY "+column);
Recommendation #2 – Sanitize user input
- Just like for OS command injection, input sanitization is important.
- Only restrictive whitelists should be used, not blacklists.
- Where appropriate, don’t allow user input to reach the database, and instead use mapping tables to translate it.
Recommendation #3 – Don’t expose database errors to the user
- Application errors should not expose internal information to the user.
- Details belong in an internal log file.
- Exposed details can be abused for tailoring SQL injection commands.
- For examples, the following error message exposes both the internal query structure and the database type, helping attackers in their efforts:
ERROR: If you have an error in your SQL syntax, check the manual that corresponds to your MySQL server version for the right syntax to use near
“x” GROUP BY username ORDER BY username ASC’ at line 1
.
Recommendation #4 – Limit database user permissions
- When user queries are executed under a restricted user, less damage is possible if SQL injection happens.
- Consider using a user with read-only permissions when database updates are not required, or use different users for different operations.
Recommendation #5 – Use stored Procedures
- Use of stored procedures mitigates the risk by moving SQL queries into the database engine.
- Fewer SQL queries will be under direct control of the application, reducing likelihood of abuse.
Recommendation #6 – Use ORM libraries
- Object-relational mapping (ORM) libraries help mitigate SQL injection
- Examples: Java Persistence API (JPA) implementations like Hibernate.
- ORM helps reduce or eliminate the need for direct SQL composition.
- However, if ORM is used improperly SQL injections may still be possible:
1
Query hqlQuery = session.createQuery("SELECT * FROM users WHERE user='"+user+"'AND pass='"+pass+"'")
Other Types of Injection
- Injection flaws exist in many other technologies
- Apart from the following, there are injection flaws also exist in Templating engines.
- … and many other technologies
- Recommendation for avoiding all of them are similar to what is proposed for OS and SQL injection.
NoSQL Injection
- In MongoDB
$where
query parameter is interpreted as JavaScript. - Suppose we take an expression parameter as input:
1
$where: "$expression"
- In simple case it is harmless:
1
$where: "this.userType==3"
- However, an attacker can perform a DoS attack:
1
$where: "d = new Date; do {c = new Date;} while (c - d < 100000;"
XPath Injection
- Suppose we use XPath expressions to select user on login:
1
"//Employee[UserName/text()='" + Request ("Username") + "' AND Password/text() = '" + Request ("Password") + "']"
- In the benign case, it will select only the user whose name and password match:
1
//Employee[UserName/text()='bob' AND Password/text()='secret']
- In the malicious case, it will select any user:
1
//Employee[UserName/text()='' or 1=1 or '1'='1' And Password/text()='']
LDAP Injection
- LDAP is a common mechanism for managing user identity information. The following expression will find the user with the specified username and password.
1
find("(&(cn=" + user +")(password=" + pass +"))")
- In the regular case, the LDAP expression will work only if the username and password match:
1
find("(&(cn=bob)(password=secret))")
- Malicious users may tweak the username to force expression to find any user:
1
find("(&(cn=*)(cn=*))(|cn=*)(password=any)")
This post is licensed under CC BY 4.0 by the author.