
PoC и эксплойт для CVE-2025-32023 / PlaidCTF 2025 "Zerodeo"
PoC и эксплойт для CVE-2025-32023 (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.
HyperLogLog в Redis — это просто ещё одна строка со своими собственными кодировками. При итерации по разрежённой (sparse) кодировке HLL необходимо суммировать длины серий (run lengths) каждого разрежённого представления, что может привести к переполнению общей длины, подсчитываемой в int i, до отрицательного значения при обработке некорректного HLL. Это позволяет атакующему выполнять запись по отрицательным смещениям в структуре HLL, что приводит к записи за пределами границ (out-of-bounds) в стеке или куче в зависимости от того, откуда взята структура HLL (например, 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 подход к эксплуатации: