聚焦源代码安全,网罗国内外最新资讯!

编译:奇安信代码卫士团队

本文讲述的是作者如何从亚马逊 Kindle 中发现严重漏洞并获得1.8万美元漏洞赏金的过程。

引言

前一段时间,我们发现亚马逊 Kindle 上新了一个名为 “Send to Kindle” 的功能,可使用户将电子书以邮件附件的形式发送到自己的设备。我们马上想到了这个功能可能存在的安全问题:如果我们能够将恶意电子书发送给毫不之情的用户会怎样?

于是,我开始研究这些潜在问题,结果发现组合利用三个漏洞可导致攻击者在 Kindle 上远程执行代码。该代码以 root 身份运行,攻击者仅需要知道分配给受害者设备的邮件地址即可。

攻击者可以访问设备凭据并使用受害者的信用卡在 Kindle 商店中购买商品。攻击者可以在商店中出售电子书并将钱转到自己的账户中。不过确认邮件可让受害者知晓购买行为。

第一个漏洞可导致攻击者将电子书发送到受害者的 Kindle 设备。在弱用户的上下文中解析电子书时,可利用第二个漏洞运行任意代码。第三个漏洞可导致攻击者提权并以root 身份运行代码。

亚马逊已发布软件更新修复该漏洞并将自动更新用户设备,用户无需任何操作。

书籍注入

那么,Send to Kindle 到底是什么功能?如之前所述,它可使Kindle 用户将 MOBI 电子书发送到自己的设备。为此,亚马逊为每个用户都生成了一个专门用于该功能的特殊的 kindle.com 电子邮件地址。用户可以以邮件附件的形式通过预先获准的邮件地址列表将电子书发送到该邮件地址,书籍就会出现在用户设备上。

什么是预先获准的邮件地址列表?问题出在哪里?实际上,邮件认证的使用范围并没有想象的那样广泛。由于很多邮件服务器并不支持认证,因此出现亚马逊不会验证发件人真实性的假设也并非不合理。

为验证这一点,我使用了一款邮件欺骗服务,欺骗邮件信息并将电子书发送到自己的设备。令人惊喜的是,电子书出现在了设备上!更糟糕的是,并没有线索表明该电子书是从电子信息中接收到的。Kindle 的主页上也通过所选封面图像的形式展示了出来,这使得钓鱼攻击变得更加容易。

亚马逊确实通过目标邮件地址 (destination email address) 为这个功能提供了安全性。攻击者必须能够预测到这个邮件地址。然而,实际上它就是 kindle.com 域名下的用户常用邮件地址(例如 name@gmail.com 转换为 name@kindle.com)。虽然某些用户的名字后可能附加了一个随机的字符串 (name_<random_string>@kindle.com),但多数地址上的熵值看似非常低,且可被暴力破解。最新用户地址的最大熵值为32位,但依然不够好。

逆向 Kindle 固件

找到向任意 Kindle 设备发送电子书的方法后,我需要找到从电子书执行代码的方式。为此,我逆向了Kindle 固件版本 5.13.2(当时是最新版)上的书籍解析代码。KindleTool 用户从固件更新文件中提取文件系统。我还有一个老旧的越狱版 Kindle PaperWhite 3(还有一个新的 Kindle 10)。这样我就可以通过固件中的 gdb 二进制调试任意进程(多么令人愉悦的惊喜),并通过Ghidra 逆向了 arm32 二进制。

在查看出现在固件上的多个库时,一个库引起了我的注意:libjpegXR.so,它似乎是用于解析名为 jpegXR 的晦涩难懂的图像格式,这真是一个完美的攻击面。

JPEG XR 漏洞

JPEG XR 是最初由微软开发的图像格式标准。当解析最新的 Kindle 文件格式 KFX 时,Kindle 支持该格式。由于使用之前的漏洞仅可发送 MOBI 文件,因此它看似无关。我试图查找支持 JPEG XR 的其它代码,发现集成的 Web 浏览器也支持它。Web 浏览器正好,因为 MOBI 文件支持 Web 链接(甚至从视觉上和 TOC 链接难以区分),因此点击书籍链接将打开浏览器。

量化参数缓冲区溢出

在阅读 JPEG XR 标准的官方参照代码时,我在 jxr_priv.h 中定义的 jxr_image 结构中发现了:

unsigned char dc_quant_ch[MAX_CHANNELS];
unsigned char lp_quant_ch[MAX_CHANNELS][MAX_LP_QPS];
unsigned char hp_quant_ch[MAX_CHANNELS][MAX_HP_QPS];

以上即是“量化参数“。r_parse.c 中执行的函数 _jxr_r_TILE_HEADER_HIGHPASS 通过图像文件中的数据填充 hp_quant_ch。拷贝数据的长度由 image->num_channels 定义,它也出现在图像文件中。缓冲区的大小是常数 (MAX_CHANNELS=16),因此看起来似乎存在一个缓冲区溢出漏洞。

参考代码通过检查 num_channels 小于 MAX_CHANNELS 的断言就可阻止该缓冲区溢出漏洞。但或许 Kindle 的开发员忘记了也有可能。我在 Ghidra 中弹出 libjpegXR.so来查找开发人员是如何实现的。我立即看到虽然严重依赖于参考代码,但断言并不存在!可能开发人员在多次编辑中将其删除了,或者在生产环境中编译了断言。不管是何种原因,现在的结果是在 Kindle 中解析 JPEG XR 时存在一个缓冲区溢出漏洞,JPEG XR 图像文件中的字节受控。

利用

在 jxr_image 结构中,紧跟溢出的缓冲区之后的是指针 struct jxr_tile_qp *tile_quant。函数 _jxr_r_TILE_HEADER_HIGHPASS 将 hp_quant_ch 拷贝到如下指针中:

memcpy(image->tile_quant[ty*(image->tile_columns) + tx].hp_quant_ch, image->hp_quant_ch, MAX_CHANNELS*MAX_HP_QPS);

因此,利用该溢出,title_quant 本可被覆盖,获取一个绝对写原语(将受攻击者控制的数据写入受攻击者控制的地址)。但情况要好得多:_jxr_r_TILE_HEADER_HIGHPASS 被调用的次数由图像文件中提供的 image->tile_columns 和 image->tile_row 定义。如此,绝对写原语可被单一图像文件使用多次。

现在,我们看下 Web 浏览器进程的内存映射 mesquite:

00008000–000a0000 r-xp 00000000 b3:01 1939 /usr/bin/mesquite
000a0000–000a2000 rwxp 00098000 b3:01 1939 /usr/bin/mesquite
000a2000–002b8000 rwxp 00000000 00:00 0 [heap]
…

该二进制被加载到一个常量地址,且具有一个可执行文件和可写部分。结合绝对写原语,利用较为容易。使用绝对写原语,可将 shellcode 写入可执行部分。接着,该原语可被再次用于“喷射“具有shellcode 地址的全局偏移表 (GOT)。Mesquite 进程是多线程的,因此其它线程之一不可避免地会从 GOT 调用要给函数,从而导致shellcode 被执行。

权限提升

Mesquite 进程在 chroot 下以弱用户 framework 身份运行。因此此前的甚至无法用于重启设备。我们需要提权。

于是我看实查看监听本地套接字的root 进程:

[root@kindle root]# netstat -ntpl | tail -n +3 | awk '{ print $7 }' | awk -F / '{ print $1 }' | xargs -I {} ps -o uname=,cmd= -p {}
9000     /app/bin/AaMenuApplication
9000     webreader
root     stackdumpd
9000     kfxreader -l
9000     /usr/java/bin/cvm -Xmx49m -Xms49m ...
root     fastmetrics
9000     kfxview
9000     /usr/java/bin/cvm -Xmx49m -Xms49m ...

Stackdumpd 看似不错,因此通过 Ghidra 打开后查看它到底是如何工作的。从我所知的理解来看,该进程负责生成崩溃进程的栈转储。它接收崩溃进程 id 和线程 id,并将其传递给 /usr/bin/dump-stack。这是通过 gdb (这就是它出现在固件中的原因所在)连接到崩溃进程的 shell 脚本,如名称所示,它负责转储栈。Shell 脚本如下:

${GDB} --quiet \--se "${PROCESS_EXE}" \--pid ${CURRENT_TID} \--batch \-ex "bt" \-ex detach

从中我们注意到 CURRENT_TID 并未被引用,因此或许能够将参数注入 gdb。由于 gdb 能够运行 command 参数中给定的任意命令,因此它本可被用于以 root 身份运行任意代码。

这种情况更加复杂。开发人员似乎意识到了这个问题,并试图通过确保 CURRENT_TID 是number而阻止该问题。第一次检查发生在 dumpstackd 中,内容是检查atoi 不会返回0:

第二次检查位于 dump-stack 中,它使用的正则表达式如下:

“$(echo “$CURRENT_TID” | grep ‘^[0–9]*$’)” != “”

只要字符串以数字开头,即可绕过 atoi 检查。在这些数字后增加一个换行符即可绕过正则表达式检查。因此简单的字符串如 “1\nsome string” 即可绕过这两种检查。因此,我们就发现了一个可在root 用户上下文中执行任意代码的漏洞。再结合我们之前发现的两个漏洞,就造成在 Kindle 上的 root RCE 后果。

PoC

如下短视频演示了在 Kindle 10 固件版本 5.13.2 上的完整利用链。

  • 攻击以通过邮件欺骗方法从已获准邮件地址发送恶意电子书的方式。

  • 接着,受害者输入看似无害的电子书并触及内容表格中的其中一个链接。

  • 该链接通过包含恶意 JPEG XR 图像的 HTML 页面打开浏览器。

  • 该图像被解析,恶意代码以 root 身份运行。Payload 更改了启动背景并重启设备。

  • 攻击者从设备接收私密凭据并登录到受害者账户。

时间线

  • 2020年10月17日:向亚马逊漏洞研究计划提交漏洞报告

  • 2020年10月19日:亚马逊证实漏洞存在

  • 2020年11月4日:获得1.2万美元的奖励

  • 2020年11月11日:获得额外6000美元的假日推广福利奖励

  • 2020年12月10日:固件 5.13.4发布,内含对 JPEG XR 溢出问题和 PE 问题的修复。

  • 2020年12月29日:协助亚马逊审计了所部署的修复方案

  • 2021年1月19日:文章发布获批准

修复方案

书籍注入

如亚马逊无法验证发件人的邮件地址,现在会向获准的地址发送验证链接:

JPEG XR 溢出

亚马逊通过简单检查 channel 数量未超过 MAX_CHANNELS 的方式,修复了溢出漏洞。

提权

Dumpstackd 中的代码变更为:

从中可见,亚马逊用一个新函数替换了 atoi 调用。该新函数检查字符串中仅包含数字。

至于 /usr/bin/dump-stack,固件之间的文件偏移即说明问题。正则表达式检查现在更加强壮:

< PROCESS_PID=$1
< PROCESS=$2
< CURRENT_TID=$3
---
> PROCESS_PID=$(echo $1 | head -n 1 | grep '^[[:digit:]]*$')
> PROCESS=$(echo $2 | head -n 1 | grep '^[[:alnum:]_]*$')
> CURRENT_TID=$(echo $3 | head -n 1 | grep '^[[:digit:]]*$')

结论

使用三个不同的漏洞,在仅向设备分配了邮件地址的情况下,我设法实现以 root 用户身份在亚马逊 Kindle 上执行任意代码的目标。这些漏洞本可导致攻击者访问设备凭据并在 Kindle 商店中购买商品,也本可用于越狱最新的 Kindle 设备。我提交的漏洞报告得到了认真对待,且在合理期限内将漏洞修复。

推荐阅读

亚马逊 AWS 大宕机,大量互联网服务无法使用

谷歌会怎么修?黑客正在利用Analytics 服务窃取电商网站的信用卡数据

我俩也组了个队,找到一个苹果RCE 0day,获 $5 万奖金

看我如何黑掉 Facebook 并获奖金 $7500

原文链接

https://medium.com/realmodelabs/kindledrip-from-your-kindles-email-address-to-using-your-credit-card-bb93dbfb2a08

题图:Pixabay License

本文由奇安信代码卫士编译,不代表奇安信观点。转载请注明“转自奇安信代码卫士 https://codesafe.qianxin.com”。

奇安信代码卫士 (codesafe)

国内首个专注于软件开发安全的

产品线。

 觉得不错,就点个 “在看” 或 "赞” 吧~

KindleDrip:从邮件地址到信用卡盗刷的严重漏洞,值$1.8万奖金相关推荐

  1. TBContact -- 导出ThunderBird邮件地址本

    我写的一个导出ThunderBird邮件地址本的小工具,使用了多线程. 其功能有: 1 自动检测系统是否装有ThunderBird,并列出所有的地址本文件*.mab. 2 可以手工指定一个或多个地址本 ...

  2. Exchange如何将邮件转发给外部邮件地址

    Exchange如何将邮件转发给外部邮件地址 最近遇到一个需求.一位已经离职的员工需要将后续的邮件转发给他自己的私人邮箱.安全,行政的审核通过后,这个问题就到了技术部门了. Exchange可以很方便 ...

  3. php正则邮箱验证,php正则表达式验证(邮件地址、Url地址、电话号码、邮政编码)...

    本文实例需要验证的内容:邮件地址.Url地址.电话号码.邮政编码,验证方法分享给大家供大家参考,具体内容如下 1.电子邮件地址的校验 /* 校验邮件地址*/ function checkMail($e ...

  4. Postfix邮件地址改写(header)

            由于工作需要,需要改写用户邮件header头地址与邮件路由地址.整理笔录 改写邮件地址是postfix的核心,在收到邮件后就会进行相应地址修改,地址补充等工作,其流程如下:以下来自po ...

  5. Lotus Domino单用户多账号多邮件地址配置

    场景说明 集团公司的邮箱地址和下属子公司的邮件地址不一致,可能会出现一个用户有多个邮箱地址,确保没个邮箱在Domino的邮件系统都能正常收发邮件. 如:用户user集团的邮件地址user@acme.c ...

  6. 海量数据处理利器之Hash——在线邮件地址过滤

    一.需求 现在我们需要设计一个在线过滤垃圾邮件地址的方案,我们的数据库里面已经有10亿个合法的邮件地址(称为合法地址集S),当有新的邮件发过来时,要检查这个邮件地址是不是在我们的数据库里面,如果在,我 ...

  7. C#验证Email是否真正存在,不是验证邮件格式,是邮件地址是否存在 .

    C#验证Email是否真正存在,不是验证邮件格式,是邮件地址是否存在 分类: .Net(C#) 2010-06-11 15:12 322人阅读 评论(0) 收藏 举报 在以往的编程中,比如编写用户的资 ...

  8. php 判断接受邮件地址,PHP:电子邮件验证并接受来自特定域的电子邮件地址

    我目前正在使用AJAX / JS制作表单,而无需单击按钮或刷新页面. 我的询问是关于电子邮件验证的. 现在,PHP代码检查电子邮件地址是否有效. 我只希望它接受来自特定域的电子邮件. 我如何通过php ...

  9. 因漏洞Dropbox用户邮件地址被泄露给垃圾邮件发送者

    Dropbox用户报告称,其唯一用于该云存储服务的电子邮件地址,收到了垃圾邮件.在昨日论坛的一篇帖子里,有位用户抱怨称,其只用于Dropbox的特定邮件地址,自2月20日以来不断收到垃圾邮件,因此怀疑 ...

最新文章

  1. 只因为离职报告多写这三个字,员工竟然倒赔公司2.9万!
  2. POJ.3648.Wedding(2-SAT)
  3. 【-】WebKit Layout (布局)
  4. Mysql价格降低20%应该怎么写_mysql优化20条原则
  5. ant更改主题色报错Inline JavaScript is not enabled. Is it set in your options? vue ant主题色更改 vue-cli3
  6. 查看mysql错误日志定位mysql错误
  7. 【PHP】Ajax跨域解决方案 、jsonp、cors
  8. 超硬核详解SpringClould之Gateway网管【含源码例子】
  9. 编译OpenJDK12:Could not find any dlls in /cygdrive/c/progra~2/wi3cf2~1/10/Redist/ucrt/DLLs/x64
  10. 2021-2027全球与中国下一代测序数据分析市场现状及未来发展趋势
  11. 一个美观的gridview样式
  12. Metasploit扫描漏洞模块
  13. 保存网页html 有什么,保存网页时HTML和MHTML区别在哪里
  14. 技术前沿与经典文章20:历史上54位伟大物理学家、科学家的专属LOGO(六)
  15. cdr安装成功后出现重启计算机,CDR安装后重启电脑就打不开是什么原因?
  16. 微信故障之后发生的三大怪现象
  17. vray许可服务器信息无名,【1人回答】vray3.6无法获取许可-3D溜溜网
  18. 计算机专业的学习方法
  19. sql for 循环
  20. 语义分析- C-- 语言

热门文章

  1. c++ 副本构造器
  2. ZH奶酪:编程语言入门经典100例【Python版】
  3. 我的最新分词进展和接口设计~
  4. javascript 滚动+停留 代码
  5. 杭电2027--统计元音
  6. 100.于电脑右下角的小喇叭不见了的解决
  7. 果你的浏览器关闭了 java,weblogic之CVE-2018-3191漏洞分析
  8. 表单元素值获取方式js及java方式
  9. Irrlicht例002--Quake3Map
  10. exp导出表结构,不导出表数据。