• 我是如何成为微软专业找 bug 的赏金猎人的
  • 发布于 2个月前
  • 496 热度
    0 评论
没错,我是做“Bug 赏金”这行的,也有人说应该叫“漏洞奖励”计划,但我觉得还是 Bug 赏金听着比较带劲。在今天的文章中,我想跟大家聊聊在找 bug 这件事上,业余和专业的到底有什么区别。这些都是我的真实经历,包括种种遗憾、惊喜和建议,希望能给各位带来一点启示。最后要强调一点,本文完全是我的主观经验,可能跟您的真实经历有所出入。

我跟 bug 赏金工作的缘分始于 2015 年初,当时我刚收到人生中第一笔官方赏金,没想到在这行一干就干到了今天。我发现的第一个 bug 是 Office 365 Outlook 中的 XSS 漏洞;2015 年底,我又在火狐浏览器里发现了自己的第一个浏览器有效 bug。这段经历为我打开了新世界的大门,之后我开始收敛心神,专注于给浏览器“挑毛病”。

过去五年来,我完成了从大学辍学生到助理系统开发者、再到网络安全工程师的职场蜕变,最后拿到了如今这份微软浏览器漏洞研究员的职位。这样的发展简直如梦似幻,连我自己都很难相信。

走过的弯路
在参与 bug 赏金活动过程中,我个人走过的最大弯路其实来自思想意识。

我之前一直觉得给浏览器找 bug 的本事不足以让自己在网络安全领域找到一份像样的工作。必须承认,浏览器 bug 研究属于网安领域内的小众方向,这种小众性也加剧了我的错误判断。我早期接触过的其他 bug 赏金同行大多是从 Web 应用程序安全起步,并一路坚持下去的,所以对自己这种痴迷于浏览器安全研究的路线,我实在是没什么信心。

但事实上,浏览器安全属于一块小而美的利基市场,我完全有资格在主要浏览器开发商那里拿下相应的职位。如今,我已经在微软浏览器团队工作一年有余,日常工作经历早就让我放下了对自己的怀疑情绪。所以在这里,我想回顾一下当初的错误,聊聊怎么为如今这份工作提前做好准备。

当初的我从来没想到自己能进入浏览器安全团队,所以一直没考虑过怎样才能保护浏览器安全。当初我找寻 bug 的主要方法就是多阅读关于浏览器和安全设计的资料,然后手动测试自己的猜测。这种方法虽然极为耗时、效率低下,但挺适合我——整个过程有点像冥想,可以说非常沉浸。如果运气不好,我也能学到关于最新 Web API 的知识;如果运气好一点,那我没准就找到了一个有趣的安全漏洞。这简直就是双赢,唯一的问题就是花费的时间有点多。

像我这种野路子出身的选手,一直都没接触过 fuzzing;更丢人的是,当时我对 fuzzing 方法的认识都有错误——我一直觉得 fuzzing 就像是加密货币圈搞的挖币,fuzzer 这东西只要跑起来就会疯狂吃掉我的 CPU 资源,直到遇上问题并引发崩溃。虽然我也知道要吃浏览器安全这碗饭,fuzzing 这关早晚得过,但原先的舒适区实在太舒适了,容我再躺会儿……

总结:寻找适合自己的利基定位,把这种定位跟个人爱好结合起来。只要迈出兴趣与工作契合的第一步,你已经赢了。

只管找,不管修
作为 bug 赏金猎人,那时候我满脑子都是找 bug。发现漏洞之后,我只需要在提交时稍做说明就直接踏上了又一段的找寻之旅。这种只管找、不管修的风格让我的技能储备出了问题,我根本不理解很多 bug 到底是怎么引发的。

这里要给新入行的朋友一点建议:如果你和当时的我一样,总想抢在别人前面早点提交新 bug,那至少记得去看看修复补丁公布。
那时候的我自以为聪明,“我为什么要自找麻烦?又没人给钱。”这话对,但也不对。过度急功近利反而适得其反。

关注 bug 原理能让我们掌握编码规则,这样我们慢慢就能理解 Chromium 的代码库和它的工作特性,提升自己发现 bug 的能力。只要把握住造成 bug 的根本原因,我们就能以同样的思路发现其他同类实例,成功把一项发现变成多项发现。在拥有原理层面的洞察力之后,我们才能正确判断 bug 的严重程度,免得把高危漏洞误当成小问题。况且,我们不光可以找 bug,更可以修 bug。编写补丁也有钱拿,增加总体收入岂不美哉?

好在那时候我有个好习惯,就是总会关注 bug 报告和相应的 Twitter 讨论。我会认真阅读每一条评论,没准哪一条就能给我重大启发。我也不会回避反对意见,而是结合自己掌握的一手信息判断对方的意见靠不靠谱、有没有参考价值。在网友们眼中不可理喻的某些设计,其实内部员工立足后端的视角上非常合理,所以应该学会从多个角度审视问题。我要是能早点领悟到这一点就好了,真的很遗憾。

加入微软之后,我的工作就不单单是提交安全 bug 了,更要跟开发人员合作进行修复。有些 bug 好修,有些却非常难修。所以在提交 bug 时,我得小心谨慎,保证自己不只提出了有限的可重现案例,更能给出比较可靠的根本原因分析和初步修复建议。当然,我现在仍然参与各类 bug 赏金计划,并在注释里尽可能帮助开发者快速理解当前问题。

我们收到的大部分上报 bug 都不是真正的安全漏洞。很多问题是之前就报过的,有一些属于设计中的正常现象,有一些无法重现,也有部分根本就是胡说八道。但也有不少案例相对复杂,会引发不同群体之间的热烈讨论。这些对话中往往隐藏着有趣的见解,所以我特别喜欢阅读这方面内容。

很神奇,我发现自己在转型成专业人士之后,经常会在讨论中向其他人解释为什么对方发现的问题并不是 bug,而是设计特性——当初的我肯定想象不到这样的场景。也正是这种跨越两种身份的经历,让我更能理解 bug 上报者们的付出与思路。

Edge 浏览器正茁壮生长,bug 总会不可避免地出现。随着新功能/变更/改进的注入,代码量膨胀必然带来更多 bug。结合个人经验,我觉得 bug 的产生主要源自以下几个方面(这里主要谈开发与安全团队方面的问题):
1.经验不足。新人们需要长时间学习才能理解 Edge 庞大代码库的来龙去脉。在学习过程中,大家肯定会犯错。
2.没做出最坏的假设。在安全保障方面,偏执的性格往往能够发挥奇效,因为这类开发者总会做出最坏的假设,并向安全团队表达相应的担忧。无论大家有没有考虑到,最坏的情况真的有可能出现。
3.缺乏安全教育。我在读计算机科学本科专业时,学校根本没有任何安全课程。虽然偶尔也会提一点编码最佳实践,但不是教学重点,内容也远远不够。所以在安全技能方面,我们基本上只能靠自己摸索。

安全教育可以说是 bug 赏金工作中的一项重点。在发现 bug 之后,我们首先得跟相关人员讨论漏洞情况、发生原因,以及如何通过自动测试防止今后再次出现。在微软,我们会接受强制性的安全培训、学习安全最佳实践并通过邮件掌握每周安全提示。总之,安全是每个人都必须承担的重要职责。

另外,我很早就发现找 bug 要比修 bug 简单得多。所以要想保护浏览器安全,首先得培养开发者的安全意识。如果没有开发环节的配合,最终安全根本无从谈起。安全是所有人的事,绝不只是安全团队的事。

我日常工作的另一部分,就是对计划引入 Edge 浏览器的新功能开展安全审查。乍听起来,这好像跟我之前的 bug 赏金经历没什么区别,但实际上完全不同。虽然两者目标相似,都是从功能中找 bug,但现在我需要查看 C++代码……当初我可不干这事。所以,我得先学会 C++,然后熟悉 Chromium-Edge 代码库。感谢同事们的帮助,我终于补上了这重要的一课。

总结:现在的积累和准备,都是为了未来能走得更稳、更快。所以要深挖代码,一定要深挖代码。

克服自我怀疑
自从干这行以来,我就总在跟自我怀疑做斗争。

记得当初第一次发现 bug 时,我的内心经历了非常复杂的斗争:“你是谁呀,就敢给那么大的公司找 bug?”但好在我尝试了,也成功了。在加入微软之后,我甚至很长一段时间都不敢相信这是真的。但确实是真的,而且我还挺称职~

现在有种说法,将这种怀疑情绪叫“冒名顶替综合症”,就是总觉得自己德不配位、没资格坐在目前的岗位上。其实没必要,我们应该压制住这种自我怀疑,并勇于尝试自以为做不到的事情,并用一个又一个意料之外的成果激励自己。

我在微软也有类似的感受,我身边的同事无论是知识储备还是业务水平都远高于我。但我还是留下来了,他们的优秀成了我提升自己的动力,我终要像他们一样优秀。

总结:大胆去做。无论看起来多么高大上的系统,我们都可以成为其中的一员。

回馈整个社群
大多数 bug 赏金猎人都是自学成才,我甚至怀疑可能这行里所有的人都没经受过系统训练。所以,大家只能从线上免费资源里总结经验。我们学习中用到的文章、博客、文献、幻灯片、演讲和视频等,都是作者们的心血与汗水。所以我们也该做出回馈,让这个开放社区更庞大、更健康、吸纳更多新鲜血液。

这绝不是什么亏本的买卖,给社群以回馈其实有很多好处。

首先,如果你是一位非英语母语的朋友,那回馈过程能提升你的写作技巧,特别是有效沟通安全问题的能力。这种沟通能力很重要,甚至可能成为支撑职业规划的关键。围绕特定主题开展写作,往往能让我们发现自己当初错过了的重要内容。

其次,这有助于提升你的互联网安全水平。我们的贡献可能在不经意间启发了某些人,他们发现的 bug 可能消除了某些隐患。

最后,这也可以为你建立声誉和认可度。你的贡献可能会让招聘方或合作方记住你,增强自身影响力永远没错。当然,很多朋友可能更希望在社交媒体上得到别人的肯定,而忽略了讨论本身的意义。我曾经也是这样,随时都要看自己“妙语”下的点赞数量又增加了多少。其实这没有意义,别用点赞数来衡量自己的价值。

我还有另一个先入为主的错误观念,就是像微软这样的大公司不会关心人们在网上写了什么。所以我之前对某些企业表达失望时,倾诉的对象主要是同行,毕竟那些“身居高位”的家伙才不会在乎。
但事实上,他们真的很在乎,而且会持续关注有价值的博客/推文。我亲眼目睹过他们如何认真对待反馈,并设定了相应的开发计划。所以别灰心,只要你的表达有价值,声音最终都会传到企业那边。


总结:参与进去,要说也要听,我们就是网络安全社区中的一分子。


调整好节奏
当初自己当“独行侠”的时候,花的都是个人时间。我想做就做,累了就休息,没什么压力。但拿着薪水正常上班可不是这样,所以我得在新岗位上找到新的平衡。
我是在新冠疫情期间加入微软的,所以跟很多朋友一样,我刚入职就开始居家办公。作为新员工,我得保证自己学到需要掌握的所有技能,而且尽最大努力适应这份新工作。居家办公确实是种新鲜体验,毕竟人在离开办公室后、大脑会暗示自己工作模式已经关闭。

所以混乱的居家办公状态让我不知不觉就工作得太久,甚至周末都在忙活,失去了正确的办公节奏。虽然公司内部一直在提醒大家关注工作和生活的平衡,但刚进大厂的我实在是兴奋,根本没听进去。

于是,问题很快就来了。我精神疲惫、睡眠不足、压力巨大。于是,我立刻采取行动,包括周末不再工作、给自己制定明确的工作日下班时间,并留出时间排解压力。我确保每天至少睡 7~8 个小时,还开始刻意少喝咖啡。这里最重要的就是休假,我第一次休假时强迫自己彻底忘掉工作,回来之后身心状态确实大为改观。倦怠感消退,我感觉自己又准备好迎接新的挑战了。

总结:调整好节奏,避免倦怠感。工作是马拉松,而不是百米短跑。

如何投身于浏览器安全领域?
这也是我被问到最多的问题之一。我当初选择这个方向只是因为我觉得浏览器 bug 很酷,找起来很带劲。加入这个领域没什么技巧可言,只能是多看相关资料、了解一切自己感兴趣的内容,总之知识储备最重要。
下面我分享一些自己当初入门学习时的链接:
Chromium代码库——包含几百万行代码,大家可以随时查看跟所关注功能相关的代码段。
Chromium bug tracker——大家提交的安全 bug 都在这里,多听多看有助于提升自身水平。
Chromium常见问题解答——这里有很多安全误报,同样值得学习。
Chromium严重性指南——通过一个个示例,帮助我们理解如何确定安全 bug 的严重性。
Mozilla bug tracker——影响火狐浏览器的 bug 都上报在这里。
Mozilla 安全公告——获取最新的火狐安全 bug 补丁,甚至包括某些未公开 bug 的补丁。

浏览器 bug 主要可以分为两类:
内存相关 bug——包括内存释放后使用啦、缓冲区溢出之类,这类 bug 占 Chromium 全部安全 bug 中的七成(一般属于高严重性 bug)。
     a. 前往‘about:crashes’就能看到已注册的崩溃列表。大家可以在 C:\Users\test\AppData\Local\Google\Chrome\User Data\Crashpad\reports 处找到转储的故障信息(以 Chrome 为例)。获取 windbg 并打开故障转储,之后执行 !analyze -v
     b. 大家也可以在这里查阅 Chromium ASAN builds,了解在正常构建时可能不会被触发的 bug 并实现更全面的堆栈跟踪。
     c. 内存 bug 一般用 fuzzing 测试就能发现。
逻辑 bug——通用 XSS、SOP 绕过、UI 欺骗等都属于跟内存无关的逻辑 bug:
     d. 常见的查找方法就是手动寻找并/或阅读源代码。

我好像天然就对逻辑 bug 更有兴趣。因为在接触安全领域之前,我主要研究 Web 技术,所以已经拥有一定的 HTML/JS/CSS/HTTP 知识背景。所以如果大家也对 Web 有所了解,那么不妨先从逻辑 bug 入手。另一方面,如果各位在逆向工程或自动化方面比较有经验,那用 fuzzing 测试查找内存损坏问题可能更好。当然,这两条线也可以共同推进。

只要掌握了足够的知识,脑袋里的各种猜测就会自己跳出来。接下里就是去验证这些猜测,虽然大部分会失败,但请千万不要放弃。最终,你会惊喜地发现安全 bug 就这么被找到了。
总结:学习、学习、再学习。有了想法就去试,失败了就再来一次。

全面自动化
Fuzzing 测试在软件应用的保护中至关重要,而自动化也是节约时间、增加结果产出的利器。
可能有些朋友还不太熟悉 fuzzing,也就是模糊测试:它是将伪随机生成的输入提供给进程(例如浏览器),之后检测进程是否崩溃的测试方法。微软在 fuzzer 方面投入了大量资金,这也是我加入以来需要补上的重要一课。
事实证明,我对 fuzzer 先入为主的观念完全是错误的。Fuzzing 本身博大精深,涉及多种不同的方法与学科。截至目前,我对 fuzzer 的体验虽然主要立足浏览器场景,但已经能体会到它的普适性潜力。这里我只列出自己新手用过的部分工具/fuzzer/生成器:
Libfuzzer——这是一个进程内用于覆盖的 fuzzer。简单来讲,我们只需要设置一个函数,它就能轻松向该函数提供各种输入并返回覆盖信息(这里的覆盖,代表在特定输入期间接触过多少代码)。Libfuzzer 的使用要求我们访问浏览器源代码,并掌握一些关于 C++的知识。
Dharma——这是一款基于语法的 fuzzer,由我们的团队成员 Christoph Diehl 开发完成。在使用时,我们需要编写一个语法文件,向 Dharma 描述某个 JavaScript API 或者 HTML 元素的样子,之后 Dharma 就会生成一大堆可以在浏览器内运行的测试用例。虽然不涉及浏览器源代码,但 Dharma 的使用要求我们掌握 JS 和 HTML 知识,并对相关语法有一定了解。
Playwright/Puppeteer——通过 NodeJS API 控制浏览器。使用这款强大的工具,我们可以对浏览器进行各种控制,例如使用浏览器执行某些重复性任务。使用过程不涉及浏览器源代码,但要求我们稍稍掌握一点 NodeJS 知识。

Octo——Fuzzing 库。在 fuzzing 期间,我们有时需要生成随机字符串、随机数或者一些随机内容。这个库能帮助我们轻松获得这些随机内容,适用于 NodeJS 项目和带有捆绑包的浏览器版本。不涉及浏览器源代码,但要求我们最好掌握一点 NodeJS/JS 知识。

总结:早点进军自动化领域、扩大视野,别在舒适区躺着不动。

上报浏览器安全 bug
安全 bug 永远存在,我真心觉得会永远存在。而且就在当下、就在我们的屏幕背后,就潜藏着一个个 bug,快把它们找出来~
假如大家在 Edge 浏览器中发现了一个 bug,那么在上报之前请注意以下几点:

它能在 Chrome 上重现吗?
是——把 bug 上报给 Chromium,而非 Edge。
否——上报给Edge。
它能在火狐上重现吗?
是——将 bug 分别上报给 Edge 和Mozilla。
否——只上报给 Edge。
你使用的是 Edge 的最新稳定版吗?
前往‘edge://settings/help’并查看是否为最新。
在报告中列出确切版本。
说明你使用的操作系统(Windows、Mac、Linux、Android 或者 iPhone)。
在报告上传一个最小化测试用例(请勿发送现场演示链接)。
上传一段关于 bug 现象的短视频(我个人喜欢用 OBS)。
找找其他浏览器中有没有对应的先例。

总结:Bug 就在那里,同志们冲啊!

写在最后
希望我的个人经历能给大家带来一点启示,特别是从我的错误中吸取教训。文中提出的当然只是些非常浅表的技巧,更有份量的知识还需要各位亲自挖掘。与其他学科一样,与 bug 的斗争同样艰难且需要深耕不辍。这就是我的 bug 赏金故事。
用户评论