Upload Lab 通关复现
本文最后更新于 2025-10-30,文章内容可能已经过时。
🧪 Upload Lab
官网:[Git Hub]
upload-labs 是一个使用 php 语言编写的,专门收集渗透测试和 CTF 中遇到的各种上传漏洞的靶场。旨在帮助大家对上传漏洞有一个全面的了解。目前一共 20 关,每一关都包含着不同上传方式。
🎈 靶机包含漏洞类型分类

🎈 如何判断上传漏洞类型?
🎠 一句话木马
请参考下面的文章
🕐 Pass-01
🔍 源码解析
function checkFile() {
var file = document.getElementsByName('upload_file')[0].value;
if (file == null || file == "") {
alert("请选择要上传的文件!");
return false;
}
//定义允许上传的文件类型
var allow_ext = ".jpg|.png|.gif";
//提取上传文件的类型
var ext_name = file.substring(file.lastIndexOf("."));
//判断上传文件类型是否允许上传
if (allow_ext.indexOf(ext_name + "|") == -1) {
var errMsg = "该文件不允许上传,请上传" + allow_ext + "类型的文件,当前文件类型为:" + ext_name;
alert(errMsg);
return false;
}
}
💡 关键代码
js 源码中变量 allow_ext 定义了白名单
var allow_ext = ".jpg|.png|.gif";
且 if 语句只允许 .jpg|.png|.gif 后缀文件上传,判断为前端过滤。
if (allow_ext.indexOf(ext_name + "|") == -1) {
var errMsg = "该文件不允许上传,请上传" + allow_ext + "类型的文件,当前文件类型为:" + ext_name;
alert(errMsg);
return false;
}
🧠 思路
-
php 文件无法上传;
-
可以上传 png 文件;
-
弹窗提示:
该文件不允许上传,请上传.jpg|.png|.gif类型的文件,当前文件类型为:.php说明有白名单; -
且 bp 可以抓到包,修改后可上传,前端过滤。
🛠️ 解题方法
💡 方法一
使用浏览器禁用 js 后直接上传 php 文件。
💡 方法二
将木马文件后缀改为 png 后上传,使用 bp 抓包,将后缀名改回 php 后放行即可。
🕑 Pass-02
🔍 源码解析
$is_upload = false;
$msg = null;
if (isset($_POST['submit'])) {
if (file_exists(UPLOAD_PATH)) {
if (($_FILES['upload_file']['type'] == 'image/jpeg') || ($_FILES['upload_file']['type'] == 'image/png') || ($_FILES['upload_file']['type'] == 'image/gif')) {
$temp_file = $_FILES['upload_file']['tmp_name'];
$img_path = UPLOAD_PATH . '/' . $_FILES['upload_file']['name']
if (move_uploaded_file($temp_file, $img_path)) {
$is_upload = true;
} else {
$msg = '上传出错!';
}
} else {
$msg = '文件类型不正确,请重新上传!';
}
} else {
$msg = UPLOAD_PATH.'文件夹不存在,请手工创建!';
}
}
💡 关键代码
$_FILES['upload_file']['type'] == 'image/jpeg')
通过检测 content-type 判断上传文件内容
-
content-type:通常是 HTTP 协议中用于标识消息主体内容类型的头部字段。在文件上传场景里,当客户端(如浏览器)向服务器发送文件时,会在请求头中包含content-type字段,用来告知服务器所发送内容的类型。不过在 PHP 中处理文件上传时,$_FILES['upload_file']['type']本质上是客户端在上传文件时提供的 MIME 类型信息,虽然和content-type有一定关联,但它并非直接的content-type字段。
$_FILES 超全局变量
-
在 PHP 里,当通过 HTML 表单上传文件时,上传的文件信息会被存储在
$_FILES这个超全局变量中。$_FILES是一个二维数组,其键名是 HTML 表单中 input 元素的 name 属性值。例如,若 HTML 表单中有一个 input 元素的 name 属性值为upload_file,那么上传文件的相关信息就会存储在$_FILES['upload_file']中。
$_FILES['upload_file']['type']
表示上传文件的 MIME 类型。
-
MIME(Multipurpose Internet Mail Extensions)类型是一种标准,用于表示文档、文件或字节流的性质和格式。在文件上传的场景中,它可以帮助我们识别上传文件的具体类型,比如图片、文本、音频等。
条件判断的意义
-
($_FILES['upload_file']['type'] == 'image/jpeg')这个条件判断会检查上传文件的 MIME 类型是否为image/jpeg,也就是判断上传的文件是否为 JPEG 格式的图像。如果是,则条件成立,返回true;如果不是,则条件不成立,返回false。
🧠 思路
-
可以上传 png 文件;
-
bp 可以抓到包,修改后缀无效,后端过滤;
-
上传 php 提示:
文件类型不正确,请重新上传! -
看到文件类型不对,可以想到是 MIME 类型。
🛠️ 解题方法
💡 方法一
将 php 木马文件上传,使用 bp 抓包,将 MIME 信息改成 image/jpeg 后上传即可
💡 方法二
同第一题方法二,将木马文件后缀改为 png(此时 MIME 会自动识别为 image/png)后上传,使用 bp 抓包,将后缀名改回 php 后放行即可。
🕒 Pass-03
🔍 源码解析
$is_upload = false;
$msg = null;
if (isset($_POST['submit'])) {
if (file_exists(UPLOAD_PATH)) {
$deny_ext = array('.asp','.aspx','.php','.jsp');
$file_name = trim($_FILES['upload_file']['name']);
$file_name = deldot($file_name);//删除文件名末尾的点
$file_ext = strrchr($file_name, '.');
$file_ext = strtolower($file_ext); //转换为小写
$file_ext = str_ireplace('::$DATA', '', $file_ext);//去除字符串::$DATA
$file_ext = trim($file_ext); //收尾去空
if(!in_array($file_ext, $deny_ext)) {
$temp_file = $_FILES['upload_file']['tmp_name'];
$img_path = UPLOAD_PATH.'/'.date("YmdHis").rand(1000,9999).$file_ext;
if (move_uploaded_file($temp_file,$img_path)) {
$is_upload = true;
} else {
$msg = '上传出错!';
}
} else {
$msg = '不允许上传.asp,.aspx,.php,.jsp后缀文件!';
}
} else {
$msg = UPLOAD_PATH . '文件夹不存在,请手工创建!';
}
}
💡 关键函数
trim()
用于去除字符串首尾的空白字符。
在代码中,trim($_FILES['upload_file']['name']) 用于去除上传文件名首尾的空白字符。
strrchr()
用于查找字符串中最后一次出现某个字符的位置,并返回从该位置到字符串末尾的所有字符。
在代码中,strrchr($file_name, '.') 用于获取上传文件的扩展名。
strtolower()
用于将字符串转换为小写。代码中使用它将文件扩展名转换为小写,以便进行不区分大小写的比较。
str_ireplace()
用于在字符串中进行不区分大小写的替换操作。
在代码中,str_ireplace('::$DATA', '', $file_ext) 用于去除文件扩展名中的 ::$DATA 字符串,这是为了防止 Windows 系统下的 NTFS 流攻击。
🧠 思路
-
bp 可以抓到包,修改后缀无效,后端过滤;
-
上传 php 获取到
提示:不允许上传.asp,.aspx,.php,.jsp后缀文件!是一个黑名单; -
后缀修改为 PHP、Php 皆不可,说明有转小写或者别的什么;
-
后缀修改为 pphphp 上传成功但是没对 php 进行过滤上传文件后缀就是 pphphp。
🛠️ 解题方法
💡 前提条件
需要修改配置 apache/nginx(取决于你的选择)的配置文件,对特殊后缀进行解析。
💡 特殊后缀绕过
后缀修改为 php3、php5、phtml 等后缀皆可(前提要对特殊后缀进行解析)。
🕓 Pass-04
🔍 源码解析
$is_upload = false;
$msg = null;
if (isset($_POST['submit'])) {
if (file_exists(UPLOAD_PATH)) {
$deny_ext = array(".php",".php5",".php4",".php3",".php2","php1",".html",".htm",".phtml",".pht",".pHp",".pHp5",".pHp4",".pHp3",".pHp2","pHp1",".Html",".Htm",".pHtml",".jsp",".jspa",".jspx",".jsw",".jsv",".jspf",".jtml",".jSp",".jSpx",".jSpa",".jSw",".jSv",".jSpf",".jHtml",".asp",".aspx",".asa",".asax",".ascx",".ashx",".asmx",".cer",".aSp",".aSpx",".aSa",".aSax",".aScx",".aShx",".aSmx",".cEr",".sWf",".swf");
$file_name = trim($_FILES['upload_file']['name']);
$file_name = deldot($file_name);//删除文件名末尾的点
$file_ext = strrchr($file_name, '.');
$file_ext = strtolower($file_ext); //转换为小写
$file_ext = str_ireplace('::$DATA', '', $file_ext);//去除字符串::$DATA
$file_ext = trim($file_ext); //收尾去空
if (!in_array($file_ext, $deny_ext)) {
$temp_file = $_FILES['upload_file']['tmp_name'];
$img_path = UPLOAD_PATH.'/'.date("YmdHis").rand(1000,9999).$file_ext;
if (move_uploaded_file($temp_file, $img_path)) {
$is_upload = true;
} else {
$msg = '上传出错!';
}
} else {
$msg = '此文件不允许上传!';
}
} else {
$msg = UPLOAD_PATH . '文件夹不存在,请手工创建!';
}
}
代码跟上一题一样,但是基本能想到的特殊后缀都被过滤了。
🧩 前置知识
以下内容基于 Apache
.htaccess 文件
-
作用:分布式配置文件,一般用于 url 重写、认证、控制访问等
-
作用范围:特定目录(一般是网站根目录),及其子目录
-
优先级:较高,可覆盖 apache 的主要配置文件(httpd-conf)
-
生效方式:修改后立刻生效
httpd-conf 文件
-
作用:包含 apache·HTTP 服务器的全局行为和默认设置
-
作用范围:整个服务器
-
优先级:较低
-
生效方式:管理员权限,重启服务器后生效
Apache 服务器中 AllowOverride 指令用于指定 .htaccess 文件可以覆盖哪些服务器配置。它的取值决定了用户通过 .htaccess 文件对服务器设置的控制程度
AllowOverride 的常用值说明如下
None:这是最严格的设置。当设置为 None 时,服务器将完全忽略并不允许 .htaccess 文件覆盖任何配置选项。这通常是为了提升性能和安全性。
All:这是最宽松的设置。当设置为 All 时,服务器允许 .htaccess 文件覆盖所有配置选项。这给予了目录最大的灵活性,但也需要更高的安全关注。
AuthConfig:此选项允许 .htaccess 文件覆盖与身份验证(Authorization) 相关的配置选项。常用的指令包括 AuthType、AuthName、AuthUserFile 等,常用于设置目录的密码保护。
FileInfo:此选项允许 .htaccess 文件覆盖与文件和文档类型 相关的配置选项。常用的指令包括 DirectoryIndex(默认首页)、DefaultType(默认 MIME 类型)、ErrorDocument(自定义错误页面)等。
Indexes:此选项允许 .htaccess 文件覆盖与目录索引(Indexing) 相关的配置选项。常用的指令包括 Options(用于启用或禁用目录列表等功能)、IndexOptions、IndexIgnore 等,这些指令控制着当目录中没有默认文件时,如何向访问者显示文件列表。
Limit:此选项允许 .htaccess 文件覆盖与访问控制(Access Control) 相关的配置选项,例如 Require 指令,可以基于 IP 地址、用户等因素来限制对目录的访问。
Options:此选项允许 .htaccess 文件覆盖与目录特性(Options) 相关的配置选项,主要是指 Options 指令本身,用于启用或禁用特定的目录功能,例如是否允许执行 CGI 脚本、是否支持服务器端包含(SSI)等。
🧠 思路
-
bp 可以抓到包,修改后缀无效,后端过滤;
-
可以上传 png 文件
-
使用上一题思路发现无解,特殊后缀都被过滤了
提示:此文件不允许上传!; -
可以上传
.htaccess文件;
🛠️ 解题方法
创建一个.htaccess 文件,写入以下内容(二选一)
AddType application/x-httpd-php .jpg .txt // 将txt文件与jpg文件当作php文件解析(其他没被过滤的文件后缀皆可)
AddType application/x-httpd-php // 不写后缀则表示所有文件都将解析为php文件
上传.htaccess 文件后,再修改木马文件后缀为 .jpg/.txt 进行上传
🕔 Pass-05
🔍 源码解析
$is_upload = false;
$msg = null;
if (isset($_POST['submit'])) {
if (file_exists(UPLOAD_PATH)) {
$deny_ext = array(".php",".php5",".php4",".php3",".php2",".html",".htm",".phtml",".pht",".pHp",".pHp5",".pHp4",".pHp3",".pHp2",".Html",".Htm",".pHtml",".jsp",".jspa",".jspx",".jsw",".jsv",".jspf",".jtml",".jSp",".jSpx",".jSpa",".jSw",".jSv",".jSpf",".jHtml",".asp",".aspx",".asa",".asax",".ascx",".ashx",".asmx",".cer",".aSp",".aSpx",".aSa",".aSax",".aScx",".aShx",".aSmx",".cEr",".sWf",".swf",".htaccess");
$file_name = trim($_FILES['upload_file']['name']);
$file_name = deldot($file_name);//删除文件名末尾的点
$file_ext = strrchr($file_name, '.');
$file_ext = str_ireplace('::$DATA', '', $file_ext);//去除字符串::$DATA
$file_ext = trim($file_ext); //首尾去空
if (!in_array($file_ext, $deny_ext)) {
$temp_file = $_FILES['upload_file']['tmp_name'];
$img_path = UPLOAD_PATH.'/'.date("YmdHis").rand(1000,9999).$file_ext;
if (move_uploaded_file($temp_file, $img_path)) {
$is_upload = true;
} else {
$msg = '上传出错!';
}
} else {
$msg = '此文件类型不允许上传!';
}
} else {
$msg = UPLOAD_PATH . '文件夹不存在,请手工创建!';
}
}
这次和上一题差不多,但是大小写没被过滤
🧩 前置知识
针对大写绕过,Windows 大小写不敏感,Linux 大小写敏感(无法解析大写 Php),所以要看看目标服务器是什么系统
🧠 思路
-
bp 可以抓到包,修改后缀无效,后端过滤;
-
依旧
提示:此文件类型不允许上传!; -
这次
.htaccess文件也无法上传了; -
发现大写 PHP 可以上传。
🛠️ 解题方法
💡 方法一:大小写绕过(Windows 限定)
直接将后缀改成 Php、PHP 等后缀直接上传
💡 方法二
🕕 Pass-06
🔍 源码解析
$is_upload = false;
$msg = null;
if (isset($_POST['submit'])) {
if (file_exists(UPLOAD_PATH)) {
$deny_ext = array(".php",".php5",".php4",".php3",".php2",".html",".htm",".phtml",".pht",".pHp",".pHp5",".pHp4",".pHp3",".pHp2",".Html",".Htm",".pHtml",".jsp",".jspa",".jspx",".jsw",".jsv",".jspf",".jtml",".jSp",".jSpx",".jSpa",".jSw",".jSv",".jSpf",".jHtml",".asp",".aspx",".asa",".asax",".ascx",".ashx",".asmx",".cer",".aSp",".aSpx",".aSa",".aSax",".aScx",".aShx",".aSmx",".cEr",".sWf",".swf",".htaccess");
$file_name = $_FILES['upload_file']['name'];
$file_name = deldot($file_name);//删除文件名末尾的点
$file_ext = strrchr($file_name, '.');
$file_ext = strtolower($file_ext); //转换为小写
$file_ext = str_ireplace('::$DATA', '', $file_ext);//去除字符串::$DATA
if (!in_array($file_ext, $deny_ext)) {
$temp_file = $_FILES['upload_file']['tmp_name'];
$img_path = UPLOAD_PATH.'/'.date("YmdHis").rand(1000,9999).$file_ext;
if (move_uploaded_file($temp_file,$img_path)) {
$is_upload = true;
} else {
$msg = '上传出错!';
}
} else {
$msg = '此文件不允许上传';
}
} else {
$msg = UPLOAD_PATH . '文件夹不存在,请手工创建!';
}
}
这次是少了个首尾去空
$file_ext = trim($file_ext); //首尾去空
🧩 前置知识
window 中保存文件时,会将后缀名后面的空格去掉后保存
也就是.php ==>.php(第一个 php 后面有空格)
linux 中保存文件时,会保留空格
🧠 思路
-
可以上传 png 文件;
-
bp 可以抓到包,修改后缀无效,后端过滤;
-
特殊后缀(大小写双写)无法上传;
-
.htaccess文件无法上传; -
尝试空格绕过。
🛠️ 解题方法
💡 方法一:空格绕过 (Windows 限定)
将 [php] 后缀改为 [.php] 后上传
💡方法二
🕖 Pass-07
🔍 源码解析
$is_upload = false;
$msg = null;
if (isset($_POST['submit'])) {
if (file_exists(UPLOAD_PATH)) {
$deny_ext = array(".php",".php5",".php4",".php3",".php2",".html",".htm",".phtml",".pht",".pHp",".pHp5",".pHp4",".pHp3",".pHp2",".Html",".Htm",".pHtml",".jsp",".jspa",".jspx",".jsw",".jsv",".jspf",".jtml",".jSp",".jSpx",".jSpa",".jSw",".jSv",".jSpf",".jHtml",".asp",".aspx",".asa",".asax",".ascx",".ashx",".asmx",".cer",".aSp",".aSpx",".aSa",".aSax",".aScx",".aShx",".aSmx",".cEr",".sWf",".swf",".htaccess");
$file_name = trim($_FILES['upload_file']['name']);
$file_ext = strrchr($file_name, '.');
$file_ext = strtolower($file_ext); //转换为小写
$file_ext = str_ireplace('::$DATA', '', $file_ext);//去除字符串::$DATA
$file_ext = trim($file_ext); //首尾去空
if (!in_array($file_ext, $deny_ext)) {
$temp_file = $_FILES['upload_file']['tmp_name'];
$img_path = UPLOAD_PATH.'/'.$file_name;
if (move_uploaded_file($temp_file, $img_path)) {
$is_upload = true;
} else {
$msg = '上传出错!';
}
} else {
$msg = '此文件类型不允许上传!';
}
} else {
$msg = UPLOAD_PATH . '文件夹不存在,请手工创建!';
}
}
这次是少了删除文件名末尾的点
$file_name = deldot($file_name);//删除文件名末尾的点
🧩前置知识
window 中,会将后缀名之后的点去掉
如.php. ==> .php
但是如果是 a.txt.php 最后会被识别成 php 文件
🧠 思路
-
可以上传 png 文件;
-
bp 可以抓到包,修改后缀无效,后端过滤;
-
特殊后缀(大小写双写)无法上传;
-
.htaccess文件无法上传; -
尝试空格绕过无解;
-
尝试在末尾加点;
🛠️ 解题方法
💡 方法一(Windows 限定)
将 [php] 后缀改为 [.php.] 后上传
🕗 Pass-08
🔍 源码解析
$is_upload = false;
$msg = null;
if (isset($_POST['submit'])) {
if (file_exists(UPLOAD_PATH)) {
$deny_ext = array(".php",".php5",".php4",".php3",".php2",".html",".htm",".phtml",".pht",".pHp",".pHp5",".pHp4",".pHp3",".pHp2",".Html",".Htm",".pHtml",".jsp",".jspa",".jspx",".jsw",".jsv",".jspf",".jtml",".jSp",".jSpx",".jSpa",".jSw",".jSv",".jSpf",".jHtml",".asp",".aspx",".asa",".asax",".ascx",".ashx",".asmx",".cer",".aSp",".aSpx",".aSa",".aSax",".aScx",".aShx",".aSmx",".cEr",".sWf",".swf",".htaccess");
$file_name = trim($_FILES['upload_file']['name']);
$file_name = deldot($file_name);//删除文件名末尾的点
$file_ext = strrchr($file_name, '.');
$file_ext = strtolower($file_ext); //转换为小写
$file_ext = trim($file_ext); //首尾去空
if (!in_array($file_ext, $deny_ext)) {
$temp_file = $_FILES['upload_file']['tmp_name'];
$img_path = UPLOAD_PATH.'/'.date("YmdHis").rand(1000,9999).$file_ext;
if (move_uploaded_file($temp_file, $img_path)) {
$is_upload = true;
} else {
$msg = '上传出错!';
}
} else {
$msg = '此文件类型不允许上传!';
}
} else {
$msg = UPLOAD_PATH . '文件夹不存在,请手工创建!';
}
}
这回少了去除字符串::$DATA
$file_ext = str_ireplace('::$DATA', '', $file_ext);//去除字符串::$DATA
🧩 前置知识
🧠 思路
-
可以上传 png 文件;
-
bp 可以抓到包,修改后缀无效,后端过滤;
-
特殊后缀(大小写双写)无法上传;
-
.htaccess文件无法上传; -
尝试空格绕过无解;
-
尝试在末尾加点无解;
-
利用 NTFS 特性
🛠️ 解题方法
💡 方法一(Windows 限定)
上传 php 文件后抓包修改后缀为.php::$DATA,验证时不匹配黑名单绕过过滤,成功上传后,系统则根据 NTFS 规则,自动忽略文件后的::$DATA,将其解释为 php 文件
注意连接时要删去::$DATA 后缀
🕘 Pass-09
🔍 源码解析
$is_upload = false;
$msg = null;
if (isset($_POST['submit'])) {
if (file_exists(UPLOAD_PATH)) {
$deny_ext = array(".php",".php5",".php4",".php3",".php2",".html",".htm",".phtml",".pht",".pHp",".pHp5",".pHp4",".pHp3",".pHp2",".Html",".Htm",".pHtml",".jsp",".jspa",".jspx",".jsw",".jsv",".jspf",".jtml",".jSp",".jSpx",".jSpa",".jSw",".jSv",".jSpf",".jHtml",".asp",".aspx",".asa",".asax",".ascx",".ashx",".asmx",".cer",".aSp",".aSpx",".aSa",".aSax",".aScx",".aShx",".aSmx",".cEr",".sWf",".swf",".htaccess");
$file_name = trim($_FILES['upload_file']['name']);
$file_name = deldot($file_name);//删除文件名末尾的点
$file_ext = strrchr($file_name, '.');
$file_ext = strtolower($file_ext); //转换为小写
$file_ext = str_ireplace('::$DATA', '', $file_ext);//去除字符串::$DATA
$file_ext = trim($file_ext); //首尾去空
if (!in_array($file_ext, $deny_ext)) {
$temp_file = $_FILES['upload_file']['tmp_name'];
$img_path = UPLOAD_PATH.'/'.$file_name;
if (move_uploaded_file($temp_file, $img_path)) {
$is_upload = true;
} else {
$msg = '上传出错!';
}
} else {
$msg = '此文件类型不允许上传!';
}
} else {
$msg = UPLOAD_PATH . '文件夹不存在,请手工创建!';
}
}
🧠 思路
🛠️ 解题方法
🕙 Pass-10
🔍 源码解析
$is_upload = false;
$msg = null;
if (isset($_POST['submit'])) {
if (file_exists(UPLOAD_PATH)) {
$deny_ext = array("php","php5","php4","php3","php2","html","htm","phtml","pht","jsp","jspa","jspx","jsw","jsv","jspf","jtml","asp","aspx","asa","asax","ascx","ashx","asmx","cer","swf","htaccess");
$file_name = trim($_FILES['upload_file']['name']);
$file_name = str_ireplace($deny_ext,"", $file_name);
$temp_file = $_FILES['upload_file']['tmp_name'];
$img_path = UPLOAD_PATH.'/'.$file_name;
if (move_uploaded_file($temp_file, $img_path)) {
$is_upload = true;
} else {
$msg = '上传出错!';
}
} else {
$msg = UPLOAD_PATH . '文件夹不存在,请手工创建!';
}
}
🧠 思路
-
可以上传 png 文件;
-
bp 可以抓到包,修改后缀无效,后端过滤;
-
双写可以上传。
🛠️ 解题方法
💡双写绕过
抓包修改后缀为.pphphp,中间的 php 会被识别过滤,剩下的 p 与 hp 又组成了.php 后缀,是文件得以正常执行
注意系统识别是从左往右扫描,所以只能写成.pphphp
如果写成.phphpp 则会被去掉前面的 php,导致后缀变成.hpp
🕚 Pass-11
🔍 源码解析
🧠 思路
🛠️ 解题方法
🕛 Pass-12
🔍 源码解析
🧠 思路
🛠️ 解题方法
🕐 Pass-13
🔍 源码解析
🧠 思路
🛠️ 解题方法
🕑 Pass-14
🔍 源码解析
🧠 思路
🛠️ 解题方法
🕒 Pass-15
🔍 源码解析
🧠 思路
🛠️ 解题方法
🕓 Pass-16
🔍 源码解析
🧠 思路
🛠️ 解题方法
🕔 Pass-17
🔍 源码解析
🧠 思路
🛠️ 解题方法
🕕 Pass-18
🔍 源码解析
🧠 思路
🛠️ 解题方法
🕖 Pass-19
🔍 源码解析
🧠 思路
🛠️ 解题方法
🕗 Pass-20
🔍 源码解析
🧠 思路
🛠️ 解题方法
参考文献
https://www.cnblogs.com/xuanxian/articles/19145657
https://blog.csdn.net/2302_80442799/article/details/1538489933