type
status
date
slug
summary
tags
category
icon
password
web342 很刺激 (
感觉对原型链污染理解又加深了呢~
web334 JS 大小写特性
搜集了半天信息,发现题目描述处有源码可以直接下载。。
user.js
login.js
即满足
我们输入的
name
不为 CTFSHOW
然后 name
转换后的大写为 CTFSHOW
,密码为 123456
即可。![notion image](https://www.notion.so/image/https%3A%2F%2Fs3-us-west-2.amazonaws.com%2Fsecure.notion-static.com%2Fd47b9af3-75a3-4c6d-b7ab-f5d1cb94a16b%2FUntitled.png?table=block&id=4298baae-ba8a-4995-8163-b1136be1e3fa&t=4298baae-ba8a-4995-8163-b1136be1e3fa&width=1500&cache=v2)
网上看了一下,其实想要的考点是
toUpperCase()
函数,字符 ı 会转变为 I ,字符 ſ 会变为 S 。toLowerCase()
函数中,字符 İ 会转变为 i ,字符 K 会转变为 k 。可以参考
这样的应该是,比如字符
s
或 S
不能出现在输入字符中就好了。web335 RCE
f12 源码提示
即简单命令执行
获取 flag
![notion image](https://www.notion.so/image/https%3A%2F%2Fs3-us-west-2.amazonaws.com%2Fsecure.notion-static.com%2Fb3fd8713-9d65-4707-9f81-9299cd10168e%2FUntitled.png?table=block&id=0194f444-b768-4f7f-86e9-25d3fe4bc87c&t=0194f444-b768-4f7f-86e9-25d3fe4bc87c&width=1500&cache=v2)
web336 RCE 黑名单绕过
f12 源码提示
即简单命令执行
获取 flag
emm 好像就 flag 文件换了个名字?
顺便收集多几个命令执行
收集过程中发现,原来第 2、3 个 被禁了,2333 原来考察黑名单
先通过全局变量读取当前目录位置
![notion image](https://www.notion.so/image/https%3A%2F%2Fs3-us-west-2.amazonaws.com%2Fsecure.notion-static.com%2F46dee939-fdf4-4e18-8951-5e058923b8d4%2FUntitled.png?table=block&id=016de793-f79c-4df3-85ce-e242fdad8c42&t=016de793-f79c-4df3-85ce-e242fdad8c42&width=1500&cache=v2)
当前目录
读文件
发现过滤了exec和load
![notion image](https://www.notion.so/image/https%3A%2F%2Fs3-us-west-2.amazonaws.com%2Fsecure.notion-static.com%2Fbd7bc86b-f5f3-4901-9cd3-d89d6008f5cb%2FUntitled.png?table=block&id=d775d3dc-4ff2-479e-8a6c-1779e4a4fdca&t=d775d3dc-4ff2-479e-8a6c-1779e4a4fdca&width=1500&cache=v2)
绕过方法
因为
require('child_process')
方法返回一个对象,可以通过类型 Python数组的方式去访问里面的成员。或者用其他模块读文件
当然还有其他姿势,比如变量拼接在执行
2023.11.6 更,发其他师傅那get到一种新姿势
![notion image](https://www.notion.so/image/https%3A%2F%2Fprod-files-secure.s3.us-west-2.amazonaws.com%2Fb88d1a4f-cef8-46ec-858e-97919b467a56%2F5fc86ba8-0c63-4bce-b109-356f266de5ac%2FUntitled.png?table=block&id=5df6e837-581c-4303-9a76-971a856de148&t=5df6e837-581c-4303-9a76-971a856de148&width=804&cache=v2)
web337 md5绕过
和 PHP 一样,数组绕过即可
![notion image](https://www.notion.so/image/https%3A%2F%2Fs3-us-west-2.amazonaws.com%2Fsecure.notion-static.com%2F4373c590-697e-4649-a316-976f43973962%2FUntitled.png?table=block&id=3dff35db-fb0d-48f7-8009-8344819e68ef&t=3dff35db-fb0d-48f7-8009-8344819e68ef&width=1498&cache=v2)
发现这样更易于理解
payload:
a[x]=1&b[x]=2
运行一下代码
![notion image](https://www.notion.so/image/https%3A%2F%2Fs3-us-west-2.amazonaws.com%2Fsecure.notion-static.com%2Fa12c4e6f-4c10-4291-a624-4880dabeda81%2FUntitled.png?table=block&id=fe762ec3-88ba-4522-ba30-cf3556b11dbe&t=fe762ec3-88ba-4522-ba30-cf3556b11dbe&width=472&cache=v2)
web338 原型链污染
题目描述处蓝奏云下载源码
先看看这篇文章了解一波什么是 JS 的原型链污染
关键代码
utils/common.js
routes/login.js
也就是说,我们不用关心
secert
是否有 ctfshow
这个属性,因为当它找不到这个属性时,它会从它自己的原型里找。这里的
secert
是一个数组,然后 utils.copy(user,req.body);
操作是 user
也是数组,也就是我们通过 req.body
即 POST 请求体传入参数,通过 user
污染数组的原型,那么 secert
数组找不到 ctfshow
属性时,会一直往原型找,直到在数组原型中发现 ctfshow
属性值为 36dboy
。那么 if
语句即判断成功,就会输出 flag 了。payload
![notion image](https://www.notion.so/image/https%3A%2F%2Fs3-us-west-2.amazonaws.com%2Fsecure.notion-static.com%2F8b703424-04c8-4b0d-b16e-a12f71ab90ca%2FUntitled.png?table=block&id=3491f131-f5f6-4db9-ac3f-190813dadf01&t=3491f131-f5f6-4db9-ac3f-190813dadf01&width=1500&cache=v2)
一般遇到这种整套代码,特别是带有 package.json 的,可以尝试 snyk ,
![notion image](https://www.notion.so/image/https%3A%2F%2Fs3-us-west-2.amazonaws.com%2Fsecure.notion-static.com%2Ff5f7564d-f1ab-4e02-b34d-89488e38ec70%2FUntitled.png?table=block&id=0c601146-8848-4581-b47b-77fab4509a85&t=0c601146-8848-4581-b47b-77fab4509a85&width=1500&cache=v2)
发现个
ejs
的 RCE先污染参数
![notion image](https://www.notion.so/image/https%3A%2F%2Fs3-us-west-2.amazonaws.com%2Fsecure.notion-static.com%2Fab7dd196-ad9e-44f3-82e9-0d576691cb54%2FUntitled.png?table=block&id=881070ef-74ea-4f21-bfac-52b56adae353&t=881070ef-74ea-4f21-bfac-52b56adae353&width=1500&cache=v2)
然后随便请求一下,触发
render
方法![notion image](https://www.notion.so/image/https%3A%2F%2Fs3-us-west-2.amazonaws.com%2Fsecure.notion-static.com%2Fff111290-cb95-4183-9445-48c7b10c86a5%2FUntitled.png?table=block&id=619f3efb-2600-4370-91bc-57033e199b7e&t=619f3efb-2600-4370-91bc-57033e199b7e&width=1500&cache=v2)
成功反弹 shell
![notion image](https://www.notion.so/image/https%3A%2F%2Fs3-us-west-2.amazonaws.com%2Fsecure.notion-static.com%2Fa1e7d163-5f98-4313-b9ca-1233820b7512%2FUntitled.png?table=block&id=fe8c46d7-e28b-479e-b8ed-b12447f0ba64&t=fe8c46d7-e28b-479e-b8ed-b12447f0ba64&width=1228&cache=v2)
不过 snyk 给出的 poc 用
filename
参数利用好像有点问题, 不太清楚为啥。。即顺便记录一下 node 项目本地启动方法,在项目文件运行下面命令即可。
![notion image](https://www.notion.so/image/https%3A%2F%2Fs3-us-west-2.amazonaws.com%2Fsecure.notion-static.com%2Fa4e05efc-9459-4243-9d0c-9d34d128ccfe%2FUntitled.png?table=block&id=d89982ca-7f2d-46ac-bb07-eb9009aa5137&t=d89982ca-7f2d-46ac-bb07-eb9009aa5137&width=814&cache=v2)
默认端口为
3000
web339 原型链污染 +
node/v10.19.0
题目描述处蓝奏云下载源码
和 web338 有点相似,不过不同点是
flag
是变量,具体值不知然后还多了个
api.js
,主要关注这行是不是和 web338 里的参考链接 PHITHON 师傅出的 Code-Breaking 2018 Thejs 如出一辙?即可以 RCE,因为这里可污染点存在的匿名函数调用
![notion image](https://www.notion.so/image/https%3A%2F%2Fs3-us-west-2.amazonaws.com%2Fsecure.notion-static.com%2F9e1ee865-6326-45d3-ad5c-46fdffc1c4cd%2FUntitled.png?table=block&id=65766466-d4d5-47cf-aeff-16e538a88c09&t=65766466-d4d5-47cf-aeff-16e538a88c09&width=1052&cache=v2)
仿照题目中的代码,先写个小demo
![notion image](https://www.notion.so/image/https%3A%2F%2Fs3-us-west-2.amazonaws.com%2Fsecure.notion-static.com%2Fe034a55f-eec9-4ed0-8a63-23c3d464e5cf%2FUntitled.png?table=block&id=9b48996d-28ee-4716-a4e8-457f99355f96&t=9b48996d-28ee-4716-a4e8-457f99355f96&width=1000&cache=v2)
为什么
query
的值是 2233
呢?也就是为啥会被调用了呢?首先看看
query
值是如何被改变的,其实就是通过 web338 的原型链污染,即 JS 中所有的对象的原型都可以继承到 Object
,然后终点是 null
对象![notion image](https://www.notion.so/image/https%3A%2F%2Fs3-us-west-2.amazonaws.com%2Fsecure.notion-static.com%2Fc0672811-51a1-4c1c-b808-97d639a9cff7%2FUntitled.png?table=block&id=5ad7d525-1c8a-480f-95b8-7797bb89385e&t=5ad7d525-1c8a-480f-95b8-7797bb89385e&width=1500&cache=v2)
如 web338 中所说的,当在当前上下文找不到相应对象时,会遍历
Object
对象是否存在相应的属性。![notion image](https://www.notion.so/image/https%3A%2F%2Fs3-us-west-2.amazonaws.com%2Fsecure.notion-static.com%2Fcf291f55-5624-487c-bdd9-d6be1b15c04e%2FUntitled.png?table=block&id=c7f5584c-0e94-422d-9095-508f29489581&t=c7f5584c-0e94-422d-9095-508f29489581&width=450&cache=v2)
到这里就很清楚的知道了,为什么
query
的值是 "return 2233"
,因为在调用 copy
时,原型链被污染了。至于
{ query: Function(query)(query)}
为何为 { query: 2233 }
JS 的函数实际上都是一个
Function
对象,它的参数为写个小demo
![notion image](https://www.notion.so/image/https%3A%2F%2Fs3-us-west-2.amazonaws.com%2Fsecure.notion-static.com%2Fd40877b3-1f54-466f-9f9c-7cf5ebb102d3%2FUntitled.png?table=block&id=1f8cda76-cb7c-4570-9889-58e07b9348b5&t=1f8cda76-cb7c-4570-9889-58e07b9348b5&width=488&cache=v2)
即
Function
对象传入构造函数里的前面参数是函数的形参,当然可以省略,最后的形参写函数体。其实作用和
eval
有点类似,详细可以看至此,利用思路明确了,只要污染了
query
对象,就可以执行任意我们想执行的代码,比如反弹个 shell 再获取 flag ~然后污染点和 web338 一致,在
login.js
里的 utils.copy(user,req.body);
,代码执行的触发点在 api.js
的 res.render('api', { query: Function(query)(query)});
处。payload ,这里用 nodejs 原生 socket,防止因系统运行环境问题 shell 弹不回来,这里服务器的监听端口为
2233
,然后如何是 windows 系统就把 /bin/sh
换成 cmd.exe
应该就可以了。先本地试试,这里服务器监听端口为
2233
![notion image](https://www.notion.so/image/https%3A%2F%2Fs3-us-west-2.amazonaws.com%2Fsecure.notion-static.com%2F7f6d6c3e-f133-4197-b914-766e499c1e05%2FUntitled.png?table=block&id=84e0c0c9-30e6-4ec5-95de-bec48f5559c5&t=84e0c0c9-30e6-4ec5-95de-bec48f5559c5&width=1500&cache=v2)
![notion image](https://www.notion.so/image/https%3A%2F%2Fs3-us-west-2.amazonaws.com%2Fsecure.notion-static.com%2F5a096d5e-b385-4b7d-8f00-81edb09bdffc%2FUntitled.png?table=block&id=e17d0586-007c-4ac4-9697-a6316ffd99ef&t=e17d0586-007c-4ac4-9697-a6316ffd99ef&width=764&cache=v2)
ok,没啥大问题。
先 POST 一下
login
接口,污染 query
对象![notion image](https://www.notion.so/image/https%3A%2F%2Fs3-us-west-2.amazonaws.com%2Fsecure.notion-static.com%2F5fd4dca0-4032-4c85-9ebe-6cfd834d311b%2FUntitled.png?table=block&id=6fbc1388-369b-49f7-b3f0-0d619d8b1481&t=6fbc1388-369b-49f7-b3f0-0d619d8b1481&width=1500&cache=v2)
然后直接 POST 一下
api
接口即可。emm,发现不行,之后访问
/login
和 /api
接口都是 404 找不到文件
,shell 也反弹不回来。试试别人的
![notion image](https://www.notion.so/image/https%3A%2F%2Fs3-us-west-2.amazonaws.com%2Fsecure.notion-static.com%2F0d2743ba-b570-4670-bc9a-7a47275d9419%2FUntitled.png?table=block&id=fee3527f-c3ab-4a1e-b3f5-96fe6fe40e02&t=fee3527f-c3ab-4a1e-b3f5-96fe6fe40e02&width=1500&cache=v2)
![notion image](https://www.notion.so/image/https%3A%2F%2Fs3-us-west-2.amazonaws.com%2Fsecure.notion-static.com%2F8f2cbe9e-4a41-4137-ad30-08f3c6592a02%2FUntitled.png?table=block&id=3b815d02-4fe8-4400-839c-4c9460e8184b&t=3b815d02-4fe8-4400-839c-4c9460e8184b&width=1500&cache=v2)
flag
![notion image](https://www.notion.so/image/https%3A%2F%2Fs3-us-west-2.amazonaws.com%2Fsecure.notion-static.com%2F243ff7ed-0e8c-49e3-a530-45e6d12cfdda%2FUntitled.png?table=block&id=06ddc091-68fe-4760-8774-355ab095ed22&t=06ddc091-68fe-4760-8774-355ab095ed22&width=964&cache=v2)
仔细对比了一下,发现了,感觉是命名空间问题,即
require
可能不被识别,尝试把 require 改为 global.process.mainModule.constructor._load
,同样服务器监听端口为 2233
也是先 POST /login 接口污染
query
对象![notion image](https://www.notion.so/image/https%3A%2F%2Fs3-us-west-2.amazonaws.com%2Fsecure.notion-static.com%2Fad2676e0-496e-44de-bd30-ee22df2e424e%2FUntitled.png?table=block&id=b9294665-d267-4870-b232-06fcbb0e5100&t=b9294665-d267-4870-b232-06fcbb0e5100&width=1500&cache=v2)
访问下 /api 接口
![notion image](https://www.notion.so/image/https%3A%2F%2Fs3-us-west-2.amazonaws.com%2Fsecure.notion-static.com%2Fbdcfbe81-a65f-41fc-96d4-8aa346b95d73%2FUntitled.png?table=block&id=3c36a984-646e-41d0-afa5-8585037e52ba&t=3c36a984-646e-41d0-afa5-8585037e52ba&width=1500&cache=v2)
反弹 shell 并获取 flag
![notion image](https://www.notion.so/image/https%3A%2F%2Fs3-us-west-2.amazonaws.com%2Fsecure.notion-static.com%2F991efd93-3a95-4f40-a58b-1015b3eb7667%2FUntitled.png?table=block&id=43c65180-a70d-4c42-9dc3-eb800cec9d17&t=43c65180-a70d-4c42-9dc3-eb800cec9d17&width=960&cache=v2)
然后顺便翻了个链接,好像确实如此~
因为 node 是基于 chrome v8 内核的,运行时,压根就不会有
require
这种关键字,模块加载不进来,自然 shell 就反弹不了了。但在 node交互环境,或者写 js 文件时,通过 node 运行会自动把 require
进行编译。还有一个其他解,见 web338 中的
ejs
RCE,一样的EXP、步骤和利用方式web340 原型连污染 ++
nodejs/v10.19.0
题目描述处蓝奏云下载源码
提取关键部分
![notion image](https://www.notion.so/image/https%3A%2F%2Fs3-us-west-2.amazonaws.com%2Fsecure.notion-static.com%2Fc6fa15e7-ed38-4184-b078-9ecaf81c2db3%2FUntitled.png?table=block&id=29e74835-046f-41ea-8cb5-4233aedaa969&t=29e74835-046f-41ea-8cb5-4233aedaa969&width=814&cache=v2)
发现
userinfo
的原型不是 Object
对象, userinfo.__proto__.__proto__
才是 Object
对象。和 web339 一样,只不过要套两层才能污染
Object
对象,同样用原生 socket,服务端监听端口为 2233
(同样 POST 一下 /login 接口污染
query
对象![notion image](https://www.notion.so/image/https%3A%2F%2Fs3-us-west-2.amazonaws.com%2Fsecure.notion-static.com%2F0bf4a314-95a2-43ef-8b56-4044e8ab1249%2FUntitled.png?table=block&id=491bcfc1-2745-4ea0-974c-7f8cad17118c&t=491bcfc1-2745-4ea0-974c-7f8cad17118c&width=1500&cache=v2)
POST 一下 /api 接口触发
![notion image](https://www.notion.so/image/https%3A%2F%2Fs3-us-west-2.amazonaws.com%2Fsecure.notion-static.com%2F9c91e85e-986a-48f6-afb9-9c736457a537%2FUntitled.png?table=block&id=08e7191d-48cf-40b7-b9f2-2991b0fbedb7&t=08e7191d-48cf-40b7-b9f2-2991b0fbedb7&width=1500&cache=v2)
获取 flag
web341 原型链污染 +++
题目描述处蓝奏云下载源码
这题和其他不同的是没有
/api
接口触发污染点了,所以使用 web338 中的 ejs
RCE。然后像 web340 一样污染要套两层。下面 EXP 也服务器监听端口是
2233
同样 POST 一下 /login 接口污染数据
![notion image](https://www.notion.so/image/https%3A%2F%2Fs3-us-west-2.amazonaws.com%2Fsecure.notion-static.com%2Fcdf73428-6991-4667-8d18-77771389d878%2FUntitled.png?table=block&id=d878eb8b-5184-4bd7-ba3c-60572e6c63be&t=d878eb8b-5184-4bd7-ba3c-60572e6c63be&width=1500&cache=v2)
然后请求一个会调用
render
方法的接口![notion image](https://www.notion.so/image/https%3A%2F%2Fs3-us-west-2.amazonaws.com%2Fsecure.notion-static.com%2Faff9544b-1b06-45e5-a74c-324b1d86c9c6%2FUntitled.png?table=block&id=2136a2f5-9803-47f4-804a-990f9bc24ccc&t=2136a2f5-9803-47f4-804a-990f9bc24ccc&width=1500&cache=v2)
即可获得 flag
![notion image](https://www.notion.so/image/https%3A%2F%2Fs3-us-west-2.amazonaws.com%2Fsecure.notion-static.com%2F2a22ec96-8798-46b6-b0eb-4f5daa2ef62a%2FUntitled.png?table=block&id=3d3a86a3-1d06-47fd-a8c0-d7482ec382f5&t=3d3a86a3-1d06-47fd-a8c0-d7482ec382f5&width=742&cache=v2)
web342 原型链污染 ++++
题目描述处蓝奏云下载源码
然后还有个提示
审计了1个小时发现的,此链目前网上未公开,难度稍大
本题就不是用
ejs
进行模板渲染了,而是使用了 jade
一开始想看其他师傅的文章
https://xz.aliyun.com/t/7025
emm,但是发现说的每个字都认识,连起来就觉得有点莫名其妙了。。于是想着先自己手动分析一下,熟悉一波,方便自己和师傅在同一个频道上,防止师傅说的每句话都感觉莫名其妙…
详细的断点分析参考
这里用 VS Code 来 debug 分析
![notion image](https://www.notion.so/image/https%3A%2F%2Fs3-us-west-2.amazonaws.com%2Fsecure.notion-static.com%2F6a564b6e-9203-4d96-9e49-3417db1998bc%2FUntitled.png?table=block&id=2d258e9c-7598-465b-ab8c-5c5f65486017&t=2d258e9c-7598-465b-ab8c-5c5f65486017&width=1056&cache=v2)
就会自动创建这样一个文件
然后下个断点,运行一下,访问网页就可以开始愉快的 debug 了
![notion image](https://www.notion.so/image/https%3A%2F%2Fs3-us-west-2.amazonaws.com%2Fsecure.notion-static.com%2F02f4f7cb-955a-4095-b66b-6e25d063d94f%2FUntitled.png?table=block&id=4767a133-1b4e-4f78-ad0c-424f2d80d455&t=4767a133-1b4e-4f78-ad0c-424f2d80d455&width=1500&cache=v2)
这里直接用 ctfshow web342 的代码进行
![notion image](https://www.notion.so/image/https%3A%2F%2Fs3-us-west-2.amazonaws.com%2Fsecure.notion-static.com%2F13cd744d-fed7-4046-ab9e-d51dac1a1f32%2FUntitled.png?table=block&id=b92e588b-632c-4405-bb12-54a0be0ed2c2&t=b92e588b-632c-4405-bb12-54a0be0ed2c2&width=1500&cache=v2)
依次进入
res.render=>app.render=>tryRender=>view.render=>this.engine
![notion image](https://www.notion.so/image/https%3A%2F%2Fs3-us-west-2.amazonaws.com%2Fsecure.notion-static.com%2Fca7aa008-f8a8-4784-a2a4-dae82c1a9a32%2FUntitled.png?table=block&id=fce3cc99-badd-4e74-baec-621a79d5a919&t=fce3cc99-badd-4e74-baec-621a79d5a919&width=1500&cache=v2)
入口是
rederFile
方法,注意 renderFile
函数返回值可执行![notion image](https://www.notion.so/image/https%3A%2F%2Fs3-us-west-2.amazonaws.com%2Fsecure.notion-static.com%2F150fb014-5e14-4357-a263-ae8dc7cf9318%2FUntitled.png?table=block&id=00590fad-b165-48b9-b0d0-844f15ad199d&t=00590fad-b165-48b9-b0d0-844f15ad199d&width=1500&cache=v2)
进入
handleTemplateCache
![notion image](https://www.notion.so/image/https%3A%2F%2Fs3-us-west-2.amazonaws.com%2Fsecure.notion-static.com%2F8305daba-0655-4d4c-84a8-208863d66580%2FUntitled.png?table=block&id=7bec1afa-4837-4be5-acea-4258389bacf2&t=7bec1afa-4837-4be5-acea-4258389bacf2&width=1500&cache=v2)
进入
compile
函数![notion image](https://www.notion.so/image/https%3A%2F%2Fs3-us-west-2.amazonaws.com%2Fsecure.notion-static.com%2Fe9f7967a-7b8d-4c6c-b216-b7012984cfc3%2FUntitled.png?table=block&id=df752b10-e2c6-4042-8a4f-b1ae57b20195&t=df752b10-e2c6-4042-8a4f-b1ae57b20195&width=1500&cache=v2)
205行 有个
parse
解析,可以看到结果返回到 parsed
,又传递给了 fn
,先不管 parse
方法,继续向下看代码218行 这里就比较有趣了,有个看似可控的代码执行(new Function,这个在 web339 有提到)
进入
parse
看看返回值中是否有可控部分![notion image](https://www.notion.so/image/https%3A%2F%2Fs3-us-west-2.amazonaws.com%2Fsecure.notion-static.com%2Fd6e68a9b-f566-474a-a7ac-55e0ae7f700b%2FUntitled.png?table=block&id=ee61e877-c2ec-43cd-b301-f98bb90424d1&t=ee61e877-c2ec-43cd-b301-f98bb90424d1&width=1500&cache=v2)
parse
方法内部可以看到先内部 parse
再内部 compile
,内部 parse
结果最终会被拼接到外层 parse
函数返回值部分即 114行的
js对象
被拼接到 148行 或 149行的 js对象
里,最终拼接到 body键
返回![notion image](https://www.notion.so/image/https%3A%2F%2Fs3-us-west-2.amazonaws.com%2Fsecure.notion-static.com%2F6bceb85f-a321-4e62-89c4-f84f58b0860b%2FUntitled.png?table=block&id=10fa7e02-f150-46df-8d0e-be6de49ec416&t=10fa7e02-f150-46df-8d0e-be6de49ec416&width=1288&cache=v2)
先跟进
114行
的 compile
方法,发现本方法返回的是 buf
![notion image](https://www.notion.so/image/https%3A%2F%2Fs3-us-west-2.amazonaws.com%2Fsecure.notion-static.com%2F70556c81-9a00-4a34-a9e5-41f02c1446ca%2FUntitled.png?table=block&id=5b9dc5f7-fa23-4a80-8f88-e8bb13cfd22a&t=5b9dc5f7-fa23-4a80-8f88-e8bb13cfd22a&width=1500&cache=v2)
跟进 66行的
this.visit(this.node);
![notion image](https://www.notion.so/image/https%3A%2F%2Fs3-us-west-2.amazonaws.com%2Fsecure.notion-static.com%2F1eacde71-32d1-4f47-8560-09b85653bc52%2FUntitled.png?table=block&id=0962b941-3665-41af-8002-84ef89ba00bd&t=0962b941-3665-41af-8002-84ef89ba00bd&width=1500&cache=v2)
发现可控(因为
node.filename
被 utils.stringify()
了)的 node.line
可以被 push
到 buf
中,条件是 this.debug=true
然后在 212行的
this.visitNode(node);
去遍历 ast 树,遍历完后回到 compile
方法![notion image](https://www.notion.so/image/https%3A%2F%2Fs3-us-west-2.amazonaws.com%2Fsecure.notion-static.com%2F23ab9cda-1507-4e44-bafc-b439dd8bf7e2%2FUntitled.png?table=block&id=3313be04-83f0-458f-94a6-e3a92c2d0edc&t=3313be04-83f0-458f-94a6-e3a92c2d0edc&width=1500&cache=v2)
可以看到
node.line
被记录到 fn 中,然后通过 Function
调用执行这部分代码。也就是说如果我们可以污染
node.line
就可以运行我们代码。也就是说
jade
本身是没有漏洞的,因为模板的渲染逻辑是如何,但问题是,如果存在可控的原型链污染,就可以帮助我们污染 node.line
。于是尝试 POST
/login
接口断点发现,,
node.line
值还是 0
、1
、2
之类的?突然醒悟,,还有一个问题,我们在调试过程中发现,
node.line
是存在值的,比如上图中的 0
、1
、2
,如果存在值的话,它会直接获取这个值,而不是获取我们污染过的 Object
对象里的值!其实原型链污染的利用核心就是:访问对象的属性/值为 undefined 才行,不然我们污染
Object
对象就没有意义了。现在看这篇文章就能看懂了,而且发现总结的非常好。。
好的,在同一频道上了。
先梳理上面分析的函数调用栈,我们断点入口在
routes/index.js
res.render('index',{title:'ctfshow'});
,调用栈如下- routes/index.js :: res.render
- jade/lib/index.js :: exports.__express
- jade/lib/index.js :: exports.renderFile
- jade/lib/index.js :: handleTemplateCache
- jade/lib/index.js :: exports.compile
- jade/lib/index.js :: parse -> compiler.compile();
- jade/lib/compiler.js :: Compiler.compile -> this.visit(this.node)jade/lib/compiler.js :: this.visitjade/lib/compiler.js :: this.buf.push
- jade/lib/index.js :: parse -> options.selfjade/lib/index.js :: fn = new Function(‘locals, jade’, fn)jade/lib/index.js :: fn(locals, Object.create(runtime))
至 4. a. iii. 这部分调用栈用下图,4. b. c. d. 的在上面 debug 也有提及,因此调用栈这部分问题不大
![notion image](https://www.notion.so/image/https%3A%2F%2Fs3-us-west-2.amazonaws.com%2Fsecure.notion-static.com%2F3cfccc6e-6d65-49b1-b879-2bebdadc591e%2FUntitled.png?table=block&id=db7612ca-db15-4a19-9021-08012085ce5e&t=db7612ca-db15-4a19-9021-08012085ce5e&width=1500&cache=v2)
问题有 3
visit
方法中this.debug=true
,不然this.buf.push
调用不了
- 在上面提到的:
node.line
在某处为undefined
才行,不然我们污染的Object
对象就没意义
- 保证能够执行到渲染阶段,因为覆盖某些属性会导致莫名其妙的异常
第 1 个问题容易解决,因为在 Jade 入口
exports.__express
,我们上面 deubg 分析时也看到options.compileDebug
无初始值,可以覆盖开启 Debug 模式(经分析,this.debug
获取的就是这里的 debug 值),当然也有另外一种情况,部署时,没有正确配置 req.app.get('env')
导致 debug 模式开启,那么这个变量也可以不用覆盖,但为了确保通用性,这里还是覆盖一下,防止正确配置,2333。这里因
utils.copy(user.userinfo,req.body);
与 web341一样,userinfo.__proto__.__proto__
才是 Object
对象的原型,所以要套两层。先打一下
![notion image](https://www.notion.so/image/https%3A%2F%2Fs3-us-west-2.amazonaws.com%2Fsecure.notion-static.com%2F629c01f1-fbeb-4fa9-a2d9-aaa86d718e7d%2FUntitled.png?table=block&id=fcb55bfe-2710-420f-9628-9c72bf298338&t=fcb55bfe-2710-420f-9628-9c72bf298338&width=1500&cache=v2)
第 3 个问题提前出现了,要先解决这个问题,保证代码能够执行到渲染阶段
![notion image](https://www.notion.so/image/https%3A%2F%2Fs3-us-west-2.amazonaws.com%2Fsecure.notion-static.com%2F9d746f15-779d-4d57-be07-52fcb2e317ee%2FUntitled.png?table=block&id=727a1fff-e408-44ce-ae8a-2a14384bcbf9&t=727a1fff-e408-44ce-ae8a-2a14384bcbf9&width=1500&cache=v2)
和先知文章里不同,这里报错有点不一样,先跟进
Compiler.visitNode
225行看一下![notion image](https://www.notion.so/image/https%3A%2F%2Fs3-us-west-2.amazonaws.com%2Fsecure.notion-static.com%2Fe57127a0-d72b-4c56-8a46-abf5d0001c46%2FUntitled.png?table=block&id=d387b051-e94e-4612-972d-54334ef98f77&t=d387b051-e94e-4612-972d-54334ef98f77&width=1000&cache=v2)
拼接一下,发现没有这个方法
![notion image](https://www.notion.so/image/https%3A%2F%2Fs3-us-west-2.amazonaws.com%2Fsecure.notion-static.com%2F85977fed-a23d-4115-adb4-a69ff7a8e537%2FUntitled.png?table=block&id=10087876-d477-42d7-9e03-404661645509&t=10087876-d477-42d7-9e03-404661645509&width=382&cache=v2)
在遍历AST树时,通常是通过
"visit" + 节点类型
来遍历所有节点的,观察错误调用栈也知,比如 visitBlock
,就是访问 Block
节点。那 Block
可用,我们就污染一下 type
就好了,当它当前上下文找不到就去找 Object
了。当然选取时,最好是选的节点附带的上下文信息进入后,啥事也不会做的,不然也有走向奇奇怪怪的逻辑,先来看看 Block 节点。
![notion image](https://cdn.nlark.com/yuque/0/2021/png/2789727/1620117442355-58168bea-2ae8-40a5-a38f-9f38e145a384.png?x-oss-process=image%2Fresize%2Cw_1500&t=92e5e84b-e2aa-4178-818d-9b71416c19b8)
image.png
这里加上这部分逻辑,来看看我们故意伪造 Block 节点会发生什么
![notion image](https://www.notion.so/image/https%3A%2F%2Fs3-us-west-2.amazonaws.com%2Fsecure.notion-static.com%2F87c96892-4fc6-4210-88e4-b773c0562adb%2FUntitled.png?table=block&id=b711eb68-a18d-4873-a34b-918efea32416&t=b711eb68-a18d-4873-a34b-918efea32416&width=1500&cache=v2)
这里
block.nodes
为 undefined
,然后 undefined.length
![notion image](https://cdn.nlark.com/yuque/0/2021/png/2789727/1620118021804-559e7fb3-5448-494e-a38d-743f1c1e2dcb.png?t=24251d81-d30c-4b42-8cb4-4772eab1d4a9)
image.png
明显,这样访问会报错,导致进入其他错误,然后
jade
没有对这块异常进行处理。也就是说,如果
vist
的节点不是这种 block.子属性.孙子属性
问题应该不大。顶多一个 undefined
然后直接结束啥的,这里试试 visitCode
,![notion image](https://www.notion.so/image/https%3A%2F%2Fs3-us-west-2.amazonaws.com%2Fsecure.notion-static.com%2Fa728c536-226e-4c52-8a6a-fe2efa3d39cf%2FUntitled.png?table=block&id=7c591a90-0b60-4dcd-9e37-828df4b932d6&t=7c591a90-0b60-4dcd-9e37-828df4b932d6&width=1500&cache=v2)
正常走到后面,没有报错,期间只触发了
this.buf.push(code.val)
,问题应该不大。![notion image](https://www.notion.so/image/https%3A%2F%2Fs3-us-west-2.amazonaws.com%2Fsecure.notion-static.com%2Fa68b5dda-00b1-44f0-b151-addfb76bad76%2FUntitled.png?table=block&id=590b269b-a838-4e0b-9b9f-1a772043f448&t=590b269b-a838-4e0b-9b9f-1a772043f448&width=1500&cache=v2)
尝试污染
type
为 Code
![notion image](https://www.notion.so/image/https%3A%2F%2Fs3-us-west-2.amazonaws.com%2Fsecure.notion-static.com%2Fd63ed352-2e95-4e07-8bc1-fb6bd103f809%2FUntitled.png?table=block&id=bad70d85-c4fb-4e62-9706-de6c4370dd9e&t=bad70d85-c4fb-4e62-9706-de6c4370dd9e&width=1500&cache=v2)
好耶,像是解决了,因为这个报错和先知文章报错一致。
![notion image](https://www.notion.so/image/https%3A%2F%2Fs3-us-west-2.amazonaws.com%2Fsecure.notion-static.com%2F528a4ed5-fc73-43c4-be88-af6f57f31767%2FUntitled.png?table=block&id=e2c91c06-0f7b-4037-877c-f630c7584d38&t=e2c91c06-0f7b-4037-877c-f630c7584d38&width=1500&cache=v2)
尝试解决这个报错,因为看错误调这里好像还没到渲染成功的地方。
分析这个错误栈,可以看到前 4 点还是属于
jade
范畴。先跟进 jade
模块最后报错的地方,即 jade/libindex.js
149行的 parse
方法,![notion image](https://www.notion.so/image/https%3A%2F%2Fs3-us-west-2.amazonaws.com%2Fsecure.notion-static.com%2F140fab87-1af1-4ffd-a873-a5bd990ef74f%2FUntitled.png?table=block&id=cfadfd59-452b-450d-90c9-40dfdd47c482&t=cfadfd59-452b-450d-90c9-40dfdd47c482&width=1262&cache=v2)
发现,程序已经走完刚刚AST遍历部分了,已经差不多要返回了。
感觉只要避免进入149行的
addWith
方法,就可以渲染成功了!然后进入149行的
addWith
方法是满足147行的 options.self
值为 False,尝试下看看这个 options.self
默认是不是 undefined
,如果是就可以污染了。![notion image](https://www.notion.so/image/https%3A%2F%2Fs3-us-west-2.amazonaws.com%2Fsecure.notion-static.com%2Ff71e7ce1-06ad-4bad-a4ae-2c04f6c59b22%2FUntitled.png?table=block&id=f216c06b-9cd2-49b8-a920-3ab85f1a6ec9&t=f216c06b-9cd2-49b8-a920-3ab85f1a6ec9&width=1224&cache=v2)
nice,就是
undefined
,尝试污染 self
为 true
,1
也可以![notion image](https://www.notion.so/image/https%3A%2F%2Fs3-us-west-2.amazonaws.com%2Fsecure.notion-static.com%2F729ecbfb-b8ec-4e17-b9e6-778818e4afa3%2FUntitled.png?table=block&id=7c525d8e-d8c4-4636-8b32-643194552bd2&t=7c525d8e-d8c4-4636-8b32-643194552bd2&width=1500&cache=v2)
![notion image](https://www.notion.so/image/https%3A%2F%2Fs3-us-west-2.amazonaws.com%2Fsecure.notion-static.com%2Faea14496-79a2-4b6c-a478-3d7363fb5257%2FUntitled.png?table=block&id=779ea181-e14a-44c9-aea5-14ee98ec508c&t=779ea181-e14a-44c9-aea5-14ee98ec508c&width=1500&cache=v2)
!!!终于走到渲染这一步了!
看到
undefined
好说,污染就完事了 (到这 index 的页面渲染就没啥问题了,到 第 2 个问题,
node.line
在某处为 undefined
才行,不然我们污染的 Object
对象就没意义这里如果一步一步动态调试会比较麻烦,直接注入测试即可
![notion image](https://www.notion.so/image/https%3A%2F%2Fs3-us-west-2.amazonaws.com%2Fsecure.notion-static.com%2F86c469e0-4a7d-46c4-9343-a8feadbab970%2FUntitled.png?table=block&id=a0850ce2-3004-4301-806b-e5a33066f521&t=a0850ce2-3004-4301-806b-e5a33066f521&width=890&cache=v2)
发现都
node
为 Block
的时候 line
是不存在的。![notion image](https://www.notion.so/image/https%3A%2F%2Fs3-us-west-2.amazonaws.com%2Fsecure.notion-static.com%2F0fb001b6-5896-4845-ae67-36d61caa0cb2%2FUntitled.png?table=block&id=421ac04c-4254-462a-894a-42466a2337c7&t=421ac04c-4254-462a-894a-42466a2337c7&width=820&cache=v2)
理论上,只要覆盖了
node.line
即可达到代码执行的目的。然后拼接上面避免报错的参数,得到
反弹 Shell
![notion image](https://www.notion.so/image/https%3A%2F%2Fs3-us-west-2.amazonaws.com%2Fsecure.notion-static.com%2F1e76c3e7-6ad0-49bf-81b1-55eb97ad304c%2FUntitled.png?table=block&id=a0f8423f-81d1-4172-90f9-8d90577f8e82&t=a0f8423f-81d1-4172-90f9-8d90577f8e82&width=1500&cache=v2)
再 POST一次,发送的数据包不用变
![notion image](https://www.notion.so/image/https%3A%2F%2Fs3-us-west-2.amazonaws.com%2Fsecure.notion-static.com%2F76c93136-b86a-4da8-a442-f7487713f733%2FUntitled.png?table=block&id=aed7861c-3a17-4435-87b0-ec332c94e8c6&t=aed7861c-3a17-4435-87b0-ec332c94e8c6&width=1500&cache=v2)
不就少了个
message
,那我污染你呗,,然后 message
后又说少了 error
继续污染,然后 error
是一个对象,就需要弄个 json
格式数据啦。![notion image](https://www.notion.so/image/https%3A%2F%2Fs3-us-west-2.amazonaws.com%2Fsecure.notion-static.com%2F09e9484b-e82f-47fc-8f71-2cb6fda8cf4b%2FUntitled.png?table=block&id=638c77eb-471f-43b6-889d-8f64ed095fcd&t=638c77eb-471f-43b6-889d-8f64ed095fcd&width=1500&cache=v2)
emmm,到这,其实一开始就犯了个很蠢的错。。。其实一开始就应该污染
line
先的,然后在试 compileDebug
、type
、self
,蠢哭了,,因为,如果不污染 line 先的话,不能保证在 line 正确的情况下试其他的,就会导致,,其他对了,加上 line
就错了。。其实这里,压根就不用污染
title
,如果是 先污染 line
,然后到 compileDebug
、type
、self
会发现,到 self
这就可以成功反弹 shell 了,人都傻了。。。最终 EXP
![notion image](https://www.notion.so/image/https%3A%2F%2Fs3-us-west-2.amazonaws.com%2Fsecure.notion-static.com%2F3e65bb00-2784-4d0b-9339-96b265d65c1d%2FUntitled.png?table=block&id=1072beb2-7f3c-4243-8dca-1fabbb5560a9&t=1072beb2-7f3c-4243-8dca-1fabbb5560a9&width=1500&cache=v2)
不用变,在POST一次即可
![notion image](https://www.notion.so/image/https%3A%2F%2Fs3-us-west-2.amazonaws.com%2Fsecure.notion-static.com%2F7b3507d2-6b3b-43cc-924e-147dae76a10a%2FUntitled.png?table=block&id=ccb07b19-1ad3-4f4b-ae9b-f1974a56cd83&t=ccb07b19-1ad3-4f4b-ae9b-f1974a56cd83&width=1500&cache=v2)
原本想用原生Socket的,不知道为啥老是报错,奇怪,,难道闭合不了?
![notion image](https://www.notion.so/image/https%3A%2F%2Fs3-us-west-2.amazonaws.com%2Fsecure.notion-static.com%2Fc0e554fc-2e0f-4a62-9ce7-9bc32175e96a%2FUntitled.png?table=block&id=865f3fc0-b490-459b-9675-20b44c13847a&t=865f3fc0-b490-459b-9675-20b44c13847a&width=1500&cache=v2)
web343 原型链污染 +++++
说有过滤,但 web342一样的 EXP 也可以打,反弹shell后看源码才发现确实多了点东西
login.js
emmm 有点不懂这个
JSON.stringify(req.body).match(/Text/ig)
过滤有啥意义就是了。。和web342一样的EXP
![notion image](https://www.notion.so/image/https%3A%2F%2Fs3-us-west-2.amazonaws.com%2Fsecure.notion-static.com%2Fb9a8de88-b9f1-4461-bdb1-6f261d00ccff%2FUntitled.png?table=block&id=3ea7c500-0dfb-4348-bb51-bc21522cf5ef&t=3ea7c500-0dfb-4348-bb51-bc21522cf5ef&width=1500&cache=v2)
![notion image](https://www.notion.so/image/https%3A%2F%2Fs3-us-west-2.amazonaws.com%2Fsecure.notion-static.com%2F9e60a48d-eb36-42fc-9160-f293792b3243%2FUntitled.png?table=block&id=16bffe08-fd80-49c7-a15c-ac17d3c9fdc2&t=16bffe08-fd80-49c7-a15c-ac17d3c9fdc2&width=1228&cache=v2)
web344 HPP
代码
即 url 中不能包含大小写
8c
、2c
和 逗号
先构造一个正常请求
发现题目会过滤掉逗号,尝试 URL 编码,
urlencode(",") = %2c
发现 2c
也被过滤HTTP协议中允许同名参数出现多次,不同服务端对同名参数处理都是不一样的,下面链接列举了一些
nodejs 会把同名参数以数组的形式存储,并且
JSON.parse
可以正常解析。![notion image](https://www.notion.so/image/https%3A%2F%2Fs3-us-west-2.amazonaws.com%2Fsecure.notion-static.com%2F1090368d-ad9d-4a32-95b1-bc976f93d93e%2FUntitled.png?table=block&id=97e057a6-4421-4c58-bd30-dc359a06b643&t=97e057a6-4421-4c58-bd30-dc359a06b643&width=1360&cache=v2)
因此构造
这里把 c进行url编码,是因为 双引号 的url编码是
%22
,和 c
连接起来就是 %22c
,会匹配到正则表达式。![notion image](https://www.notion.so/image/https%3A%2F%2Fs3-us-west-2.amazonaws.com%2Fsecure.notion-static.com%2F718901bb-4bd4-4096-9569-28c5ff671494%2FUntitled.png?table=block&id=e59ebbb5-5358-4ba8-bc8e-91390f16ee8f&t=e59ebbb5-5358-4ba8-bc8e-91390f16ee8f&width=1500&cache=v2)
一些参考的题解