游客发表
2021年冬天,独立漏洞Log4j那个漏洞爆出来的独立漏洞时候,我正坐在一间会议室里听人讲季度规划。独立漏洞手机震了一下,独立漏洞是独立漏洞运维群里发的消息:线上几个服务开始疯狂往外发请求,目标地址指向一个从没见过的独立漏洞IP。排查到凌晨三点,独立漏洞结论出来了——有人在利用Log4j的独立漏洞JNDI注入,试图拉取远程恶意类。独立漏洞我们运气好,独立漏洞防火墙拦住了。独立漏洞隔壁那家公司就没这么幸运,独立漏洞第二天新闻里说他们被挖矿程序塞满了整个集群。独立漏洞
这个漏洞后来被命名为Log4Shell,独立漏洞CVSS评分满分10分。独立漏洞但真正让我后背发凉的,不是它的破坏力,而是它的存在方式。Log4j作为一个日志组件,被无数Java应用当作“基础设施”引入。你写业务代码的时候根本不会想到它,它就在那里,安安静静地记录着每一条日志。直到有人发现,一段看起来人畜无害的${ jndi:ldap://...}字符串,就能让它变成入侵的跳板。
我后来翻了不少漏洞报告,发现一个挺有意思的现象。很多高危漏洞的根源,都不是什么高深的技术缺陷,而是“默认配置”和“历史兼容”这两件事搅在一起。Log4j支持JNDI查询,本来是为了方便在日志里动态获取一些环境信息。这个功能在二十年前可能很实用,但放在今天,它就成了一个没人记得关的后门。开发者不知道它存在,安全团队不知道它存在,连写Log4j的人可能都没想到会有人这么用。
这让我想起更早的Struts2漏洞。2013年到2017年那几年,Struts2每隔几个月就爆一个远程代码执行。每次的修复方式都差不多——加个黑名单,过滤掉某些特殊字符。然后过一阵子,有人换个编码方式绕过去,再爆一次。那段时间做Java Web安全的人,几乎人手一份Struts2的绕过笔记。大家一边骂一边修,修完继续骂。
独立漏洞这个词,是我自己瞎编的。我想说的是那种“不依赖复杂攻击链、单点就能打穿”的漏洞。它不需要你组合三四个条件,不需要你绕过什么深度防御,就是一个请求发过去,服务器就缴械了。Log4Shell是,Struts2的很多CVE是,Redis未授权访问也是。这类漏洞有个共同点:它们都藏在“默认信任”里。你信任内网,所以Redis不设密码;你信任日志内容,所以Log4j不检查输入;你信任框架,所以Struts2的参数过滤形同虚设。
去年有个朋友让我帮他看一个刚上线的系统。我扫了一遍,发现一个接口可以直接读取任意文件。他挺惊讶,说这个接口是内部用的,没打算对外。我问他,你知道你们前端打包的时候,把这个接口的路径写进JS里了吗?他愣了一下,说不可能吧。然后我打开浏览器控制台,把那个请求发给他看。他沉默了几秒,说“我回去改”。
这种事我见得太多。漏洞从来不是“被发现的”,它一直在那里,只是没人去看。安全圈有句话叫“攻击面管理”,听着挺专业,说白了就是:你得知道自己开了哪些门、哪些窗,哪些窗户看起来关着但其实插销是坏的。大多数团队连自己有多少个服务在跑都数不清楚,更别说每个服务依赖了什么、每个依赖又依赖了什么。
Log4j事件之后,SBOM(软件物料清单)这个概念火了一阵。大家都在说要搞清楚自己的软件里有什么。但两年过去,我接触的团队里,能拿出一份完整依赖清单的,一只手数得过来。不是不想做,是做着做着就发现,这事儿比想象中麻烦太多。一个Java项目,直接依赖几十个,间接依赖几百个,每个依赖的版本还在不停变。你今天理清楚了,明天发个版又乱了。
所以独立漏洞会一直存在。只要软件还在用别人的代码,只要默认配置还倾向于“方便”而不是“安全”,只要开发者还在赶进度而不是做审计,这类漏洞就不会消失。它不需要什么APT组织、不需要什么0day储备,一个脚本小子拿着公开的POC就能扫一片。这才是它真正可怕的地方——门槛太低了。
我写这些不是想贩卖焦虑。只是觉得,做技术的人得有个基本认知:你写的每一行代码,引的每一个包,开的每一个端口,都是在给自己挖坑。有些坑浅,掉进去爬出来就行;有些坑深,掉进去就出不来了。区别只在于,你什么时候发现它。
友情链接