Skip to content

Instantly share code, notes, and snippets.

@pschichtel
Last active November 25, 2021 19:14
Show Gist options
  • Save pschichtel/b6959a4897fcf0da1cc0ce638bec57fe to your computer and use it in GitHub Desktop.
Save pschichtel/b6959a4897fcf0da1cc0ce638bec57fe to your computer and use it in GitHub Desktop.
A script to add an address to an alias in a pfSense firewall. The intended use is for fail2ban like tools.
#!/usr/bin/env python
from requests import Session
from re import findall
from argparse import ArgumentParser
parser = ArgumentParser()
parser.add_argument('--pfsense', type=str, metavar='address', required=True, help="Firewall base url")
parser.add_argument('--username', type=str, metavar='username', required=True, help="Firewall login username")
parser.add_argument('--password', type=str, metavar='password', required=True, help="Firewall login password")
parser.add_argument('--alias', type=str, metavar='alias id', required=True, help="The firewall alias ID (extract this from the alias URL)")
parser.add_argument('--listen', default=False, action='store_true', help="If true listens as an API server, otherwise reads from STDIN")
parser.add_argument('--listen-port', type=int, default=8080, help="The port to listen on if listen is set to true")
parser.add_argument('--reason', type=str, default="Spammed a node", help="The reason the given IPs get blocked")
def process_input(input_string):
base_url = args.pfsense
alias_edit_url = '/firewall_aliases_edit.php'
alias_list_url = '/firewall_aliases.php'
alias_id = args.alias
s = Session()
r = s.get(base_url, verify=False)
text = r.text
action = findall('<form id="iform"[^>]+?action="([^"]+)"', text)[0]
csrf_token = findall('name=\'__csrf_magic\'\s*value="([^"]+)"', text)[0]
login_payload = {
'__csrf_magic': csrf_token,
'usernamefld': args.username,
'passwordfld': args.password,
'login': 'Login'
}
s.post(base_url + action, data=login_payload, verify=False)
r = s.get(base_url + alias_edit_url + '?id=' + alias_id, verify=False)
text = r.text
csrf_token = findall('name=\'__csrf_magic\'.*?value="([^"]+)', text)[0]
alias_name = findall('name="origname".*?value="([^"]+)', text)[0]
alias_desc = findall('name="descr".*?value="([^"]+)', text)[0]
addresses = findall('name="(address\d+)".*?value="([^"]+)', text)
details = findall('name="(detail\d+)".*?value="([^"]+)', text)
alias_payload_base = {
'__csrf_magic': csrf_token,
'origname': alias_name,
'name': alias_name,
'id': alias_id,
'tab': 'ip',
'descr': alias_desc,
'type': 'host'
}
ips = set(findall('\\b(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\\b', input_string))
addr_count = len(addresses)
new_ids = [str(x) for x in range(addr_count, addr_count + len(ips))]
new_addresses = dict([("address" + i, addr) for (i, addr) in zip(new_ids, ips)])
new_details = dict([("detail" + i, args.reason) for i in new_ids])
alias_payload = {
**alias_payload_base,
**dict(addresses),
**dict(details),
**new_addresses,
**new_details
}
s.post(base_url + alias_edit_url, data=alias_payload, verify=False)
r = s.get(base_url + alias_list_url, verify=False)
csrf_token = findall('name=\'__csrf_magic\'.*?value="([^"]+)', r.text)
apply_payload = {
'__csrf_magic': csrf_token,
'apply': 'Apply changes',
'tab': 'ip'
}
r = s.post(base_url + alias_list_url, data=apply_payload, verify=False)
print(r.status_code)
args = parser.parse_args()
if args.listen:
from bottle import Bottle, request, run
app = Bottle()
@app.post('/block')
def block():
print(app)
print(request)
process_input(request.body.getvalue().decode())
run(app, port=args.listen_port)
else:
import sys
process_input(''.join(sys.stdin))
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment