1.취약점 Info
Microsoft Office 소프트웨어가 메모리의 개체를 제대로 처리하지 못하는 경우 발생하는 취약점이다. MS오피스에 포함된 수식 편집기 프로그램, 즉 EQNEDT32.EXE 관련 취약점으로, 각각 2017년 11월에 공개되었다. 이들은 모두 메모리 손상 취약점(Memory Corruption Vulnerability)으로, EQNEDT32.EXE가 메모리상에서 특정 오브젝트를 적절하게 처리하지 못하는 과정에서 발생한다. MS는 CVE-2017-11882 취약점 해결을 위한 보안 패치를 발표했으나, 결과적으로 또 다른 취약점인 CVE-2018-0802가 존재하게 되었다. 이로 인해 MS는 자사 오피스 패키지에서 EQNEDT32.EXE를 제외하기에 이르렀다.
2.취약점 Target
먼저 취약점이 발생되는 EQNEDT32.EXE에 대해서 알아보자. EQNEDT32.EXE란 문서에 방정식을 삽입하거나 편집할 때 사용하는 수식편집기 이다. 문서에 삽입된 수식은 OLE 개체이고, OLE사양에 맞게 설계되어 있다. 또한 OLE는 MS의 기반 기술로 일반적으로 복합 문서를 지칭한다. 복합문서에는 다양한 종류의 정보 객체들이 들어있는데 이 정보객체를 OLE object라고 한다. 이 구성 요소는 2000년 11월 9일에 컴파일 되어 약 17년간 취약점을 가지고 있었던 것으로 알려지며, 오래전 MS 2000, 2003을 컴파일 하던 시기부터 취약했다. 버전 호환성의 이유로 MS Office제품에서 삭제되지 않아 시스템 패치를 진행하지 않은 탓에 최근버전(MS Office 2000 ~ 2016)에서도 취약한 것으로 알려져 있다.
취약점이 발생하는 부분은 sub_41160F에서 발생한다.
int __cdecl sub_41160F(char *a1, char *a2, int a3)
{
int result; // eax
char v4; // [esp+Ch] [ebp-88h]
char v5; // [esp+30h] [ebp-64h]
__int16 v6; // [esp+51h] [ebp-43h]
char *v7; // [esp+58h] [ebp-3Ch]
int v8; // [esp+5Ch] [ebp-38h]
__int16 v9; // [esp+60h] [ebp-34h]
int v10; // [esp+64h] [ebp-30h]
__int16 v11; // [esp+68h] [ebp-2Ch]
char v12; // [esp+6Ch] [ebp-28h]
int v13; // [esp+90h] [ebp-4h]
LOWORD(v13) = -1;
LOWORD(v8) = -1;
v9 = strlen(a1);
strcpy(&v12, a1);
_strupr(&v12);
v11 = sub_420FA0();
LOWORD(v10) = 0;
while ( v11 > (signed __int16)v10 )
{
if ( sub_420FBB(v10, &v5) )
{
strcpy(&v4, &v5);
if ( v6 == 1 )
_strupr(&v4);
v7 = strstr(&v4, a1);
if ( v7 || (v7 = strstr(&v4, &v12)) != 0 )
{
if ( !a2 || !strstr(&v4, a2) )
{
if ( (signed __int16)strlen(&v5) == v9 )
{
strcpy((char *)a3, &v5);
return 1;
}
if ( v7 == &v4 )
LOWORD(v8) = v10;
else
LOWORD(v13) = v10;
}
}
}
LOWORD(v10) = v10 + 1;
}
if ( (v8 & 0x8000u) != 0 )
{
if ( (v13 & 0x8000u) != 0 )
{
result = 0;
}
else
{
sub_420FBB(v13, &v5);
strcpy((char *)a3, &v5);
result = 1;
}
}
else
{
sub_420FBB(v8, &v5);
strcpy((char *)a3, &v5);
result = 1;
}
return result;
}
EQNEDT32.EXE를 IDA를 통해 디컴파일한 결과이다. strcpy함수를 사용해서 값을 처리하는것을 확인 할 수 있다.
strcpy함수는 NULL문자를 포함하여 strsource를 strdestination으로 지정된 위치에 복사해주는 함수이다. 즉 strsource에 대한 길이 검증을 하지 않기 때문에 Buffer Overflow가 발생할 수 있다.
추가적으로 EQNEDT32.exe에 어떤 보호기법이 적용되어있는지 Get-PESecurity power shellscript를 활용해 확인해보았다.
ASLR이나 DEP SafeSEH와 memory 보호기법들이 하나도 적용되어있지 않다. 따라서 취약점이 발생한다면 해당 취약점 을 이용한 exploit을 작성이 매우 쉬워질 것이다.
3.PoC Execute
https://github.com/embedi/CVE-2017-11882
위 github주소에서 CVE-2017-11882에 대한 PoC를 얻을 수 있다. Exploit.rtf를 다운로드해 동적을 확인해보자.
다운로드한 exploit.rtf를 실행시키면 word가 실행되면서 계산기도 함께 실행되는것을 확인 할 수 있다. rtfdump.py도구를 이용해 rtf파일의 정보를 확인해보자.
https://github.com/DidierStevens/DidierStevensSuite/blob/master/rtfdump.py
objectclass Equation.3임을 확인 할 수 있다.
HEX값을 확인하기 위해 아래와같이 명령을 입력하였다.
계산기를 실행시키는 shellcode가 삽입되어있을거라 예상하고 ascii값이 뜨게 출력하였는데 calc.exe와 같은 문자열은 확인하지 못하였다.
일단 어떤 취약점이 발생하는 함수의 위치와 CVE-2017-11882를 이용하는 PoC를 이용해 정상적으로 exploit이 완료된느 것이 확인되므로 debugger에 붙여서 정확이 어떤일이 발생하는지 확인해보자. Word실행부터 EQNEDT32.EXE가 shellcode를 실행하는 과정까지를 보려면 특정 조건이 만족되었을때 Debbuger에 attach 시켜야한다.
Windbg 내부에 내장되어있는 기능인 GFlag를 이용하면 EQNEDT32.EXE가 실행될때 자동으로 지정한 Debugger로 잡아줄 수 있다.
먼저 Windbg를 설치하는 방법은 따로 설명하지 않겠다. 구글링하면 잘나온다....... 이후 아래 경로로 들어가면 Gflags를 실행시킬 수 있다.
현재 EQNEDT32.EXE가 실행되는 순간 Debugger에 붙일 것이기 때문에 Image File 섹션에 들어가야한다. 또한 image는 EQNEDT32.EXE이고 attach에 사용할 Debugger는 x32를 이용할 것이다. 아래와 같이 설정하면 된다.
이후 exploit.rtf파일을 실행하면 자동적으로 EQNEDT32.EXE를 x32 debugger에 attach시킬 수 있다.
일단 취약점이 발생한다고 알려진 sub_0x0041106F에 break point를 걸고 해당 위치로 이동해보자.
위 IDA를 통해 확인하였던 strcpy함수를 확인 할 수 없다. 하지만 rep movsd 명령이 strcpy함수와 같다는 것을 확인 할 수 있었다.
몇번의 실행 끝에 calc.exe가 stack상에 올라가는 부분을 확인 할 수 있었다.
따라서 정확히 취약점이 trigger되는 부분은 아래 line18의 strcpy함수이다. 즉 char v12변수 위치에서 dummy 값을 덮어쓰고 ret를 조작 할 것이다.
위 dump 상에서 확인했듯이 0x430C12 주소 ret가 덮여쓰여진 것을 알 수 있다. 해당 주소를 확인해보자.
WinExec가 호출되는 주소임을 알 수 있다. 인자로 들어가는 값은 무엇인지 확인해보자.
WinExec함수도 조금 더 알아보자
따라서 calc.exe 즉 계산기가 실행될것이다. 두번째 인자값인 uCmdshow는 0이기 때문에 새로운 window에 calc.exe를 보여줄것이다. 여기서 문제는 실제 악성 스크립트 및 bof는 sub_40116F함수의 두번째 호출에서 발생하며 처음 strcpy를 호출했을때 destnation address값이 WinExec함수의 인자로 들어가지않는다는점이다. 즉 정확히 어떤 형태의 rtf 파일을 생성해야 buffer overflow를 이용한 ret 변조가 가능한지 알 수 없다. 따라서 조금더 분석을 진행해보자.
일단 위에서 확인한 dummy값과 cmd~~calc.exe가 rtf파일에서 어느 부분에 위치하는지 확인해보자.
앞에서 똑바로 못봐서 그런지 aaaaa...aaa를 기반으로 41414...41414이 나오는 위치를 확인 할 수 있었다. 특별히 shellcode를 stack에 올려서 공격하는 방식이 아니라 cmd.exe /c calc.exe 를 스택에 올려서 ret를 WinExec함수 위치로 변조해 calc.exe를 실행하는 것 같다. cmd.exe /c calc.exe 문자열 앞에 오는 hex값은 아래와 같은 의미를 가진다.
즉 03 01 01 ...... 12 0c 43 00까지의 문자열이 가지는 의미를 확인 할 수 있다. 그러면 어떻게 해서 stack에 push되는 값이 cmd.exe /c calc.exe 00을 가르키는지 확인해보자.
앞서 언급했듯 strcpy의 취약점을 이용해 ret를 변조하는 과정은 sub_41106F함수의 두번쨰 호출에서 발생한다.
위 내용을 따라가보면 sub_4112FD함수에서 호출하는 것을 확인 할 수 있다.
즉 sub_4112FD에서 aTimesNewRoman을 인자로준 case로 호출하고 2차적으로 atimes가 인자로들어가는 경우 bufferoverflow가 발생되는 것을 예상 할 수 있다.
이제 두번째 sub_41106F함수의 호출시 x32를 통해 exploit을 위한 인자세팅을 이해해보자.
현재 req movsd 즉 strcpy함수가 호출되기전에 break point를 걸어 놓은 상태이다. 위 어셈블리 명령을 해석하면 아래와 같다.
lea edi ,dword ptr ss:[ebp-28]: edi 레지스터에 ebp-28의 주소를 넣어준다. 즉 v12변수의 주소값을 넣어주는 것이다.
mov esi,edx : esi 레지스터에 edx의 값을 넣어준다. 이때 esi는 인자 a1으로 copy할 문자열의 source를 의미한다.
rep movsd : edi에 esi의 값을 복사한다.
따라서 EDI의 값으로 ESI에 들어있은 문자열 값이 복사되게될것이다.
ESI : 0x0018F354
EDI :0x0018F1A8 before rep movsd
EDI :0x0018F1A8 after rep movsd
즉 문자열이 성공적으로 복사된것을 확인 할 수 있다. 그리고 ret 변조가 발생했을 것이기 때문에 stack의 상황도 확인해보자.
현재 ebp는 0x18F1D0이다. 또한 ebp-0x28위치인 0x0018F1A8 부터 우리가 의도했던 cmd.exe /c calc.exe가 성공적으로 들어간것을 확인할 수 있다. 또한 ebp 이후 위치인 ret에 0x0018F1D4가 WinExec함수의 주소인 0x00430C12로 변조된것역시 확인 가능하다.
이후 leave 명령을 지나면 ret가 실행되기전에 스택이 아래와 같이 세팅된다
결과적으로 stack에 push된 값인 esp + 4는 cmd.exe /c calc.exe를 가르키고 esp + 8은 SH_HIDE인 0을 가지게 되고 0x430c12로 jmp한다면 계산기의 실행이 가능해진다.
해당 취약점을 이용해 과연 몇바이트의 길이의 명령을 실행할 수 있는지 알아보자.
strcpy함수를 통해 복사되는 문자열이 시작되는 위치와 0x430C12로 덮을 ret 앞까지의 거리는 아래와 같다.
즉 43 byte만큼의 공간이 있다. 43 byte면 windows의 shellcode를 넣어주기에는 조금 무리가 존재한다. 분석에 사용한 PoC 제작자도 위와 같은 공간문제 때문에 직접 shellcode를 올리는 방식이 아니라 WinExec함수에 들어갈 인자를 인코딩한뒤 WinExec로 JMP하는 방식으로 exploit을 작성한것 같다.
'Pwnable' 카테고리의 다른 글
Exploit writing tutorial part2 : how to jmp shellcode (0) | 2021.02.21 |
---|---|
Exploit writing tutorial part3 : SEH base exploit (0) | 2021.02.14 |
Exploit writing tutorial part1 : Stack Based Overflows (1) | 2021.01.08 |