関数名を書かずにC言語で関数を呼び出す方法
Calling a function in C without naming it
学校の自動採点システムは、許可された関数以外の使用をAST解析で検出する。execveを直接呼べないため、ASanで置き換えられたprintfとmmapのオフセットを漏洩させ、unionで関数ポインタを偽装。mmapで書き込み可能かつ実行可能なページを確保し、syscall命令を配置してexecveを呼び出すことに成功した。
C言語では、安全性の欠如は機能です。だからunionをそのまま使うことができます。
- ashdnazg
うちの大学はずっとずさんで、提出物は他のすべてと同じネットワーク上で、ほぼ権限のないユーザーで実行していただけだった。
自動テストが僕の提出物をクラッシュさせたとき、`system`を使ってテスト入力をホームディレクトリにダンプしただけだった。でもパーミッションの設定を忘れてしまい、実際にはアクセスできなかった!何度か再提出してchmodを追加し、毎回別のものを台無しにしながら、なんとかバグを再現し、修正し、再提出して、証拠をすべて(あるいはほとんど)消し去ることに成功した。
- Kevin_Flynn
私たちのコードはASanでコンパイルされていると分かっていたので、常に許可されている関数であるprintfと、任意のアセンブリコード実行を可能にするmmapとの間のオフセットをリークさせることを選んだ。これにより学校のチェックを回避して任意のシステムコールを呼び出せる。私たちの場合はexecveでシェルアクセスを得た。
それ以上は調査せず、この可能性のある問題を学校に報告しただけだ。
これを修正する簡単な方法は見当たらない。
欠陥は提出システムにあるようだ。
提出システムは、あなたのコードをトランポリンライブラリにビルド/再リンクし、禁止される各関数の本体をエラー報告とabortに置き換えることができる。あなたの例では、次のものをトラップするだろう:
char *code =
notmmap.fn(NULL, 4096, PROT_READ | PROT_WRITE | PROT_EXEC,
MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
そして提出検証の実行フェーズ中にPROT_EXECフラグの使用を防ぐ。
AIによると、Linuxでは:「...各プロセスがプログラムを実行し始める前に適用されるseccomp-BPFフィルタ。これはmmapのprot引数を検査し、PROT_EXECが設定されている場合にEPERMを返すことができる。」
さらにLinuxでは:「systemdはサービスに対してMemoryDenyWriteExecute=yesを提供している。これはすべての実行可能マッピングを禁止するよりも制限が緩い:書き込み可能かつ実行可能なマッピングと、メモリを実行可能にする関連する方法を対象としている。」
(記事を正しく読んでいれば)
ps. 提案された解決策を学科長や他の権威に提出して、何らかの恩恵をもらえるかもしれない […]
- PeterWhittaker
学校はseccompのdenylistで物事をラップする必要があるようだ。簡単ではないかもしれないが、面白いかもしれない。