Skip to content
KitploitKITPLOIT
ツールエクスプロイトブログ
Log in
提出
ツールエクスプロイトブログ
提出

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

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

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

ツールディレクトリ

カテゴリ

すべてのカテゴリを見る
Loading categories
CVE-2019-8601 — パッチ適用済みのJavaScriptCoreの脆弱性を悪用する | Kitploit
ツール/GitHubGitHub/badaccess11/cve-2019-8601
脆弱性分析エクスプロイトウェブアプリケーション悪用学習と教育ペイロード開発バイナリエクスプロイト
GitHubbadaccess11/cve-2019-8601

CVE-2019-8601

パッチ適用済みのJavaScriptCoreの脆弱性を悪用する

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

人気

すべて見る →

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

すべてのツールを探索

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

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

CVE-2019-8601 のエクスプロイト

これは、バンクーバーで開催された pwn2own コンテストで Fluoroacetate によって発見された WebKit の脆弱性に対するエクスプロイトです。私はこのバグを発見したわけではありませんが、エクスプロイト開発スキルを練習するためにこのエクスプロイトを作成しました。このエクスプロイトの元の解説記事は Zero Day Initiative による こちら です。この解説記事は非常に優れており、脆弱性の理解に役立ちましたが、脆弱性を検証する人の視点から書かれています。このエクスプロイトをゼロから作成しようとした際に、いくつかの重要な詳細が欠けていることに気づき、ZDI の解説記事では見落とされたギャップを埋め、複雑なエクスプロイトをゼロから設計する実践的なスキルを身につけたいと考えています。

エクスプロイトの手順

以下の手順は、WebKit の JavaScript エンジンである JavaScriptCore (JSC) 内で任意のコード実行を達成するための概要です。

  • 脆弱性の特定
  • 脆弱性をトリガーし ASAN を有効にしてクラッシュさせる
  • leakAddr および fakeObj プリミティブを取得する
  • 読み取りおよび書き込みプリミティブを達成するために配列のバタフライを破壊する
  • 読み取り/書き込みプリミティブを使用して JSC 内で任意のコード実行を達成する

脆弱性の特定

悪用される脆弱性は、WebKit の DFG ジャストインタイム (JIT) コンパイラによって生成されるコードで発生する整数オーバーフローです。これは特に compileNewArrayWithSpread 関数で発生します。この関数は、JavaScript スプレッド構文 を使用して新しい配列を作成するコードが DFG によって JIT コンパイルされるときに呼び出されます。

compileNewArrayWithSpread

JIT コード内では、まず配列のサイズを計算します。これは、配列コンストラクタに渡された各引数の長さを加算することで行います。各加算のサイズを計算する際に、サイズのオーバーフローをチェックします。その後、この関数で計算された長さを引数として compileAllocateNewArray 関数を呼び出します。

compileAllocateNewArrayWithSize

compileAllocateNewArray は、先に計算された長さを emitAllocateButterfly に渡します。

emitAllocateButterfly

emitAllocateButterfly は、サイズを 3 ビット左シフトします。これは 8 倍することに相当します。しかし、オーバーフローのチェックはなく、そのため 0x20000001 のような数値が 0x8 にオーバーフローする可能性があります。

次の C プログラムはこの脆弱性を示しています:

overflow-example2

overflow-example

この脆弱性を利用して、JavaScript エンジンにサイズ 0x20000001 の配列を割り当てたと思い込ませながら、実際には 1 つの JSValue (8 バイト) 分のスペースしか割り当てていないように仕向けることができます。これにより、バウンダリ外 (OOB) の読み取りおよび書き込み (R/W) プリミティブが発生し、これを利用して任意の R/W を達成し、最終的にはリモートコード実行 (RCE) が可能になります。

  • 脆弱性の特定

ASAN を使用した脆弱性のトリガー

OOB 読み取りが可能であることを確認するために、JSC の アドレスサニタイザー (ASAN) ビルドでこの脆弱性をトリガーしてみます。

これを行うには、WebKit ディレクトリから次のコマンドを実行します:```bash Tools/Scripts/set-webkit-configuration --asan Tools/Scripts/build-jsc --jsc--only --debug

これにより、JSCのデバッグビルドをASAN有効でビルドし、脆弱性を正常にトリガーできたかどうかを確認できるようになります。

以下がexploit.jsの最初のイテレーションです。```javascript
function jitMe(array){
  return [...array]
}

let dummy = [1.1]
for(let i = 0; i < 200; i++){
  jitMe(dummy);
}

let a = []

let len = 0x20000001                                                                     

for(let i = 0; i < len; i++){
  a[i] = 1.1 
}

jitMe(a)

これを実行すると、次のエラーが発生します:

プログラムはシグナルSIGKILLで終了しました、Killed。 プログラムはもう存在しません。

私の推測では、そのような大きな配列を割り当てようとした際にメモリを消費しすぎたのではないかと考えました。これを確認するために、JITコードにブレークポイントを追加しました。compileNewArrayWithSpread内にm_jit.breakpoint()の呼び出しを追加することで、JITコードにint3命令を追加しました。

ブレークポイントを追加したところ、それがヒットしなかったため、長さ0x20001でテストすることにしました。その後、コードがコンパイルさえされていないことに気づき、DFGコンパイラを起動するためにイテレーションを増やしました。```javascript function jitMe(array){ for(let i = 0; i < 0x4000; i++){ let x = 1 + 1 } return [...array] }

let dummy = [1.1] for(let i = 0; i < 60; i++){ print(i) jitMe(dummy); }

let a = []

let len = 0x20000001

for(let i = 0; i < len; i++){ a[i] = 1.1 }

jitMe(a)

プログラムをそのままテストするとSIGKILLが発生しますが、より小さな長さでテストするとブレークポイントにヒットします。この時点では、JSCがその巨大な配列を処理しようとしてメモリ不足になっているように思われます。

この問題に対処するため、より小さな `a` 配列を割り当て、スプレッド構文を使用してそれを複数回利用し、破損した配列を作成することにしました。結果として、次のような `exploit.js` ができました。```
function jitMe(array){
  for(let i = 0; i < 0x4000; i++){
    let x = 1 + 1
  }
  return [...array, ...array, ...array, ...array, ...array, ...array, ...array, ...array, ...array, ...array, ...array, ...array, ...array, ...array, ...array, ...array]
}

let dummy = [1.1]
for(let i = 0; i < 100; i++){
  print(i)
  jitMe(dummy);
}

let a = []

let len = 0x20000010 / 0x10

for(let i = 0; i < len; i++){
  a[i] = 1.1
}

jitMe(a)

このコードを使って、SIGKILLなしでブレークポイントにヒットできました!よくあることですが、一つの問題を修正すると別の問題が現れ、代わりにSIGABORTが発生しました... gdbのbtコマンドを使うと、operationNewArrayWithSizeが呼び出され、それがcreateを呼び出したことがわかります。backtrace1

JITコンパイルされたコードがoperationNewArrayWithSizeを呼び出すのは奇妙に思えます。何らかの理由で、JITコードがJavaScriptエンジンへのスローパスを取らなければならなかったに違いありません。

slowcases

compileAllocateNewArrayWithSize内で、確かにoperationNewArrayWithSizeへのベイルアウトがあることがわかります。そこで、なぜスローパスにベイルアウトするのかを正確に突き止める必要があります。

compileNewArrayWithSpreadの中で、shouldConvertLargeSizeToArrayStorageがfalseに設定されており、スローパスはコンパイルされたコードに含まれないことがわかります。compileNewArrayWithSpread2

したがって、スローパスはemitAllocateJSObject内のどこかでヒットしていると考えるのが妥当です。

emitAllocateJSObject

emitAllocateJSObjectはemitAllocateJSCellを呼び出し、さらにemitAllocateを呼び出します。

emitAllocate

emitAllocateWithNonNullAllocator

WebKitアロケータの動作を知らなければ、これはかなり混乱するように見えます。そこで、gdbでいくつかブレークポイントを追加し、ステップ実行することにしました。

emitAllocateButterflyによって呼び出されたemitAllocateVariableSizedに設定したブレークポイントにヒットした後、次のようなアセンブリコードが見えました。assemblyEmitAllocateVariableSized

これは、JITコンパイラがここで出力したコードに対応しています。emitAllocateVariableSized

アロケーションサイズに0xfが加算され、4ビット右シフトされていることがわかります。その後、0x1f6と比較され、スローパス分岐に対応します。その後、サブスペースアロケータをrsiに移動し、計算結果に基づいてこのポインタにインデックスを付けます。そして、emitAllocateWithNonNullAllocatorに設定したブレークポイントに進み、次のアセンブリコードを見つけます。

assemblyEmitAllocateWithNonNullAllocator.png

これは、JITコンパイラがここで出力したコードに対応します。emitAllocateWithNonNullAllocator

アセンブリをいくつかステップ実行したので、何が起こっているのか少しコンテキストが掴めました。さらに2命令ステップ実行すると、ジャンプを行うことがわかります。

stepFoward2

C++コードを見ると、これはこのアロケータのフリーリストに残りスペースがゼロであることを意味し、ポップパスを取ることが推測できます。

jumpPerformed

ジャンプを実行し、次の2命令を実行すると、ジャンプが直接スローパスを取ることに相当していることがわかります。スローパスを取るのは、アロケータの秘密がアロケータのスクランブルされた先頭とXORされ、結果がゼロになるからです。WebKitアロケータについてこれ以上知識がなければ、何が起こっているのかを正確に把握するのは困難です。

WebKitアロケータについてもっと時間をかけて学びたいところですが、より簡単な方法として、いくつかのアイデアを試して、異なる結果が得られるかどうかを見て、そこからデバッグすることにしました。

ツールをダウンロード