ブログ(脅威調査)

Windowsにおける画像解析のファジング パート2: 初期化されていないメモリ

Windowsにおける画像解析の脆弱性の続きとして、比較的知られていない脆弱性のクラスである、初期化されていないメモリについて見てみましょう。この投稿では、Windowsの組み込み画像パーサー(特に初期化されていないメモリの使用)に関連する脆弱性について見ていきます。

脆弱性:初期化されていないメモリ

CやC++などの非管理言語では、変数はデフォルトで初期化されません。初期化されていない変数を使用すると、未定義の動作が発生し、クラッシュする可能性があります。初期化されていないメモリには、およそ2つのバリアントがあります。

  • 直接的な初期化されていないメモリ使用量: 初期化されていないポインタまたはインデックスが読み取りまたは書き込みで使用されています。これによりクラッシュする可能性があります。
  • 初期化されていないメモリの使用による情報漏えい: 初期化されていないメモリの内容は、セキュリティの境界を越えてアクセス可能です。たとえば、ユーザー・モードからアクセス可能な初期化されていないカーネル・バッファが情報開示につながります。

本ブログでは、Windowsの画像パーサーの2つ目のバリアントについて詳しく説明します。これは攻撃者がJavaScriptを使用してデコードされた画像を読み戻すことができるWebブラウザなどによって、情報開示ができるものです。

初期化されていないメモリの脆弱性の検出

ヒープ・オーバーフローやuse-after-freeなどのメモリ破損の脆弱性と比較して、初期化されていないメモリの脆弱性自体は、アウト・オブ・バウンドまたはアウト・オブ・スコープのメモリにはアクセスしません。そのためこれらの脆弱性の検知は、メモリ破損の脆弱性よりも少し複雑になります。直接的に初期化されていないメモリ使用量はクラッシュを引き起こし、検出される可能性がありますが、情報漏えいによってクラッシュが発生することは通常はありません。検出には、MemorySanitizerなどのコンパイラー装置や、Valgrindなどのバイナリ装置または再コンパイル・ツールが必要です。

迂回: Linuxでの初期化されていないメモリの検出

ここでは、初期化されていないメモリを検出する方法を説明し、Windowsの組み込み機能と比較してみましょう。コンパイラーはいくつかの初期化されていない変数についてアラートを出しますが、初期化されていないメモリ使用量の複雑なケースのほとんどは、コンパイル時に検出されません。このため、実行時検知メカニズムを使用できます。MemorySanitizerは、初期化されていないメモリ読み出しを検出する、GCCとClangの両方のコンパイラー装置です。その仕組みの例を図1に示します。

$ cat sample.cc
#include <stdio.h>

int main()
{
    int *arr = new int[10];
    if(arr[3] == 0)
    {
         printf("Yay!\n");
    }
    printf("%08x\n", arr[3]);
    return 0;
}

$ clang++ -fsanitize=memory -fno-omit-frame-pointer -g sample.cc

$ ./a.out
==29745==WARNING: MemorySanitizer: use-of-uninitialized-value
    #0 0x496db8  (/home/dan/uni/a.out+0x496db8)
    #1 0x7f463c5f1bf6  (/lib/x86_64-linux-gnu/libc.so.6+0x21bf6)
    #2 0x41ad69  (/home/dan/uni/a.out+0x41ad69)

SUMMARY: MemorySanitizer: use-of-uninitialized-value (/home/dan/uni/a.out+0x496db8)
Exiting

図1: 初期化されていないメモリーのMemorySanitizer検知

同様に、Valgrindを使用して、実行時に初期化されていないメモリを検知することもできます。

Windowsでの初期化されていないメモリの検出

Linuxと比較して、Windowsには、初期化されていないメモリ使用量を検出するための組み込みメカニズムがありません。Visual StudioとClang-clは最近AddressSanitizerのサポートを導入しましたが、MemorySanitizerやその他のサニタイザーは本ブログの執筆時点では実装されていません。

PageHeapなどのメモリ破損の脆弱性を検知するためのWindowsの便利なツールの一部は、初期化されていないメモリの検知に役立ちません。逆に、PageHeapはメモリ割り当てをパターンで埋められ、基本的には初期化されます。

Dr. Memoryなど、サードパーティ製のツールには、ヒープ・オーバーフロー、初期化されていないメモリ使用、空き容量の使用など、メモリの安全性の問題を検知するためにバイナリ装置を使用するものはほとんどありません。

画像デコードにおける初期化されていないメモリの検出

Windowsで初期化されていないメモリを検出するには、通常、特にソースコードにアクセスできない場合にバイナリ装置が必要です。初期化されていないメモリ使用を検知するために使用できるインジケーターの1つ(特に画像デコードの場合) は、画像がデコードされた後のピクセルになります。

画像がデコードされると、未処理ピクセルのセットになります。画像のデコードで初期化されていないメモリを使用すると、ピクセルの一部またはすべてがランダムになることがあります。より単純な言い方をすれば、初期化されていないメモリが使用される場合、画像を複数回デコードすると、毎回異なる出力になる可能性があります。この出力の違いは、初期化されていないメモリの検出や、Windows画像デコーダをターゲットとしたファジング・ハーネスの記述に役立ちます。ファジング・ハーネスの例を図2に示します。

#define ROUNDS 20

unsigned char* DecodeImage(char *imagePath)
{
      unsigned char *pixels = NULL;     

      // use GDI or WIC to decode image and get the resulting pixels
      ...
      ...     

      return pixels;
}

void Fuzz(char *imagePath)
{
      unsigned char *refPixels = DecodeImage(imagePath);     

      if(refPixels != NULL)
      {
            for(int i = 0; i < ROUNDS; i++)
            {
                  unsigned char *currPixels = DecodeImage(imagePath);
                  if(!ComparePixels(refPixels, currPixels))
                  {
                        // the reference pixels and current pixels don't match
                        // crash now to let the fuzzer know of this file
                        CrashProgram();
                  }
                  free(currPixels);
            }
            free(refPixels);
      }
}

図2:ディフ・ハーネス

このファジング・ハーネスの背景にあるアイデアは新しいものではありません。以前は、lcamtufをオープンソースの画像パーサーで初期化されていないメモリを検知するために同様のアイデアとして使用し、ピクセルの違いを表示するためにWebページを使用していました。

ファジング

差分ハーネスの準備ができたら、サポートされている画像フォーマットの検索とコーパスの収集に進むことができます。コーパスの画像ファイルの収集は、インターネット上でほぼ無制限に利用可能であればかなり簡単ですが、同時に独自のコード・カバレッジを持つ数百万のファイルの中から良いコーパスを見つけるのは困難です。Windows画像解析のコード・カバレッジ情報は、WindowsCodecs.dllから追跡されます。

通常のWindowsのファジングとは異なり、PageHeapがパターンを使用してヒープ割り当てを「初期化」するため、今回はPageHeapを有効にしないことに注意してください。

結果

この調査中に、Windows組み込み画像パーサーをファジング処理している間に初期化されていないメモリ使用の3つのケースを発見しました。そのうちの2つについては、次のセクションで詳しく説明します。初期化されていないメモリ使用量の根本原因分析は重要ではありません。トレースを戻すためのクラッシュ場所がないため、結果のピクセル・バッファを使用し、トレースを戻して根本原因を見つけるか、トリックを使用して差分を見つける必要があります。

CVE-2020-0853

この脆弱性の根本原因に入る前に、概念実証(PoC)ファイルのレンダリングを見てみましょう。このために、PoC画像を複数回読み込み、ピクセルと基準ピクセルを比較するlcamtufのHTMLを使用します。


図3:CVE-2020-853

結果の画像(図3)からわかるように、出力は各デコードで大幅に変化し、このPoCが多くの初期化されていないメモリをリークすると想定できます。

これらの脆弱性の根本原因を特定するために、Time Travel Debugging(TTD)を広範囲に使用しました。実行をトレース・バックし、メモリ・アドレスを追跡することは面倒な作業ですが、TTDはアドレスと値を一定に保ち、無制限の前方および後方実行を提供することによって、わずかな作業しか行いません。

トレースをデバッグするのにかなりの時間がかかりましたが、windowscodecs!CFormatConverter::Initializeで初期化されていないメモリのソースを見つけました。ソースは見つかりましたが、このメモリが上書きされずにピクセルの計算に終わることは当初明確ではありませんでした。この謎を解決するために、PoC実行トレースと通常のTIFFファイル・デコードを比較することによって、追加のデバッグが行われました。以降のセクションでは、初期化されていない値のピクセル計算への割り当て、コピー、および脆弱性の実際の根本原因を示します。

初期化されていないメモリの割り当てと利用

windowscodecs!CFormatConverter::Initialize は、図4に示すように0x40バイトのメモリを割り当てます。

0:000> r
rax=0000000000000000 rbx=0000000000000040 rcx=0000000000000040
rdx=0000000000000008 rsi=000002257a3db448 rdi=0000000000000000
rip=00007ffaf047a238 rsp=000000ad23f6f7c0 rbp=000000ad23f6f841
 r8=000000ad23f6f890  r9=0000000000000010 r10=000002257a3db468
r11=000000ad23f6f940 r12=000000000000000e r13=000002257a3db040
r14=000002257a3dbf60 r15=0000000000000000
iopl=0         nv up ei pl zr na po nc
cs=0033  ss=002b  ds=002b  es=002b  fs=0053  gs=002b             efl=00000246
windowscodecs!CFormatConverter::Initialize+0x1c8:
00007ffa`f047a238 ff15ea081200    call    qword ptr [windowscodecs!_imp_malloc (00007ffa`f059ab28)] ds:00007ffa`f059ab28={msvcrt!malloc (00007ffa`f70e9d30)}
0:000> k
 # Child-SP          RetAddr               Call Site
00 000000ad`23f6f7c0 00007ffa`f047c5fb     windowscodecs!CFormatConverter::Initialize+0x1c8
01 000000ad`23f6f890 00007ffa`f047c2f3     windowscodecs!CFormatConverter::Initialize+0x12b
02 000000ad`23f6f980 00007ff6`34ca6dff     windowscodecs!CFormatConverterResolver::Initialize+0x273

//Uninitialized memory after allocation:
0:000> db @rax
00000225`7a3dbf70  d0 b0 3d 7a 25 02 00 00-60 24 3d 7a 25 02 00 00  ..=z%...`$=z%...
00000225`7a3dbf80  00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00  ................
00000225`7a3dbf90  00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00  ................
00000225`7a3dbfa0  00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00  ................
00000225`7a3dbfb0  00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00  ................
00000225`7a3dbfc0  00 00 00 00 00 00 00 00-64 51 7c 26 c3 2c 01 03  ........dQ|&.,..
00000225`7a3dbfd0  f0 00 2f 6b 25 02 00 00-f0 00 2f 6b 25 02 00 00  ../k%...../k%...
00000225`7a3dbfe0  60 00 3d 7a 25 02 00 00-60 00 3d 7a 25 02 00 00  `.=z%...`.=z%...

図4:メモリの割り当て

メモリは書き込まれず、初期化されていない値はwindowscodecs!CLibTiffDecoderBase::HrProcessCopyで反転され、さらにwindowscodecs!GammaConvert_16bppGrayInt_128bppRGBAや、後に呼び出されるスケーリング関数で処理されます。

HrProcessCopyの前に初期化されていないメモリへの読み取りまたは書き込みがないため、実行をHrProcessCopyからトレース・バックし、実行トレースと通常のtiffデコード・トレースを比較しました。通常のTIFFファイルと比較して、PoCファイルでのwindowscodecs!CLibTiffDecoderBase::UnpackLineの動作に違いがあり、UnpackLineの関数パラメータの1つは初期化されていないバッファへのポインタでした。

UnpackLine関数には、TIFF画像のサンプルあたりのビット数(BPS)を使用する一連のswitch-caseステートメントがあります。PoC TIFFファイルでは、BPS値は0x09です。これはUnpackLineではサポートされておらず、制御フローがバッファに書き込むコードパスに到達することはありません。これは、初期化されていないメモリの根本的な原因であり、パイプラインの処理をさらに遅らせ、最終的にピクセル・データとして表示されます。

パッチ

この分析をMicrosoftに提示した後、彼らは、サポートされていないBPS値を持つファイルを無効にすることで、脆弱性にパッチを適用することにしました。これにより、すべてのデコードが回避され、ロードの非常に早い段階でファイルが拒否されます。

CVE-2020-1397


図5:CVE-2020-1397のレンダリング

前述の脆弱性とは異なり、出力の違いは図5に示すように、この例ではかなり限定されています。特定のタイプの初期化されていないメモリ使用量を判断するために使用できる、より単純な根本原因分析手法の1つは、2つの異なる出力を生成するrunの実行トレースを比較することです。この特定の手法は、初期化されていない変数がプログラムで制御フローの変更を引き起こし、出力に違いが生じる場合に役立ちます。このために、バイナリ実装スクリプトが作成されました。このスクリプトは、その登録とともに実行されたすべての命令とアクセスされたメモリ値を記録しました。

命令ポインタ(RIP)の値を比較して2つの異なる実行トレースを差分すると、初期化されていない値の使用により、windowscodecs!CCCITT::Expand2DLineに制御フローの変更が見つかりました。TTDトレースを使用した初期化されていない値のバックトレースは、例外的ではありますが根本原因を見つけるのに役立ちました。以降のセクションでは、初期化されていない値の割り当て、分布、および利用を示します。これがピクセル出力の制御フローの変更と偏差へつながります。

割り当て

windowscodecs!TIFFReadBufferSetup は、図6に示すように、0x400バイトのメモリを割り当てます。

windowscodecs!TIFFReadBufferSetup:
    ...
    allocBuff = malloc(size);
    *(v3 + 16) |= 0x200u;
    *(v3 + 480) = allocBuff;

0:000> k
 # Child-SP          RetAddr           Call Site
00 000000aa`a654f128 00007ff9`4404d4f3 windowscodecs!TIFFReadBufferSetup
01 000000aa`a654f130 00007ff9`4404d3c9 windowscodecs!TIFFFillStrip+0xab
02 000000aa`a654f170 00007ff9`4404d2dc windowscodecs!TIFFReadEncodedStrip+0x91
03 000000aa`a654f1b0 00007ff9`440396dd windowscodecs!CLibTiffDecoderBase::ReadStrip+0x74
04 000000aa`a654f1e0 00007ff9`44115fca windowscodecs!CLibTiffDecoderBase::GetOneUnpackedLine+0x1ad
05 000000aa`a654f2b0 00007ff9`44077400 windowscodecs!CLibTiffDecoderBase::HrProcessCopy+0x4a
06 000000aa`a654f2f0 00007ff9`44048dbb windowscodecs!CLibTiffDecoderBase::HrReadScanline+0x20
07 000000aa`a654f320 00007ff9`44048b40 windowscodecs!CDecoderBase::CopyPixels+0x23b
08 000000aa`a654f3d0 00007ff9`44043c95 windowscodecs!CLibTiffDecoderBase::CopyPixels+0x80
09 000000aa`a654f4d0 00007ff9`4404563b windowscodecs!CDecoderFrame::CopyPixels+0xb5

 

After allocation:
0:000> !heap -p -a @rax
    address 0000029744382140 found in
    _HEAP @ 29735190000
              HEAP_ENTRY Size Prev Flags            UserPtr UserSize - state
        0000029744382130 0041 0000  [00]   0000029744382140    00400 - (busy)
          unknown!noop

//Uninitialized memory after allocation        
0:000> db @rax
00000297`44382140  40 7c 5e 97 29 5d 5f ae-73 31 98 70 b8 4f da ac  @|^.)]_.s1.p.O..
00000297`44382150  06 51 54 18 2e 2a 23 3a-4f ab 14 27 e9 c6 2c 83  .QT..*#:O..'..,.
00000297`44382160  3a 25 b2 f6 9d e7 3c 09-cc a5 8e 27 b0 73 41 a9  :%....<....'.sA.
00000297`44382170  fb 9b 02 b5 81 3e ea 45-4c 0f ab a7 72 e3 21 e7  .....>.EL...r.!.
00000297`44382180  c8 44 84 3b c3 b5 44 8a-c9 6e 4b 2e 40 31 38 e0  .D.;[email protected]
00000297`44382190  85 f0 bd 98 3b 0b ca b8-78 b1 9d d0 dd 4d 61 66  ....;...x....Maf
00000297`443821a0  16 7d 0a e2 40 fa f8 45-4f 79 ab 95 d8 54 f9 44  .}[email protected]
00000297`443821b0  66 26 28 00 b7 96 52 88-15 f0 ed 34 94 5f 6f 94  f&(...R....4._o.

図6:メモリの割り当て

バッファへの部分的な分布

0x10バイトは、入力ファイルからTIFFReadRawStrip1によって割り当てられたこのバッファにコピーされます。バッファの残りの部分は、図7に示すように、変数として初期化されないままになります。

if ( !TIFFReadBufferSetup(v2, a2, stripCount) ) {
      return 0i64;
}
if ( TIFFReadRawStrip1(v2, v3, sizeToReadFromFile, "TIFFFillStrip") != sizeToReadFromFile )

 

0:000> r
rax=0000000000000001 rbx=000002973519a7e0 rcx=000002973519a7e0
rdx=0000000000000000 rsi=0000000000000000 rdi=0000000000000010
rip=00007ff94404d58c rsp=000000aaa654f128 rbp=0000000000000000
 r8=0000000000000010  r9=00007ff94416fc38 r10=0000000000000000
r11=000000aaa654ef60 r12=0000000000000001 r13=0000000000000000
r14=0000029744377de0 r15=0000000000000001
iopl=0         nv up ei pl nz na pe nc
cs=0033  ss=002b  ds=002b  es=002b  fs=0053  gs=002b             efl=00000202
windowscodecs!TIFFReadRawStrip1:
00007ff9`4404d58c 488bc4          mov     rax,rsp
0:000> k
 # Child-SP          RetAddr           Call Site
00 000000aa`a654f128 00007ff9`4404d491 windowscodecs!TIFFReadRawStrip1
01 000000aa`a654f130 00007ff9`4404d3c9 windowscodecs!TIFFFillStrip+0x49
02 000000aa`a654f170 00007ff9`4404d2dc windowscodecs!TIFFReadEncodedStrip+0x91
03 000000aa`a654f1b0 00007ff9`440396dd windowscodecs!CLibTiffDecoderBase::ReadStrip+0x74
04 000000aa`a654f1e0 00007ff9`44115fca windowscodecs!CLibTiffDecoderBase::GetOneUnpackedLine+0x1ad
05 000000aa`a654f2b0 00007ff9`44077400 windowscodecs!CLibTiffDecoderBase::HrProcessCopy+0x4a
06 000000aa`a654f2f0 00007ff9`44048dbb windowscodecs!CLibTiffDecoderBase::HrReadScanline+0x20
07 000000aa`a654f320 00007ff9`44048b40 windowscodecs!CDecoderBase::CopyPixels+0x23b
08 000000aa`a654f3d0 00007ff9`44043c95 windowscodecs!CLibTiffDecoderBase::CopyPixels+0x80
09 000000aa`a654f4d0 00007ff9`4404563b windowscodecs!CDecoderFrame::CopyPixels+0xb5

0:000> db 00000297`44382140
00000297`44382140  5b cd 82 55 2a 94 e2 6f-d7 2d a5 93 58 23 00 6c  [..U*..o.-..X#.l             // 0x10 bytes from file
00000297`44382150  06 51 54 18 2e 2a 23 3a-4f ab 14 27 e9 c6 2c 83  .QT..*#:O..'..,.             // uninitialized memory
00000297`44382160  3a 25 b2 f6 9d e7 3c 09-cc a5 8e 27 b0 73 41 a9  :%....<....'.sA.
00000297`44382170  fb 9b 02 b5 81 3e ea 45-4c 0f ab a7 72 e3 21 e7  .....>.EL...r.!.
00000297`44382180  c8 44 84 3b c3 b5 44 8a-c9 6e 4b 2e 40 31 38 e0  .D.;[email protected]
00000297`44382190  85 f0 bd 98 3b 0b ca b8-78 b1 9d d0 dd 4d 61 66  ....;...x....Maf
00000297`443821a0  16 7d 0a e2 40 fa f8 45-4f 79 ab 95 d8 54 f9 44  .}[email protected]
00000297`443821b0  66 26 28 00 b7 96 52 88-15 f0 ed 34 94 5f 6f 94  f&(...R....4._o.

図7:メモリの一部

初期化されていないメモリの使用

0:000> r
rax=0000000000000006 rbx=0000000000000007 rcx=0000000000000200
rdx=0000000000011803 rsi=0000029744382150 rdi=0000000000000000
rip=00007ff94414e837 rsp=000000aaa654f050 rbp=0000000000000001
 r8=0000029744382550  r9=0000000000000000 r10=0000000000000008
r11=0000000000000013 r12=00007ff94418b7b0 r13=0000000000000003
r14=0000000023006c00 r15=00007ff94418bbb0
iopl=0         nv up ei pl nz na po nc
cs=0033  ss=002b  ds=002b  es=002b  fs=0053  gs=002b             efl=00000206
windowscodecs!CCCITT::Expand2DLine+0x253:
00007ff9`4414e837 0fb606          movzx   eax,byte ptr [rsi] ds:00000297`44382150=06             ; Uninitialized memory being accessed

 

0:000> db 00000297`44382140
00000297`44382140  5b cd 82 55 2a 94 e2 6f-d7 2d a5 93 58 23 00 6c  [..U*..o.-..X#.l             // 0x10 bytes from file
00000297`44382150  06 51 54 18 2e 2a 23 3a-4f ab 14 27 e9 c6 2c 83  .QT..*#:O..'..,.             // uninitialized memory
00000297`44382160  3a 25 b2 f6 9d e7 3c 09-cc a5 8e 27 b0 73 41 a9  :%....<....'.sA.
00000297`44382170  fb 9b 02 b5 81 3e ea 45-4c 0f ab a7 72 e3 21 e7  .....>.EL...r.!.
00000297`44382180  c8 44 84 3b c3 b5 44 8a-c9 6e 4b 2e 40 31 38 e0  .D.;[email protected]
00000297`44382190  85 f0 bd 98 3b 0b ca b8-78 b1 9d d0 dd 4d 61 66  ....;...x....Maf
00000297`443821a0  16 7d 0a e2 40 fa f8 45-4f 79 ab 95 d8 54 f9 44  .}[email protected]
00000297`443821b0  66 26 28 00 b7 96 52 88-15 f0 ed 34 94 5f 6f 94  f&(...R....4._o.

 

0:000> k
 # Child-SP          RetAddr           Call Site
00 000000aa`a654f050 00007ff9`4414df80 windowscodecs!CCCITT::Expand2DLine+0x253
01 000000aa`a654f0d0 00007ff9`4412afcc windowscodecs!CCCITT::CCITT_Expand+0xac
02 000000aa`a654f120 00007ff9`4404d3f0 windowscodecs!CCITTDecode+0x7c
03 000000aa`a654f170 00007ff9`4404d2dc windowscodecs!TIFFReadEncodedStrip+0xb8
04 000000aa`a654f1b0 00007ff9`440396dd windowscodecs!CLibTiffDecoderBase::ReadStrip+0x74
05 000000aa`a654f1e0 00007ff9`44115fca windowscodecs!CLibTiffDecoderBase::GetOneUnpackedLine+0x1ad
06 000000aa`a654f2b0 00007ff9`44077400 windowscodecs!CLibTiffDecoderBase::HrProcessCopy+0x4a
07 000000aa`a654f2f0 00007ff9`44048dbb windowscodecs!CLibTiffDecoderBase::HrReadScanline+0x20
08 000000aa`a654f320 00007ff9`44048b40 windowscodecs!CDecoderBase::CopyPixels+0x23b
09 000000aa`a654f3d0 00007ff9`44043c95 windowscodecs!CLibTiffDecoderBase::CopyPixels+0x80
0a 000000aa`a654f4d0 00007ff9`4404563b windowscodecs!CDecoderFrame::CopyPixels+0xb5

図8:初期化されていない値の読み取り

初期化されていない値(図8)に応じて、Expand2DLineで異なるコード・パスが取得され、出力ピクセルが変更されることを図9で示します。

  {
    {
        if ( v11 != 1 || a2 )
        {
            unintValue = *++allocBuffer | (unintValue << 8);          // uninit mem read
        }
        else
        {
            unintValue <<= 8;
            ++allocBuffer;
        }
        --v11;
        v16 += 8;
      }
      v29 = unintValue >> (v16 - 8);
      dependentUninitValue = *(l + 2i64 * v29);                           
      v16 -= *(l + 2i64 * v29 + 1);
      if ( dependentUninitValue >= 0 )             // path 1
        break;
      if ( dependentUninitValue < '\xC0' )
        return 0xFFFFFFFFi64;                     // path 2
  }
  if ( dependentUninitValue <= 0x3F )              // path xx
      break;

図9:条件が満たされている場合の初期化されていないメモリの使用

パッチ

Microsoftは、割り当てられたメモリをゼロで初期化するmallocの代わりにcallocを使用して、この脆弱性にパッチを適用することを決定しました。

結論

このブログシリーズのパート2では、Windowsの組み込み画像パーサーに複数の脆弱性があることを紹介しました。次回の投稿では、RAW、HEIFなど、Windowsでサポートされている新しい画像形式について探ります。

 

本ブログは機械翻訳(MT)を使用して翻訳しています。原文と翻訳版の意味、文言が異なる場合は原文を有効とします。

原文:March 03, 2021 「Fuzzing Image Parsing in Windows, Part Two: Uninitialized Memory