PF update pf table via web

generic

Member

Reaction score: 7
Messages: 53

I'd like to add another layer of security to my PF config and I'm looking for a way to add an IP address to a table via web.

General idea behind that is that sometimes I need to connect to my server from random location and I'd like to be able to add IP of that location to my <ssh> table.
I've seen such solution some time ago on hacker news, but unfortunately I can't find it.

Were you able to come with similar solution?
 

SirDice

Administrator
Staff member
Administrator
Moderator

Reaction score: 12,017
Messages: 38,467

The safest and simplest way would be to create a file with the IP addresses. You can easily code that with PHP for example. Then have a cronjob scheduled every 5 minutes that reads the file, checks if they are valid IP addresses and then uses pfctl -t mytable -T add <IP address> to add them to the table.

You really don't want to allow the www user direct access to the firewall, so you're going to need to put something in between.
 
OP
G

generic

Member

Reaction score: 7
Messages: 53

You really don't want to allow the www user direct access to the firewall, so you're going to need to put something in between.
I definitely don't want that. :)
Instead of doing anything with php I’d rather use some static content behind password auth.
Looking further ;)
 

Zirias

Daemon

Reaction score: 1,413
Messages: 2,467

"static content" kind of defeats the purpose to do something :-/

I do some (other) automation using special-purpose ssh keys. E.g. for a simple dns updater in ~/.ssh/authorized_keys of the target machine:
Code:
restrict,pty,command="/usr/local/sbin/dyndns-update $SSH_ORIGINAL_COMMAND" ssh-rsa XXXXXXXXXXXXXXXXXXXX[...] keyname
 

SirDice

Administrator
Staff member
Administrator
Moderator

Reaction score: 12,017
Messages: 38,467

Instead of doing anything with php I’d rather use some static content behind password auth.
How are you going to get a static HTML page to write form data to a file? Granted my HTML skills are still stuck in the 4.0 era but I'm pretty sure you can't do this with static pages alone. You're going to need some CGI (really old school), REST or some other dynamic PHP code to receive the form data and write it to a file. I'm fairly certain there are tons of PHP examples to be found on the internet (they're probably not coded in the safest way so be careful with those).
 

msplsh

Aspiring Daemon

Reaction score: 187
Messages: 569

  • Turn on TLS, turn off port 80, require client certificates, use a client certificate to connect
  • Alternatively, don't use client certificates (but still TLS) but a odd /path/to/access and username/password that are both ridiculously long and complicated
  • Hardlink the file to inside the web server area
  • Use WebDAV to write the file
  • Alternatively, as SirDice suggested, use a REST style POST with a cgi/php/python/whatever
  • Forget the web and do something like what Zirias suggested
Don't actually directly edit conf files (it's more likely you'll blow yourself up), have them reload tables or something per SirDice
 

sezgin

New Member


Messages: 3

you can do it minimal php script

Sample Code :
PHP:
<?php
$ip_address = $_POST['ip_address']; // form post action
// or
// $ip_address = $_GET['ip_address']; // url parameter based
shell_exec("pfctl -t mytable -T add ".$ip_address);

// if dont have permission install sudo and set config and use this line
// shell_exec("/usr/local/bin/sudo /sbin/pfctl -t mytable -T add ".$ip_address")

?>


// if don't have apache or nginx user permission U you can use sudo package
pkg install sudo

and change/add lines for www permission in file /usr/local/etc/sudoers

##

Code:
## User privilege specification
##
root ALL=(ALL) ALL
www ALL=NOPASSWD: ALL
 

SirDice

Administrator
Staff member
Administrator
Moderator

Reaction score: 12,017
Messages: 38,467

Code:
www ALL=NOPASSWD: ALL
Really? You're just going to hand the keys to the kingdom like that? Anything I can get the, probably shoddy, PHP scripts to do would give me instant root access? Ever heard of shell code injection? Or Principle of Least Privilege?

What happens when I post ip_address=127.0.0.1; rm+-rf+/?
 

Trihexagonal

Son of Beastie

Reaction score: 2,315
Messages: 2,885

I just looked through the ports/security and there was a port to remove old entries from a pf table but I did not see one that adds new entries.

I only need local access on an Ethernet LAN. I do not require remote access, disable Services, wi-fi and Bluetooth on my FreeBSD boxen so it is not going to happen for anybody.
 

Tieks

Active Member

Reaction score: 107
Messages: 249

generic said:
Were you able to come with similar solution?

Instead of using a firewall, sshd will only run when I need it. I have two ways to achieve that. First way, I sent a specially crafted e-mail to an alias of root. Procmail would then start sshd.
The second way is what I use now. When I call my home number using my mobile phone a script that logs incoming phone calls will start sshd.
In both cases sshd runs on a high port, not port 22. A running sshd will be terminated by a cron job after about one hour.
 

sezgin

New Member


Messages: 3

Really? You're just going to hand the keys to the kingdom like that? Anything I can get the, probably shoddy, PHP scripts to do would give me instant root access? Ever heard of shell code injection? Or Principle of Least Privilege?

What happens when I post ip_address=127.0.0.1; rm+-rf+/?
I was write sample script and sample config

I can't write all the scripts he wants

He should check get or post parameter security and sudoers config

Sample sudoers
www ALL=(ALL) NOPASSWD: /sbin/pfctl

www user only allow command pfctl

and
sample php control


PHP:
$ip_address = $_GET['ip_address'];

if(is_valid_ip_address($ip_address))
 // run command


thank you for criticizing me
 

xtaz

Well-Known Member

Reaction score: 142
Messages: 472

I do this for allowing remote access via SSH. I have some code on my website that allows me to go to example.com/s/123456 where 123456 is an OTP code I read from an app on my phone. If the code isn't correct it responds with a 404 not found. If the code is correct it adds the remote IP to a pf table which allows access to port 22.

My code basically does what the above code is doing and execs sudo:

Code:
ip = request.headers.get('X-Real-IP', request.remote_addr)
process = subprocess.run(['/usr/local/bin/sudo', '/sbin/pfctl', '-t', 'ssh', '-T', 'add', ip], capture_output=True, encoding='utf-8')

But in my case it's a lot tighter in the sudoers file:

Code:
www ALL=(root) NOPASSWD: /sbin/pfctl -t ssh -T *

I then have a crontab that flushes the pf ssh table every 15 minutes. The nice thing is after I've logged in the connection will remain in the state table so the hole in the firewall is closed, but the SSH connection remains up.
 

ShelLuser

Son of Beastie

Reaction score: 2,091
Messages: 3,782

I can only crinche and facepalm when reading this thread.

There is a very easy solution: get proper server hosting. My servers are VPS based and hosted with a provider that also provides console access through a web interface. So if I need to change a PF table all I have to do is log onto my ISP (which is a completely separate authentication process than that of my server, safety first!), hop onto the console from which I simply change my 'table file' and reload it. Done.

Generally speaking: making things "easier" is bound to decrease overall security.
 

xtaz

Well-Known Member

Reaction score: 142
Messages: 472

Think you've misunderstood what's going on. It's not making things easier at all. It's making them considerably more difficult. Doesn't matter if it was a server at home or a VPS, I'd still set up the same security on it.

Bottom line is port 22 is completely closed to the internet, there is no way to SSH my server on any port, nothing obfuscated like some people do by putting it on a random high port. That's as secure as you can get.

Most of the time I use a wireguard VPN to connect to the server and I use SSH over the top of that, but there are occasions when I want to SSH it directly from something that doesn't have wireguard installed or configured on it, and in those cases I use what I described above.

It relies on a one time pass code that only I have to temporarily open port 22 to my source IP address and then closes it again after 15 minutes. Again, seems pretty secure (and definitely more difficult than not doing that). Impossible for anybody else to use, or even detect that it exists, as providing the wrong code gives a 404 error.

I believe that's what the OP was asking about, so I just explained how I did it, although I have the added complexity of the OTP stuff which they didn't ask for.
 
Top