Slide 1

Slide 1 text

Pwning Old Webkit for Fun and Profit Feb. 22th, 2022 @ Security.Tokyo #1

Slide 2

Slide 2 text

$ 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

Slide 3

Slide 3 text

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

Slide 4

Slide 4 text

Why Targeting Old WebKit Even in 2023? Pwning Old Webkit for Fun and Profit ― Security.Tokyo #1

Slide 5

Slide 5 text

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

Slide 6

Slide 6 text

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

Slide 7

Slide 7 text

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

Slide 8

Slide 8 text

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

Slide 9

Slide 9 text

Stop Using QtWebKit and also wkhtmltopdf Pwning Old Webkit for Fun and Profit ― Security.Tokyo #1

Slide 10

Slide 10 text

"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

Slide 11

Slide 11 text

…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

Slide 12

Slide 12 text

2012年周辺のWebKitの脆弱性 CVE-2012-3748 : 配列ソートのコールバックでTOCTOU 報告者: Joost Pol & Daan Keuper, Certified Secure Moible Pwn2Own 2012で実演された(iOS6) CVE-2013-2842 : のイベントハンドラで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

Slide 13

Slide 13 text

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 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

Slide 14

Slide 14 text

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

Slide 15

Slide 15 text

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

Slide 16

Slide 16 text

CVE-2012-3748 (cont...) 各ノードから m_vector へソート済みの要素を書き戻す。 ... // Copy the values back into m_storage. AVLTree::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

Slide 17

Slide 17 text

Demo ― CVE-2012-3748 Arbitrary Code Execution Pwning Old Webkit for Fun and Profit ― Security.Tokyo #1

Slide 18

Slide 18 text

Happy Hacking~! Pwning Old Webkit for Fun and Profit ― Security.Tokyo #1

Slide 19

Slide 19 text

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