• Heap/Stack Overflow(CVE-2017-0541)

漏洞出现在PushcdlStack函数中,如下所示
 
# /external/sonivox/arm-wt-22k/lib_src/eas_mdls.c
static EAS_RESULT PushcdlStack (EAS_U32 *pStack, EAS_INT *pStackPtr, EAS_U32 value)
{ /* stack overflow, return an error */
if (*pStackPtr >= CDL_STACK_SIZE)
return EAS_ERROR_FILE_FORMAT; /* push the value onto the stack */
*pStackPtr = *pStackPtr + 1;
pStack[*pStackPtr] = value;
return EAS_SUCCESS;
}
 
程序中将*pStackPtr加一后,执行pStack[*pStackPtr] = value。这里没有校验*pStackPtr加一后的值是否超过pStack大小,造成栈溢出。
回到调用PushcdlStack函数的上一层函数Parse_cdl,如下所示
 
static EAS_RESULT Parse_cdl (SDLS_SYNTHESIZER_DATA *pDLSData, EAS_I32 size, EAS_U32 *pValue)
{
EAS_RESULT result;
EAS_U32 stack[CDL_STACK_SIZE];
EAS_U16 opcode;
EAS_INT stackPtr;
EAS_U32 x, y;
DLSID dlsid; stackPtr = -1;
*pValue = 0;
x = 0;
while (size)
{
/* read the opcode */
if ((result = EAS_HWGetWord(pDLSData->hwInstData, pDLSData->fileHandle, &opcode, EAS_FALSE)) != EAS_SUCCESS)
return result; /* handle binary opcodes */
if (opcode <= DLS_CDL_EQ)
{
/* 省略部分代码 */
} else if (opcode == DLS_CDL_NOT)
{
/* 省略部分代码 */
} else if (opcode == DLS_CDL_CONST)
{
if ((result = EAS_HWGetDWord(pDLSData->hwInstData, pDLSData->fileHandle, &x, EAS_FALSE)) != EAS_SUCCESS)
return result;
} else if (opcode == DLS_CDL_QUERY)
{
/* 省略部分代码 */
} else if (opcode == DLS_CDL_QUERYSUPPORTED)
{
/* 省略部分代码 */
}
else
{ /* dpp: EAS_ReportEx(_EAS_SEVERITY_WARNING, "Unsupported opcode %d in DLS file\n", opcode); */ } /* push the result on the stack */
if ((result = PushcdlStack(stack, &stackPtr, x)) != EAS_SUCCESS) //漏洞点
return result;
} /* pop the last result off the stack */
return PopcdlStack(stack, &stackPtr, pValue);
}
部分无关代码这里没有显示,只看漏洞相关代码,opcode是从文件读取中的,所以可控;当opcode == DLS_CDL_CONST时,x的值也来从文件中读取,所以可控;
循环的最后会执行漏洞函数PushcdlStack(stack, &stackPtr, x),stack大小为CDL_STACK_SIZE(CDL_STACK_SIZE的值为8),stackPtr初始值为-1,
因此我们只要循坏执行PushcdlStack(stack, &stackPtr, x)函数8次之后,stackPtr等于7,再执行一次PushcdlStack(stack, &stackPtr, x),
即可将可控x写入stack[8],造成栈溢出。
 
漏洞是在解析.xmf文件时出现的
 
修复方案就是将PushcdlStack函数if (*pStackPtr >= CDL_STACK_SIZE)改为if (*pStackPtr >= CDL_STACK_SIZE - 1)
 
  • Integer Overflow(CVE-2017-0597)

 
以下是该漏洞的git diff
 
@@ -110,9 +110,24 @@
mUid = clientUid;
// ALOGD("Creating track with %d buffers @ %d bytes", bufferCount, bufferSize);
+
+ size_t bufferSize = buffer == NULL ? roundup(frameCount) : frameCount;
+ // check overflow when computing bufferSize due to multiplication by mFrameSize.
+ if (bufferSize < frameCount // roundup rounds down for values above UINT_MAX / 2
+ || mFrameSize == 0 // format needs to be correct
+ || bufferSize > SIZE_MAX / mFrameSize) {
+ android_errorWriteLog(0x534e4554, "34749571");
+ return;
+ }
+ bufferSize *= mFrameSize;
+
size_t size = sizeof(audio_track_cblk_t);
- size_t bufferSize = (buffer == NULL ? roundup(frameCount) : frameCount) * mFrameSize;
if (buffer == NULL && alloc == ALLOC_CBLK) {
+ // check overflow when computing allocation size for streaming tracks.
+ if (size > SIZE_MAX - bufferSize) {
+ android_errorWriteLog(0x534e4554, "34749571");
+ return;
+ }
size += bufferSize;
}
 
通过比较,可以看出漏洞是由于对frameCount的值没有进行校验,导致的整形溢出
 
frameCount本身是无符号整型
 
在size_t bufferSize = (buffer == NULL ? roundup(frameCount) : frameCount) * mFrameSize;中frameCount*frameCount肯回造成溢出
导致最终bufferSize的值小于frameCount) * mFrameSize
 
之后的代码会以bufferSize的值申请一块内存,之后对这块内存进行访问时,会造成缓冲区溢出
 
  • Type Confusion(CVE-2017-0546)

 
直接查看漏洞点
 
void SurfaceFlinger::setTransactionState(
const Vector<ComposerState>& state, ——>State是我们可以控制的
const Vector<DisplayState>& displays,
uint32_t flags)
{
/* 省略部分代码 */
count = state.size();
for (size_t i=0 ; i<count ; i++) {
const ComposerState& s(state[i]); ——>循环处理state[i]
// Here we need to check that the interface we're given is indeed
// one of our own. A malicious client could give us a NULL
// IInterface, or one of its own or even one of our own but a
// different type. All these situations would cause us to crash.
//
// NOTE: it would be better to use RTTI as we could directly check
// that we have a Client*. however, RTTI is disabled in Android.
if (s.client != NULL) {
sp<IBinder> binder = IInterface::asBinder(s.client);——> s.client是一个IBinder指针
if (binder != NULL) {
String16 desc(binder->getInterfaceDescriptor());
if (desc == ISurfaceComposerClient::descriptor) {—->比较binder->getInterfaceDescriptor()和ISurfaceComposerClient::descriptor的值
sp<Client> client( static_cast<Client *>(s.client.get()) );——>类型转换
transactionFlags |= setClientStateLocked(client, s.state);
}
}
}
}
/* 省略部分代码 */
}
 
State是我们可以控制的,s.client是一个IBinder指针,之后通过比较binder->getInterfaceDescriptor()字符串和ISurfaceComposerClient::descriptor
的值,之后进行类型转换,将s.client转换为Client,之后调用setClientStateLocked(client, s.state)
 
在setClientStateLocked函数中会执行Client对象的虚函数
 
uint32_t SurfaceFlinger::setClientStateLocked(
const sp<Client>& client,
const layer_state_t& s)
{
uint32_t flags = 0;
sp<Layer> layer(client->getLayerUser(s.surface));
/* 省略部分代码 */
}
 
可以看到,类型转换前,校验知识简单的比较了两个字符串的值,我们可以伪造一个符合条件的对象,进而在调用虚函数时,执行伪造对象的虚函数
 
修复方案如下
 
    count = state.size();
for (size_t i=0 ; i<count ; i++) {
const ComposerState& s(state[i]);
// Here we need to check that the interface we're given is indeed
// one of our own. A malicious client could give us a NULL
// IInterface, or one of its own or even one of our own but a
// different type. All these situations would cause us to crash.
//
// NOTE: it would be better to use RTTI as we could directly check
// that we have a Client*. however, RTTI is disabled in Android.
if (s.client != NULL) {
sp<IBinder> binder = IInterface::asBinder(s.client);
if (binder != NULL) {
if (binder->queryLocalInterface(ISurfaceComposerClient::descriptor) != NULL) {
sp<Client> client( static_cast<Client *>(s.client.get()) );
transactionFlags |= setClientStateLocked(client, s.state);
}
}
}
}
  • NPD(Null Pointer Dereference)(CVE-2016-6765)

漏洞代码如下:
 
status_t MPEG4Extractor::parseChunk(off64_t *offset, int depth) {
/* 省略部分代码 */
case FOURCC('b', 't', 'r', 't'):
{
*offset += chunk_size; uint8_t buffer[12];
if (chunk_data_size != sizeof(buffer)) {
return ERROR_MALFORMED;
} if (mDataSource->readAt(
data_offset, buffer, chunk_data_size) < chunk_data_size) {
return ERROR_IO;
} uint32_t maxBitrate = U32_AT(&buffer[4]);
uint32_t avgBitrate = U32_AT(&buffer[8]);
if (maxBitrate > 0 && maxBitrate < INT32_MAX) {
mLastTrack->meta->setInt32(kKeyMaxBitRate, (int32_t)maxBitrate); ——-> 空指针引用
}
if (avgBitrate > 0 && avgBitrate < INT32_MAX) {
mLastTrack->meta->setInt32(kKeyBitRate, (int32_t)avgBitrate); ——-> 空指针引用
}
break;
}
/* 省略部分代码 */
}
 
在调用mLastTrack指针的函数前没有验证mLastTrack指针是否为空,造成空指针引用漏洞
 
在MPEG4Extractor对象的构造函数中,将mLastTrack的值置为空
 
MPEG4Extractor::MPEG4Extractor(const sp<DataSource> &source)
: mMoofOffset(0),
mMoofFound(false),
mMdatFound(false),
mDataSource(source),
mInitCheck(NO_INIT),
mHasVideo(false),
mHeaderTimescale(0),
mFirstTrack(NULL),
mLastTrack(NULL), ———> mLastTrack的值置为空
mFileMetaData(new MetaData),
mFirstSINF(NULL),
mIsDrm(false) {
}
 
修复方案就是增加空指针校验,通过查看源码可以看到处理其他case时是有校验的,可是偏偏这一个case没有校验,有点意思
 
  • TOCTOU(Time Of Check Time Of Use)(CVE-2017-0419)

 
漏洞点
 
1207status_t AudioFlinger::EffectHandle::command(uint32_t cmdCode,
1208 uint32_t cmdSize,
1209 void *pCmdData,
1210 uint32_t *replySize,
1211 void *pReplyData)
1212{ /* 省略部分代码 */ 1232 Mutex::Autolock _l(mCblk->lock);
1233 if (mCblk->clientIndex > EFFECT_PARAM_BUFFER_SIZE ||
1234 mCblk->serverIndex > EFFECT_PARAM_BUFFER_SIZE) {
1235 mCblk->serverIndex = 0;
1236 mCblk->clientIndex = 0;
1237 return BAD_VALUE;
1238 }
1239 status_t status = NO_ERROR;
1240 while (mCblk->serverIndex < mCblk->clientIndex) {
1241 int reply;
1242 uint32_t rsize = sizeof(int);
1243 int *p = (int *)(mBuffer + mCblk->serverIndex); —————>越界访问
1244 int size = *p++; /* 省略部分代码 */
}
 
这里主要是因为mCblk对象的特殊性,mCblk位于共享内存,在一个进程使用期间被另一个进程使用,通过进程间通信控制mCblk这个对象
所以这里即使判断了mCblk->clientIndex和mCblk->serverIndex值的有效性,在之后有可能mCblk->serverIndex和mCblk->serverIndex值会被其他进程改变
从而在之后越界访问缓冲区
 
修复方案就是保存事先mCblk->clientIndex和mCblk->serverIndex值,如下:
 
1380        Mutex::Autolock _l(mCblk->lock);
1381 // keep local copy of index in case of client corruption b/32220769
1382 const uint32_t clientIndex = mCblk->clientIndex; ——> 保存mCblk->clientIndex
1383 const uint32_t serverIndex = mCblk->serverIndex; —-> 保存mCblk->serverIndex
1384 if (clientIndex > EFFECT_PARAM_BUFFER_SIZE ||
1385 serverIndex > EFFECT_PARAM_BUFFER_SIZE) {
1386 mCblk->serverIndex = 0;
1387 mCblk->clientIndex = 0;
1388 return BAD_VALUE;
1389 }
1390 status_t status = NO_ERROR;
1391 effect_param_t *param = NULL;
1392 for (uint32_t index = serverIndex; index < clientIndex;) {
1393 int *p = (int *)(mBuffer + index);
1394 const int size = *p++;
 
  • Missing Permission Check(CVE-2017-0490)

 
漏洞代码如下
 
50    public static WifiConfiguration buildConfig(String uriString, byte[] data, Context context)
51 throws IOException, GeneralSecurityException, SAXException {
52 Log.d(TAG, "Content: " + (data != null ? data.length : -1));
53
54 byte[] b64 = Base64.decode(new String(data, StandardCharsets.ISO_8859_1), Base64.DEFAULT);
55 Log.d(TAG, "Decoded: " + b64.length + " bytes.");
56
57 dropFile(Uri.parse(uriString), context);
 
传入的URI在解析后直接被调用了删除dropfile。缺少了权限检查
 
修复方案:
 
官网修复方案是直接把dropFile(Uri.parse(uriString), context);这一句删掉了
 
  • OOB(Out Of Boundary)(CVE-2015-6620)

 
漏洞点:
 
status_t BnMediaCodecList::onTransact(
uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
{
/* 省略部分代码 */
case GET_CODEC_INFO:
{
CHECK_INTERFACE(IMediaCodecList, data, reply);
size_t index = static_cast<size_t>(data.readInt32());
const sp<MediaCodecInfo> info = getCodecInfo(index);
if (info != NULL) {
reply->writeInt32(OK);
info->writeToParcel(reply);
} else {
reply->writeInt32(-ERANGE);
}
return NO_ERROR;
}
break;
/* 省略部分代码 */
}
 
漏洞代码中通过getCodecInfo(index)得到对应的info对象指针,而index是从可控的data中得到的
 
再看getCodecInfo函数
 
    virtual sp<MediaCodecInfo> getCodecInfo(size_t index) const {
        return mCodecInfos.itemAt(index);
    }
 
该函数没有对index的值做校验,意味着可以对向量mCodecInfos后的值进行访问,造成越界访问
 
修复方案:
 
    virtual sp<MediaCodecInfo> getCodecInfo(size_t index) const {
if (index >= mCodecInfos.size()) {
ALOGE("b/24445127");
return NULL;
}
return mCodecInfos.itemAt(index);
}
 
对index进行了校验
 
  • UAF(Use After Free)(CVE-2017-0444)

 
漏洞点:
 
status_t SoftAVC::initDecoder() {
/* 省略部分代码 */
status = ivdec_api_function(mCodecCtx, (void *)&s_create_ip, (void *)&s_create_op); mCodecCtx = (iv_obj_t*)s_create_op.s_ivd_create_op_t.pv_handle;
mCodecCtx->pv_fxns = dec_fxns;
mCodecCtx->u4_size = sizeof(iv_obj_t); if (status != IV_SUCCESS) {
ALOGE("Error in create: 0x%x",
s_create_op.s_ivd_create_op_t.u4_error_code);
deInitDecoder();
mCodecCtx = NULL;
return UNKNOWN_ERROR;
}
/* 省略部分代码 */
}
 
漏洞很明显,程序居然是先使用再校验是否分配成功,有点意思
在ivdec_api_function函数中分配了一块堆,保存在mCodecCtx上,如果分配错误就会释放掉分配的内存
可是漏洞程序因为是先使用,所以造成了UAF
 
更有意思的是在ivdec_api_function函数中释放mCodecCtx的位置
本因该在释放堆块之后将mCodecCtx置为null,可没看到对应代码,这也是漏洞产生原因之一
 
修复方案就是将校验和使用调换个位置:
 

      status = ivdec_api_function(mCodecCtx, (void *)&s_create_ip, (void *)&s_create_op);

        if (status != IV_SUCCESS) {
ALOGE("Error in create: 0x%x",
s_create_op.s_ivd_create_op_t.u4_error_code);
deInitDecoder();
mCodecCtx = NULL;
return UNKNOWN_ERROR;
} mCodecCtx = (iv_obj_t*)s_create_op.s_ivd_create_op_t.pv_handle;
mCodecCtx->pv_fxns = dec_fxns;
mCodecCtx->u4_size = sizeof(iv_obj_t);
 
 

AOSP常见漏洞类型简介的更多相关文章

  1. Linux环境下常见漏洞利用技术(培训ppt+实例+exp)

    记得以前在drops写过一篇文章叫 linux常见漏洞利用技术实践 ,现在还可以找得到(https://woo.49.gs/static/drops/binary-6521.html), 不过当时开始 ...

  2. android WebView详解,常见漏洞详解和安全源码

    这篇博客主要来介绍 WebView 的相关使用方法,常见的几个漏洞,开发中可能遇到的坑和最后解决相应漏洞的源码,以及针对该源码的解析.  转载请注明出处:http://blog.csdn.net/se ...

  3. PHP安全之道3:常见漏洞和攻防

    第一篇 SQL注入 安全配置和编程安全并不是万全之法,攻击者往往可以通过对漏洞的试探找到新的突破口,甚至0days. 下面总结以下常见漏洞,在日常开发维护工作中可以留意. *聊聊老朋友:SQL注入漏洞 ...

  4. 编译流程,C开发常见文件类型名

    编译流程 我们常说的编译是一个整体的概念,是指从源程序到可执行程序的整个过程,实际上,C语言编译的过程可以进一步细分为预编译->编译->汇编->链接 预编译是把include关键字所 ...

  5. Windows XP与Windows 7系统常见漏洞

    1.Windows XP系统常见漏洞 Windows XP系统常见的漏洞有UPNP服务漏洞.升级程序漏洞.帮助和支持中心漏洞.压缩文件夹漏洞.服务拒绝漏洞.Windows Media Player漏洞 ...

  6. php上传常见文件类型对应的$_FILES["file"]["type"](转)

    php上传常见文件类型对应的$_FILES["file"]["type"] from:http://hi.baidu.com/7book/item/374971 ...

  7. MySQL常见错误类型

    MySQL常见错误类型:1005:创建表失败1006:创建数据库失败1007:数据库已存在,创建数据库失败1008:数据库不存在,删除数据库失败1009:不能删除数据库文件导致删除数据库失败1010: ...

  8. 计算机程序的思维逻辑 (64) - 常见文件类型处理: 属性文件/CSV/EXCEL/HTML/压缩文件

    对于处理文件,我们介绍了流的方式,57节介绍了字节流,58节介绍了字符流,同时,也介绍了比较底层的操作文件的方式,60节介绍了随机读写文件,61节介绍了内存映射文件,我们也介绍了对象的序列化/反序列化 ...

  9. JS弹出下载对话框以及实现常见文件类型的下载

    写在前面 JS要实现下载功能,一般都是这么几个过程:生成下载的URL,动态创建一个A标签,并将其href指向生成的URL,然后触发A标签的单击事件,这样就会弹出下载对话框,从而实现了一个下载的功能. ...

随机推荐

  1. 大话重构 之 原来反OO天天见

    在OO(面向对象)时代长大的小伙伴们一定记得: 面向对象的基石:把数据和依赖该数据的行为封装在一起. 但我们经常遇到一个类依赖其它类的数据的情况.不多的话,正常,对象间势必存在交互,毕竟完全独立的类无 ...

  2. springBoot2.0 配置 mybatis+mybatisPlus+redis

    一.Idea新建springBoot项目 next到完成,然后修改使用自己的maven 等待下载包 二.pom.xml文件 <?xml version="1.0" encod ...

  3. git教程3-分支

    https://git-scm.com/book/zh/v1/Git-%E5%88%86%E6%94%AF-%E5%88%86%E6%94%AF%E7%9A%84%E7%AE%A1%E7%90%86 ...

  4. 扩展JMeter - 创建自定义函数 - String Joiner (翻译)

    JMeter是测试自动化社区中最好的开源工具之一.它提供了所有可能的扩展,可以快速提供我们的测试脚本.为了让我们的生活更轻松,它还让我们通过实现几个接口来提出我们自己的插件. 在本文中,让我们看看如何 ...

  5. Helvetic Coding Contest 2016 online mirror C2

    Description Further research on zombie thought processes yielded interesting results. As we know fro ...

  6. vbox和宿主机共享文件夹

    首先,查看vbox安装的ubuntu是否支持vboxsf模块 sudo modprobe vboxsf dmesg | grep vboxsf 如果没有安装,需要安装vboxsf模块:(如果安装了请跳 ...

  7. Oozie安装的说明

    不多说,直接干货! Oozie相当于Hadoop的一个客户端,因此集群中要有一台机器部署Oozie server端即可,由于可以有任意多个客户端连接Oozie,故每个客户端都必须部署Oozie cli ...

  8. ElasticSearch 全文检索— ElasticSearch 安装部署

    ElasticSearch 规划-集群规划 ElasticSearch 规划-集群规划 ElasticSearch 规划-用户规划 ElasticSearch 规划-目录规划 ElasticSearc ...

  9. 汇编debug

    R:查看.改变CPU寄存器的内容 D:查看内存中的内容 E:改写内存中的内容 U:将内存中的机器指令翻译成汇编指令 T:执行一条机器指令 A:以汇编指令的格式在内存中写入一条机器指令 第一步:先是[开 ...

  10. vnc安装问题

    在xenserver中安装vncserver软件.启动显示正常 用grep命令查看也确实有线程在运行. 但实际上用命令service vncserver status查看vnc状态,显示没有桌面在运行 ...