嘉手納スマートコントラクトを例として、リエントラント攻撃とクロスファンクション攻撃を回避する方法を簡単に分析する

CertiK
本文约1860字,阅读全文需要约7分钟
リエントランシーとクロスファンクションリエントランシーの違いは何ですか?チューリングの不完全性はどのようにしてこれらの攻撃の一部を防ぐのでしょうか?

ZEPfV3PENOBVAiAbPLUJIhQ06B2YPQgAjrBi3o4w.jpeg

この記事では、リエントランシーとクロスファンクションリエントランシーの違いと、チューリング不完全性がこれらの攻撃の一部をどのように防ぐことができるかについて簡単に説明します。

その中で、嘉手納ブロックチェーンがプログラミング言語 Pact を使用する、機能間のリエントランシー悪用の事例を紹介しますが、チューリングの不完全性はこの悪意のある悪用の発生を防ぐことはできません。

イベント紹介

Kadena ブロックチェーンは、他の L1 チェーンよりも高い拡張性、セキュリティ、可用性を実現するように設計されています。同社は、スマート コントラクトを作成するための新しい言語、Pact を開発しました。

この言語は人間が可読で、形式的な検証が容易で、セキュリティを強化するためにチューリング不完全性を備えています。

ここで言うチューリングの不完全性とは、チューリング完全なプログラミング言語 (Solidity や Haskell など) でできることが Pact ではできないことを意味します。これは欠点のように思えるかもしれませんが、実際には、スマート コントラクト プログラミング、さらには最も複雑な DeFi であっても、プロトコルがチューリング完全性を必要とすることはほとんどありません。

チューリングの不完全さの最も重要な点は、無制限の再帰が存在しないことです。これにより攻撃対象領域は大幅に減少しますが、一部の「古典的な」攻撃を 100% 回避することはできないため、次に機能間の再入の問題に対処します。

古典的なリエントラント攻撃

再入攻撃は非常に一般的なセキュリティ問題です。この問題は開発者にとって発見が難しいだけでなく、監査人にとってもそれが引き起こす可能性のあるすべての結果を検討することも困難です。

再入攻撃は、外部呼び出しの前後で関数が特定のタスクを実行する順序に依存します。

コントラクトが信頼できない外部コントラクトを呼び出す場合、攻撃者はこの関数呼び出しを何度も繰り返し、再帰呼び出しを形成する可能性があります。また、再入力された関数が重要なタスク (アカウントの残高の更新など) を実行すると、悲惨な結果につながる可能性があります。

以下に簡略化した例を示します。

脆弱な契約を安全でない契約、悪意のある契約を攻撃契約と呼びます。

1. 攻撃者は、危険なコントラクトを呼び出して、資金を攻撃コントラクトに転送します。

2. 呼び出しを受信した後、アンセーフ コントラクトはまず攻撃者が資金を持っているかどうかを確認し、その資金を攻撃コントラクトに転送します。

3. 資金を受け取った後、攻撃コントラクトはフォールバック機能を実行し、残高を更新する前に安全でないコントラクトにコールバックして、プロセスを再開します。

3LPJzMqUazzySylYYyGQmQcCmk7lXt4EXkI6avcS.png

この攻撃は無制限の再帰呼び出しを通じて実行されるため、言語がチューリング完全でない場合、攻撃は不可能です。

機能間の再入可能

クロスファンクションのリエントラントは、リエントラント関数が外部呼び出しを行う関数とは異なる関数を持つことを除いて、従来のリエントラント攻撃に似ています。この種の再入攻撃は通常、検出が困難です。複雑なプロトコルでは、考えられるすべての結果を手動でテストするには組み合わせが多すぎるためです。

これは、Pact 言語を使用した単純な機能横断型リエントランシー攻撃という概念実証につながります。

  • Pact モジュールでのシンプルなクロスファンクション再入可能

以下のコード スニペットでわかるように、コントラクト内の関数は、特定のインターフェイスを実装する別のコントラクトへの外部呼び出しを行います。これにより、適切に設計された攻撃コントラクトへの再入が可能になります。 Pact の機能は、機密タスクを実行するためのアクセス許可をユーザーに付与する組み込み関数です。次のコードは説明のみを目的としており、実際の契約事例から抜粋されたものではありません。

私たちが使用するコード例には 3 つの部分があります。

画像の説明

J2WHVGPxSOWonrvIjKSY0DlFDOGbT2wxJKG6LXaB.png

メインコントラクトを悪意のある外部モジュールと対話させるには

画像の説明

tmlkGQ8SqVwGS6LYwQ9cFRJ9V93kzkm6A4fu0tbY.png

攻撃された模擬契約例

まず、データベースは、文字列が 10 進数に関連付けられた行に格納されるテーブルとして定義されます。

次に、機能が定義されます: CREDIT (この例では常に true)。この条件は、credit 関数で必要になりますが、with_capability ステートメントの bad_function によって内部的にのみ許可されます。これは、クレジットを直接呼び出すと失敗することを意味します。

ここで、関数 Credit は次のように定義されます。入力として与えられた文字列に残高 (小数点) を追加します。また、アドレスがまだテーブルにない場合にもエントリを作成します。

最後に、関数 bad_function は、legit_address の残高を増やしますが、入力パラメーターとして提供できる、以前に定義されたインターフェイスに準拠するコントラクトへの呼び出しも実行します。
関数 get-balance を使用すると、このテーブルを読み取ることができます。

画像の説明

jfXX2RR6S1k9JrsiOuUTwoB6OIZwqtBwNSEzmrbT.png

メインモジュールに再度入り、クレジット関数を呼び出します。

一般的なプロセスは次のとおりです。

a. 攻撃コントラクトをパラメータとして bad_function を呼び出します。

b. CREDIT機能が付与されている

c.「legit_address」の残高が10増加します

d. 悪意のあるモジュールの external_function を呼び出します: まだ CREDIT 関数があるため、コントラクトを再入力してクレジット関数を直接呼び出すことができます。"attacker_address "バランスは100です。

qvtDriKxelZNcqzUtvyQF17Wa8gisJsg7wATenex.png

その後、(バランスをとる)"legit_address") 10 を返します (get-balance"attacker_address") 100 を返します。

再突入に成功しました。

ここで、credit を再入的に呼び出す代わりに、再度 bad_function を再入的に呼び出してみるとどうなるでしょうか? Credit への最初の呼び出しが成功したとしても、bad_function では再入可能であるため、再帰呼び出しとなり、実行は失敗します。

WxYF01kddh7e3Ngdd39o8njMiqDdnhIILfVmuGdy.png


最後に書きます

DsGM0RFnkPp5qDJdbsGFluS2kfQByi3sxJPIMwpe.png

最後に書きます

無制限の再帰を取り除くことにより、チューリング不完全性は、再入攻撃のいくつかのベクトルを防ぎます。

ただし、関数間の再入は再帰呼び出しなしで発生する可能性があるため、チューリング不完全性がそのような攻撃ベクトルをすべて防ぐわけではないため、ユーザーはこの言語を操作するときに再入が無害であると想定すべきではありません。

リエントランシーやクロスファンクションリエントランシーは非常に一般的なセキュリティ問題であり、Web3.0分野でも大規模な攻撃が相次いで発生しています。

Pact は、スマート コントラクト プログラミング言語として大きな可能性を秘めています。

Solidity や Haskell などの他の言語とは多少異なるアプローチを採用しています。 Pact はセキュリティに関してチューリングの不完全性にのみ依存しているわけではなく、言語は読みやすく、理解しやすく、正式に検証しやすいように設計されています。

ただし、あらゆる攻撃ベクトルの影響を受けないプログラミング言語はありません。したがって、開発者は使用している言語の固有の機能を理解し、展開前にすべてのプロジェクトを徹底的に監査することが不可欠です。

現在、CertiK の監査およびエンドツーエンドのソリューションは、現在市場に出ているほとんどのエコシステムをカバーしており、ほぼすべての主流プログラミング言語をサポートしており、このチェーンはセキュリティ技術サポートを提供しています。