• 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. 《权限系列shiro+cas》---封装公共验证模块

    操作系统:Windows8.1 显卡:Nivida GTX965M 开发工具:Visual Studio 2017 Introduction 我们现在可以将任意属性传递给每个顶点的顶点着色器使用.但是 ...

  2. Python网络爬虫(二)

    Urllib库之解析链接 Urllib库里有一个parse这个模块,定义了处理URL的标准接口,实现 URL 各部分的抽取,合并以及链接转换.它支持如下协议的 URL 处理:file.ftp.goph ...

  3. centos7虚拟机安装

    Centos7 第1章 CENTOS 7 简介 1.1 centos的演变 启动流程sysvinit 串行启动:一次一个, 一个一个启动 并行启动:全部的一起启动 init优点 运行非常良好.主要依赖 ...

  4. jdbc 开启事务

    package com.itheima.tx; import java.sql.Connection; import java.sql.PreparedStatement; import java.s ...

  5. net start命令发生系统错误5和错误1058的解决方法

    net start命令用于开启服务,格式为:net start [服务名](与之对应的"net stop [服务名]"为关闭服务命令) 5是没有管理员权限,右键管理员即可 1058 ...

  6. ORA-29875 出现问题解决办法

    出现问题:Underlying DBMS error [ORA-29875: 无法执行 ODCIINDEXINSERT 例行程序ORA-20085: Insert Spatial Reference ...

  7. Linux软件相关记录

    Pidgin+lw-web的聊天记录的文件对应的目录为.purple/logs/webqq/你的QQ号码/,进入之后有选择的删除. mkdir -p 递归创建目录:pwd 显示当前目录:cd .. 回 ...

  8. LitePal——安卓数据库library

    简介:一个让开发者使用SQLite数据库更加容易的库文件 LitePal for Android,项目地址:点击打开 LitePal是一个开源的android库,它让开发者使用SQLite数据变得容易 ...

  9. Linux常用命令汇总(渐更)

    后台启动jar nohup java -jar xxxxx.jar > xxxx.out 2>&1 & 封禁ip iptables -I INPUT -s 200.194. ...

  10. jQuery读取和设定KindEditor值的方法

    转载自:https://www.jb51.net/article/43595.htm 侵删 jQuery读取和设定KindEditor值的方法 更新时间:2013年11月22日 09:03:56   ...