前言
nodejs 8.12.0版本的请求拆分攻击(感觉现在叫http走私要好一点2333),pug模板的注入导致rce
0x01 首页
当我们访问http://web2.ctf.nullcon.net:8081/后会显示下面的页面。

由于上面没有什么特点,url参数,交互框等,因此我们查看源代码看看有没有什么提示。
通过源码(F12查看的)我们可以看到它在页面加载js代码完成后发送了个ajax请求:
1 | var xhttp = new XMLHttpRequest(); |
我使用get请求发送/core?q=1,但是结果跟上面的首页是一样的只有一个动图,这时你可能会想会不会是sql注入,服务器端注入等,但是经过一系列的反恐尝试之没有什么用。
但是在我们查看源代码的时候还给了个提示<!-- /source -->通过访问/source可以获取题目源码。
1 | //node 8.12.0 |
0x02 代码分析
通过阅读上面的代码,我们可以看到node的版本是8.12.0,服务器端使用的框架是express,使用nodejs自带的http包发送某些请求,服务端使用pug作为渲染模板(原理加jade)。
在没有发现漏洞之前,先梳理一下代码的流程:
1./:
使用sendFile来读取index.html页面并且渲染该页面,通过前面我们知道该页面有提示的内容。
2./source:
该页面返回了服务器端的全部代码。
3./getMeme:
该页面没有什么用就是返回了一个iframe框架,其中是个动图。
4./flag:
这里验证远程地址包含127.0.0.1,adminauth===secretpassword,headers头中必须包含pug字段并且其值不能包含小写字母,最后会用pug引擎渲染pug,但是这里在渲染容易受到服务器端注入攻击https://zhuanlan.zhihu.com/p/28823933,由此我们可以断定前面需要用SSRF结合CRLF来绕过,不由联想到node的版本号,因为该版本存在request splitting漏洞。
pug模板注入示例:
1 | const pug=require('pug'); |
结果如下:
1 | 1 |
对于pug模板的相关知识可以参考如下链接:
https://pugjs.org/language/interpolation.html
通过动态的调试我们可以看到代码的拼接过程:
1 | var runtime = require('./'); |
到:
1 | (function anonymous(pug |
上面的这段代码中的template函数就是通过Function来构造的,代码拼接进去的部分就是\u003C后面的console.log("1")和\u003E前面的console.log("1"),拼接了两个console.log("1")这就是,然后在函数运行的时候就会执行console.log("1")。
我们可以看到代码拼接进去了,结合上面两段代码简化一下就是:
1 | const t=Function('pug','function template(locals) {(console.log(locals))}'+'\n' + |
request splitting漏洞代码示例:
1 | const http = require('http') |
结果如下:
1 | listening on [any] 8000 ... |
由上面的结果可知我们已经成功实现了CRLF注入(上面的显示:为%7B %7D可能是我kali的问题)。
接下来我们需要看那里调用了http.get导致SSRF。
5./core
这里的q是我们可控的,而且这里使用了http.get来发起请求刚好满足我们上面的条件,但是构造的url中不能有["global", "process","mainModule","require","root","child_process","exec","\"","'","!"]字符串,我们可以对代码进行jsfuck加密绕过,但是由于加密后的代码太大,请求量会很大,因此一般用js的匿名函数来绕过,且字母我们可以用8进制,16进制来代替,例如:
1 | []['map']['constructor']('alert(1)')(); |
构造的脚本如下:
1 | function stringToHex(str,mode=8){ |
上面的原理相当于构造了个new Function("alert(1)")();,由于Object的constructor是指向Function的,示例如下:
1 | //我们可以使用以下方式创建一个函数: |
代码我们也梳理了一遍,现在我们来看看怎么rce拿到flag。
0x03 利用过程:
solve.py
1 | # coding=UTF-8 |