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

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

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

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

ツールディレクトリ

カテゴリ

すべてのカテゴリを見る
Loading categories
CVE-2026-2763-POC — CVE-2026-2763の概念実証エクスプロイト。MozillaのJavaScriptエンジンにおけるuse-after-free脆弱性であり、制約付き1ビット書き込みプリミティブを実証し、境界外読み取り/書き込みへと導く。 | Kitploit
ツール/GitHubGitHub/ppwwiinn/cve-2026-2763-poc
メモリフォレンジック脆弱性分析エクスプロイトウェブセキュリティバイナリエクスプロイト
GitHubppwwiinn/cve-2026-2763-poc

CVE-2026-2763-POC

CVE-2026-2763の概念実証エクスプロイト。MozillaのJavaScriptエンジンにおけるuse-after-free脆弱性であり、制約付き1ビット書き込みプリミティブを実証し、境界外読み取り/書き込みへと導く。

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

人気

すべて見る →

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

すべてのツールを探索

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

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

脆弱性

この脆弱性は、for-in 構文の実装に起因します。

for-in ループのスコープは、JSOP::Iter と JSOP::EndIter という2つのバイトコードのペアで表されます。

root@kitploit:~
CASE(Iter) {
      MOZ_ASSERT(REGS.stackDepth() >= 1);
      HandleValue val = REGS.stackHandleAt(-1);
      JSObject* iter = ValueToIterator(cx, val); // [1]
      if (!iter) {
        goto error;
      }
      REGS.sp[-1].setObject(*iter); // [2]
    }

...

CASE(EndIter) {
      MOZ_ASSERT(REGS.stackDepth() >= 2);
      CloseIterator(&REGS.sp[-2].toObject());
      REGS.sp -= 2; // [3]
    }

スコープの開始時、[1] で ValueToIterator が呼び出され、PropertyIteratorObject が作成されます。インタープリタはその後、[2] でそれをインタープリタスタックに格納(プッシュ)します。スコープが終了すると、PropertyIteratorObject は [3] で削除されます。

root@kitploit:~
static PropertyIteratorObject* GetIteratorImpl(JSContext* cx, HandleObject obj,
                                               bool wantIndices,
                                               bool forObjectKeys) {
...
  PropertyIteratorObject* iterobj = CreatePropertyIterator(
      cx, obj, keys, supportsIndices, indicesPtr, cacheableProtoChainLength,
      ownPropertyCount, forObjectKeys); // [1]
  if (!iterobj) {
    return nullptr;
  }
  if (!forObjectKeys) {
    RegisterEnumerator(cx, iterobj->getNativeIterator(), obj); // [2]
  }
...
  return iterobj;
}

static inline void RegisterEnumerator(JSContext* cx, NativeIterator* ni,
                                      HandleObject obj) {
  ni->initObjectBeingIterated(*obj);

  // Register non-escaping native enumerators (for-in) with the current
  // context.
  ni->link(cx->compartment()->enumeratorsAddr());

  MOZ_ASSERT(!ni->isActive());
  ni->markActive();
}

ValueToIterator 内では、上記のようにオブジェクトの作成が行われます。[1] でイテレータオブジェクトを割り当てた後、[2] でグローバルなリンクリストにリンクされます。この時点で、PropertyIteratorObject への唯一の参照はインタープリタスタック上に保持されています。

root@kitploit:~
void js::CloseIterator(JSObject* obj) {
  if (!obj->is<PropertyIteratorObject>()) {
    return;
  }

  // Remove iterator from the active list, which is a stack. The shared iterator
  // used for for-in with null/undefined is immutable and unlinked.

  NativeIterator* ni = obj->as<PropertyIteratorObject>().getNativeIterator();
  if (ni->isEmptyIteratorSingleton()) {
    return;
  }

  ni->unlink();

  MOZ_ASSERT(ni->isActive());
  ni->markInactive();

  ni->clearObjectBeingIterated();

  // Reset the enumerator; it may still be in the cached iterators for
  // this thread and can be reused.
  ni->resetPropertyCursorForReuse();
}

スコープが終了すると、CloseIterator が呼び出され、イテレータが先ほどリンクされたリストからリンク解除され、スコープ外からの PropertyIteratorObject へのアクセスが防止されます。

しかし、yield が正しく処理されないため、CloseIterator が実行される前にループスコープ外でコードを実行することが可能です。

この状況では、PropertyIteratorObject への唯一の強い参照がインタープリタスタック上にあるため、yield が実行され、返されたジェネレータも参照されない場合、GC が実行されると PropertyIteratorObject が収集(解放)される可能性があります。

root@kitploit:~
static bool SuppressDeletedPropertyHelper(JSContext* cx, HandleObject obj,
                                          Handle<JSLinearString*> str) {
  NativeIteratorListIter iter(obj->compartment()->enumeratorsAddr());
  while (!iter.done()) {
    NativeIterator* ni = iter.next();
    if (!SuppressDeletedProperty(cx, ni, obj, str)) { // [1]
      return false;
    }
  }

  return true;
}

この関数は、delete が使用されたときに呼び出されます。グローバルなリンクリストを走査し、削除されたプロパティを考慮してイテレータオブジェクトを更新します。[1] でコールバックが呼び出される可能性があり、これが GC をトリガーすると、参照されていない PropertyIteratorObject が解放される可能性があります。そのファイナライザも対応する ni オブジェクトを解放するため、use-after-free(UAF)が発生します。


エクスプロイト

root@kitploit:~
static bool SuppressDeletedProperty(JSContext* cx, NativeIterator* ni,
                                    HandleObject obj,
                                    Handle<JSLinearString*> str) {
  ...
  // Check whether id is still to come.
  Rooted<JSLinearString*> idStr(cx);
  IteratorProperty* cursor = ni->nextProperty();
  for (; cursor < ni->propertiesEnd(); ++cursor) {
    idStr = cursor->asString();
    // Common case: both strings are atoms.
    if (idStr->isAtom() && str->isAtom()) {
      if (idStr != str) {
        continue;
      }
    } else {
      if (!EqualStrings(idStr, str)) {
        continue;
      }
    }
    ...
    cursor->markDeleted(); // [1]
    ni->markHasUnvisitedPropertyDeletion();
    return true;
  }

  return true;
}

NativeIterator のサイズは、ターゲットオブジェクトのプロパティ数によって制御でき、cursor は削除済みとしてマークされるプロパティスロットへのポインタです。[1] は実質的に単一ビットの OR を行うため、これにより制約付きプリミティブが得られます。つまり、任意の(8バイトアラインされた)アドレスへの1ビット書き込みです。

NativeIterator は GC アロケータを介して割り当てられるのではなく、js::MallocArena から割り当てられます。その結果、制御された GC ヒープオブジェクトをその隣に配置するための一般的な JS オブジェクトスプレーを進めることはできません。

root@kitploit:~
js::UniquePtr<ImmutableScriptData> js::ImmutableScriptData::new_(
    FrontendContext* fc, uint32_t codeLength, uint32_t noteLength,
    uint32_t numResumeOffsets, uint32_t numScopeNotes, uint32_t numTryNotes) {
  auto size = sizeFor(codeLength, noteLength, numResumeOffsets, numScopeNotes,
                      numTryNotes);
  if (!size.isValid()) {
    ReportAllocationOverflow(fc);
    return nullptr;
  }

  // Allocate contiguous raw buffer.
  void* raw = fc->getAllocator()->pod_malloc<uint8_t>(size.value());
  MOZ_ASSERT(uintptr_t(raw) % alignof(ImmutableScriptData) == 0);
  if (!raw) {
    return nullptr;
  }

  // Constuct the ImmutableScriptData. Trailing arrays are uninitialized but
  // GCPtrs are put into a safe state.
  UniquePtr<ImmutableScriptData> result(new (raw) ImmutableScriptData(
      codeLength, noteLength, numResumeOffsets, numScopeNotes, numTryNotes));
  if (!result) {
    return nullptr;
  }

  // Sanity check
  MOZ_ASSERT(result->endOffset() == size.value());

  return result;
}

js::MallocArena に割り当てられる有用なオブジェクトの1つに、JS バイトコードを格納する ImmutableScriptData があります。

root@kitploit:~
static MOZ_ALWAYS_INLINE void InitElemArrayOperation(JSContext* cx,
                                                     jsbytecode* pc,
                                                     Handle<ArrayObject*> arr,
                                                     HandleValue val) {
  MOZ_ASSERT(JSOp(*pc) == JSOp::InitElemArray);

  // The dense elements must have been initialized up to this index. The JIT
  // implementation also depends on this.
  uint32_t index = GET_UINT32(pc); // [1]
  MOZ_ASSERT(index < arr->getDenseCapacity());
  MOZ_ASSERT(index == arr->getDenseInitializedLength());

  // Bump the initialized length even for hole values to ensure the
  // index == initLength invariant holds for later InitElemArray ops.
  arr->setDenseInitializedLength(index + 1); // [2]

  if (val.isMagic(JS_ELEMENTS_HOLE)) {
    arr->initDenseElementHole(index);
  } else {
    arr->initDenseElement(index, val);
  }
}

これは、JS 配列を初期化するときに使用されるバイトコードハンドラです。

バイトコードストリームから4バイトの値を読み取り、[2] で配列の InitializedLength を設定するために使用します。

1ビット書き込みが [1] のバイトコードに適用された場合、InitializedLength を配列の実際の容量を超えて設定することが可能になります。そこから、エクスプロイトは OOB 読み取り/書き込みプリミティブを活用して進行します。

ツールをダウンロード