* 오역 가능성이 있습니다.
1. 개요
1.1 취약점 요약
CVE-2017-17969는 Zip Shrink에서 발생한 heap buffer overflow이다. Shrink는 Lempel-Ziv-Welch(LZW) 압축 알고리즘을 구현한 것이다. 이는 1993년에 출시된 2.0 버전 이전의 PKZIP에서 사용되었다. Shrink는 9bit에서 13bit사이의 크기를 가지는 동적 코드 LZW이고 부분적으로 Dictionary를 지울 수 있는 기능을 한다. 7-Zip v.16.04에서 발생한 취약점으로 버퍼 오버플로우가 발생해 ZIP 압축을 처리할 때 공격자가 parent 노드를 지울 수 있고 서비스 거부 공격 또는 임의코드를 실행할 수 있다.
1.2 취약점 개요
취약점 이름 | ZIP Shrink Heap Buffer Overflow | ||
최초 발표일 | 2017.12.29 | CVSS 3.0 | 7.8 |
위험 등급 | 높음 | 현재 상태 | 패치 |
취약점 영향 | Out of Bounds | 밴더 | MITRE |
2. 분석
2.1 공격 기법 및 기본 개념
압축 모델은 LZW dictionary를 저장하는 _parents와 _suffixes로 구성된다. 추가로 버퍼인 _stack이 구성된다.
UInt16 _parents[kNumItems];
Byte _suffixes[kNumItems];
Byte _stack[kNumItems];
문제가 되는 부분은 NCompress::NShrink::CDecoder::CodeReal 의 일부이다.
unsigned cur = sym;
unsigned i = 0;
while (cur >= 256) {
_stack[i++] = _suffixes[cur];
cur = _parents[cur];
}
i 값의 검증 절차가 없다. 힙 버퍼인 _stack을 오버플로우하는 방법은 _parents 배열을 사이클을 형성하도록 시퀀스를 만드는 것이다. 이 방법이 가능한 이유는 decoder가 parents 노드가 자기 자신을 가리키지 않게만 보장하기 때문이다. PKZIP의 구버전은 자기 자신을 가리키는 parents 노드를 포함해 압축 archives를 만들기 때문에 이것을 받아들여야 한다.
특수 시퀀스인 256,2를 사용하면 공격자가 parents 노드를 삭제할 수도 있다. 삭제된 노드는 kNumItems로 설정되어 parent 노드가 삭제되었는지 아닌지 확인할 수 없게 된다. 따라서 parents 배열은 Out Of Bounds 오류가 발생한다.
decoder가 공격자가 제어한 out of bound 데이터를 쓸 수 있게 하는 archives를 만드는 것이 가능하게 된다. 그러나 무한 루프에 빠지지 않게 하는 쉬운 방법을 찾지 못했다. i가 while문이 돌 때마다 증가하기 때문에 무한 루프는 Segmentation fault를 발생시켜 코드 실행을 위한 공격을 어렵게 할 것이다.
2.2 패치 내역
// ShrinkDecoder.cpp
lastSym = sym;
unsigned cur = sym;
unsigned i = 0;
while (cur >= 256) {
_stack[i++] = _suffixes[cur];
cur = _parents[cur];
// don't change that code:
// Orphan Check and self-linked Orphan check (_stack overflow check);
+ if (cur == kEmpty || i >= kNumItems)
+ break;
}
+ if (cur == kEmpty || i >= kNumItems)
+ break;
자기 자신을 가리키는 노드를 검사하는 코드가 추가되었다. 또 kNumItems보다 i 값이 큰지 검사해 마무리한다.
위의 그림 1은 7z.dll v.16.04를 디어셈블리한 것이고 표시된 빨간 부분의 오프셋, 0x000a5ab4와 0x000a5abb의 변경 사항이 보인다.
아래는 Shrink Decoder.cpp의 수정된 부분과 같은 패치 코드이다.
; CVE-2017-17969 patch for 7z.dll 16.04
MODULE_PATH "C:\0patch\Patches\7zip\16.4\7z.dll"
PATCH_ID 316
PATCH_FORMAT_VER 2
VULN_ID 3295
PLATFORM win32
patchlet_start
PATCHLET_ID 1
PATCHLET_TYPE 2
PATCHLET_OFFSET 0x000a5ab4
JUMPOVERBYTES 5
N_ORIGINALBYTES 5
;piggybacking jnb
;3D 00 01 00 00 cmp eax, 100h
;73 CE jnb short loc_100AAF28
;if (cur == kEmpty || i >= kNumItems)
; break;
code_start
cmp eax, 100h
jne skip1 ;cur != kEmpty?
STC ;set piggyback condition for jnb to NOT jump
call PIT_ExploitBlocked
jmp end
skip1:
cmp esi, 2000h
jb skip2 ;i < kNumItems?
STC ;set piggyback condition for jnb to NOT jump
call PIT_ExploitBlocked
jmp end
skip2:
cmp eax, 100h ;original code
end:
code_end
patchlet_end
patchlet_start
PATCHLET_ID 2
PATCHLET_TYPE 2
PATCHLET_OFFSET 0x000a5abb
PIT 7z.dll!0xa5bc4
JUMPOVERBYTES 0
N_ORIGINALBYTES 5
code_start
cmp eax, 100h
je block ; cur == kEmpty?
cmp esi, 2000h
jge block ; i >= kNumItems?
jmp skip
block:
call PIT_ExploitBlocked
jmp PIT_0xa5bc4 ; break
skip:
code_end
patchlet_end
참고
https://landave.io/2018/01/7-zip-multiple-memory-corruptions-via-rar-and-zip/?hn#fn:10
https://blog.0patch.com/2018/02/two-interesting-micropatches-for-7-zip.html
'보안 > 취약점 분석' 카테고리의 다른 글
CVE-2023-38934: Tenda Router Vulnerability on formSetDeviceName function (0) | 2023.08.14 |
---|---|
CVE-2023–37734: Buffer-overflow in mp3_audio_converter (0) | 2023.08.11 |
CVE-2022-0453: A Remote Stack Overflow in The Linux Kernel (0) | 2023.08.08 |
CVE-2019-6498: GattLib 0.2 Stack Buffer Overflow (0) | 2023.08.08 |
CVE-2017-15048: Zoom Linux Client Stack-based Buffer Overflow (0) | 2023.08.08 |