보안정보

[CVE-2017-0541] Sonivox Parse_cdl RCE

침해사고분석팀 2017.04.26

1.개요
sonivox 외부 라이브러리는 안드로이드에서 MIDI 파일을 처리하는데 사용된다.
EAS_Prepare 공용 API에 Parse_cdl 함수에서 메모리 손상 취약점이 존재한다.
해당 취약점은 Extensible Music Files(XMF)을 통해 발생된다.

 

2.확인 내역
이 취약점은 eas_mdls.c의 Parse_cdl 함수로 인해 발생한다. 아래 코드는 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)
        {
            /* pop X and Y */
            if ((result = PopcdlStack(stack, &stackPtr, &x)) != EAS_SUCCESS)
                return result;
                ...
            switch (opcode)
            {
                case DLS_CDL_AND:
                    x = x & y;
                    break;
                case DLS_CDL_OR:
                    x = x | y;
                    break;
                ...
        }

        else if (opcode == DLS_CDL_NOT)
        {
        if ((result = PopcdlStack(stack, &stackPtr, &x)) != EAS_SUCCESS)
            return result;
        x = !x;
        }
        
        else if (opcode == DLS_CDL_CONST)

        {

            if ((result = EAS_HWGetDWord(pDLSData->hwInstData, pDLSData->fileHandle, &x, EAS_FALSE)) != EAS_SUCCESS)
                return result;
        }
        ...
        else

            { /* dpp: EAS_ReportEx(_EAS_SEVERITY_WARNING, "Unsupported opcode %d in DLS file ", 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);
    }
    Parse_cdl is called by DLSParser:

    EAS_RESULT DLSParser (EAS_HW_DATA_HANDLE hwInstData, EAS_FILE_HANDLE fileHandle, EAS_I32 offset, EAS_DLSLIB_HANDLE *ppDLS)
    {
        ...

        while (pos < endDLS)
        {
            chunkPos = pos;

            /* get the next chunk type */
            if ((result = NextChunk(&dls, &pos, &temp, &size)) != EAS_SUCCESS)
                return result;

            /* parse useful chunks */
            switch (temp)
            {
                case CHUNK_CDL:
                    if ((result = Parse_cdl(&dls, size, &temp)) != EAS_SUCCESS)
                        return result;

            ...

<표 - 1 > Parse_cdl 코드


 

Parse_cdl함수에서 while 반복 구문의 "size" 값은 xmf 파일에서 파싱된 값이기 때문에 공격자가 조절이 가능한 값이다. 그리고 변수인 opcode의 값도 EAS_HWGetWord()에 의해서 세팅이되는데 이 값 또한 공격자가 조절이 가능하다.

 

<그림 - 1> 공격자가 조작 가능한 opcode

 

opcode의 값이 다음의 IF 구분문의 어느 조건이라도 만족하지 않을 때 변수 x의 값은 PushcdlStack(stack, &stackPtr, x)에 의해서 스택에 저장된다.

 

<그림 - 2> 변수 x 저장

 

아래 <그림 - 3>은  PushcdlStack의 코드이다.

 

<그림 -3> PushcdlStack 코드

 

코드의 내용은 처음에 *pStackPtr의 값을 체크한다. 그 후엔 *pStackPtr에 1을 더하고, pStackPtr안에 값을 저장한다. if 구문에서 체크하는 값이 일치하지 않는다면 PushcdlStack()함수는 8번 반복이 된다.따라서 *pStackPtr의 값은 -1~7이 된다.

Parse_cdl()의 함수에서 while문이 9번째 반복될 때, opcode는 DLS_CDL_CONST(0x0010)으로 세팅된다. 이 때 x의 값은 공격자가 조절 가능한 xmf 파일로 부터 가져오고 스택에 저장한다. 이제 PushcdlStack()을 호출할 때 *pStackPtr은 7에서 1일 더해지고, 스택오버 플로우가 발생한다.

 

3.정리

해당 취약점은 안드로이드 기기에서 .xmf 파일을 실행할 때 발생하는 BoF 취약점이다. 공격자는 이 취약점을 통해 RCE 공격이 가능하다. 

 

4.대응 방안

1) 구글에서 공개한 보안 업데이트를 진행한다.

2) Sniper IPS에서는 아래와 같은 패턴으로 대응 가능하다.

-정오탐 확인중(4월 4주차 릴리즈예정)

3)Snort Rule 시큐어 캐스트에서 확인 가능하다.

 

5.참고

https://source.android.com/security/bulletin/2017-04-01
https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2017-0541
http://www.securityfocus.com/bid/97330