[하루한줄] CVE-2024-33078: Tencent libpag에서 발견된 두 가지 취약점
URL
https://github.com/Tencent/libpag/issues/2229
https://github.com/Tencent/libpag/issues/2230
Target
- libpag
Explain
vector 및 raster 기반의 PAG(Portable Animated Graphics) 파일용 실시간 렌더링 라이브러인 libpag에서 발견된 두 가지 취약점의 세부 정보가 공개되었습니다. 두 취약점 모두 DecodeStream.cpp
구현에 존재합니다.
CVE-2024-33078 - Heap Buffer Oveflow
첫 번째 취약점은 DecodeStream::readUTF8String()
함수에 존재합니다.
std::string DecodeStream::readUTF8String() {
if (_position < dataView.size()) {
auto text = reinterpret_cast<const char*>(dataView.bytes() + _position);
auto textLength = strlen(text);
if (textLength > dataView.size() - _position) {
textLength = dataView.size() - _position;
positionChanged(static_cast<off_t>(textLength));
} else {
positionChanged(static_cast<off_t>(textLength + 1));
}
return {text, textLength};
} else {
PAGThrowError(context, "End of file was encountered.");
}
return "";
}
해당 함수는 dataView.bytes() + _poisition
위치의 문자열 text
길이인 textLength
를 strlen()
함수를 사용해 구합니다. text
가 가리키는 문자열이 null로 끝나지 않는 경우 strlen()
은 정확한 길이를 측정하지 못하고 예상보다 큰 값을 반환합니다. 이후 textLength
길이만큼 메모리를 읽는 과정에서 파일 스트림이 할당된 메모리 이후의 값을 읽어 Heap Buffer Oveflow가 트리거됩니다.
취약점의 패치는 아래와 같이 strnlen()
함수를 사용함으로써 읽을 수 있는 최대 길이를 maxLength
만큼 지정하는 것으로 이루어졌습니다. 해당 패치 커밋은 링크에서 확인 가능합니다.
std::string DecodeStream::readUTF8String() {
if (_position < dataView.size()) {
auto text = reinterpret_cast<const char*>(dataView.bytes() + _position);
auto maxLength = dataView.size() - _position;
auto textLength = strnlen(text, maxLength);
if (textLength < maxLength) {
positionChanged(static_cast<off_t>(textLength + 1));
return {text, textLength};
}
}
PAGThrowError(context, "End of file was encountered.");
return "";
}
Unknown CVE - Integer Overflow
CVE Number가 할당되지 않은 두 번째 취약점은 DecodeStream.h
헤더의 타입 선언 및 DecodeStream::checkEndOfFile()
함수에 존재합니다.
// DecodeStream.h
//...
private:
tgfx::DataView dataView = {};
uint32_t _position = 0; //(1)
uint64_t _bitPosition = 0;
void bitPositionChanged(off_t offset);
void positionChanged(off_t offset);
bool checkEndOfFile(uint32_t bytesToRead);
};
//...
// DecodeStream.cpp
//...
bool DecodeStream::checkEndOfFile(uint32_t bytesToRead) {
if (_position + bytesToRead > dataView.size()) { //(2)
PAGThrowError(context, "End of file was encountered.");
return true;
}
return false;
}
//...
DecodeStream::checkEndOfFile()
함수는 EOF 여부를 확인하는 함수로, 현재 스트림 커서 위치 _position
과 bytesToRead
를 더한 값이 파일 전체 크기보다 크면 현재 파일의 끝으로 간주합니다.
그러나 (1)에서 _position
이 uint32_t
로 선언되어 있어 (2)의 조건 연산 결과가 uint32_t
표현범위보다 큰 경우 integer overflow가 발생하고, 이로 인해 파일의 EOF를 넘어 Heap Buffer Overflow 등의 추가적인 영향을 줄 수 있습니다.
취약점 패치는 스트림 처리 관련 변수들의 타입을 size_t
로 변경하는 것으로 이루어졌으며, 패치 커밋은 링크에서 확인 가능합니다.
Reference
본 글은 CC BY-SA 4.0 라이선스로 배포됩니다. 공유 또는 변경 시 반드시 출처를 남겨주시기 바랍니다.