Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Pwning Old WebKit for Fun and Profit

Pwning Old WebKit for Fun and Profit

Hiroki MATSUKUMA

March 15, 2023
Tweet

Other Decks in Technology

Transcript

  1. $ whoami @hhc0null 昔Pwnやってたペンテスター バイナリ読むのは苦手です Pwning Old Webkit for Fun

    and Profit ― Security.Tokyo #1 T wi t t erロゴ : ht t ps : // about .t wi t t er.com / en/ who-we-are/ brand-t ool k i t G i t Hubロゴ : ht t ps : // gi t hub.com / l ogos
  2. Outline & Recaps 1. Why Targeting Old WebKit Even in

    2023? Because old WebKit-based browsers are still running even in 2023... 2. Stop Using QtWebKit and also Wkhtmltopdf If an attacker feed a malicious HTML to QtWebKit-based browser like wkhtmltopdf, your system could be compromised! 3. Demo ― CVE-2012-3748 The demo probably works for me... Pwning Old Webkit for Fun and Profit ― Security.Tokyo #1 3
  3. Why Targeting Old WebKit Even in 2023? Pwning Old Webkit

    for Fun and Profit ― Security.Tokyo #1
  4. WebKit OSSのWebブラウザエンジン Apple Safariの中身 以下のコンポーネントから構成される bmalloc: WebKitのmalloc実装 WTF(Web Template Framework):

    独自のテンプレートライブラリ JavaScriptCore: JavaScriptエンジン WebCore: Web APIやHTML, XMLとCSSパーサの実装 WebKitLegacy: macOSのWebViewとiOSのUIWebViewの実装 WebKit: macOSとiOSのWKWebViewの実装 もっとある…! Pwning Old Webkit for Fun and Profit ― Security.Tokyo #1 [1] [1] WebKit/Introduction.md at dacbd7c36056647c1867f34236ade6815002e1f1 · WebKit/WebKit https://github.com/WebKit/WebKit/blob/dacbd7c/Introduction.md WebKitロゴ: https://webkit.org/wp-content/themes/webkit/images/webkit.svg 5
  5. Fun: WebKitは"教材"がいっぱいで楽しい みんな寄って集って叩く ハッキングコンテスト(Pwn2Own, Tianfu Cup, etc…) バグバウンティ(ZDI, Zerodium、etc…) ゲームコンソールハッキング(PlayStaionシリーズ,

    Wiiシリーズ、etc…) そして、叩き方を教えてくれる "Exploiting WebKit on Vita 3.60" by @xyzz "Attacking JavaScript Engines: A case study of JavaScriptCore and CVE-2016-4622" by @saelo "Ode to the use-after-free: one vulnerable function, a thousand possibilities" by @scarybeasts この記事を参考にしてExploitを書きました etc… ググるときのキーワード: webkit, javascriptcore (jsc), vuln, exploit, pwn Pwning Old Webkit for Fun and Profit ― Security.Tokyo #1 6
  6. Profit: こんなところにもWebKit 組込み機器で動くWebブラウザ WPE(Web Platform for Embedded) セルフビルド サーバサイドで動くWebブラウザ PhantomJS(開発が終了したヘッドレスブラウザ)

    wkhtmltopdf(最近開発が終了したPDFコンバータ) SSRFやLFIの事例あり Pwning Old Webkit for Fun and Profit ― Security.Tokyo #1 [2][3] [2] "NVD - CVE-2020-21365" https://nvd.nist.gov/vuln/detail/CVE-2020-21365 [3] "NVD - CVE-2022-35583" https://nvd.nist.gov/vuln/detail/CVE-2022-35583 7
  7. TM WebKitのPorting メンテナンスされているPort Apple: Mac Port, Windows Port GNOME: WebKitGTK

    WPE WebKit Team: WPE WebKit メンテナンスされていないPort Qt: QtWebKit qt/qtwebkit: Qt WebEngine誕生 により終了 qtwebkit/qtwebkit: WebKitのアップグレードを 狙った、有志によるQtWebKit復活プロジェクト Pwning Old Webkit for Fun and Profit ― Security.Tokyo #1 [4] [4] "Introducing the Qt WebEngine" https://www.qt.io/blog/2013/09/12/introducing-the-qt- webengine GNOMEのロゴ: https://foundation.gnome.org/logo-and-trademarks/ Qtのロゴ: https://brand.qt.io/design#logos 8
  8. "Stop Using QtWebKit" Michael Catanzaro氏によるQtWebKitの危険性を指摘した2022年のブログ記事 "Stop Using QtWebKit" のタイトル 2016年にも

    "On WebKit Security Updates" というブログ記事の中で問題を指摘していた Pwning Old Webkit for Fun and Profit ― Security.Tokyo #1 …Do not feed untrusted data into QtWebKit. Don’t give it any HTML that you didn’t write yourself, and certainly don’t give it anything that contains injected data. Uninstall it and whatever applications depend on it. “ ” Linux distributions have a problem with WebKit security. “ ” 10
  9. …and Also wkhtmltopdf wkhtmltopdfはQtWebKit(≒古いWebKit)を使ったPDFコンバーター 自前でwkhtmltopdf/qtを使っている QtWebKitのソースコードは /src/3rdparty/webkit にある WebKitのリリースでいうとSafari-536.11(2012-05-11) 1.

    upstreamによる変更を探してcommit 929b444 を見つける 2. Changelogのコミットメッセージ"Fix build with GLib 2.31"を検索 する 3. commit ca8ddd2 に辿り着く Pwning Old Webkit for Fun and Profit ― Security.Tokyo #1 [5] [6] [7] [5] "Updated WebKit to 2dea2a19feedc165596b933fe9509ddd0caf4d15 · wkhtmltopdf/qt@929b444" https://github.com/wkhtmltopdf/qt/commit/929b444 [6] "Search · Fix build with GLib 2.31" https://github.com/WebKit/WebKit/search?q=Fix+build+with+GLib+2.31&type=commits [7] "Fix build with GLib 2.31 · WebKit/WebKit@ca8ddd2" https://github.com/WebKit/WebKit/commit/ca8ddd2 11
  10. 2012年周辺のWebKitの脆弱性 CVE-2012-3748 : 配列ソートのコールバックでTOCTOU 報告者: Joost Pol & Daan Keuper,

    Certified Secure Moible Pwn2Own 2012で実演された(iOS6) CVE-2013-2842 : <object> のイベントハンドラでUAF 報告者: Cyril Cattiaux Chromiumで見つかったが、WebKitのコードにもあった Pwning Old Webkit for Fun and Profit ― Security.Tokyo #1 [9] [10] [8] "97603 – (CVE-2012-3748) (Mobile Pwn2Own) ZDI-CAN-1657: : WebKit Shiftcount Vulnerability" https://bugs.webkit.org/show_bug.cgi?id=97603 [9] "226696 - Security: use-after-free removing a frame from its parent in a beforeload event of an OBJECT element - chromium" https://bugs.chromium.org/p/chromium/issues/detail?id=226696 古いWebKitのロゴ: https://web.archive.org/web/20120410050046/http://www.webkit.org/images/icon-gold.png 12
  11. CVE-2012-3748 ソート前のArrayの配列の要素数をとって、 ... void JSArray::sort(ExecState* exec, JSValue compareFunction, CallType callType,

    const CallData& callData) { ... ArrayStorage* storage = m_storage; // ArrayStorage を保持してしまっている ... unsigned usedVectorLength = min(storage->m_length, m_vectorLength); unsigned nodeCount = usedVectorLength + (storage->m_sparseValueMap ? storage->m_sparseValueMap->size() : 0); AVL木を用意して配列の要素の数のノードを確保して、 ... AVLTree<AVLTreeAbstractorForArrayCompare, 44> tree; // Depth 44 is enough for 2^31 items tree.abstractor().m_exec = exec; tree.abstractor().m_compareFunction = compareFunction; ... tree.abstractor().m_nodes.grow(nodeCount); // ノード数が決定されてしまう if (callType == CallTypeJS) tree.abstractor().m_cachedCall = adoptPtr(new CachedCall(exec, asFunction(compareFunction), 2)); ... Pwning Old Webkit for Fun and Profit ― Security.Tokyo #1 13
  12. CVE-2012-3748 (cont.) Arrayがcontiguousと想定しながらソート対象を詰めて、sparseであればチェックしながら詰めつつ、 ... unsigned numDefined = 0; unsigned numUndefined

    = 0; // Iterate over the array, ignoring missing values, counting undefined ones, and inserting all other ones into the tree. for (; numDefined < usedVectorLength; ++numDefined) { JSValue v = storage->m_vector[numDefined].get(); // storageの指す領域は以前のm_storageとして使われていないかも! if (!v || v.isUndefined()) break; tree.abstractor().m_nodes[numDefined].value = v; tree.insert(numDefined); // コールバックが呼ばれる } for (unsigned i = numDefined; i < usedVectorLength; ++i) { JSValue v = storage->m_vector[i].get(); // storageの指す領域は以前のm_storageとして使われていないかも! if (v) { if (v.isUndefined()) ++numUndefined; else { tree.abstractor().m_nodes[numDefined].value = v; tree.insert(numDefined); // コールバックが呼ばれる ++numDefined; } } } ... Pwning Old Webkit for Fun and Profit ― Security.Tokyo #1 14
  13. CVE-2012-3748 (cont..) sparseな場合に必要とするサイズが現在のmapより大きければ、ベクタを確保し直して詰めて、 ... unsigned newUsedVectorLength = numDefined + numUndefined;

    if (SparseArrayValueMap* map = storage->m_sparseValueMap) { // storageの指す領域は以前のm_storageとして使われていないかも! newUsedVectorLength += map->size(); if (newUsedVectorLength > m_vectorLength) { // Check that it is possible to allocate an array large enough to hold all the entries. if ((newUsedVectorLength > MAX_STORAGE_VECTOR_LENGTH) || !increaseVectorLength(newUsedVectorLength)) { ... // エラーを返してリターンする } } storage = m_storage; // increaseVectorLength(newUsedVectorLength)で確保し直すが、結局はm_storageを保持してしまっている SparseArrayValueMap::iterator end = map->end(); // map の終端も保持されてしまう for (SparseArrayValueMap::iterator it = map->begin(); it != end; ++it) { tree.abstractor().m_nodes[numDefined].value = it->second.get(); tree.insert(numDefined); // コールバックが呼ばれる ++numDefined; } ... delete map; // mapの指す領域は以前のstorage->m_sparseValueMapとして使われていないかも! storage->m_sparseValueMap = 0; // storageの指す領域は以前のm_storageとして使われていないかも! } ... Pwning Old Webkit for Fun and Profit ― Security.Tokyo #1 15
  14. CVE-2012-3748 (cont...) 各ノードから m_vector へソート済みの要素を書き戻す。 ... // Copy the values

    back into m_storage. AVLTree<AVLTreeAbstractorForArrayCompare, 44>::Iterator iter; iter.start_iter_least(tree); JSGlobalData& globalData = exec->globalData(); for (unsigned i = 0; i < numDefined; ++i) { // storageの指す領域は以前のm_storageとして使われていないかも! storage->m_vector[i].set(globalData, this, tree.abstractor().m_nodes[*iter].value); ++iter; } // Put undefined values back in. for (unsigned i = numDefined; i < newUsedVectorLength; ++i) storage->m_vector[i].setUndefined(); // storageの指す領域は以前のm_storageとして使われていないかも! // Ensure that unused values in the vector are zeroed out. for (unsigned i = newUsedVectorLength; i < usedVectorLength; ++i) storage->m_vector[i].clear(); // storageの指す領域は以前のm_storageとして使われていないかも! storage->m_numValuesInVector = newUsedVectorLength; // storageの指す領域は以前のm_storageとして使われていないかも! ... } ... Pwning Old Webkit for Fun and Profit ― Security.Tokyo #1 16
  15. References 1. WebKit/Introduction.md at dacbd7c36056647c1867f34236ade6815002e1f1 · WebKit/WebKit https://github.com/WebKit/WebKit/blob/dacbd7c/Introduction.md 2. "NVD

    - CVE-2020-21365" https://nvd.nist.gov/vuln/detail/CVE-2020-21365 3. "NVD - CVE-2022-35583" https://nvd.nist.gov/vuln/detail/CVE-2022-35583 4. "Introducing the Qt WebEngine" https://www.qt.io/blog/2013/09/12/introducing-the-qt-webengine 5. "Updated WebKit to 2dea2a19feedc165596b933fe9509ddd0caf4d15 · wkhtmltopdf/qt@929b444" https://github.com/wkhtmltopdf/qt/commit/929b444 6. "Search · Fix build with GLib 2.31" https://github.com/WebKit/WebKit/search? q=Fix+build+with+GLib+2.31&type=commits 7. "Fix build with GLib 2.31 · WebKit/WebKit@ca8ddd2" https://github.com/WebKit/WebKit/commit/ca8ddd2 8. "97603 – (CVE-2012-3748) (Mobile Pwn2Own) ZDI-CAN-1657: : WebKit Shiftcount Vulnerability" https://bugs.webkit.org/show_bug.cgi?id=97603 9. "226696 - Security: use-after-free removing a frame from its parent in a beforeload event of an OBJECT element - chromium" https://bugs.chromium.org/p/chromium/issues/detail?id=226696 Pwning Old Webkit for Fun and Profit ― Security.Tokyo #1 19