プログラミング
さらに別の、括弧なしで関数を呼び出す方法
Yet another way to invoke functions without parentheses (blog.ikaes.de)
要約
この記事では、JavaScriptにおいて括弧を使わずに任意の関数を呼び出す新たな手法が紹介されています。`Error.prototype.prepareStackTrace`と`Array.prototype.toString`を操作することで、スタックトレースのフォーマット機能を利用して関数を生成し、実行することが可能になります。このテクニックは、`Object.prototype.message`のプロトタイプ汚染などを利用してペイロードを仕込み、`valueOf`トリックなどで最終的に関数を呼び出すことで実現されます。
全文翻訳
さらに別の、括弧なしで関数を呼び出す方法
私は、括弧を使わずに任意のJavaScript関数を呼び出す、さらに別の方法を見つけました。
このペイロードは、ErrorオブジェクトのprepareStackTrace関数を上書きすることで、任意の関数を生成します。これは通常、スタックトレースをフォーマットするために使用され、エラーのstack属性にアクセスしたときに呼び出されます。
この関数のパラメータは、エラーと「スタックの構造化された表現」であり、これは単なるコード位置の配列です。これは、JavaScript関数を生成するために使用されるFunctionコンストラクタと同じ関数シグネチャを持っています。ただし、2番目の引数が有効なJavaScriptコードである必要があります。
この方法で生成された関数を呼び出そうとすると、構文エラーが発生します。これは予想されることです。なぜなら、スタックトレースは有効なJavaScriptコードではなく、コード位置の配列だからです。
ペイロードを機能させるためには、Array.prototype.toString()関数の出力を制御し、それが望ましいJavaScriptペイロードを返すようにする必要があります。これは2つの方法で実現できます。まず、単に定数関数で上書きしてペイロードを返すようにするか、プロトタイプ汚染を使用してペイロードを別の関数に忍び込ませてから、Arrayプロトタイプを上書きします。
私は、Errorの領域にとどまり、Object.prototype.message変数を汚染することで操作できるError.prototype.toString関数を使用できることを発見しました。これにはさらに多くの方法があるはずです。
さて、すべてをまとめると、prepareStackTrace関数を使用した関数生成と、配列を任意の文字列に変換する方法により、任意のJavaScript関数を生成できます。最後に、新しい関数を呼び出す必要があります。幸いなことに、これには多くの方法があり、私はvalueOfトリックを選択しました。これは、オブジェクトのデフォルトのvalueOf関数を上書きし、それをプリミティブとして呼び出すことで機能します。あるいは、toStringを使用してからオブジェクトと文字列を連結することもできます。
最終的なペイロードは次のとおりです。
Object.prototype.message='alert\x281337\x29';Array.prototype.toString=Error.prototype.toString;Error.prepareStackTrace = Function;const x = new Error;x.valueOf=x.stack;+x;
ブラウザのコンソールで自由に試してみてください。