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. Pwning Old Webkit for Fun and Profit
    Feb. 22th, 2022 @ Security.Tokyo #1

    View full-size slide

  2. $ 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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

  10. "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

    View full-size slide

  11. …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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide