
CVE-2025-32023 / PlaidCTF 2025 "Zerodeo"에 대한 PoC 및 익스플로잇
CVE-2025-32023에 대한 PoC 및 Exploit (GHSA-rp2m-q4j6-gr43) / PlaidCTF 2025 "Zerodeo"
redis:7.4.2-alpine3.21@sha256:02419de7eddf55aa5bcf49efb74e88fa8d931b4d77c07eff8a6b2144472b6952에 대해 테스트했습니다.
Redis 2.8 이상 버전에 영향을 미칩니다. 8.0.3, 7.4.5, 7.2.10, 6.2.19에서 패치되었습니다. redis/redis@5018874 참조.
Redis의 HyperLogLog는 고유한 커스텀 인코딩을 가진 또 하나의 문자열일 뿐입니다. 희소 HLL 인코딩을 반복 처리하려면 각 희소 표현의 런 길이를 더해야 하는데, 잘못된 HLL을 대상으로 할 경우 int i에 누적되는 총 길이가 오버플로하여 음수 값이 될 수 있습니다. 이로 인해 공격자는 HLL 구조체의 음수 오프셋에 덮어쓸 수 있으며, HLL 구조체가 어디서 비롯되었는지에 따라 스택/힙에 대한 out-of-bounds 쓰기가 발생할 수 있습니다(예: hllMerge()는 스택에 할당된 구조체를, hllSparseToDense()는 힙에 할당된 구조체를 받습니다).
아래 패치 스니펫을 참조하세요:
int hllMerge(uint8_t *max, robj *hll) {
struct hllhdr *hdr = hll->ptr;
int i;
if (hdr->encoding == HLL_DENSE) {
hllMergeDense(max, hdr->registers);
} else {
uint8_t *p = hll->ptr, *end = p + sdslen(hll->ptr);
long runlen, regval;
+ int valid = 1;
p += HLL_HDR_SIZE;
i = 0;
while(p < end) {
if (HLL_SPARSE_IS_ZERO(p)) {
runlen = HLL_SPARSE_ZERO_LEN(p);
+ if ((runlen + i) > HLL_REGISTERS) { /* Overflow. */
+ valid = 0;
+ break;
+ }
i += runlen;
p++;
} else if (HLL_SPARSE_IS_XZERO(p)) {
runlen = HLL_SPARSE_XZERO_LEN(p);
+ if ((runlen + i) > HLL_REGISTERS) { /* Overflow. */
+ valid = 0;
+ break;
+ }
i += runlen;
p += 2;
} else {
runlen = HLL_SPARSE_VAL_LEN(p);
regval = HLL_SPARSE_VAL_VALUE(p);
- if ((runlen + i) > HLL_REGISTERS) break; /* Overflow. */
+ if ((runlen + i) > HLL_REGISTERS) { /* Overflow. */
+ valid = 0;
+ break;
+ }
while(runlen--) {
if (regval > max[i]) max[i] = regval;
i++;
}
p++;
}
}
- if (i != HLL_REGISTERS) return C_ERR;
+ if (!valid || i != HLL_REGISTERS) return C_ERR;
}
return C_OK;
}
익스플로잇은 표준적인 Redis pwnable 방식입니다: