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

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

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

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

ツールディレクトリ

カテゴリ

すべてのカテゴリを見る
Loading categories
CVE-2026-40003 — CVE-2026-40003 のエクスプロイト。ZXIC/Sanechips ZX297520V3 SoC BootROM における任意メモリ書き込みの脆弱性であり、USB ダウンロードモードを介したコード実行を可能にします。 | Kitploit
ツール/GitHubGitHub/rva3/cve-2026-40003
組み込みシステムセキュリティエクスプロイトリバースエンジニアリングハードウェアハッキングペイロード開発ファームウェア解析バイナリエクスプロイト
GitHubrva3/cve-2026-40003

CVE-2026-40003

CVE-2026-40003 のエクスプロイト。ZXIC/Sanechips ZX297520V3 SoC BootROM における任意メモリ書き込みの脆弱性であり、USB ダウンロードモードを介したコード実行を可能にします。

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

人気

すべて見る →

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

すべてのツールを探索

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

すべてのツールを見る →
共有
ウェブサイト

CVE-2026-40003、通称Joselitoは、ZXIC/Sanechips ZX297520V3 SoC BootROMで発見された任意メモリ書き込みの脆弱性です。

[!CAUTION] このPoCは研究目的のみで公開されています。このエクスプロイトを悪意のある目的で使用してはいけません。所有していないデバイスや、所有者の明示的な同意なしにエクスプロイトを使用してはいけません。

ステータス

この脆弱性は2026年3月以降の新しいSoCリビジョンで修正される予定です。パッチ適用済みチップを使用した既知の製品はまだありません。既存のすべてのデバイスが脆弱です。

どのように動作するのか?

要約: ローダーコードを確認してください。

BootROMはスタックポインタを0x81FF0に設定して0x4番地から開始します。コードは特別なテストポイントまたはフラッシュからイメージをロードする機能に基づいてモード選択を実行します。BootROMがフラッシュ上のイメージのロードまたは検証に失敗した場合、USBダウンロードモードにフォールバックします。

この動作はここで確認できます:

root@kitploit:~
v0 = MEMORY[0x13B004] & 7; // hardware pin
switch ( (char)v0 )
{
  case 0:
    if ( nand_init() )
      goto LABEL_12;
    parse_header((Header *)0x8A000);
    v4 = "\nMODE:NAND\n";
    goto LABEL_11;
  case 1:
    if ( !nand_init() )
    {
      parse_header((Header *)0x8A000);
      uart_puts("\nMODE:USB-N\n");
    }
    usbdl_init(0x1500000);
    v5 = "TURN TO NAND\n";
    goto LABEL_16;
/* ... */
LABEL_16:
  uart_puts(v5);
LABEL_7:
  verify_and_jump((Header *)0x8A000, 0, 1);
  break;

usbdl_init関数はUSB IPを初期化し、ダウンロードループに入ります:

root@kitploit:~
void __fastcall usbdl_init(int usb_base)
{
  char *v1; // r0

  if ( usb_base == 0x1500000 )
  {
    alt_usb_base = 0;
    usb_init();
  }
  else
  {
    alt_usb_base = 1;
    noidea();
  }
  if ( usb_setup() )
  {
    try_sync_with_host();
    v1 = "FAILED\n";
  }
  else
  {
    v1 = "\nNOLINK\n";
  }
  uart_puts(v1);
}

逆アセンブラ出力:

root@kitploit:~
ROM:00001F68 ; void __fastcall usbdl_init(int usb_base)
ROM:00001F68 usbdl_init                              ; CODE XREF: entry+5E↑p
ROM:00001F68                                         ; entry+7C↑p ...
ROM:00001F68                 PUSH            {R4,LR}
ROM:00001F6A                 MOVS            R2, #0x1500000
ROM:00001F6E                 LDR             R1, =dword_8014C
ROM:00001F70                 MOV             R4, R0
ROM:00001F72                 CMP             R0, R2
ROM:00001F74                 BNE             loc_1F80
ROM:00001F76                 MOVS            R0, #0
ROM:00001F78                 STRB            R0, [R1,#(alt_usb_base - 0x8014C)]
ROM:00001F7A                 BL              usb_init
ROM:00001F7E                 B               loc_1F88
ROM:00001F80 ; ---------------------------------------------------------------------------
ROM:00001F80
ROM:00001F80 loc_1F80                                ; CODE XREF: usbdl_init+C↑j
ROM:00001F80                 MOVS            R0, #1
ROM:00001F82                 STRB            R0, [R1,#(alt_usb_base - 0x8014C)]
ROM:00001F84                 BL              noidea
ROM:00001F88
ROM:00001F88 loc_1F88                                ; CODE XREF: usbdl_init+16↑j
ROM:00001F88                 MOV             R0, R4
ROM:00001F8A                 BL              usb_setup
ROM:00001F8E                 CMP             R0, #0
ROM:00001F90                 BEQ             loc_1F9E
ROM:00001F92                 BL              try_sync_with_host
ROM:00001F96                 ADR             R0, aFailed ; "FAILED\n"
ROM:00001F98
ROM:00001F98 loc_1F98                                ; CODE XREF: usbdl_init+38↓j
ROM:00001F98                 BL              uart_puts
ROM:00001F9C                 POP             {R4,PC}
ROM:00001F9E ; ---------------------------------------------------------------------------
ROM:00001F9E
ROM:00001F9E loc_1F9E                                ; CODE XREF: usbdl_init+28↑j
ROM:00001F9E                 ADR             R0, aNolink ; "\nNOLINK\n"
ROM:00001FA0                 B               loc_1F98
ROM:00001FA0 ; End of function usbdl_init

try_sync_with_hostは同期バイト(0x5A)を待機し、メインループに入ります。

root@kitploit:~
void try_sync_with_host()
{
  int v0; // r4
  unsigned int i; // r0
  int v2; // r5
  int v3; // r2
  int v4; // r3
  int v5; // r2
  int v6; // r3
  int v7; // r0

  v0 = 0x805A0;
  time_to_boot = 0;
  for ( i = 0; i < 0x40; ++i )
    *(_BYTE *)(i + 0x805A0) = 0;
  g_state = 0;
  v2 = 0x200;
  if ( usb_recv(byte_805A0, 0x200, 0x5A) == 1 ) // 0x5a = ack sent by the host
  {
    uart_puts("TIMEOUT\n");
  }
  else
  {
    resp[0] = 0xA5;
    usb_send((int)resp, 1, v3, v4);
    g_state = 1;
    while ( !time_to_boot )
    {
      v7 = sub_11CA(v0, v2, v5, v6);
      handler(v0, v7);
      if ( g_state == 4 )
      {
        v2 = size;
        v0 = start_addr;
      }
      else
      {
        v0 = 0x805A0;
        v2 = 0x200;
      }
    }
    verify_and_jump(unk_80160, 0, 1);
  }
}

ハンドシェイクが完了すると、BootROMはメインループに入り、通常はブリックしたデバイスの復旧に使用されるステージ1バイナリを待機します。ただし、BootROMは宛先アドレスを検証しないため、0x7Aコマンドを介した任意書き込みが可能になります。0xA1ステータスは、イメージアドレスとサイズが受け入れられたことを意味します。

root@kitploit:~
usb_send:
        resp[0] = status;
        v5 = 1;
        v6 = resp;
        return usb_send((int)v6, v5, state, v3);
      case 3u: // 0x7A
        if ( *(int *)&resp[4] >= 4 )
        {
          if ( *(int *)&resp[4] < 8 )
            *(_DWORD *)&resp[12] = (*(_DWORD *)&resp[12] << 8) | result;
        }
        else
        {
          *(_DWORD *)&resp[8] = (*(_DWORD *)&resp[8] << 8) | result;
        }
        v3 = *(_DWORD *)&resp[4] + 1;
        *(_DWORD *)&resp[4] = v3;
        if ( v3 != 8 )
          continue;
        *(_DWORD *)&resp[4] = 0;
        start_addr = *(_DWORD *)&resp[8];
        size = *(_DWORD *)&resp[12];
        g_state = 4;
        status = 0xA1;
        goto usb_send;

verify_and_jump関数は、デバイスがフューズドされている場合にイメージ検証を実行します。

root@kitploit:~
int __fastcall verify_and_jump(Header *a1, int zero, int must_verify)
{
  int *p_sp; // r6
  int result; // r0

  p_sp = (int *)&a1->sp;
  result = memcmp((int)a1->magic, 0x80008, 2u);
  if ( !result )
  {
    if ( !zero || (result = a1->usbdl_en, result == 0x5A) )
    {
      if ( !must_verify )
        return jump(p_sp);
      result = verify(a1);
      if ( !result )
        return jump(p_sp);
    }
  }
  return result;
}

verify関数はハードウェアMD5およびRSAエンジンを使用してイメージの整合性を検証し、jumpはイメージヘッダーのアドレスにスタックポインタを設定してエントリポイントにジャンプします。

ARM/Thumb呼び出し規約では、関数呼び出しは通常PUSH {regs, LR}で始まり、末尾呼び出し、BX LRまたはPOP {regs, PC}で終わります。usbdl_initはコンパイラによって末尾呼び出しとして最適化されていないため、PUSHおよびPOP命令を含みます。

もうお分かりですか?


BootROMにはワンタイムダウンロード用のフラグがないため、必要なだけ多くのイメージを送信できます。このエクスプロイトは、この機能(それ自体は脆弱性ではありません)を任意メモリ書き込みと組み合わせて悪用します。

  1. 指定されたアドレスにペイロードを送信する
  2. スタックオフセットを計算する: 6(entry関数: PUSH {R3-R7,LR})+ 2(usbdl_init関数: PUSH {R4,LR})。レジスタサイズを掛けると、8 * 4 = 32
  3. スタック上の保存されたLRレジスタにジャンプアドレスを送信する(簡略化のため、PoCはすべての保存されたレジスタに同じアドレスを繰り返します)
  4. ジャンプコマンドを送信する
  5. イメージ検証を失敗させる(ヘッダーマジックが欠落)
  6. verify_and_jump関数はusbdl_initに戻る
  7. usbdl_initはFAILEDを出力し、POP {R4, PC}命令を実行してペイロードを実行する

ソースからビルドするには

  • curl、llvm-objcopy(通常はllvmパッケージの一部)、gccをインストールします。Ubuntu 22.04の例: sudo apt update && sudo apt install curl llvm gcc
  • curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | shまたはディストリビューション固有のパッケージマネージャを使用してrustupをインストールします
  • rustコマンドが利用可能であることを確認します: . "$HOME/.cargo/env"(bash)またはsource "$HOME/.cargo/env.fish"(fish)
  • ペイロードをビルド: cd payload && ./build.sh && cd ..
  • ホストツールを実行: sudo -E cargo r -p loader -- target/thumbv6m-none-eabi/release/payload

次に、USBダウンロードモード(特別なテストポイントまたは破損したフラッシュのいずれか)をトリガーしたデバイスを接続し、UART出力を確認します。

タイムライン

  • 2月5日 - 初期報告
  • 3月18日 - ZTE PSIRTによって確認
  • 5月7日 - 公開リリース

外部クレジット

  • SoCリバースエンジニアリングの多く: Stefan Dösinger
  • フューズドデバイスでのテスト: Mio Naganohara
  • 別のフューズドデバイスでのリリース前テスト: exp-3

ライセンス

AGPLv3

ツールをダウンロード