[GYCTF2020]Ez_Express
首页一个登录框和一个提示框,提示框内容:
友情提示
如果您还不是会员,请注册
用户名只支持大写
请使用ADMIN登录
在Node.js 常见漏洞学习与总结文章中描述了javascript大小写特性:
对于toUpperCase(): 字符
"ı"
、"ſ"
经过toUpperCase处理后结果为"I"
、"S"
\对于toLowerCase(): 字符
"K"
经过toLowerCase处理后结果为"k"
(这个K不是K)
注册账号ADMıN
之后,又给了一个提示框:
Hint: Hello,ADMIN ,flag in /flag
且源码提示/www.zip
存在源码泄露。
审计一波,在index.js代码文件发现了merge函数,Node.js 常见漏洞学习与总结文章中同样总结merge函数,考点是原型链污染。
继续寻找,路由/action
中调用了merge函数:
|
|
但是这里并没有执行命令和回显字段的函数,所以继续向下寻找,在/info
找到了利用点:
|
|
老朋友render
,将内容渲染到index,且
|
|
我们可以利用这个去实现污染,抓包/action
,将Content-Type改成application/json
,发送payload。
payload
|
|
疑问:
- 为什么第一个payload中的
t=1;
不加就会报语法错误,不知道是不是只有return导致函数结构不完整(加了t=1;
也不完整。。。);(未解决) execSync
用exec
替代时会回显[object Object]
,而该对象的属性中并没有执行我们传入的的系统命令。
两个函数在Nodejs文档中这样介绍:
child_process.exec() 返回:<ChildProcess>
child_process.execSync() 返回:<Buffer>
|<string>
命令的 stdout。
[HFCTF2020]JustEscape
主页面提示信息:
真的是 PHP 嘛 \
再结合前面的new%20Date()
,本地php尝试一波发现不存在Date类(不排除出题人定义了一个Date类,但是这样不是浪费时间嘛),百度一下new%20Date()
,输出的都是Js的内容,应该确定了考点就是Js。
接下来访问run.php
,得到源码:
|
|
看到这有点迷惑,难道猜错了?搜了一下才知道原来Js也有eval函数,现在完全确定这就是Js。
输入引号后回显hacking,存在waf,就不fuzz了。参考Node.js code injection (RCE)数组绕过方法,使用常规payload:require('child_process').exec('ls');
,回显ReferenceError: require is not defined
,没思路了,看wp。
输入Error().stack
,回显错误信息:
VM.run (/app/node_modules/vm2/lib/main.js:219:62)
研究一下为什么会用Error().stack
:
Error().stack
可以分为两个过程:
- 实例化Error类
- 调用stack方法
同理,
new Error().stack
也能够回显相同内容。
介绍一下Error类
:
Error 对象会捕获堆栈跟踪,详细说明实例化 Error 的代码点,并可能提供错误的文本描述。
详细说明实例化 Error 的代码点这个功能提供了返回代码信息甚至文件信息的可能性。
接下来介绍stack属性
:
Error.captureStackTrace(targetObject[, constructorOpt])
方法在 targetObject 上创建一个.stack 属性
,当访问时返回一个表示代码中调用 Error.captureStackTrace() 的位置的字符串。
也就是说当我们实例化Error类并调用stack属性时,我们会得到调用 Error.captureStackTrace() 的位置的字符串,也就是代码的部分信息。
言归正传,从回显内容我们能发现使用的是vm2
,上payload:
|
|
[HITCON 2016]Leaking
|
|
主页面GET传参data,通过数组绕过长度判断。
方法一 - vm2逃逸
用[HFCTF2020]JustEscape
的payload就行,
payload
|
|
方法二 - Buffer读取
低版本的node可以使用buffer()来查看内存,只要调用过的变量,都会存在内存中,那么我们可以构造paylaod读取内存。
|
|