1. 从“黑盒”到“白盒”:我的WEB漏洞实战心法
干了这么多年安全,我越来越觉得,WEB漏洞的攻防就像一场永不停歇的“猫鼠游戏”。新手入门时,面对SQL注入、XSS、文件上传这些名词,往往觉得眼花缭乱,工具一顿乱扫,报告一堆,但真到实战,面对一个稍微复杂点的目标,还是无从下手。问题出在哪?我觉得是思路没打通。今天,我就结合自己踩过的坑和总结的经验,抛开那些教科书式的定义,聊聊怎么把常见的WEB漏洞“玩明白”,形成一套从信息收集到漏洞利用,再到深入挖掘的实战思路。这不仅仅是工具的使用,更是一种思考方式的转变。
很多人一上来就直奔漏洞扫描器,这没错,但那是“黑盒”视角。真正的进阶,是尝试理解代码为什么会出问题,也就是“白盒”思维。即使你没有源码,通过观察应用的行为、参数传递、错误回显,也能在脑子里构建出它大致的逻辑。比如,一个搜索功能,你输入admin和输入admin',回显的页面结构或响应时间是否有细微差别?这种差别就是线索。我们常说的“常见漏洞”,其核心无非是程序没有处理好“数据”与“指令”的边界。用户输入的数据,被程序当成了代码的一部分去执行,漏洞就产生了。接下来,我们就拆开几个最典型的漏洞,看看它们背后的逻辑和实战中的那些“骚操作”。
2. 注入类漏洞:与数据库和服务器“直接对话”
这是WEB安全的老大哥,也是危害性极高的一类。核心就一句话:程序将用户输入的数据,未经充分处理就直接拼接到了数据库查询语句或系统命令中,导致攻击者可以“注入”并执行额外的指令。
2.1 SQL注入:不仅仅是' or '1'='1
经典的' or '1'='1是入门,但实战中远不止如此。现在的应用多少都有点防护,比如过滤了单引号、用了预编译(但可能用错地方)。我的思路是分层测试:
第一步,探针与指纹识别。不要一上来就union select。先通过参数插入一些特殊字符,看回显。
- 数字型参数:
id=1和id=1-0结果是否一致?如果一致,可能存在数字型注入,因为1-0在数据库里计算结果也是1。 - 字符型参数:
search=test和search=test'。观察页面是否报错(数据库错误信息直接暴露),或者页面布局是否错乱(闭合了引号导致后续HTML无法正常渲染)。 - 此外,提交
search=test和search=test\"(带反斜杠),如果后者正常,说明前端或后端可能做了转义,需要进一步测试绕过。
第二步,判断数据库类型。不同数据库的注入函数、系统表、注释符号都不同。通过报错信息是最快的。如果没有报错,可以用时间盲注的方式探测:
- MySQL:
id=1 and sleep(5)-- - PostgreSQL:
id=1 and pg_sleep(5)-- - MSSQL:
id=1;waitfor delay '0:0:5'--
一个很实用的技巧是,观察应用本身的错误页面。有时404页面会带上Powered by XXX,或者通过HTTP响应头里的Server、X-Powered-By字段,也能判断后端技术栈,从而推测数据库。
第三步,绕过常见的过滤。这是体现思路的地方。假设它过滤了空格和select。
- 绕过空格:用
/**/(MySQL)、%0a(换行符)、%0b(垂直制表符)、()括号包裹。 - 绕过关键词:大小写混合
SeLeCt、双写selselectect(如果过滤是删除关键词,双写后删除中间的select,剩下的又组合成了select)、内联注释/*!select*/(MySQL特有)、用like、regexp等函数替代=。 - 编码绕过:对注入语句进行URL编码、十六进制编码、Unicode编码。有时前端做了检查,但后端解码后直接使用。
注意:盲注(布尔盲注、时间盲注)是实战中的常态。页面没有明确回显数据,但你可以通过页面返回的真/假状态(如图片是否加载、关键词是否存在)或者响应时间差,来一位一位地“猜”出数据。这个过程很枯燥,必须用工具(如sqlmap的
--level和--risk调高,或自己写脚本),但思路要清晰:构造一个条件语句,让数据库根据我们想知道的数据位是1还是0,返回不同的可观测结果。
2.2 命令注入与代码注入:更底层的危险
当用户输入被拼接到系统命令(如ping、ls)或后端脚本代码(如eval()、system())中时,就会发生这类漏洞。危害极大,直接导致服务器被控制。
命令注入的测试点:任何调用系统命令的功能都可能存在,比如网络工具(ping、traceroute)、文件操作、系统信息查询。
- 测试方法:在参数后拼接命令分隔符。
- Linux:
;、&、|、\n(换行)、反引号 - Windows:
&、|、||、%0a
- Linux:
- 例如:一个
ping功能,参数是ip=127.0.0.1。尝试ip=127.0.0.1;whoami或ip=127.0.0.1 || dir。 - 如果过滤了分隔符,可以尝试:
- 变量拼接:
a=who;b=ami;ip=127.0.0.1;$a$b - 编码绕过:将命令进行base64编码,然后通过
echo <base64> | base64 -d | bash这种方式执行。 - 利用环境变量:
ip=127.0.0.1;${PATH:0:1}可能返回/,再配合其他字符构造命令。
- 变量拼接:
代码注入:常见于使用了eval()、assert()、preg_replace()的/e模式(PHP)等危险函数的场景。
- 例如,一个计算器功能:
calc.php?expr=1+1,后端可能用eval("return $expr;")。 - 测试:
expr=1;phpinfo()。或者利用反引号执行命令:expr=\whoami``。 - 在模板注入(SSTI)中,用户输入被当成了模板语言的一部分。比如
{{7*7}}返回49,就很可能存在服务端模板注入。不同框架的payload不同(Jinja2, Twig, Freemarker, Velocity等),需要先识别框架。
实操心得:对于命令/代码注入,一个关键的技巧是参数污染。有时应用为了兼容性,会接受多个同名参数,如
file=test1&file=test2,后端可能只取了第一个或最后一个。你可以尝试file=legal.jpg;ls&file=test.jpg,看看执行的命令是哪个参数触发的。另外,注意观察错误信息,有时命令执行失败会回显部分错误,这能帮你调整payload。
3. 跨站脚本攻击:在用户浏览器里“做文章”
XSS的核心是恶意脚本在受害者的浏览器中执行。它不直接攻击服务器,而是利用服务器作为“跳板”,攻击其他用户。根据脚本的存储和触发位置,分为反射型、存储型和DOM型。
3.1 反射型与存储型XSS:寻找未过滤的输出点
反射型XSS:Payload在URL参数中,服务器直接将其拼接到响应页面里,一次性的。比如搜索功能:search=<script>alert(1)</script>。
- 测试思路:找所有用户输入并回显到页面的地方。不仅仅是
<input>的value属性,还有:- HTTP头部的回显(如
User-Agent,Referer,有时会被显示在管理后台的日志页面)。 - 错误信息中的回显。
- 重定向参数(如
redirect_to)。
- HTTP头部的回显(如
- 绕过过滤:
- 如果过滤了
<script>,尝试其他标签:<img src=1 onerror=alert(1)>、<svg onload=alert(1)>、<body onload=alert(1)>。 - 如果过滤了事件处理器(
onerror等),尝试利用href或src属性执行JavaScript:<a href="javascript:alert(1)">click</a>,或者利用<iframe>、<embed>标签。 - 如果对输入做了HTML实体编码(如
<变成<),但输出点是在JavaScript代码段中,比如:<script>var userInput = '<?php echo $input; ?>';</script>。这里你需要闭合字符串和语句:输入';alert(1);//,最终变成var userInput = '';alert(1);//';,成功注入。
- 如果过滤了
存储型XSS:Payload被保存到服务器数据库或文件里(如留言板、昵称、文章评论),每当用户访问相关页面就会触发,危害更大。
- 测试思路:所有用户可以提交并持久化数据,且其他用户能查看的地方。要特别注意富文本编辑器,它可能允许一些HTML标签,但过滤不全。
- 实战技巧:
- 测试过滤逻辑:先提交一段包含各种标签和属性的复杂但无害的HTML,看哪些被保留,哪些被删除或转义。这能帮你摸清WAF或过滤函数的行为。
- 利用编码绕过:如果过滤函数只执行一次,可以尝试多重编码。例如,先将
<编码为<,服务器可能解码一次变成<,然后过滤函数发现是<就转义成<,但最终输出时,浏览器会解码<再次变成<,导致过滤失效。这需要精确判断服务器的处理流程。 - 结合其他漏洞:如果网站存在文件上传漏洞,且上传的HTML/JS文件能够被浏览器访问,那么直接上传一个包含恶意脚本的HTML文件,然后诱导管理员访问,也是一种存储型XSS的利用方式(常被用于钓鱼攻击的后台)。
3.2 DOM型XSS:纯前端的“魔术”
DOM型XSS比较特殊,漏洞的根源在前端JavaScript代码中。数据从源头(如URL的location.hash、document.referrer)到接收器(如innerHTML、eval()、document.write())的传递过程中,没有经过安全的净化处理。
挖掘思路:
- 寻找源(Source):在浏览器开发者工具的Sources或Debugger中,搜索以下关键词:
location.hash、location.search、document.referrer、window.name、postMessage数据、URL解析函数(如decodeURIComponent)。 - 寻找汇(Sink):搜索危险的DOM操作函数:
innerHTML、outerHTML、document.write()、eval()、setTimeout()/setInterval()(第一个参数是字符串时)、location赋值(如location.href=,可能导致跳转,也算一种利用)。 - 手动分析数据流:找到从源到汇的代码路径,看中间是否有过滤或编码。一个经典例子:
攻击者访问var hash = location.hash.substring(1); // 从URL的#后取数据 document.getElementById('message').innerHTML = 'Welcome, ' + hash; // 直接拼接进innerHTMLhttp://site.com/page.html#<img src=1 onerror=alert(1)>,即可触发XSS。
自动化辅助:可以使用浏览器插件(如DOM Invader)或Burp Suite的DOM XSS扫描器,它们能自动追踪源到汇的数据流,并尝试插入探测payload。
注意事项:DOM型XSS的利用Payload构造需要格外小心浏览器的解析差异。例如,
<img src=x onerror=alert(1)>在通过innerHTML插入时,如果标签没有被正确闭合,可能不会执行。有时需要利用JavaScript伪协议,或者通过<svg>标签来更稳定地触发。在测试时,务必在多种浏览器(Chrome, Firefox, Edge)下验证效果。
4. 文件上传漏洞:通往服务器的一扇“后门”
文件上传功能如果处理不当,就是给攻击者直接上传一个可执行脚本到服务器的机会,危害通常是致命的。
4.1 绕过客户端与服务器端检查
一个健壮的上传防御应该是多层的,而我们的攻击就是逐层绕过。
第一层:客户端检查(JavaScript校验)
- 表现:选择文件后,立刻弹出“文件类型不正确”,但还没开始上传。
- 绕过:太简单了。直接禁用浏览器JavaScript(F12开发者工具,Settings里Disable JavaScript),或者用Burp Suite拦截请求,修改
filename和Content-Type后再放行。因为检查只在浏览器端,请求根本没到服务器。
第二层:服务端Content-Type检查
- 表现:服务器检查HTTP请求头中的
Content-Type是否为允许的类型(如image/jpeg,image/png)。 - 绕过:用Burp Suite将
Content-Type改为image/jpeg即可。这层防护非常弱。
第三层:服务端文件扩展名检查这是重点。黑名单和白名单两种策略。
- 黑名单策略:禁止上传
.php,.asp,.jsp等。- 绕过方法:
- 大小写:
.Php,.pHp - 双重扩展名:
.php.jpg,.php.(注意末尾的点,Windows系统可能会忽略) - 特殊后缀:
.php5,.phtml,.phps(某些服务器配置下仍可解析) - 利用解析漏洞:最经典的是IIS 6.0的目录解析(
/upload/test.asp/1.jpg会被当作.asp文件执行)和分号解析(test.asp;.jpg)。Apache的multiviews漏洞(test.php.jpg如果找不到test.php.jpg,会尝试找test.php)。Nginx的畸形解析(如test.jpg/.php,如果配置不当,会交给PHP解析test.jpg)。 - 在文件名末尾加空格、点、
::$DATA(Windows NTFS流特性)。
- 大小写:
- 绕过方法:
- 白名单策略:只允许
.jpg,.png,.gif。这安全得多,但仍有绕过可能。- 条件竞争攻击:有些应用先允许上传任意文件到临时目录,然后检查,检查通过再移动到正式目录。攻击者可以疯狂上传一个
.php文件,同时疯狂访问这个临时文件的URL,在它被删除之前访问到,就能执行。 - 结合服务器解析漏洞:比如上传一个
.jpg文件,但文件内容其实是<?php phpinfo();?>。如果服务器存在文件包含漏洞(下面会讲),就可以通过包含这个图片马,来执行其中的PHP代码。 - 修改文件幻数(Magic Number):在文件开头添加图片的文件头(如
GIF89a),后面再接PHP代码。绕过了一些基于文件内容头的检查。
- 条件竞争攻击:有些应用先允许上传任意文件到临时目录,然后检查,检查通过再移动到正式目录。攻击者可以疯狂上传一个
第四层:服务端文件内容检查
- 图像二次渲染:最有效的防御。服务器用GD库等重新生成一张图片,任何嵌入的恶意代码都会被清除。
- 绕过:极难。一种研究方向是制作Polyglot文件,即一个文件同时是合法的图片和合法的脚本。例如,精心构造一个既符合GIF规范,又能被PHP解析的文件。这需要深厚的文件格式知识,且成功率不高。
4.2 上传后的利用与组合拳
成功上传一个Webshell只是第一步,如何访问和执行它?
- 确定上传路径:通过上传正常图片,查看其在前端显示的URL,来推断上传目录的路径规则。
- 利用文件包含漏洞(LFI/RFI):这是上传漏洞的“黄金搭档”。如果网站存在本地文件包含(LFI),即使你上传的是图片马,也可以通过包含它来执行PHP代码。例如:
index.php?page=uploads/evil.jpg。 - 利用.htaccess或web.config文件:如果能上传这些配置文件,可以重写服务器解析规则。例如,上传一个
.htaccess文件,内容为AddType application/x-httpd-php .jpg,那么之后上传的所有.jpg文件都会被当作PHP执行。(这通常需要上传目录有执行权限,且AllowOverride设置允许) - 绕过WAF:一些云WAF或硬件WAF会检查请求体中的文件内容。可以尝试将Payload进行多重编码、分块传输编码(Chunked Transfer Encoding)、或者利用WAF解析HTTP协议与后端服务器解析的差异(协议层绕过)。
踩坑记录:我曾遇到一个场景,白名单只允许
.zip。我上传了一个包含PHP webshell的ZIP包,然后利用服务器的文件解压漏洞——服务器会自动解压上传的ZIP到固定目录,但目录名和文件名可控。我通过目录穿越,将shell解压到了Web目录下。所以,永远不要只盯着一个点,要思考整个功能流程的每个环节是否都可能出问题。
5. 信息泄露与逻辑漏洞:被忽视的“致命伤”
这类漏洞不涉及复杂的代码执行,但往往能直接导致严重的安全问题,甚至成为攻击链条的关键一环。
5.1 敏感信息泄露:主动发现与被动收集
- 源码泄露:
.git目录、.svn目录、.DS_Store文件被部署到线上。直接访问即可下载整个版本库,里面可能包含数据库配置、后台路径、甚至源码中的硬编码密码。工具:dvcs-ripper。 - 备份文件泄露:
www.zip,www.rar,bak文件,index.php.bak等。通过字典爆破目录和文件。 - 配置错误:错误的服务器或应用配置导致信息泄露。
- 目录列表:Apache的
Options +Indexes未关闭,直接列出目录下所有文件。 - 默认页面/文件:
phpinfo.php,test.php,admin/等。 - 错误信息过于详细:将数据库错误、堆栈跟踪直接返回给用户,暴露表结构、路径等信息。
- 目录列表:Apache的
- HTTP头信息泄露:
Server,X-Powered-By,X-AspNet-Version等,暴露了服务器、语言、框架版本,方便攻击者寻找已知漏洞。 - CORS错误配置:如果
Access-Control-Allow-Origin被设置为*或不可信的来源,可能导致敏感数据被恶意网站通过JavaScript读取。
信息收集技巧:这不仅是漏洞扫描器的工作,更需要手工浏览和观察。
- 用Burp Suite的
Target->Site map功能,仔细查看每一个请求和响应。 - 关注每一个JS文件,里面可能包含API接口路径、隐藏的参数、甚至硬编码的密钥。
- 使用
ffuf或dirsearch进行目录和文件爆破时,字典要全面,特别是针对目标技术栈的字典(如针对PHP的、Java的)。
5.2 业务逻辑漏洞:与开发人员“斗智斗勇”
这是我最喜欢挖的一类漏洞,因为它考验的是对业务的理解和“脑洞”。常见的有:
- 越权访问:
- 水平越权:修改请求中的ID参数(如
/user/profile?id=123改为id=124),访问其他用户的资源。 - 垂直越权:普通用户通过修改Cookie、参数或直接访问管理员URL(如
/admin/deleteUser),获得管理员权限。测试时,用一个低权限账号登录,抓包,然后换高权限账号的Cookie或Token重放请求,看是否成功。
- 水平越权:修改请求中的ID参数(如
- 密码重置漏洞:
- 验证码可爆破:4位或6位数字验证码,无次数限制或失效时间长。
- 验证码回显在响应中:直接在返回的JSON或HTML里找到。
- 修改接收手机号/邮箱的参数:将
email=victim@xxx.com改为email=attacker@xxx.com。 - 跳过验证步骤:直接访问重置密码的最后一步(
/reset/final?token=xxx),尝试构造或预测token。
- 支付逻辑漏洞:
- 金额篡改:支付请求中,将
amount=100改为amount=0.01或-100(如果后端没校验负数)。 - 数量篡改:购买数量改为负数,可能导致总额为负,增加余额。
- 重复提交:网络延迟时多次点击提交订单,后端未做幂等性校验,导致只扣一次钱却发了多个实物。
- 最终支付状态依赖前端返回:支付成功后,前端告诉后端“支付成功”,后端就发货。攻击者可以拦截前端请求,伪造成功信号。
- 金额篡改:支付请求中,将
- 竞争条件:除了文件上传,还常见于优惠券领取、限量商品购买、积分兑换等场景。核心是“检查”和“使用”不是原子操作。用Burp Suite的
Turbo Intruder插件同时发起上百个请求,很容易绕过“一人限领一张”的限制。
思路技巧:挖掘逻辑漏洞,最好的方法是把自己当成一个“挑剔”的用户,或者一个想“钻空子”的用户。仔细走一遍核心业务流程(注册、登录、修改信息、下单、支付、售后),对每一个步骤、每一个参数都问一句:“如果我修改这个会怎样?”“如果我跳过这一步会怎样?”“如果我重复做这件事会怎样?” 多账户测试(至少两个普通用户,一个管理员)是发现越权问题的黄金法则。
6. 漏洞的串联与组合利用
真实的渗透测试中,很少靠一个漏洞就直达目标。更多时候是像拼图一样,把多个低危或中危漏洞串联起来,形成一条完整的攻击链。
一个经典的攻击场景:
- 信息收集:通过目录扫描发现
/phpinfo.php,泄露了网站绝对路径和服务器配置。 - SQL注入:在某个搜索框发现时间盲注,用sqlmap获取了后台管理员账号的密码哈希。
- 密码破解:哈希是MD5,扔到彩虹表网站成功破解出弱密码。
- 登录后台:通过信息收集猜出后台地址是
/admin/login.php,用破解的账号密码登录。 - 文件上传:后台有上传插件/主题的功能,但做了白名单限制,只允许
.zip。 - 文件包含:在网站某处发现本地文件包含漏洞(LFI),参数是
?file=../templates/header.php。 - 组合利用:在后台上传一个ZIP压缩包,里面包含一个图片Webshell(
shell.jpg,内容为<?php system($_GET[‘c’]);?>)。假设它被解压到/uploads/目录。然后利用LFI漏洞去包含这个图片马:?file=../uploads/shell.jpg&c=whoami,成功执行系统命令,获得服务器权限。
这个链条里,任何一个单独的漏洞可能都不足以直接GetShell,但组合起来就威力无穷。所以,在测试时,要有“链路思维”,每发现一个漏洞,都要想想它能为你后续的攻击提供什么信息或铺垫(如获取路径、账号、特定权限等)。
7. 防御视角下的思考与工具选用
理解了攻击,才能更好地防御。从开发和安全运维的角度,我有几点深刻的体会:
- 安全开发生命周期(SDL):安全不是最后一步才考虑的。在需求设计阶段就要考虑威胁建模,编码阶段要使用安全的函数和框架(如使用预编译语句防SQL注入,使用安全的输出编码防XSS),测试阶段要有专门的安全测试。
- 最小权限原则:Web服务器进程(如www-data, apache用户)的权限要严格控制,数据库用户只用赋予其必要的最小权限(SELECT, INSERT,而不是ALL PRIVILEGES)。
- 纵深防御:不要依赖单一防护措施。比如文件上传,要结合前端校验、后端白名单、重命名、文件内容检查、存储到非Web目录、通过脚本读取后再分发等多种手段。
- 输入验证与输出编码:这是防御大多数WEB漏洞的基石。对所有用户输入进行严格的、符合业务逻辑的验证(类型、长度、范围、格式)。在所有数据输出到不同上下文(HTML、JavaScript、URL、CSS)时,进行相应的编码。
- 依赖组件安全:定期更新框架、库、中间件(如Struts2, Spring, Redis, Nginx)。一个爆出漏洞的第三方库,可能让你所有的安全努力付诸东流。
工具是手臂,思路才是大脑。我常用的工具链:
- 信息收集:
Burp Suite(Proxy, Spider, Scanner)、nmap、ffuf/dirsearch、Subfinder/Assetfinder。 - 漏洞探测:
Burp Suite Active Scan、sqlmap、XSStrike(专精XSS)、Upload-Labs(本地搭建练习环境)。 - 漏洞利用:
Metasploit、Cobalt Strike(后渗透)、各种语言的Webshell。 - 辅助分析:浏览器开发者工具、
Wappalyzer(识别技术栈)、Postman(调试API)。
最后,保持学习和实践。WEB安全领域变化飞快,新的漏洞利用方式、绕过技巧层出不穷。多看看安全社区(如Seebug、先知、安全客)的案例分享,自己在合规的靶场(如DVWA、WebGoat、PentesterLab)里反复练习,把思路和手法变成肌肉记忆。真正的安全高手,靠的不是某一个神级工具,而是在海量经验中积累起来的、对漏洞本质的深刻理解和对攻击链路的敏锐直觉。