背景介绍
参加2017 NJCTF比赛时碰见了一道NodeJS的web题,之前也没学过NodeJS, 于是上网搜了一下,搜到了原题 https://www.smrrd.de/nodejs-hacking-challenge-writeup.html, 发现NJCTF在原题基础上改了入口代码,虽说在github上能搜到改过的原题,倒不如直接给源码来的痛快,这里就不提改过的题目了,直接分析原题,其中有几个点还是值得好好学习的。
环境搭建
安装好nodejs的环境,切换到源码更目录,安装依赖包npm install
, 运行npm start run
, 然后访问本机http://localhost:3000
.
关键点分析
- post 请求
/admin
页面提交password
,会向/login
发送一个JSON类型的数据。
而NJCTF的题目更改了发送请求,直接发送的POST的数据(e.g. “password=…”),可以通过代理工具,更改发送请求类型,发送JSON类型的数据,以后做测试时要考虑服务器是否接受发送JSON类型的请求,如果接受,可以很好的扩大发送数据的类型。
服务器响应头返回Cookie设置session
和session.sig
,而session
明显是base64编码过,解码为{"admin":"no"}
,由于有session.sig
的校验,单纯改session
的值是无效的,要实现成功伪造session
值,必须获得config.js
配置的session_keys
的值,然后本地搭建,获取session.sig
.
- 内存泄露
session_keys
1 | router.post('/login', function(req, res, next) { |
index.js
中根据用户提交的password
生成新的Buffer对象,当password
为字符串类型时,会生成同等大小的内存块,而当password
为数字类型时,则生成指定大小的内存块, 而且Buffer返回的并不是全是0的内存块,而是之前在堆上分配的数据,这样就可以泄露内存数据,获取源码和数据。
1 | > Buffer('AAAA') |
令password=100(整数,也可以是更大的数,泄露出更多的数据), 多次重复发送post请求,会泄露出想要的session_keys: ALLES{session_key_K.GKQeR0JS2b9OhwSH#UdMhL4EddxeD?}
1 | curl http://xxx.xxx.xxxx.xxx:3000/login -X POST -H "Content-Type: application/json" --data "{\"password\": 100}" | hexdump -C |
于是本地搭建环境,更改conf.js的session_keys
, 然后更改app.js
,强制令req.session.admin = 'yes'
, 就可以获取了有效的session
和session.sig
.
1 | app.use(function(req, res, next) { |
伪造cookie访问目标网站即可。
