很多人挖存储型XSS,存储存的错误上来就找输入点,挖掘看到输入框就填payload,过程提交完刷页面,存储存的错误没弹窗就换下一个。挖掘这路子不对。过程存储型XSS的存储存的错误核心不在输入,在输出。挖掘数据存进数据库只是过程第一步,真正触发的存储存的错误地方是后续某个页面把它读出来渲染的时候。你盯着输入点猛打,挖掘等于在银行门口晃悠,过程却不去看金库的存储存的错误门有没有锁。
我见过一个典型错误:测试评论功能时,挖掘用户在昵称字段填了
<script>alert(1)</script>,过程提交后页面没反应,就判定不存在漏洞。但实际情况是,昵称在评论区列表里被转义了,可后台管理页面用innerHTML直接拼接渲染,管理员一打开审核列表就中招。前端页面不弹,不代表后端页面不弹。只测用户侧、不测管理侧,是存储型XSS挖掘里最常踩的坑。另一个高频错误是payload太“标准”。
<script>alert(1)</script>这种教科书式的写法,现在的WAF和过滤函数闭着眼都能拦。有人被拦了就放弃,觉得没戏。其实换个思路:<img src=x onerror=alert(1)>被过滤了,试试<svg/onload=alert(1)>;再不行,看看能不能利用HTML属性逃逸,比如输入" onmouseover="alert(1),前提是输出点落在标签属性内部。payload的变形能力,直接决定你能不能绕过那层过滤。还有个隐蔽的错误:忽略存储和输出之间的时间差与上下文变化。你提交的数据可能先存进数据库,几个小时后被定时任务捞出来,拼进一封邮件模板或者导出成CSV。这时候输出环境完全变了——CSV里没有HTML解析,但邮件正文里可能有。有人只盯着Web页面,忘了邮件、日志、导出文件这些二次渲染场景。存储型XSS的“存储”二字,意味着数据会流动,流动到哪儿,哪儿就是潜在的触发点。
编码问题也经常把人带沟里。你输入
%3Cscript%3E,以为会被解码成<script>,结果后端存的就是原样的百分号编码,输出时浏览器不解析,白忙活。反过来,有些地方你输入原始尖括号,前端JS用decodeURIComponent解一遍再塞进DOM,反而弹了。搞不清楚每一层对数据做了什么处理,就是在盲猜。最要命的是不验证输出点的DOM结构。有人看到页面源码里出现了自己的payload,就兴奋地喊“存在XSS”。但payload可能落在
<textarea>或者<title>里面,浏览器根本不执行。得看它到底在哪个标签、哪个属性、哪个JS变量里。用开发者工具看渲染后的DOM,比看View Source靠谱得多。View Source看到的是原始响应,DOM才是浏览器实际解析的结果。说个具体的。某次测一个工单系统,我在工单标题里塞了
<img src=x onerror=alert(document.domain)>。提交后自己看工单详情,没弹。差点就过了。后来用管理员账号登录,打开工单列表,弹了。原因很简单:用户详情页对标题做了HTML实体编码,但管理列表页用的是Vue的v-html。同一个字段,两个输出点,一个安全一个不安全。只测自己能看到的那一面,漏报就是这么来的。挖掘存储型XSS,别急着填payload。先理清数据从输入到输出的完整链路,找到所有渲染点,再针对每个渲染点的上下文构造对应的绕过方式。这活儿急不得,急了就只剩误报和漏报。
顶: 15435踩: 681






评论专区