readFileSync浅分析
前言
前言:在刚过去的祥云杯中,web类型题目有一个rustwaf的题目(corCTF 2022 simplewaf 改编而来),其中有个关于readFileSync的trick,这里分析一下
源码分析
看下官方文档对readFileSync的解释,注意看,path可以是字符串,Buffer类对象,URL类对象等等
调用链
1 | fs.readFileSync |
node/fs.js at v18.x · nodejs/node (github.com)
lib/fs.js,查看readFileSync的源码,其调用了fs.openSync,并将path和options作为参数传入
跟进fs.openSync(lib/fs.js),其调用了getValidatedPath函数,将path作为参数传入
跟进getValidatedPath(/lib/internal/fs/utils.js),根据函数名,也就是获取路径的意思
这里调用了toPathIfFileURL,将path传入作为参数,字面意思(如果是URL实例,就转换为路径)
跟进toPathIfFileURL(lib/internal/url.js),如果不是URL实例,就直接返回fileURLOrPath
;如果是URL实例,就返回fileURLToPath(fileURLOrPath);
我们跟进isURLInstance(/lib/internal/url.js)
看下是怎么判断是否为URL实例的
我们发现判断是否为URL实例的依据就是是否含有href和origin属性
,所以我们添加这两个属性之后就可以伪造URL实例
而判断URL实例成功后,则返回fileURLToPath(fileURLOrPath)
,跟进(/lib/internal/url.js)
发现需要path.protocol为file:
,然后根据操作系统,调用对应的函数
我们看下getPathFromURLPosix(url)
hostname属性需要为空,然后对pathname进行url解码
调试分析
为什么一开始没有源码分析呢?
因为刚开始从readFileSync函数下断点,进不去函数里面,后来发现了一篇文章corCtf2022一道有意思的node题 - 腾讯云开发者社区-腾讯云 (tencent.com),配了下环境,就可以了,就是把skipFiles中node_internals给注释掉
前面的跳过,主要看最后的
for循环用于检验传入的URL实例中的属性 pathname
中是否包含 url编码后的 /
,若包含则抛出一个异常
在1410行,将传入的URL实例中 pathname
中的值进行url解码并返回
这也就是最终fs.openSync函数中最终获取的path
payload
所以最后该json实例需要满足如下条件:
- .href exists
- .origin exists
- .protocol === ‘file:’
- .hostname === ‘’
- .pathname is
/app/flag.txt
这里我们知道了传入之后,其会进行一次url解码