Android提权漏洞CVE-2014-7920&CVE-2014-7921分析

简介: 这是Android mediaserver的提权漏洞,利用CVE-2014-7920和CVE-2014-7921实现提权,从0权限提到media权限,其中CVE-2014-7921影响Android 4.0.3及以后的版本,CVE-2014-7920影响Android 2.2及以后的版本。Googl


 Android提权漏洞CVE-2014-7920&CVE-2014-7921分析


没羽@阿里聚安全



这是Android mediaserver的提权漏洞,利用CVE-2014-7920CVE-2014-7921实现提权,从0权限提到media权限,其中CVE-2014-7921影响Android 4.0.3及以后的版本,CVE-2014-7920影响Android 2.2及以后的版本。Google直到Android5.1才修复这2个漏洞。该漏洞[1]披露过程如下:

2016124日漏洞作者发布了漏洞分析及exploit[2],拿到exploit后在几个Android版本上均没能运行成功,遂分析原因,学习漏洞利用思路。记录如下,欢迎大家交流学习。

不熟悉Android Binder的同学,请自行网上搜索学习资料,下面直接分析漏洞。


0x1漏洞成因

前文提到这2个漏洞出在mediaservermediaservermain_mediaserver.cpp[3]实现,其main()函数中初始化了2service


一个是AudioFlinger[4]service name“media.audio_flinger”;另一个是AudioPolicyService[5]service name“media.audio_policy”

1.1内存写漏洞

内存写漏洞产生在“media.audio_policy”中,接口类为IAudioPolicyService[6][7],其中startOutput()接口存在递增的内存写漏洞,stopOutput()接口存在递减的内存写漏洞。

startOutput()接口定义为:

startOutput(audio_io_handle_t output, audio_stream_type_t stream, int session = 0)

stopOutput ()接口定义为:

stopOutput(audio_io_handle_t output, audio_stream_type_t stream, int session = 0)

1startOutput的递增写漏洞

熟悉Android Binder的同学都知道,该接口的native类为BnAudioPolicyService[8],当客户端请求“START_OUTPUT”codestartOutput()接口时,BnAudioPolicyService::onTransact()收到请求,然后执行下面的代码:

继续调用AudioPolicyService ::startOutput()[9]方法:

mpAudioPolicy->start_output(mpAudioPolicy, output, stream, session);

mpAudioPolicyaudio_policy类型,audio_policy:: start_output()audio_policy_hal.cpp中被定义为ap_start_output(),该方法调用:

lap->apm->startOutput()AudioPolicyManagerBase:: startOutput()方法实现,该方法调用:

我们来看AudioOutputDescriptor:: changeRefCount()[10]方法的代码:

2if语句都为假时,mRefCount[stream] += delta;语句将被执行。

此时如果索引stream可被控制,那么mRefCount内存的相对偏移内存将可被修改为加delta。恰巧stream为接口参数之一,也没校验,在AudioPolicyManagerBase:: startOutput()中传入的delta,也就是说这里存在一个递增1的内存写漏洞。这个内存写漏洞的产生需要满足以下条件:

l  isDuplicated()False:幸运的是默认情况大部分output不是duplicated的。

l  (delta + (int)mRefCount[stream]) < 0:由于这个判断条件,mRefCount[stream]<0x7FFFFFFF时才会为False,这就限制了这个内存写漏洞,只能对内存内容小于0x7FFFFFFF的内存值进行递增。

2stopOutput的递减写漏洞

stopOutput()接口类似于startOutput()接口,我们直接看AudioPolicyManagerBase::stopOutput()方法,该方法调用的是:

outputDesc->changeRefCount(stream, -1);

startOutput()接口类似,也存在相同的写限制,不同的是这递减1的内存写漏洞。

1.2内存读漏洞

内存写漏洞也产生在“media.audio_policy”中,问题出在isStreamActive()接口。该接口定义为:

bool isStreamActive(audio_stream_type_t stream, uint32_t inPastMs)

类似于startOutput()接口,该接口调用了AudioPolicyManagerBase::isStreamActive()方法,该方法调用:

AudioOutputDescriptor::isStreamActive()方法,该方法代码为:

如果根据isStreamActive() 返回值判断mRefCount[stream]是否为0,需要满足2个条件:

l  mRefCount[stream] != 0

l  ns2ms(sysTime - mStopTime[stream]) > inPastMs

sysTime - mStopTime[stream]为时间差值,为正值,当inPastMs>=0x80000000时,该不等式成立。

所以可以通过控制streaminPastMs的值判断mRefCount内存相对偏移的值是否为0


0x2利用之前

2.1利用技巧小结

1)利用内存读,模糊匹配audio_hw_device对象

audio_hw_device这个结构包含了audio硬件设备函数指针,在“media.audio_policy”“media.audio_flinger” service提供的接口中会被调用,这有利于写exploitaudio_hw_device结构定义如下:

分析发现audio_hw_device对象中reservedfunction_ptrs-> get_supported_devices0,其它字段为非0。该结构用0和非0的形式可表示为:

前面提到可以通过isStreamActive()接口判断内存值是否为非0,这样结合audio_hw_device结构的特征在内存中搜索,恰巧在mRefCount的上下内存区域中可以搜索到audio_hw_device对象。

2)利用内存写,泄漏内存地址

 “media.audio_flinger”提供了getInputBufferSize()接口[11],接口定义为:

其服务端代码为:

当客户端调用getInputBufferSize()接口,服务端最终调用get_input_buffer_size()audio_hw.cpp::adev_get_input_buffer_size()函数,最后返回size。由arm指令特性可知,get_input_buffer_size(dev, &config)函数的反汇编中,通过R0传入dev指针,即audio_hw_device对象,函数执行完后,返回值通过R0传回。如果修改get_input_buffer_size函数指针,让其指向“BX LR”,那个就可拿到audio_hw_device对象的内存地址。

恰巧get_input_buffer_size ()函数指针也存储于audio_hw_device对象中,使用内存写漏洞让audio_hw_device. get_input_buffer_size指向一个“BX LR”的地址即可获取audio_hw_device对象地址。

2.2踩到的坑

笔者在调试exploit时发生多次crash,将update后的exploit放在https://github.com/Vinc3nt4H/cve-2014-7920-7921_update,编译环境:Android 4.3_r2.1,运行环境:AVD 4.34.3_r2.1)。

1)搜索audio_hw_device对象时mediaserver crash

在运行exploit时,可以搜索到audio_hw_device对象,但mediaserver crash了,可能是由于搜索的内存范围过大,导致非法内存访问。可缩小搜索范围试试,比如设置MAX_OFFSET-3000

2)总是获取不到adev_open_output_stream()地址

笔者在AVD 4.3上使用原gadget read_r0_offset_108,总是获取不到adev_open_output_stream函数的指针,然后在camera.goldfish.so中找了一个gadgetthumb):

3android 4.4.2crash

开始时笔者在AVD 4.4.2中执行exploit总是不成功,调试发现audio_hw_device. get_input_buffer_size的值被置了0,如下图:

因为mediaserver中加载的audio.primary.goldfish.so基址大于0x7FFFFFFF,也就是mRefCount[offset_get_input_buffer_size] > 0x7FFFFFFF,即为负数,在利用递增1/递减1时,changeRefCount()方法,如果(delta + (int)mRefCount[stream]) < 0,则将mRefCount[stream]置为0。在4.4.2上很难利用成功。


0x3漏洞利用分析

3.1搜索audio_hw_device对象相对偏移

2.1-1中提到利用audio_hw_device结构的特征在mediaserver进程中搜索匹配的对象。利用isStreamActive()的内存读漏洞读取mRefCount附件内存区域生产0/0的内存映射,然后与audio_hw_device结构特征匹配,计算出audio_hw_device对象相对于mRefCount的相对偏移。

3.2 Bypass ASLR

2.1-2中有提到利用内存写漏洞获取内存地址,接下来我们来分析exploit是如何利用内存写绕过ASLR的。

1)获取audio.primary.goldfish.so基地址

首先修改audio_hw_device. get_input_buffer_size指针的值,get_input_buffer_size原始指向adev_get_input_buffer_size,修改使其指向 camera.goldfish.so::0x1E290+1,记为gadget1,代码如下:

其中library_offset为所使用的lib基址与audio.primary.goldfish.so库基址之间的偏移,gadget_offset为相对于该lib库基址的偏移;RELATIVE_ADDRESS_OF_GET_INPUT_BUFFER_SIZEadev_get_input_buffer_size函数地址在audio.primary.goldfish.so中的偏移;modify_value()函数是内存递增1 /递减1操作的封装。gadget1为:

然后调用AudioFlinger::getInputBufferSize()跳到gadget1

uint32_t read_function_pointer_address = af->getInputBufferSize(0, (audio_format_t)0, (audio_channel_mask_t)0);

gadget1执行时R0devaudio_hw_device对象,参考audio_hw_device结构,R0+0x64open_output_streamadev_open_output_stream的值,通过R0返回。

再减去adev_open_output_streamaudio.primary.goldfish.so中的偏移READ_FUNCTION_POINTER_OFFSET_FROM_BASE_ADDRESS,即可得到audio.primary.goldfish.so的基址。

2)获取audio_hw_device对象地址

修改audio_hw_device. get_input_buffer_size指针使其指向libcamera_client.so::0x208FC+1,即gadget2

gadget2运行时直接返回devR0)的值,即audio_hw_device对象的地址。

3)设置write gadget

修改audio_hw_device. get_input_buffer_sizelibcamera_client.so: 0x208f0+1,记为gadget3,利用代码如下:

我们再来看看AudioFlinger::getInputBufferSize()方法,其中:

gadget3,写数据调用接口getInputBufferSize(address, 0, value)(该接口定义为getInputBufferSize(uint32_tsampleRate, audio_format_t format, audio_channel_mask_t channelMask)),走到get_input_buffer_size(dev, config)时,R0dev, R1&configgadget3执行如下:

至此我们将audio_hw_device. get_input_buffer_size指向gadget3,再调用getInputBufferSize(address, 0, value)就可以向address-0xC内存写入value

3.3布局Gadget Buffer

system()函数地址及参数写到audio_hw_device.reserved中,再修改audio_hw_device.get_input_buffer_size指向一个call gadget,当再次调用get_input_buffer_size()call gadget被触发。

1)写入system()函数参数

看利用代码:


write32()函数写数据分为2步:

a)设置数据偏移

调用modify_value(aps, g_primary_device_offset + 1, offset - g_current_write_offset);修改dev.version的内容,该字段作为后面数据写入时的数组偏移;dev.version首次从0x200递减直到0xC

b)写入数据

调用af->getInputBufferSize(g_primary_device_address + sizeof(uint32_t) + 12, (audio_format_t)0, (audio_channel_mask_t)value)触发gadget3执行,调试时断在gadget3上:

此时R0指向devR1&config

查看[R1]内存,R1[0]config. sampleRateaddress,为要写入的地址,address&dev[0]+4+12 R1[1]config. channelMaskvalue ,值为“/dat”

gadget3的伪代码大致如下:

gadget(某次)运行完后,数据已被写入audio_hw_device对象中:

2)写入system()函数地址

根据audio.primary.goldfish.so的基址计算出system()函数的地址,调用gadget3写到dev+36

3)写入call gadget

调用gadget3修改audio_hw_device. get_input_buffer_size指针的值,使用指向,libstagefright.so: 0x5EF88+1,记为gadget4

gadget4

3.4触发代码执行

利用代码为:

af->getInputBufferSize(0, (audio_format_t)0, (audio_channel_mask_t)0);

当调用getInputBufferSize()时触发gadget4执行:

寄存器值:

调用system()函数,加载外命令/data/local/tmp/a。笔者写了个远程shell命名为a,下图是运行成功后获取的shell,为“media”权限:


0x4参考链接

[1]http://bits-please.blogspot.com/2016/01/android-privilege-escalation-to.html

[2]https://github.com/laginimaineb/cve-2014-7920-7921

[3]http://androidxref.com/4.3_r2.1/xref/frameworks/av/media/mediaserver/main_mediaserver.cpp#40

[4]http://androidxref.com/4.3_r2.1/xref/frameworks/av/services/audioflinger/AudioFlinger.cpp

[5]http://androidxref.com/4.3_r2.1/xref/frameworks/av/services/audioflinger/AudioPolicyService.cpp

[6]http://androidxref.com/4.3_r2.1/xref/frameworks/av/include/media/IAudioPolicyService.h

[7]http://androidxref.com/4.3_r2.1/xref/frameworks/av/media/libmedia/IAudioPolicyService.cpp

[8]http://androidxref.com/4.3_r2.1/xref/frameworks/av/media/libmedia/IAudioPolicyService.cpp#384

[9]http://androidxref.com/4.3_r2.1/xref/frameworks/av/services/audioflinger/AudioPolicyService.cpp#234

[10]http://androidxref.com/4.3_r2.1/xref/hardware/libhardware_legacy/audio/AudioPolicyManagerBase.cpp#3083

[11]http://androidxref.com/4.3_r2.1/xref/frameworks/av/media/libmedia/IAudioFlinger.cpp#346

[12]https://github.com/Vinc3nt4H/cve-2014-7920-7921_update



 

作者:没羽@阿里聚安全,更多技术文章,请点击阿里聚安全博客



阿里聚安全由阿里巴巴移动安全部出品,面向企业和开发者提供企业安全解决方案,全面覆盖移动安全、数据风控、内容安全、实人认证等维度,并在业界率先提出“以业务为中心的安全”,赋能生态,与行业共享阿里巴巴集团多年沉淀的专业安全能力。

相关文章
|
4月前
|
开发框架 前端开发 Android开发
Flutter 与原生模块(Android 和 iOS)之间的通信机制,包括方法调用、事件传递等,分析了通信的必要性、主要方式、数据传递、性能优化及错误处理,并通过实际案例展示了其应用效果,展望了未来的发展趋势
本文深入探讨了 Flutter 与原生模块(Android 和 iOS)之间的通信机制,包括方法调用、事件传递等,分析了通信的必要性、主要方式、数据传递、性能优化及错误处理,并通过实际案例展示了其应用效果,展望了未来的发展趋势。这对于实现高效的跨平台移动应用开发具有重要指导意义。
396 4
|
4月前
|
安全 Android开发 数据安全/隐私保护
深入探讨iOS与Android系统安全性对比分析
在移动操作系统领域,iOS和Android无疑是两大巨头。本文从技术角度出发,对这两个系统的架构、安全机制以及用户隐私保护等方面进行了详细的比较分析。通过深入探讨,我们旨在揭示两个系统在安全性方面的差异,并为用户提供一些实用的安全建议。
|
6月前
|
开发工具 Android开发 Swift
安卓与iOS开发环境对比分析
在移动应用开发的广阔舞台上,安卓和iOS这两大操作系统无疑是主角。它们各自拥有独特的特点和优势,为开发者提供了不同的开发环境和工具。本文将深入浅出地探讨安卓和iOS开发环境的主要差异,包括开发工具、编程语言、用户界面设计、性能优化以及市场覆盖等方面,旨在帮助初学者更好地理解两大平台的开发特点,并为他们选择合适的开发路径提供参考。通过比较分析,我们将揭示不同环境下的开发实践,以及如何根据项目需求和目标受众来选择最合适的开发平台。
72 2
|
4月前
|
安全 Android开发 数据安全/隐私保护
深入探索Android与iOS系统安全性的对比分析
在当今数字化时代,移动操作系统的安全已成为用户和开发者共同关注的重点。本文旨在通过比较Android与iOS两大主流操作系统在安全性方面的差异,揭示两者在设计理念、权限管理、应用审核机制等方面的不同之处。我们将探讨这些差异如何影响用户的安全体验以及可能带来的风险。
125 21
|
3月前
|
Java 开发工具 Android开发
安卓与iOS开发环境对比分析
在移动应用开发的广阔天地中,安卓和iOS两大平台各自占据半壁江山。本文深入探讨了这两个平台的开发环境,从编程语言、开发工具到用户界面设计等多个角度进行比较。通过实际案例分析和代码示例,我们旨在为开发者提供一个清晰的指南,帮助他们根据项目需求和个人偏好做出明智的选择。无论你是初涉移动开发领域的新手,还是寻求跨平台解决方案的资深开发者,这篇文章都将为你提供宝贵的信息和启示。
53 8
|
5月前
|
缓存 Java Shell
Android 系统缓存扫描与清理方法分析
Android 系统缓存从原理探索到实现。
146 15
Android 系统缓存扫描与清理方法分析
|
5月前
|
存储 Linux Android开发
Android底层:通熟易懂分析binder:1.binder准备工作
本文详细介绍了Android Binder机制的准备工作,包括打开Binder驱动、内存映射(mmap)、启动Binder主线程等内容。通过分析系统调用和进程与驱动层的通信,解释了Binder如何实现进程间通信。文章还探讨了Binder主线程的启动流程及其在进程通信中的作用,最后总结了Binder准备工作的调用时机和重要性。
Android底层:通熟易懂分析binder:1.binder准备工作
|
6月前
|
安全 Android开发 数据安全/隐私保护
探索安卓与iOS的安全性差异:技术深度分析与实践建议
本文旨在深入探讨并比较Android和iOS两大移动操作系统在安全性方面的不同之处。通过详细的技术分析,揭示两者在架构设计、权限管理、应用生态及更新机制等方面的安全特性。同时,针对这些差异提出针对性的实践建议,旨在为开发者和用户提供增强移动设备安全性的参考。
237 3
|
6月前
|
安全 Linux Android开发
探索安卓与iOS的安全性差异:技术深度分析
本文深入探讨了安卓(Android)和iOS两个主流操作系统平台在安全性方面的不同之处。通过比较它们在架构设计、系统更新机制、应用程序生态和隐私保护策略等方面的差异,揭示了每个平台独特的安全优势及潜在风险。此外,文章还讨论了用户在使用这些设备时可以采取的一些最佳实践,以增强个人数据的安全。
|
5月前
|
开发工具 Android开发 Swift
安卓与iOS开发环境的差异性分析
【10月更文挑战第8天】 本文旨在探讨Android和iOS两大移动操作系统在开发环境上的不同,包括开发语言、工具、平台特性等方面。通过对这些差异性的分析,帮助开发者更好地理解两大平台,以便在项目开发中做出更合适的技术选择。

热门文章

最新文章

  • 1
    【08】flutter完成屏幕适配-重建Android,增加GetX路由,屏幕适配,基础导航栏-多版本SDK以及gradle造成的关于fvm的使用(flutter version manage)-卓伊凡换人优雅草Alex-开发完整的社交APP-前端客户端开发+数据联调|以优雅草商业项目为例做开发-flutter开发-全流程-商业应用级实战开发-优雅草Alex
  • 2
    Android历史版本与APK文件结构
  • 3
    【01】噩梦终结flutter配安卓android鸿蒙harmonyOS 以及next调试环境配鸿蒙和ios真机调试环境-flutter项目安卓环境配置-gradle-agp-ndkVersion模拟器运行真机测试环境-本地环境搭建-如何快速搭建android本地运行环境-优雅草卓伊凡-很多人在这步就被难倒了
  • 4
    当flutter react native 等混开框架-并且用vscode-idea等编译器无法打包apk,打包安卓不成功怎么办-直接用android studio如何打包安卓apk -重要-优雅草卓伊凡
  • 5
    APP-国内主流安卓商店-应用市场-鸿蒙商店上架之必备前提·全国公安安全信息评估报告如何申请-需要安全评估报告的资料是哪些-优雅草卓伊凡全程操作
  • 6
    【03】仿站技术之python技术,看完学会再也不用去购买收费工具了-修改整体页面做好安卓下载发给客户-并且开始提交网站公安备案-作为APP下载落地页文娱产品一定要备案-包括安卓android下载(简单)-ios苹果plist下载(稍微麻烦一丢丢)-优雅草卓伊凡
  • 7
    【09】flutter首页进行了完善-采用android studio 进行真机调试开发-增加了直播间列表和短视频人物列表-增加了用户中心-卓伊凡换人优雅草Alex-开发完整的社交APP-前端客户端开发+数据联调|以优雅草商业项目为例做开发-flutter开发-全流程-商业应用级实战开发-优雅草Alex
  • 8
    【02】仿站技术之python技术,看完学会再也不用去购买收费工具了-本次找了小影-感觉页面很好看-本次是爬取vue需要用到Puppeteer库用node.js扒一个app下载落地页-包括安卓android下载(简单)-ios苹果plist下载(稍微麻烦一丢丢)-优雅草卓伊凡
  • 9
    Cellebrite UFED 4PC 7.71 (Windows) - Android 和 iOS 移动设备取证软件
  • 10
    【01】仿站技术之python技术,看完学会再也不用去购买收费工具了-用python扒一个app下载落地页-包括安卓android下载(简单)-ios苹果plist下载(稍微麻烦一丢丢)-客户的麻将软件需要下载落地页并且要做搜索引擎推广-本文用python语言快速开发爬取落地页下载-优雅草卓伊凡