AOSP常见漏洞类型简介

  • 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);

原文地址:https://www.cnblogs.com/elvirangel/p/10448590.html

时间: 2024-10-01 23:46:12

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

网站常见漏洞的危害与解决方案

一.SQL注入漏洞 SQL注入漏洞的危害不仅体现在数据库层面,还有可能危及承载数据库的操作系统:如果SQL注入被用来挂马,还可能用来传播恶意软件等,这些危害包括但不限于: 1.数据库信息泄漏:数据库中存储的用户隐私信息泄露. 2.网页篡改:通过操作数据库对特定网页进行篡改. 3.网站被挂马,传播恶意软件:修改数据库一些字段的值,嵌入网马链接,进行挂马攻击. 4.数据库被恶意操作:数据库服务器被攻击,数据库的系统管理员帐户被窜改. 5.服务器被远程控制,被安装后门:经由数据库服务器提供的操作系统支

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

这篇博客主要来介绍 WebView 的相关使用方法,常见的几个漏洞,开发中可能遇到的坑和最后解决相应漏洞的源码,以及针对该源码的解析. 由于博客内容长度,这次将分为上下两篇,上篇详解 WebView 的使用,下篇讲述 WebView 的漏洞和坑,以及修复源码的解析. 下篇:android WebView详解,常见漏洞详解和安全源码(下) 转载请注明出处:http://blog.csdn.net/self_study/article/details/54928371. 对技术感兴趣的同鞋加群 54

Fckeditor常见漏洞的挖掘与利用整理汇总

查看编辑器版本 FCKeditor/_whatsnew.html ------------------------------------------------------------- 2. Version 2.2 版本 Apache+linux 环境下在上传文件后面加个.突破!测试通过. ------------------------------------------------------------- 3.Version <=2.4.2 For php 在处理PHP 上传的地方并未

Python&lt;9&gt;动态类型简介

动态类型以及它提供的多态性,无疑是Python语言简洁性和灵活性的基础. 一.变量 <1>变量创建 一个变量a,当代码第一次给它赋值时就创建了它,之后的赋值将会改变已创建的变量名的值. <2>变量类型 变量永远不会有任何的和它关联的类型信息或约束.变量原本是通用的,它只是在一个特定的时间点,简单的引用了 一下特定的对象而已. <3>变量使用 当变量出现在表达式中,它会马上被当前引用的对象所替代(对象是有类型的).此外所有的变量必须在使用前明确的 赋值,使用未赋值的变量会

android WebView详解,常见漏洞详解和安全源码(下)

上篇博客主要分析了 WebView 的详细使用,这篇来分析 WebView 的常见漏洞和使用的坑. 上篇:android WebView详解,常见漏洞详解和安全源码(上) 转载请注明出处:http://blog.csdn.net/self_study/article/details/55046348 对技术感兴趣的同鞋加群 544645972 一起交流. WebView 常见漏洞 WebView 的漏洞也是不少,列举一些常见的漏洞,实时更新,如果有其他的常见漏洞,知会一下我-- WebView

服务器系统及软件常见漏洞

服务器系统及软件常见漏洞 漏洞名称 允许Traceroute探测 远端WWW服务支持TRACE请求 远端WWW服务提供了对WebDAV的支持 远端WEB服务器上存在/robots.txt文件 远端VNC服务正在运行 远端HTTP服务器类型和版本信息泄漏 远端DNS服务允许递归查询 远程代理服务器允许连接任意端口 远程代理服务器接受POST请求 远程VNC HTTP服务正在运行 利用SMB会话可以获取远程域或工作组列表 利用SMB会话可以获取远程浏览列表 利用SMB会话可以获取远程共享列表 利用S

手机验证码常见漏洞总结

0X00 前言 手机验证码在web应用中得到越来越多的应用,通常在用户登陆,用户注册,密码重置等业务模块用手机验证码进行身份验证.针对手机验证码可能存在的问题,收集了一些手机验证码漏洞的案例,这里做一个归纳总结,在测试中,让自己的思路更加明确.常见的手机验证码漏洞如下: 1.无效验证 2.客户端验证绕过 3.短信轰炸 4.验证码爆破 5.验证码与手机号未绑定 0X01 无效验证 有验证码模块,但验证模块与业务功能没有关联性,此为无效验证,一般在新上线的系统中比较常见. 案例一: 获取短信验证码后

Android常见漏洞

Android常见漏洞 漏洞名称: Log敏感信息泄露 漏洞描述: 程序运行期间打印了用户的敏感信息,造成泄露 修改建议: 建议禁止隐私信息的log 漏洞名称: web https校验错误忽略漏洞 漏洞描述: 漏洞可导致中间人攻击 修改建议: 建议不要忽略ssl认证错误 漏洞名称: sql注入漏洞 漏洞描述: 漏洞可能导致用户数据库中的信息泄露或者篡改 修改建议: 建议使用安全sqlite,如sqlcipher 漏洞名称: https空校验漏洞 漏洞描述: 漏洞可导致中间人攻击 修改建议: se

简单的python爬虫 爬的乌云漏洞类型

import urllib.request import re starturl="http://wooyun.org/searchbug.php?q=%E9%87%91%E8%9E%8D" def get_html_response(url): html_response = urllib.request.urlopen(url).read().decode('utf-8') return html_response def geturl(starturl): a=get_html_