-->

[크래쉬 분석] Access violation - code c0000005 (오디오편집 프로그램)

때는 바야흐로..... 수림아 돈도없는데 제로데이한번 찾아보자...라는 생각에 2019년 12월에 2~3주정도 밤낮으로 퍼징을 돌렸었다. 그리고 하고많은 크래쉬중 거르고 거르고 걸렀다가 분석하다 걸렀다가 exploit 해볼라다가 안돼서 거르고 거르고 걸러 뭔가 될것같은!!!!! 느낌의 크래쉬를 겨우 얻어서 일주일간 분석했었다.

 

결국 edi값(destination address)과 입력파일과의 연계점을 알아내 edi를 원하는 값으로 조정하는 것이 가능했지만 쉬프트 연산 때문에 조정할 수 있는 edi값이 무조건 ~04로 끝나게 되는데, 리턴주소를 덮기 위해 가장 가깝게 edi를 조정한 주소값과 esi(source address)와의 차이가 0x13보다 커서 어찌어찌 길이값도 조정을 해보려 했으나 다른값들까지 다같이 변하는 상황으로 인해...결국 익스플로잇은 실패로 끝났지만ㅠ 그래도 공부는 진짜 많이 됐었다. 삽질 분석기를 여기에 정리한다.

 

 

Access Violation 크래쉬 확인

0x40c74f 지점에서 esi값을 edi에 쓰려다가 Access Violoation이 발생했다. esi가 접근할 수 없는 영역이었을 수도 있고 edi가 접근할 수 없는 영역일 수도 있는데 이 크래쉬의 경우 edi 값이 문제였다. msec를 사용해 exploitable 여부를 확인해보면, 100% 신뢰할 수 있는 것은 아니지만 일단 exploitable하다고 나온다.

 

(aac.694): Access violation - code c0000005 (!!! second chance !!!)
eax=00000013 ebx=00223a80 ecx=00000013 edx=00000000 esi=00828ac2 edi=0fc32d04
eip=0040c74f esp=00223900 ebp=00223938 iopl=0         nv up ei pl nz na po nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00010202
*** ERROR: Module load completed but symbols could not be loaded for C:\Users\SANS_PC0\Desktop\Fuzzing\05 Audio\results\convert_v5.5.7\crashers\EXPLOITABLE\0x331a60b0.0xb551eece_0x5a3ab53__\XXXXX.exe

XXXXX+0xc74f:
0040c74f f3a4            rep movs byte ptr es:[edi],byte ptr [esi]

0:000> !load msec

0:000> !exploitable
!exploitable 1.6.0.0
Exploitability Classification: EXPLOITABLE
Recommended Bug Title: Exploitable - User Mode Write AV starting at XXXXX+0x000000000000c74f (Hash=0xd6e35f86.0x3a26a413)

 

 

크래쉬 분석

 

크래쉬는 0040C710의 함수 copy_mp_vul0 의 qmemcpy에서 발생한다. [esi]를 [edi]에 복사하려다가 edi 값을 읽을 수 없어 Access Violation이 발생한 것이다. 그럼 여기서 edi 값이 문제라는 것은 결국 [ebp+arg_8] 즉 해당 함수로 넘어온 인자값이 문제라는 것을 알 수 있다.

 

참고로 add edi, edx에서 edx가 문제일 것이라고 생각할 수도 있지만 동적으로 확인결과 edx값은 계속 상당히 작은 값이였기 때문에 제외했다. 왜냐하면 edi값이 2xxxxx 영역에서 갑자기 fxxxxxxx 영역으로 뛰었기 때문에 edx가 갖는 영향은 미비할 것이라고 생각했기 때문이다.

 

 

콜스택을 기반으로 해당 함수를 호출하는 부분을 찾은 후, 인자값을 확인해보면 [ebp+arg_8]은 결국 edx이고 edx는 다시 [wordpointer]라는 것을 알 수 있다.

 

 

그렇다면 이제 [wordpointer] 에 쓰는 부분을 찾아야 하는데 단순히 xref로 확인해보면 w 부분이 상당히 많은 것을 알 수 있다. 이렇게되면 어느 부분이 문제가 되는 시점인지 확인하기가 힘들고 사실 어느 부분이 문제가 되는 것이 아니라 많은 부분이 복합적으로 작용하여 [wordpointer] 값이 구성된 것이라면 분석하기 상당히 까다롭게 될 것이다.

 

 

따라서 어느 특정 시점에 [wordpoiner]가 급격한 변화를 보이는 상황인지 확인해보기 위해 WinDbg에서 아래와 같은 방법으로 확인해본다. 참고로 데이터 bp를 걸기 위해선 해당 데이터영역이 할당이 된 상태에서 bp를 걸어야 정상적으로 동작한다. wordpointer는 정적으로 박혀있는 값(00810690) 이고 대략 mainCRTStartup_vul4 함수인 00401280에 진입 후 할당이 된다. 데이터 bp는< ba w 4 00810690 "dd 00810690 L1;g" > 로 걸어주었다. 이렇게되면 [wordpointer]에 값이 쓰이는 부분을 연속적으로 확인할 수 있다.

 

확인결과, [wordpointer] 값이 어느 한 부분에서 0022bb92에서 0fc32d04로 뛰는 것을 확인할 수 있다. 즉, Access Violation이 나기 직전의 wordpointer 계산 부분만 봐도 된다는 것이다.

 

00810690 00223e63
00810690 00223e65
00810690 00223e67
00810690 00223e68
00810690 0022bb92
00810690 0fc32d04

(f0c.c68): Access violation - code c0000005 (first chance)
First chance exceptions are reported before any exception handling.
This exception may be expected and handled.
eax=00000013 ebx=00223a80 ecx=00000013 edx=00000000 esi=009be1ca edi=0fc32d04
eip=0040c74f esp=00223900 ebp=00223938 iopl=0 nv up ei pl nz na pe nc
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00010206
image00400000+0xc74f:
0040c74f f3a4 rep movs byte ptr es:[edi],byte ptr [esi]

0:000> bl
0 e 00810690 w 4 0001 (0001) 0:**** image00400000+0x410690 "dd 00810690 L1;g"

 

< ba w 4 00810690 "dd 00810690 L1;u;g" > 로 쓰는 부분의 코드까지 확인해본다. 따라서 eebb92에서 fc32d04가 되는 지점은 40cb5b 이전 코드임을 알 수 있다.

 

00810690 0022bb92
image00400000+0xcbd2
0040cbd28b83945a0000 mov eax,dword ptr [ebx+5A94h]
0040cbd8 8d04c0 lea eax,[eax+eax*8]
0040cbdb c1e008 shl eax,8

00810690 fc32d04 #eip확인하면, 실행되고 나서 이게된것
image00400000+0xcb5b:
0040cb5bc705b006810000000000 mov dword ptr [image00400000+0x4106b0 (008106b0)],0
0040cb65 837b34ff cmp dword ptr [ebx+34h],0FFFFFFFFh
0040cb69 0f8497feffff je image00400000+0xca06 (0040ca06)

(f24.ad0): Access violation - code c0000005 (first chance)
First chance exceptions are reported before any exception handling.
This exception may be expected and handled.
eax=00000013 ebx=00223a80 ecx=00000013 edx=00000000 esi=00c6e1ca edi=0fc32d04
eip=0040c74f esp=00223900 ebp=00223938 iopl=0 nv up ei pl nz na pe nc
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00010206

image00400000+0xc74f:
0040c74f f3a4 rep movs byte ptr es:[edi],byte ptr [esi]

 

40cb5b 이전 코드 주소는 0040CB56이고 0040CB56여기서 마지막으로 [wordpointer]가 fc32d04가 된다. lea eax, [edx+eax+200]에서 @edx인지 @eax인지 @edx&@eax 인지 헷갈리지만 동적 확인 결과 edx는 고정적으로 223B04임을 확인했다. 따라서 @eax 이다. 마지막으로 eax는 1-[ebx+5A94] 임이 확인된다. (참고로 @edx는 edx가 문제인지 라는 뜻의 축약으로 사용했다)

 

여기서 다시 @ebx인지 @[ebx+5A94]인지 헷갈리지만 ebx는 00223A80으로 고정이고 [ebx+5A94]는 계속 0이거나 1인데 해당 지점에서만 주소값을 갖는 것으로 보아선 [ebx+5A94]가 입력 파일의 문제로 인해 덮어씌어졌다는 것을 알 수 있다. 따라서 @[ebx+5A94] 이다. 즉, [ebx+5A94]는 0 or 1을 확인하는 부분이었는데 파일 파싱의 문제로 파일 hex값으로 뒤덮혀져 문제의 E58FF570이 됐을 것이다.

 

 

그럼 이제, ebx+5A94 (229514) 에 값이 쓰여지는 부분들을 확인해보자. 229515 메모리는 대략 아래 두개사이에서 할당되는데 한번 호출되고 마는게 아니라 큰 반복문 안에서 반복되므로 40C9AC bp를 걸고 실행시킨 후 데이터 bp를 건다. 40c9ac에 bp가 걸린 지점에서 계속 걸리기 때문에 해당 bp는 지우고 데이터 bp를 새로 건다.< ba w1 229514 "dd 229514 L4;u;g" >

 

 

실행결과를 확인해보면, 0, 1이 반복되다가 1a700a91 이 됐다가e58ff570이 된다. 하지만 여기서 e58ff570가 되는 40CB40은 1에서 뺀 후 다시 덮어주는 상황이기 때문에 고려하지 않는다. 1a700a91값을 추적하면 되는데, 1-1a700a91를 하면 문제의 E58FF570이 되기 때문이다.

 

00229514 00000000 d8efb544 3fc44866 53909e8f
image00400000+0xcb46:
0040cb46 8d04c0 lea eax,[eax+eax*8]
0040cb49 c1e008 shl eax,8
0040cb4c 8b55e0 mov edx,dword ptr [ebp-20h]

00229514 00000001 3f927f67 3f58bd41 599c5be3
image00400000+0xcb46:
0040cb46 8d04c0 lea eax,[eax+eax*8]
0040cb49 c1e008 shl eax,8
0040cb4c 8b55e0 mov edx,dword ptr [ebp-20h]

00229514 00000000 3f927f67 3f58bd41 599c5be3
image00400000+0xcb46:
0040cb46 8d04c0 lea eax,[eax+eax*8]
0040cb49 c1e008 shl eax,8
0040cb4c 8b55e0 mov edx,dword ptr [ebp-20h]

00229514 1a700a91cee1b9cf f3dc54d2 2efdfcef ################
image00400000+0xc751:
(이전코드: 0040C74F)
0040c751 01c2 add edx,eax
0040c753 8b4b04 mov ecx,dword ptr [ebx+4]
0040c756 014108 add dword ptr [ecx+8],eax

00229514 e58ff570cee1b9cf f3dc54d2 2efdfcef ################
image00400000+0xcb46:
(이전코드: 0040CB40)
0040cb46 8d04c0 lea eax,[eax+eax*8]
0040cb49 c1e008 shl eax,8
0040cb4c 8b55e0 mov edx,dword ptr [ebp-20h]

(b4c.9f4): Access violation - code c0000005 (first chance)
First chance exceptions are reported before any exception handling.
This exception may be expected and handled.
eax=00000013 ebx=00223a80 ecx=00000013 edx=00000000 esi=0030e1ca edi=0fc32d04
eip=0040c74f esp=00223900 ebp=00223938 iopl=0 nv up ei pl nz na pe nc
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00010206

image00400000+0xc74f:
0040c74f f3a4 rep movs byte ptr es:[edi],byte ptr [esi]

 

따라서 [229514]가 1a700a91이 되는 코드인 0040C74F를 확인해 본다. x64Dbg에서 40c74f에 [229514] == 1a700a91 를 조건으로 bp를 건후 실행상황을 보면 esi 버퍼값을 edi 버퍼로 복사하는데 [229514]가 이과정에서 덮히게 되고 덮히게 된 hex값을 확인해 보면 실제로 파일 내에 있는 hex값들이다.

 

 

esi값은 88E132로 아래 부분이다.

 

 

리턴주소는 아래와 같다.

 

 

 

즉 crash_mp3.mp3 파일 내의 31FE90의 4바이트를 원하는 주소가 되는 값의 주소로 변경하면 [229514]값을 조정할 수 있고 결국 _wordpointer에 원하는 값을 넣을 수 있고,이 wordpointer는 0040CDBC의 edx로 들어가고 edx는 다시 [esp+8]로 (copy_mp_vul0)의 세번째 인자로 들어가고 그 세번째 인자가 다시 0040C743의 edi로 들어가고 esi 버퍼를 edi 버퍼로 복사하는 과정에서 edi를 읽을 수 없기 때문에 access violation이 발생한다.

 

그럼 어쨋든 직접적으로 call을 조작할 수는 없지만 레지스터들은 계산하에 원하는 값으로 조정할 수 있다.

 

함수 주소 어셈 비고  
copy_mp_vul0 40C74F rep movsb

bp조건: [229515] == 1a700a91

[229514] = 1A700A91

[229514] = FD8E38E5
_decodeMP3_vul1 40CB35 mov eax, 1 eax = 1  
_decodeMP3_vul1 40CB3A sub eax, [ebx+5A94h]

@[ebx+5A94] ([ebx+5A94h] =

[229514] = 1A700A91 -> eax = E58FF570)

 
_decodeMP3_vul1 40CB40 mov [ebx+5A94h], eax @[ebx+5A94] = E58FF570 271C71C
_decodeMP3_vul1 40CB46 lea eax, [eax+eax*8] @eax =120FA0F0 @eax = 15FFFFFC
_decodeMP3_vul1 40CB49 shl eax, 8 @eax =FA0F000 @eax = FFFFFC00
_decodeMP3_vul1 40CB4C mov edx, [ebp+var_20] Fedx = 223B04 Fedx = 223B04
_decodeMP3_vul1 40CB4F lea eax, [edx+eax+200h]

@eax = [223B04 + FA0F000 + 200]

= FC32D04(edx는 고정)

@eax =[223B04 + FFFFFC00 + 200]

223904

_decodeMP3_vul1 40CB56 mov ds:_wordpointer, eax @eax = 0fc32d04  
_decodeMP3_vul1 40CDBC mov edx, ds:_wordpointer @[wordpointer] = 0fc32d04  
_decodeMP3_vul1 40CDC2 mov [esp+8], edx @edx = 0fc32d04  
copy_mp_vul0 40C743 mov edi, [ebp+arg_8] @[ebp+arg_8] = 0fc32d04  
copy_mp_vul0 40C74F rep movsb (qmemcpy) @edi = 0fc32d04 223904

 

 

위표를 보면 알 수 있지만 쉬프트 연산 때문에 조정할 수 있는 edi값은 무조건 04로 끝나게 된다. 리턴주소를 덮기위해 가장 가깝게 edi값을 조정한게 223904이기 때문에 ecx(복사하는 크기)가 22393C-223904 보다 커야되는데 13으로 되어있다.

 

리턴주소 말고도 실제로 터지기 전에 eip 변조에 영향을 줄 수 있는 것이 있는지 등등 여러가지를 살펴봤지만 없었다ㅠ_ㅠ 그래서 마지막으로 ecx값을 바꿀 수 있는지 봐보기로했다. 사실, ecx값을 바꿀 수 있다고 하더라도 전체적인 cf가 변할 것 같아서 안될 것 같은 예감이 들었지만 일단 해보기로 했다. 중요한건 아래 분기로, 아래 분기에서 왼쪽 분기를 타야한다. 오른쪽 분기를 타면 ecx 길이 값이 13이나 20으로 fix되어있다.

 

 

다설명하자면 매우 길지만 어쨋든 ecx값도 계산에 파일 내부 바이트가 영향을 주는건 맞았다. 그래서 파일 내부에 특정 바이트를 변경해서 아까 해당 분기에서 fix된 ecx가 설정되지 않도록 해서 ecx가 73이 나오긴했는데 역시나 예상대로 정확히 ecx만 딱 바뀌지 않았당ㅋㅋ다른곳에서 크래쉬가 터진다 흐아

 

아래부분에서 파일에서 가져온 부분이 0이고 eax가 0이되고 esi가 FFFB9900이고 두개 or한게 FFFB9900인데 FFFB9900 & 100000 -> 1이기 때문에 분기가 11, 20 그쪽으로 타게된다.

 

 

 

실제 크래쉬를 분석해보는 건 처음이라 삽질도 많이하고 시간도좀 걸렸다.

언젠간 제보를 해볼 수 있길 바라며,

나의 첫 실제 크래쉬 분석은 여기서 끝.

 

댓글

Designed by JB FACTORY