자바스크립트가 어떻게 다른 영역의 주소로 침범할 수 있는건지 궁금합니다.

조회수 1613회

안녕하세요.

아래와 같이 자바스크립트로 힙 스프레이 같은 기법으로 다른 메모리 주소를 침범할 수 있는데, 시스템 명령도 없는 자바스크립트가 어떻게 다른 메모리 주소를 변경할 수 있는걸까요?

자바스크립트로 IE나 크롬에서 계산기 등을 실행하는 PoC를 보고 궁금해서 질문드립니다.
<html>
<script >
// heap spray test script
// corelanc0d3r
// don't forget to remove the backslashes
tag = unescape('%u\4F43%u\4552'); // CORE
tag += unescape('%u\414C%\u214E'); // LAN!

chunk = '';
chunksize = 0x4000;
nr_of_chunks = 200;

for ( counter = 0; counter < chunksize; counter++)
{
    chunk += unescape('%u\9090%u\9090');    //nops
}

document.write("size of NOPS at this point : " + chunk.length.toString() + "<br>");
chunk = chunk.substring(0,chunksize - tag.length);
document.write("size of NOPS after substring : " + chunk.length.toString() + "<br>");

// create the array
testarray = new Array();
for ( counter = 0; counter < nr_of_chunks; counter++)
{
    testarray[counter] = tag + chunk;
    document.write("Allocated " + (tag.length+chunk.length).toString() + " bytes <br>");
}
alert("Spray done")

</script>
</html>

감사합니다.

  • (•́ ✖ •̀)
    알 수 없는 사용자
  • 궁금해서 실행해 봤는데 계산기가 실행이 안되는데요. PoC가 먼가요? 유연수 2016.2.10 17:07

1 답변

  • 이거 자체로 계산기가 실행되는 PoC는 아닌거같구요, 그냥 일단 힙에 저 내용들을 채워넣는 스크립트같아요.

    브라우저에서 자바스크립트로 계산기 띄우기?

    보통 브라우저에서 웹페이지를 이용해서 계산기를 띄운다는 경우는 브라우저의 버그를 이용해서 특정 영역의 메모리를 조작하거나 프로그램 흐름을 강제로 돌려서 브라우저 자체를 공격하는 경우(또는 자바, 플래시 등의 플러그인을 뚫는 경우도 있어요)를 가리킬거에요. 이런 행위를 "브라우저 등의 프로그램을 Exploit 한다" 라고 한답니다.

    예를 들어, 브라우저에 아래와 같은 코드가 있어서 자바스크립트에서 지정한 주소로 함수 포인터를 지정한 후 실행한다고 해보죠. 이건 명백한 버그일거에요, 적어도 브라우저에서 js 코드로 브라우저를 크래시내는걸 원하진 않을테니까요.

    typedef char (*callback) ();
    callback ptr = 0x0c0c0c0c; /* from js */
    ptr();
    

    이런식으로 있다고 해보죠. 이럴 때 만약 메모리에 올린 임의의 데이터가 코드로서 실행이 가능하고 (해당 메모리 영역에 실행 권한이 있고) 이쪽으로 함수 포인터를 돌릴 수 있다면 사용자는 임의의 네이티브 코드를 올려서 자유롭게 실행할 수 있을거에요.

    힙 주소, 그리고 ASLR

    브라우저에서는 기본적으로 마우스를 움직이거나 간단한 문서 작업, 스크립트 실행을 하는 데에도 힙 할당/해제를 아주 많이 해요. 따라서 메모리 전체에서 어디쯤에 방금 올린 문자열 데이터가 있는지를 알아내기는 힘들 수 있어요.

    또한 요즘 운영체제는 대부분 ASLR(Address Space Layout Randomization)이라는 기능이 생겨서 힙이 할당되는 주소가 천차만별이죠. ASLR의 등장으로 힙이나 코드들은 프로그램이 실행할 때마다 랜덤한 위치에 로딩이 되게 되었어요. 따라서 위의 코드가 있어도 올린 데이터의 주소를 디버거로 확인한 후 주소값에 바로 적용시키거나 프로그램 내의 system함수로 뛰게 하는 일은 어려워졌어요.

    이렇게 메모리의 어느 부분에 무엇이 있는지 확신하기 힘든 상황이 되다보니 대부분 세 가지 접근 방식을 취해요.

    1. 주소 등의 값을 유출시켜서 참고한다.
    2. 메모리 주소가 맞을 때까지 시도한다.
    3. 메모리 주소의 하위 부분만 조작한다.

    3번 방법은 물론 있으면 좋지만 있는 경우가 그렇게 많지는 않고, 2번 방법은 한 번 메모리 접근 에러가 나면 크래시가 나서 더이상 시도를 못하는 프로그램에서는 쓰기 힘들거에요. 따라서 유추 범위를 줄이거나 아예 없애버리는 방법을 생각해볼 수 있죠.

    힙 스프레이의 등장

    힙 스프레이는 이런 방법의 일종으로, 메모리를 동적으로 할당시켜서 원하는 데이터를 올릴 수 있을 경우 시도해봐야 할 메모리 주소 범위를 어느 정도 줄여주는, 극단적으로는 아예 고정시키는 방법이에요.

    가령 malloc + memcpy로 동적 할당된 메모리에 원하는 데이터를 넣을 수 있다고 했을 때, 그러니까 아래와 같을 때요.

    int i;
    for(i = 0; i < 100000; i++) {
        memcpy(malloc(0x1000), "\x90\x90...[code]", 0x1000);
    }
    

    만약 힙 할당 주소의 시작지점이 0x08000000일 경우 아래와 같이 되겠죠.

    0x04000000 +----------------+
               | program        |
               |----------------|
               |                |
               | ...            |
               |                |
               |----------------|
    0x08000000 | \x90\x90..     | 힙 주소 시작지점은 랜덤일 수 있음
    ...        | ..[c+g] \x90.. | 0x08000000은 힙 스프레이상 가상의 주소임.
    0x0c0c0c0c | ..[c+g] \x90.. | [c+g]는 [code] + [중간에 할당된 것]
    ...        |                | 또는 힙 메타데이터들.
    0x???????? | \x90.. [code]  |
               |----------------|
               |...             |
    
    

    이런식으로 메모리에 다량의 \x90을 채운 다음 위의 코드같은 경우 대충 고정된 주소인 0x0c0c0c0c로 프로그램 흐름을 돌려요. 그러니까, 힙 스프레이 시작 지점 ~ 끝 지점 중 꼭 0x0c0c0c0c라는 주소는 들어간다는 가정을 하는거죠.

    \x90으로 값을 채워준 이유는, \x90은 어셈블리어로 nop, 그러니까 아무것도 안 함(No OPeration) 명령어이기 때문이에요. 1바이트짜리 명령어라서 중간에 깨질 염려도 없죠. 그래서 \x90이 많이 있는 곳으로 프로그램의 흐름을 돌려도 그 뒤에 있는 코드까지 쭉 실행되는거죠. 이런걸 NOP 썰매: NOP Sledding라고 한답니다.

    물론 중간에 할당된 부분이나 힙 메타데이터로 뛸 가능성이 있지만, 그럴 확률은 거의 없다고 가정을 하곤 해요.

    물론 힙 스프레이가 효율적이지 못할 때도 있어요. 메모리에 많은 데이터를 올리지 못한다던지, 올려도 데이터가 있는 주소 범위를 예측하기 힘들다던지 - 특히 64비트로 들어서면서 주소 범위가 2의 64승이다보니, ASLR로 랜덤화된 주소 범위가 상당히 넓어서 메모리를 다 채우거나 메모리의 위치를 예측하기 힘들어졌어요 - 이런 경우도 있겠죠.

    다시 한번 정리하자면,

    1. 위에 질문을 하신 코드는 그 자체로 계산기를 실행하는 PoC는 아니에요. 힙 스프레이를 하는 예제로 보입니다.
    2. 힙 스프레이를 이용하면 공격 시 도움이 될 때가 있어요. 물론 항상 Exploit 코드의 안전성을 100%로 올려주진 않아요.

    결론

    따라서 만약 진짜로 계산기를 띄우는 코드를 찾고 싶으시다면, 그 브라우저에 대한 exploit 코드를 검색해 보세요. 참고 링크 4번에는 Internet Explorer 6.0 버전에 대한 Metasploit용 PoC가 있어요.

    물론 대부분은 이미 최신 버전에서는 해결된 취약점일 것이라서 테스트하시려면 구버전, 혹은 코드에 제시된 환경 / 버전을 쓰셔야 할거에요.

    참고 링크

    1. Heap Spraying - Wikipedia
    2. Exploit writing tutorial part 11 : Heap Spraying Demystified - Corlean Team
    3. Heap Spray - OVERTIME 한글 문서
    4. CVE-2010-0249 MS10-002 Microsoft Internet Explorer "Aurora" Memory Corruption - Rapid7
    5. Heap Spray Exploit Tutorial: Internet Explorer Use After Free Aurora Vulnerability - The Grey Corner
    • (•́ ✖ •̀)
      알 수 없는 사용자
    • (•́ ✖ •̀)
      알 수 없는 사용자

답변을 하려면 로그인이 필요합니다.

프로그래머스 커뮤니티는 개발자들을 위한 Q&A 서비스입니다. 로그인해야 답변을 작성하실 수 있습니다.

(ಠ_ಠ)
(ಠ‿ಠ)