Typo3 CVE-2019-12747 反序列化漏洞分析

本文详细分析了Typo3 CMS的CVE-2019-12747反序列化漏洞,该漏洞允许后台用户执行任意PHP代码。受影响版本为8.x-8.7.26和9.x-9.5.7。漏洞利用涉及两个组件:Backend和Core API。文章深入探讨了补丁分析、Backend和Core ext的漏洞点利用过程,强调了TCA在漏洞利用中的作用。漏洞利用的关键步骤包括变量覆盖和构造特殊字符串以实现代码执行。
摘要由CSDN通过智能技术生成

 

作者:mengchen@知道创宇404实验室

1. 前言

TYPO3是一个以PHP编写、采用GNU通用公共许可证的自由、开源的内容管理系统。PHP大马

2019年7月16日,RIPS的研究团队公开了Typo3 CMS的一个关键漏洞详情[1],CVE编号为CVE-2019-12747,它允许后台用户执行任意PHP代码。

漏洞影响范围:Typo3 8.x-8.7.26 9.x-9.5.7。

 

2. 测试环境简述

Nginx/1.15.8PHP 7.3.1 + xdebug 2.7.2MySQL 5.7.27Typo3 9.5.7

 

3. TCA

在进行分析之前,我们需要了解下Typo3的TCA(Table Configuration Array),在Typo3的代码中,它表示为$GLOBALS[‘TCA’]。

在Typo3中,TCA算是对于数据库表的定义的扩展,定义了哪些表可以在Typo3的后端可以被编辑,主要的功能有

  • 表示表与表之间的关系
  • 定义后端显示的字段和布局
  • 验证字段的方式

这次漏洞的两个利用点分别出在了CoreEngine和FormEngine这两大结构中,而TCA就是这两者之间的桥梁,告诉两个核心结构该如何表现表、字段和关系。

TCA的第一层是表名:天天好彩

$GLOBALS['TCA']['pages'] = [
    ...];
$GLOBALS['TCA']['tt_content'] = [
    ...];

其中pages和tt_content就是数据库中的表。

接下来一层就是一个数组,它定义了如何处理表,

$GLOBALS['TCA']['pages'] = [
    'ctrl' => [ // 通常包含表的属性
        ....    ],
    'interface' => [ // 后端接口属性等
        ....    ],
    'columns' => [
        ....    ],
    'types' => [
        ....    ],
    'palettes' => [
        ....    ],
];

在这次分析过程中,只需要了解这么多,更多详细的资料可以查询官方手册[2]。

 

4. 漏洞分析

整个漏洞的利用流程并不是特别复杂,主要需要两个步骤,第一步变量覆盖后导致反序列化的输入可控,第二步构造特殊的反序列化字符串来写shell。第二步这个就是老套路了,找个在魔术方法中能写文件的类就行。这个漏洞好玩的地方在于变量覆盖这一步,而且进入两个组件漏洞点的传入方式也有着些许不同,接下来让我们看一看这个漏洞吧。

4.1 补丁分析

从Typo3官方的通告[3]中我们可以知道漏洞影响了两个组件——Backend & Core API (ext:backend, ext:core),在GitHub上我们可以找到修复记录[4]

很明显,补丁分别禁用了backend的DatabaseLanguageRows.php和core中的DataHandler.php中的的反序列化操作。

4.2 Backend ext 漏洞点利用过程分析

根据补丁的位置,看下Backend组件中的漏洞点。

路径:typo3/sysext/backend/Classes/Form/FormDataProvider/DatabaseLanguageRows.php:37

public function addData(array $result){
if (!empty($result['processedTca']['ctrl']['languageField'])
        && !empty($result['processedTca']['ctrl']['transOrigPointerField'])
    ) {
        $languageField = $result['processedTca']['ctrl']['languageField'];
        $fieldWithUidOfDefaultRecord = $result['processedTca']['ctrl']['transOrigPointerField'];
if (isset($result['databaseRow'][$languageField]) && $result['databaseRow'][$languageField] > 0
            && isset($result['databaseRow'][$fieldWithUidOfDefaultRecord]) && $result['databaseRow'][$fieldWithUidOfDefaultRecord] > 0
        ) {// Default language record of localized record
            $defaultLanguageRow = $this->getRecordWorkspaceOverlay(
                $result['tableName'],
                (int)$result['databaseRow'][$fieldWithUidOfDefaultRecord]
            );
if (empty($defaultLanguageRow)) {
throw new DatabaseDefaultLanguageException('Default language record with id ' . (int)$result['databaseRow'][$fieldWithUidOfDefaultRecord]
                    . ' not found in table ' . $result['tableName'] . ' while editing record ' . $result['databaseRow']['uid'],1438249426
                );
            }
            $result['defaultLanguageRow'] = $defaultLanguageRow;
// Unserialize the "original diff source" if givenif (!empty($result['processedTca']['ctrl']['transOrigDiffSourceField'])                && !empty($result['databaseRow'][$result['processedTca']['ctrl']['transOrigDiffSourceField']])            ) {                $defaultLanguageKey = $result['tableName'] . ':' . (int)$result['databaseRow']['uid'];                $result['defaultLanguageDiffRow'][$defaultLanguageKey] = unserialize($result['databaseRow'][$result['processedTca']['ctrl']['transOrigDiffSourceField']]);            }//省略代码        }//省略代码    }//省略代码}

很多类都继承了FormDataProviderInterface接口,因此静态分析寻找谁调用的DatabaseLanguageRows的addData方法根本不现实,但是根据文章中的演示视频,我们可以知道网站中修改page这个功能中进入了漏洞点。在addData方法加上断点,然后发出一个正常的修改page的请求。

当程序断在DatabaseLanguageRows的addData方法后,我们就可以得到调用链

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值