EdXposed 框架遭恶意代码攻击事件——一场本不该发生的闹剧
wxx9248
2020年05月18日 19:03

0x00 前言

我第一次写专栏(也不太会写文章),有任何不妥当的地方请适当指出~

最早看到这件事情是在周六早上9点左右(EDT,北美东部夏令时),有人在我自己私下的一个小群推送了本次事件的相关资料。

推特 @mnihyc

当时我正在忙着调试工程,就草草瞅了一眼和上面的消息一起发送的酷安评论区截图,然后就放到了晚上看。

@mnihyc 提供的酷安评论截图

当时这条评论给我的感觉是,EdXposed官方翻车了,和微软的1809事件差不多。

等到了晚上,我点开Github链接阅读了所有的相关Pull Request(下文简称PR)和评论,发现这件事情的性质远比我想象的严重,直接威胁到了中国程序员的国际声望。

但是这还没让我下决心写一篇专栏,直到某位弯弯的出现,下文述。

直接戳痛一位留学狗的一句言论之一


0x01 事件陈述

下文所涉及的概念在此统一列出,如果不了解可以去查找相关资料:

  • EdXposed

  • Continuous Integration / Continuous Deployment (CI/CD)

  • Pull Request

事件的起源是EdXposed官方Git源下的537号PR。

该PR由Github ID:NekoInverter提交于 2020-5-16 5:33 AM EDT,具体动机不详。

链接:https://github.com/ElderDrivers/EdXposed/pull/537

#537 PR

此PR提交后立刻被NekoInverter自己关闭,同时在AppVeyor CI上,由于PR被关闭,Canary版本构建终止,未成功推送给用户。

链接:https://ci.appveyor.com/project/ElderDrivers/edxposed/builds/32916567

AppVeyor 对 #537 PR 的响应

随后NekoInverter又于 2020-5-16 5:34 AM EDT 重新开启了此PR,相隔仅为一分钟。

但是这次,AppVeyor CI的记录显示,此PR被成功构建,构建号为:0.4.6.3 (4549)-fexbxflm,构建耗时为4分22秒。

链接:https://ci.appveyor.com/project/ElderDrivers/edxposed/builds/32916577

AppVeyor 对 #537 PR 的再次响应

#537 PR 被构建成功

该PR的仅在EdXposed的安装脚本内加入如下代码:

#537 PR 内容

代码解释:

  • rm是UNIX/Linux操作系统的删除文件命令,-rf开关强制并递归地删除此目录(Recursively and Forcibly),即删除此文件夹以及其下的所有文件和文件夹。

  • /data是Android系统内存储用户数据的文件夹;

  • *是通配符,作用是匹配所有的字符串,在此处代指所有文件;

也就是说,如果你安装了 0.4.6.3 (4549)-fexbxflm 版本的EdXposed,你的所有数据会在显示完那一句欢迎之后被清空。

随后,NekoInverter于 2020-5-16 5:36 AM EDT 开启了#538 PR。

链接:https://github.com/ElderDrivers/EdXposed/pull/538

#538 PR

内容和#537 PR相同:

#538 PR 内容

NekoInverter于 2020-5-16 5:39 AM EDT 关闭了#538 PR,以及#​537 PR。

由于PR被过早地关闭,AppVeyor CI的记录显示,此PR未被成功构建。

链接:https://ci.appveyor.com/project/ElderDrivers/edxposed/builds/32916594

#538 PR 未被构建成功

但是,由于两次PR的间隔时间(3分钟)小于AppVeyor API指定的更新周期(5分钟),编译成功的软件包未被分发给最终用户。

至此NekoInverter的操作结束。


此时Github ID:BlueJett发现了NekoInverter提交的两个PR,于 2020-5-16 6:06 AM EDT 提交了#539 PR:

链接:https://github.com/ElderDrivers/EdXposed/pull/539

#539 PR

内容如下:

#539 PR 内容

仅对不同代码作解释:

  • /sdcard在最初的Android版本是外置SD卡的挂载目录,在现在的版本里是Android系统的内置存储(存储你的照片、视频和下载的文件等),是FUSE从/data/media/下的当前用户的数据文件夹映射过来的;

从向Console打印的消息“How about delete all your files”(删掉你所有的文件怎么样)来看,BlueJett是出于恶作剧的心理提交了这次PR。

由于BlueJett立刻关闭了此PR,AppVeyor CI的记录显示,此PR未被成功构建。

链接:https://ci.appveyor.com/project/ElderDrivers/edxposed/builds/32916846

AppVeyor 对 #539 PR 的响应


同样,Github ID:huanruomengyun看到了前几次的PR,也于 2020-5-16 6:08 AM EDT 提交了#540 PR。

链接:https://github.com/ElderDrivers/EdXposed/pull/540

#540 PR

内容如下:

#540 PR 内容

代码解释:

  • /data/data是Android系统用于存储所有App数据的文件夹,你在App设置页里面看到的“清空数据”的按钮就是将这个文件夹下对应App的数据文件夹清空;

  • chattr是Linux下用来给文件设置属性的命令,-R开关和rm命令的-r开关效果一样,递归地设置文件夹下所有文件和文件夹的属性,+i的意思是给这些文件设置不可变(Immutable)属性,即文件/文件夹不能被修改、删除、重命名和被创建链接,即使对于root来说也是一样;

同时,从PR标题“Improve smooth and battery life”(改善流畅度和续航)来看,huanruomengyun也是带着恶作剧的心理提交了这次PR。

根据AppVeyor CI的记录显示,此PR被成功构建,构建号为:0.4.6.3 (4549)-kihnewnj,构建耗时4分32秒。

链接:https://ci.appveyor.com/project/ElderDrivers/edxposed/builds/32916861

AppVeyor 对 #540 PR 的响应

#540 PR 构建成功

与NekoInverter不同的是,这次的构建被成功的分发给最终用户,这也是第一批受害者安装的版本。

huanruomengyun于 2020-5-16 7:23 AM EDT 关闭了此PR。


在#540 PR被提交后,BlueJett又于2020-5-16 6:20 AM EDT提交了#541 PR:

链接:https://github.com/ElderDrivers/EdXposed/pull/541

#541 PR

内容如下:

#541 PR 内容

代码解释:

  • /data/media是FUSE映射/sdcard的来源,前文已经说明;

PR标题是“Not bad, right?”(还不错吧?),说明BlueJett已经看到了#540 PR的内容,觉得”那次PR还挺‘不错’的“。

AppVeyor CI显示,此PR被成功构建,构建号为:0.4.6.3 (4549)-noofbiwx,构建耗时4分20秒。

链接:https://ci.appveyor.com/project/ElderDrivers/edxposed/builds/32916959

AppVeyor 对 #541 PR 的响应

#540 PR 构建成功

这次的构建被成功的分发给最终用户,是第二批受害者安装的版本。

BlueJett于 2020-5-16 6:25 AM EDT 关闭了此PR。

至此,对EdXposed源的恶作剧操作结束。


BlueJett发现事情不对,于 2020-5-16 7:02 AM EDT 提交了#542 PR。

链接:https://github.com/ElderDrivers/EdXposed/pull/542

#542 PR

内容如下:

#542 PR 内容

该PR试图覆盖最新版本的构建,让以后的用户不再接收到错误版本,但是为时已晚。


Github ID:singleNeuron于 2020-5-16 8:44 AM EDT 提交#544 PR。

链接:https://github.com/ElderDrivers/EdXposed/pull/544

#544 PR

内容如下:

#544 PR 内容

同样,该PR试图覆盖错误构建,事件到此结束。

huanruomengyun在Github发表道歉:https://github.com/ElderDrivers/EdXposed/pull/542#issuecomment-629814069

BlueJett在酷安发表道歉:https://www.coolapk.com/feed/18890939?shareKey=Y2ZmNWNjOWNiMTE1NWVjMjVhYzU~&shareUid=906959&shareFrom=com.coolapk.market_10.1.2 

开发者尝试关闭AppVeyor的Pull Request构建所提交的PR:


0x02 原因分析

  • 直接原因@NekoInverter、@BlueJett和@huanruomengyun作为开发者,对用户不负责,将可能危及用户信息安全的操作视为恶作剧,而后两者的行为直接导致了这场悲剧的发生;

  • 间接原因EdXposed的CI/CD机制存在严重缺陷,将未经审核和合并的PR代码编译为最终用户可以接收到的Canary版本,间接导致了此事件发生。


0x03 后续影响

  • 许多Github用户直接在涉事PR下开喷:

#537 PR 评论

#541 PR 评论

就不列举了。


私货:在看以上评论的时候,我还没有要写这个专栏的心:

请看#540 PR下面这个**:

吱吱吱宁是耗子吗?

这我就忍不了了,扯犊子呢,趁虚背刺也就是弯弯能干的出来吧。

赞同

呵呵


0x04 随便说几句

  • 这次的事件有损中国程序员的国际名望,同时还被一些恶势力趁虚而入,抓住把柄,贬低所有的中国人。作为一个计算机科学专业的留学生,我感到非常的痛心。我想看到中国在国际上被称赞,而不是留给那些未接触过中国、且对中国没有恶意的外国人一个不好的印象。所以真心希望像这样的事件不要再发生,尤其是在有着良好开发交流氛围的开源环境里面。

  • 玩笑可以开,但是什么事情都有一个度。请将rm -rf这种操作限制在聊天框内。


这篇文章写了半个通宵(2点到现在快7点了),本来还说做数电作业呢~我也不求赞和硬币什么的,希望喜欢的人能转发扩散,让更多的人看到。

转载请注明作者:wxx9248。

感谢@mnihyc向群内转载事件信息。

附IT之家的报道:https://m.ithome.com/html/487702.htm

// 脖子疼