[하루한줄] Windows: Out-of-bounds write in WindowsCodecsRaw!COlympusE300LoadRaw

URL

Issue 2137: Windows: Out-of-bounds write in WindowsCodecsRaw!COlympusE300LoadRaw

Target

Windows 10 20H1

Explain

Windows에서는 Olympus E300의 raw 이미지 파일을 처리할 때, Windows Imaging Component (WIC)를 통해 처리합니다. 이 때 WindowsCodecsRaw.dllCOlympusE300LoadRaw::olympus_e300_load_raw() 함수가 실행됩니다. 취약점이 발생한 함수의 코드는 다음과 같습니다.

void CLASS olympus_e300_load_raw()
{
  uchar  *data,  *dp;
  ushort *pixel, *pix;
  int dwide, row, col;

  dwide = raw_width * 16 / 10;               // (1)
  data = malloc (dwide + raw_width*2);
  merror (data, "olympus_e300_load_raw()");
  pixel = (ushort *) (data + dwide);
  for (row=0; row < height; row++) {
    fread (data, 1, dwide, ifp);
    for (dp=data, pix=pixel; pix < pixel+raw_width; dp+=3, pix+=2) {  //  (2)
      if (((dp-data) & 15) == 15) dp++;
      pix[0] = dp[1] << 8 | dp[0];                                    // (3)
      pix[1] = dp[2] << 4 | dp[1] >> 4;                               // (4)
    }
    for (col=0; col < width; col++)
      BAYER(row,col) = (pixel[col] & 0xfff);
  }
  free (data);
}

먼저 (1)에서 디코딩된 데이터를 저장할 메모리를 할당합니다. 디코딩은 열 단위로 디코딩을 진행하는데, 한 열에는 height만큼의 픽셀이 존재하며 픽셀은 각각 2 bytes의 데이터로 디코딩 됩니다. 그리고 (2)에서부터 실질적인 디코딩 작업이 진행됩니다. 조건문을 pix < pixel+raw_width로 설정함으로써 디코딩 과정에서 OOB가 발생하지 않도록 신경썼지만 raw_width0xd79같이 홀수일 경우, 한 픽셀 당 2 bytes 씩 디코드하기 때문에 해당 loop의 마지막에서 (3)에서는 버퍼의 마지막에 데이터를 쓰지만 (4)에서 버퍼 밖의 메모리 영역에 데이터를 쓰게 되어 1 byte 의 OOB Write가 발생하게 됩니다.