Skip to content
KitploitKITPLOIT
StrumentiBlog
Invia
StrumentiBlog
Invia

Strumenti di Hacking, PenTest e Cybersecurity per il tuo Arsenale di Sicurezza!

Kitploit è una directory di strumenti di hacking, cybersecurity e pentesting. Scopri gli ultimi aggiornamenti dei progetti per trovare vulnerabilità, analizzare sistemi, automatizzare i test e rafforzare la tua sicurezza.

··Feed·Contatto·Privacy·© 2026 Kitploit

Directory degli strumenti

Categorie

Vedi tutte le categorie
Loading categories
CVE-2026-25243 — CVE-2026-25243 — Redis RESTORE zipmap double-free → esecuzione remota di codice (ASLR attivo). | Kitploit
Strumenti/GitHubGitHub/dinosn/cve-2026-25243
Memory ForensicsAnalisi delle VulnerabilitàExploitReverse EngineeringPenetration TestingStrumento di Accesso RemotoSviluppo PayloadBinary Exploitation
GitHubdinosn/cve-2026-25243

CVE-2026-25243

CVE-2026-25243 — Redis RESTORE zipmap double-free → esecuzione remota di codice (ASLR attivo).

Vedi Repository
132 mesi faNon ancora revisionato

Più Popolari

Vedi tutti →

Scopri gli strumenti più utilizzati dalla nostra community.

Esplora tutti gli strumenti

Sfoglia la nostra collezione di strumenti

Vedi tutti gli strumenti →
Condividi

CVE-2026-25243 — Redis RESTORE zipmap double-free → esecuzione remota di codice

TL;DR. Un payload DUMP malformato passato a RESTORE innesca una doppia free nell'heap nel loader legacy hash-zipmap di Redis. Con il jemalloc predefinito la doppia free è silenziosa (il server continua a funzionare), il che la trasforma in una primitiva type confusion controllabile. Questo repository la trasforma in esecuzione remota di codice con ASLR attivo — il worker Redis chiama system("<stringa dell'attaccante>") e continua a servire richieste. Non è un DoS.

root@kitploit:~
# default Redis (DEBUG disabled), ASLR on — the most self-contained exploit (NO libc offsets):
$ python3 exploits/poc_rce_aslr_pie_rop.py --cmd "id > /tmp/pwned_pie 2>&1"
[*] self-cal: blob_base=0x7f352d800009 blob_robj=0x7f353286b8d8 pie_base=0x557ea9149000  (NO libc)
[*] fake dictType F=0x7f352e013c36  g1=0x557ea93cca87 execve=0x557ea91cee80
$ cat /tmp/pwned_pie
uid=0(root) gid=0(root) groups=0(root),...    # <- execve("/bin/sh","-c",<cmd>) as the redis process

La fuga di informazioni che sconfigge l'ASLR non usa DEBUG — legge l'indirizzo della C-closure Lua redis.call (EVAL 'return tostring(redis.call)'), la stessa tecnica autonoma e senza DEBUG del nostro precedente exploit Redis. blob_base/blob_robj e la base PIE vengono poi derivati in fase di runtime dall'over-read (nessun offset fisso). Il finale PIE-ROP chiama execve@plt tramite uno stack-pivot JOP, quindi usa zero indirizzi libc — le uniche costanti specifiche della build sono gli offset dei gadget relativi alla PIE letti dal binario redis-server, esattamente come la tabella gadget per-build del nostro precedente exploit HLL. Verificato uid=0(root), ASLR attivo, 8/8, su un server predefinito con DEBUG disabilitato.

Sono previsti due finali. poc_rce_aslr_pie_rop.py (sopra) è il più autonomo — nessuna libc, completamente auto-calibrato — ma execve sostituisce il worker (usa una reverse-shell con --cmd; ideale per una shell vera). poc_rce_aslr_selfcal.py mantiene vivo il worker (system() fa fork) al costo di due offset legati alla versione della libc. Scegli in base al fatto che il server debba sopravvivere.


Il bug

RESTORE key 0 <DUMP-payload> deserializza un oggetto serializzato. Per il tipo legacy RDB_TYPE_HASH_ZIPMAP (0x09), il validatore e il convertitore non concordano su quanti byte occupi un campo di lunghezza:

  • zipmapValidateIntegrity() scorre con la dimensione effettiva codificata (5 per il prefisso sovralungo 0xFE);
  • zipmapNext() durante la conversione zipmap → listpack usa 1 byte per qualsiasi lunghezza decodificata < 254.

Una lunghezza piccola scritta nella forma sovralunga di 5 byte supera la validazione ma fa sì che zipmapNext() avanzi in modo errato di 4 byte. Dallo stesso avanzamento errato derivano due conseguenze: un over-read nell'heap (zipmap.c) e, solo in Redis, una doppia free nell'heap nel loader hash-zipmap di rdb.c:

root@kitploit:~
sds field = sdstrynewlen(fstr, flen);
if (!field || dictAdd(dupSearchDict, field, NULL) != DICT_OK || !lpSafeToAdd(lp, flen + vlen)) {
    dictRelease(dupSearchDict);   // (1) dictAdd took ownership of `field` -> freed here
    sdsfree(field);               // (2) freed AGAIN  -> double-free

Valkey protegge tutto ciò (if (!field_added) sdsfree(field)); Redis a monte non lo faceva, quindi la doppia free è solo Redis. Il fix rifiuta la lunghezza corta codificata in forma sovralunga e riordina i controlli al momento del caricamento.

La catena dell'exploit (Redis 8.6.2, x86-64, jemalloc, PIE/NX/partial-RELRO)

root@kitploit:~
silent double-free  ->  type-confusion overlap  ->  arbitrary pointer-forge
   ->  forge a hashtable hash's  dict->type  to a fake dictType
   ->  HGET hd "<field>"   ==   dictFind -> type->hashFunction(field)
      libc path  (selfcal): hashFunction = &system            -> system("<cmd>")   (worker survives)
      PIE path   (pie_rop): hashFunction = JOP-pivot g1, field = ROP chain
                            -> leave;ret pivots rsp onto the field
                            -> execve("/bin/sh","-c","<cmd>")  via execve@plt        (no libc, no DEBUG)

Il dictType falso viene piazzato all'interno di una stringa da 16 MB (SETRANGE) nell'unico offset i cui byte bassi dell'indirizzo corrispondono all'header sds della stringa dell'attaccante. L'ASLR viene sconfitto interamente in fase di runtime:

  • system — una singola leak di un puntatore all'heap. Il percorso consigliato è senza DEBUG: l'indirizzo della C-closure Lua di redis.call (EVAL 'return tostring(redis.call)') — la stessa leak autonoma usata dal nostro precedente exploit Redis. Le arene jemalloc si trovano a un offset costante rispetto alla libc, quindi system = leaked_robj + Δlibc + system_off. (DEBUG OBJECT è solo una comodità da laboratorio quando scripting è disabilitato ma DEBUG è abilitato — la configurazione più rara.)
  • l'indirizzo del blob da 16 MB (una mmap randomizzata in modo indipendente) — letto con l'arbitrary-read del bug stesso: forgi il dict di una SET così che il suo membro sia una sds SDS_TYPE_32 da 107 KB, SMEMBERS fa over-read sull'heap adiacente, e robj.ptr del blob viene letto al suo offset noto.

Vedi WRITEUP.md per l'analisi completa primitiva-per-primitiva e i dettagli jemalloc / Redis-8.x conquistati a fatica (limite della classe 64, tagging delle entry del dict, mstr dei campi hash, pre-crescita del keyspace).

Laboratorio

root@kitploit:~
docker build -t cve-2026-25243 .
# stock (jemalloc) demo — DoS-or-not? shows the type confusion (no tooling):
docker run --rm -p 6379:6379 cve-2026-25243

# full chain — DEFAULT config (DEBUG disabled), the recommended exploit:
sysctl -w kernel.randomize_va_space=2            # ASLR ON
redis-server &                                   # DEBUG is off by default
python3 exploits/poc_rce_aslr_selfcal.py --host 127.0.0.1 --port 6379 --cmd "id > /tmp/pwned 2>&1"

La fuga di informazioni che sconfigge l'ASLR (senza DEBUG)

La leak di un puntatore all'heap per il bootstrap segue lo stesso approccio del nostro precedente exploit Redis: si fa trapelare l'indirizzo della C-closure Lua redis.call con EVAL 'return tostring(redis.call)'. Lua scripting è attivo per impostazione predefinita; DEBUG è disattivato per impostazione predefinita (enable-debug-command no) — quindi la leak Lua è la via primaria realistica, e DEBUG OBJECT (poc_rce_aslr.py) è solo una comodità da laboratorio. poc_rce_aslr_selfcal.py poi deriva blob_base e blob_robj in fase di runtime dall'over-read (scansionando la firma del robj del blob da 16 MB), quindi DLUA/DFOBJ devono solo essere vicini.

Per il finale con system, l'over-read del piccolo heap non contiene puntatori libc, quindi la libc non può essere auto-derivata — poc_rce_aslr_selfcal.py mantiene due offset legati alla versione della libc (DLIBC, SYSTEM_OFF). Il finale poc_rce_aslr_pie_rop.py elimina del tutto questa dipendenza: lo stesso over-read contiene puntatori PIE (un dictType condiviso compare ripetutamente), quindi la base PIE viene auto-calibrata come most-common-PIE-value − DICTTYPE_OFF, e la catena termina in execve@plt tramite uno stack-pivot JOP (mov rbp,rdi; call *0x8(rax) → leave;ret sposta rsp sul campo HGET controllato dall'attaccante, che è la ROP chain execve("/bin/sh","-c",<cmd>)). Le uniche costanti specifiche della build sono gli offset dei gadget relativi alla PIE letti da — estraili per ogni target con /, esattamente come il nostro precedente exploit HLL associa una tabella di gadget a ogni ELF Build-ID. Non viene usato alcun indirizzo libc.

Screenshot

screenshots/05-pie-rop-libc-free.png (la self-cal NO libc + uid=0, l'esecuzione più autonoma), 01-rce-aslr-on.png (lo screenshot decisivo con uid=0), 02-reliability.png (5/5), 03-exploit-chain.png (il codice) e 04-debug-free-selfcal.png (l'esecuzione system senza DEBUG e auto-calibrante su un Redis predefinito).

Impatto e versioni interessate

  • Remoto, nessun privilegio speciale. RESTORE è un comando ordinario — su un Redis non autenticato/esposto (senza requirepass) qualsiasi client connesso può eseguirlo; su un'istanza autenticata, qualsiasi utente senza una regola ACL -restore di negazione. Lo stesso profilo di accesso dei comandi sulle strutture dati usati da altre RCE Redis.
  • Confermato: doppia free silenziosa nell'heap, type confusion, lettura arbitraria della memoria di processo (info-leak che esfiltra chiavi/segrete/puntatori) ed esecuzione remota di codice (questo repository).
  • Interessate: Redis < {6.2.22, 7.2.14, 7.4.9, 8.2.6, 8.4.3, 8.6.3} — cioè dalla 6.2.x fino alle 8.x attuali; Valkey è solo DoS/over-read (la sua guardia field_added blocca la doppia free).

Mitigazione

Aggiorna a una release corretta. Se non puoi: limita RESTORE (ACL … -restore), non esporre mai Redis senza autenticazione e disabilita DEBUG.


Ricerca di sicurezza autorizzata, pubblicata per la consapevolezza dei difensori. Non eseguire contro sistemi che non possiedi o su cui non hai esplicito permesso di test.

Scarica lo strumento
filecosa dimostra
★ exploits/poc_rce_aslr_pie_rop.pyil più autonomo — RCE su un Redis predefinito (DEBUG disattivato), NESSUN offset libc; auto-calibra blob_base/blob_robj/pie_base; execve@plt tramite JOP pivot (il worker viene sostituito). 8/8.
★ exploits/poc_rce_aslr_selfcal.pysopravvivenza del worker — stessa catena ma hashFunction=&system (fork); costa due offset legati alla versione della libc (DLIBC/SYSTEM_OFF). Leak della Lua-closure, auto-calibrazione di blob_base/blob_robj.
exploits/poc_rce_aslr_nodebug.pysenza DEBUG (leak Lua), ma con offset fissi (calibrati con DEBUG attivo)
exploits/poc_rce_aslr.pyvariante comoda per il laboratorio: leak di bootstrap con DEBUG OBJECT (richiede DEBUG abilitato)
exploits/poc_rce_aslr_off.pyRCE con ASLR disattivato (indirizzi calibrati)
exploits/poc_typeconfusion.pydoppia free → due chiavi condividono un buffer dell'heap (senza strumenti)
exploits/poc_doublefree.pyla doppia free (ASan: heap-use-after-free in sdsfree)
exploits/poc_dos_overread.pyil crash per over-read (ASan)
redis-server
ROPgadget
objdump