Home

PHP(parse_url和反序列化)

2019/04/30

1、parse_url()

parse_url — 解析 URL,返回其组成部分

parse_url ( string $url [, int $component = -1 ] ) : mixed

本函数解析一个 URL 并返回一个关联数组,包含在 URL 中出现的各种组成部分。 本函数不是用来验证给定 URL 的合法性的,只是将其分解为下面列出的部分。不完整的 URL 也被接受,parse_url() 会尝试尽量正确地将其解析。

返回值:
• scheme - 如 http
• host
• port
• user
• pass
• path
• query - 在问号 ? 之后
•fragment - 在散列符号 # 之后
如果指定了 component 参数, parse_url() 返回一个 string (或在指定为 PHP_URL_PORT 时返回一个 integer)而不是 array。如果 URL 中指定的组成部分不存在,将会返回 NULL。

$Url=”http://username:password@hostname/path?arg=value#anchor
parse_url($url)的返回值为:
image

Note:
parse_url() 是专门用来解析 URL 而不是 URI 的。不过为遵从 PHP 向后兼容的需要有个例外,对 file:// 协议允许三个斜线(file:///…)。其它任何协议都不能这样。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<?php
$url=parse_url($_SERVER['REQUEST_URI']);
var_dump($url);
parse_str($url['query'],$query);
var_dump($query);
foreach($query as $value){
if (preg_match("/flag/",$value)) {
die('stop hacking!');
exit();
}
}
$value = $_GET["value"];
echo "<br/>" . $value;
echo "<br/>right";
?>

当url为:http://127.0.0.1/test.php?value=flag时
返回
image
当url为:http://127.0.0.1///test.php?value=flag时
parse_url()会返回false,绕过验证:
image

2、反序列化

serialize ( mixed $value ) : string
serialize() 返回字符串,此字符串包含了表示 value 的字节流,可以存储于任何地方。
这有利于存储或传递 PHP 的值,同时不丢失其类型和结构。

unserialize ( string $str ) : mixed
unserialize() 对单一的已序列化的变量进行操作,将其转换回 PHP 的值。

1
2
3
4
5
6
7
8
9
10
<?php
class test{
private $test1 = "aaa";
public $test2 = "bbb";
protected $test3 = "ccc";
}
$test = new test();
echo(serialize($test));
?>

输出结果如下:
image

O:4:"test":3:{s:11:"\00test\00test1";s:3:"aaa";s:5:"test2";s:3:"bbb";s:8:"\00*\00test3";s:3:"ccc";}

2、1绕过__wakeup魔术方法

php面向对象的magic function(魔术方法):

1. __construct()
__contstruct()函数被称为构造函数,当实例化类的时候会自动调用该函数
2. __destruct()
__destruct()函数被称为析构函数,当类结束的时候自动调用该函数
3. __sleep()
__sleep()函数是当php进行序列化操作(serialize)的时候自动调用该函数,可以用于清理对象,并返回一个包含对象中所有应被序列化的变量名称的数组。如果该方法未返回任何内容,则 NULL 被序列化,并产生一个 E_NOTICE 级别的错误。
4. __wakeup()
__wakeup()函数是当php进行反序列化操作(unserialize)的时候自动调用该函数
5. __toString()
__toString()函数是当对象被当做字符串的时候会自动调用该函数

__wakeup()函数是当php进行反序列化操作(unserialize)的时候自动调用的,而当成员属性数目大于实际数目时可绕过wakeup方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
<?php
class test{
public $aaa = "222";
function __wakeup(){
$this->aaa = "222";
echo "Wake up!<br/>";
}
function __destruct(){
echo "Destruct<br/>aaa=".$this->aaa;
}
}
$test1 = 'O:4:"test":1:{s:3:"aaa";s:3:"111";}';
unserialize($test1);
?>

变量aaa默认值为222,在反序列化时先将传入的值111赋给变量aaa,再在反序列化后执行__wakeup()魔术方法将变量aaa的值重置为222,最后结果:
image

而绕过__wakeup()魔术方法的方法就是让成员属性数目大于实际数目:

$test1 = 'O:4:"test":2:{s:3:"aaa";s:3:"111";}';

image

这个漏洞存在PHP5.6.25之前版本和7.0.10之前的7.x版本中