Category: Security

Link: FreePBX security advisory – SIP extension types

 

Important
This is an edited version of a post that originally appeared on a blog called The Michigan Telephone Blog, which was written by a friend before he decided to stop blogging. It is reposted with his permission. Comments dated before the year 2013 were originally posted to his blog.
We can set defaults for all these, so why not extension type?
We can set defaults for all these, so why not extension type?

The SysAdminMan blog has posted a new article related to FreePBX security, that I strongly urge you to read if you are running FreePBX or any FreePBX-based distribution:

FreePBX security advisory – SIP extension types

The basic issue is that by default, FreePBX sets extensions to type=friend rather than the more secure type=peer.  The article says it’s for historical reasons but I suspect there have been other reasons at play here (pure stubbornness, perhaps?).  But with the growing body of evidence that type=friend is bad, and because FreePBX now has an Advanced Settings module that allows you to to change certain defaults (though not yet this one), I have put in a Feature Request asking that system administrators be allowed to select a default type for extensions.  We’ll see if it goes anywhere (and it might help if anyone who supports this idea would add a comment to that ticket), but given that in the past they’ve been reluctant to even entertain the idea of changing the default, I fear that they may once again refuse to even consider it.  And for those of us who want to keep our systems as secure as reasonably possible, that would be a real shame.

How to isolate a second router from the rest of your local network

 

Important
This is an edited version of a post that originally appeared on a blog called The Michigan Telephone Blog, which was written by a friend before he decided to stop blogging. It is reposted with his permission. Comments dated before the year 2013 were originally posted to his blog.

I was recently asked how to solve a particular problem and I came up with what I think is an interesting solution, especially given my overall rather limited knowledge of networking.  The issue was this: In the home in question, they have cable broadband and a router that feeds jacks throughout the house.  For security reasons, the homeowner never installed any kind of wireless networking (even though his primary router supports it, he keeps it turned off).  Also his primary router is down in the basement.

Recently he got his wife a Motorola XOOM table computer and wouldn’t you know, it requires Wi-Fi access to connect to the Internet.  In order to extend the range, and so that he or his wife could easily turn off the Wi-Fi when the XOOM isn’t in use, he bought a second Wi-Fi router and put it upstairs.  Note that this router is connected BEHIND the original router in the basement.  In other words, the sequence of connection is as follows:

Cable Modem —> Basement (Primary) Router —> Upstairs (Wi-Fi) Router —> Tablet Computer

Now, as I said, he is very security conscious.  So the question he asked me is, if someone managed to break into his Wi-Fi, is there a way to set it up so that they could ONLY get to the Internet, and not to any other system on his local network.  I said I didn’t know, but to first try accessing other machines on his network (the ones that had web interfaces, anyway) from the XOOM.  Turned out that he could do so without any problem.  Because the Wi-Fi router used a different network segment from the original (addresses in the 192.168.2.x range, whereas the original router handed out address in the 192.168.0.x range), as far as anything connected to the Wi-Fi router was concerned, anything on the primary router might as well have been on the Internet (please forgive the non-technical explanation, I’m probably missing several technical details here, but that’s the gist of the problem).

I didn’t think it would be a good idea to try to make the Wi-Fi router use the same address space for both WAN and LAN, and while I could assign it a static IP address on the WAN side, it had to be able to reach the router/gateway at 192.168.0.1.  So here is what we did.

On the PRIMARY router, we took a look at the LAN settings and found that its DHCP server was assigning addresses starting at 192.168.0.2.  We changed that to start at 192.168.0.5 (probably could have used 192.168.0.4 in retrospect).

This way, we could change the WAN address of the Wi-Fi router to use a STATIC IP address of 192.168.0.2, and (this is the important part) a NETMASK of 255.255.255.252.

This means that as far as the Wi-Fi router is concerned, there are only four valid IP addresses in the 192.168.0.x range:

192.168.0.0 (not used)
192.168.0.1 (primary router/gateway)
192.168.0.2 (Wi-Fi router)
192.168.0.3 (Reserved for “broadcast” as far as Wi-Fi router is concerned)

One thing to remember is that after changing the DHCP assignment on the PRIMARY router is that computers already using IP address 192.168.0.2 and 192.168.0.3 will not automatically vacate those addresses until their DHCP lease comes up for renewal.  So if you change the second router’s WAN address to 192.168.0.2, it may not actually be able to connect until the computer or device currently on 192.168.0.2 “loses its lease”.  Rebooting the primary router may help, but in some cases you may have to track down the computer with the conflicting address and shut it off, or if you know how, renew its IP address assignment (this can usually be done from within the network settings panel).  Eventually, though, it should work, and at that point you should find that devices connected to the secondary router cannot connect to any addresses in the 192.168.0.x range outside the three mentioned above, which means they won’t be able to “see” anything else on your network that’s been assigned a DHCP address.

This tip falls into the category of “it worked in this particular situation, but I don’t guarantee it will work for you”.  So if you try this, be sure to test to make sure that the other machines on your primary network are actually unreachable from the secondary router.

Now let the comments begin, telling me how there’s a better way to do this, or why it won’t work, or something to that effect…

Running Asterisk 1.8 and Fail2Ban? You need a new configuration file…

 

Important
This is an edited version of a post that originally appeared on a blog called The Michigan Telephone Blog, which was written by a friend before he decided to stop blogging. It is reposted with his permission. Comments dated before the year 2013 were originally posted to his blog.

… And Ward Mundy of Nerd Vittles and PBX in a Flash has one for you. The explanation and instructions are here, and the file is here.

(And for all you people who say my articles are too verbose, take THAT!) 🙂

Link: Interesting security technique for Asterisk and FreePBX users (may work with other SIP-based PBX’s also)

 

Important
This is an edited version of a post that originally appeared on a blog called The Michigan Telephone Blog, which was written by a friend before he decided to stop blogging. It is reposted with his permission. Comments dated before the year 2013 were originally posted to his blog.

This article was originally posted in November, 2010.

NOTE: For some reason WordPress absolutely hates it when I try to edit this post, and turns links and other things into piles of steaming poo.  If things don’t look right here please e-mail me or leave a comment and I’ll check it out.  WordPress, I KNOW how I want my articles to look, why can’t you just leave them alone?

One problem faced by some SIP-based VoIP PBX administrators is the issue of security when you have external extensions (that is, extensions located anywhere in the world that’s not a part of your local network). You want to allow those extensions (the ones you’ve authorized) to connect to your system, but you prefer to keep everyone else out, and preferably not even tip them off that there’s a PBX there. The idea is, if the bad guys that would like to break into PBX’s don’t even realize that there is a PBX at your IP address, they won’t waste any time trying to crack into your system.

There have been other suggestions for how to handle this but many of them require your users to take some additional action(s) that they would not normally have to take, and users hate having to lift a finger to do anything to enhance their security. Which brings us to a rather clever technique that doesn’t require user to do anything other than use their phones as they normally would. It might be a tiny bit of a pain to set up initially, but the results may be worth it. I would call this medium level security because if someone is sniffing your packets, this alone may not keep them out, but most of the lowlifes that try to break into PBX’s don’t actually have sufficient access to sniff your packet stream (and also, they’d have to know the exact technique you’re using to be able to crack this). So without further ado…

Secure your VoIP server with the SunshineNetworks knock

(As of October 24, 2012, the above link appears to be DEAD — see the edit at the end of this article)

Note that while the article recommends changing the SIP port to something other than 5060, their basic technique (the “knock”) should still work even if you feel you need to stay on 5060. My only fear about changing the SIP port would be the possibility of losing communications with VoIP providers and with other systems I legitimately send/receive voice traffic to/from. They’re probably going to keep using 5060 even if I don’t. EDIT: My concern here may be unfounded — note the comment below from Alex of Sunshine Networks, who said that “changing the SIP port is quite safe. Your SIP server will send this SIP port along in it’s first SIP invite registration to the VoIP provider. So unless your VoIP provider is actively blocking out anything else than port 5060, it should work fine. We use this technique with 3 different major SIP providers in Australia and never had problems. So far we haven’t seen any unintended consequences.”

I haven’t personally tested this, so if you do, please consider leaving a comment to let me know how it worked for you. The two things I wonder are, do these rules survive a reboot, and can you have more than one secret phrase that would let people in (in case you want to use a different one for each external extension)? EDIT: Those questions are also addressed in Alex’s comment below. Also, those of you running PBX in a Flash should take note of Ward Mundy’s comment about changing an entry in /etc/sysconfig/iptables in this thread. In that same thread, there appears a method to view the “knock” each extension is currently sending — just do “sip debug” from the Asterisk CLI for an hour or so (long enough for all your endpoints to register, after which you can use “sip no debug” to turn it off), then run this at the Linux command prompt (not from the CLI!):

grep "From: " /var/log/asterisk/full|cut -f1 --delimiter=; | sort -u

For each of your remote extensions, you’ll see a line that looks something like this:

From: The Knock <sip:234@nn.nn.nn.nn>

“The Knock” may or may not be enclosed in quotation marks, but it apparently doesn’t matter (you don’t include them in the iptables rules). If you haven’t used a specific “knock”, it could be the actual user’s name, if you set that up when you first set up the endpoint. Anyway, I’d suggest running this BEFORE you actually implement the iptables rules, so you know ahead of time what each endpoint is sending.

EDIT (Added January 8, 2012): I am now using a slight variation on this technique on one of the systems I administer. Without going into too many specifics, I will just note that some SIP devices and VoIP adapters actually already send a unique string that you can use as a “knock” – you do not have to configure a new one, you just need to find out what the device is already sending and use that. For example, let’s say you have an VoIP device connecting to your Asterisk server as extension 234. All you have to do is go to the Asterisk CLI (NOT the Linux command prompt) and enter this:

sip set debug peer 234

(Replace 234 with the actual extension number). Now, assuming that the device is connecting to your server, you will start to see SIP packets scroll across your screen. Within a few minutes you should see one like this (IP addresses have been xx’ed out):

<--- SIP read from UDP:xx.xx.xx.xx:5061 --->

REGISTER sip:xx.xx.xx.xx:5060 SIP/2.0
Call-ID: e10700c2@xx.xx.xx.xx
Content-Length: 0
CSeq: 56790 REGISTER
From: <sip:234@xx.xx.xx.xx>;tag=SP8f427e45f1e19cb24
Max-Forwards: 70
To: <sip:234@xx.xx.xx.xx>
Via: SIP/2.0/UDP xx.xx.xx.xx:5061;branch=z4b9hGK-4f0473a8;rport
Authorization: DIGEST algorithm=MD5,nonce=”37cd169d”,realm=”asterisk”,response=”a726bfed5db321a7bc967b997b5157c2″,uri=”sip:xx.xx.xx.xx:5060″,username=”234″
User-Agent: xxxxxx/xxxxxx-x.x.x.x
Contact: <sip:234@xx.xx.xx.xx:5061>;expires=60;+sip.instance=”<urn:uuid:nnnnnnnn-nnnn-nnnn-nnnn-nnnnnnnnnnnn>”
Allow: ACK,BYE,CANCEL,INFO,INVITE,NOTIFY,OPTIONS,REFER
Supported: replaces

<————->

If you don’t see this you may need to increase the debug level. After you see a packet like this, you can turn off sip debugging:

sip set debug off

The string you are looking for is in the Contact: string above (the nnnnnnnn-nnnn-nnnn-nnnn-nnnnnnnnnnnn is replaced by a unique string). So, where in the instructions for the “knock” they show a sample string such as:

iptables -I door 1 -p udp --dport 5060 -m string --string "mysecretpass" --algo bm -m recent --set --name portisnowopen

I would change the --dport parameter to 5060:5061 (since an VoIP adapter sometimes uses port 5061 for the second service provider — for an device that allows up to fours service providers, use 5060:5063) and the --string parameter to “<urn:uuid:nnnnnnnn-nnnn-nnnn-nnnn-nnnnnnnnnnnn>”, but using the actual string sent by the device, of course. I know the Sunshine Network people recommend using something other than port 5060 but I just can’t bring myself to go quite that far, and even their examples show 5060.

Some other SIP-compliant devices also send unique strings in their REGISTER packets. One that does NOT do so, as far as I am aware, is the venerable Linksys PAP2. And I also do not believe that any of the Sipura line of devices send such a unique string.

Naturally, if an intruder KNOWS you are using that technique, they could try a brute-force attack on the unique string. So I recommend only using this with “uncommon” extension numbers (not 200 or 1000, for example) and with a VERY strong secret/password on the SIP connection. But it is another line of defense against would-be intruders!

EDIT (Added October 24, 2012): The original article, and most of the original site for that matter, seems to have gone offline. While I’m not going to repost the original article here without permission, I will give you a few more details and a couple of excerpts. First, they advised that you change the SIP port to something other than 5060 – they suggested using something in the range 20001 through 49000, though I am not sure why. They uses port 34122 in their examples, and noted that if you are running PBX software that has a “SIP Settings” module, if your find a setting for “Bind Port”, that would be the one to change. Of course if you do this, you then have to change the SIP port on ALL your SIP-based phones and VoIP adapters.

With regard to the “knock” itself, they said this:

Technical information :
… Technically, our knock consists of a secret passphrase which is sent together with the first SIP packet from the phone to the server. SIP packets are text files, very much readable like http packets are. The SIP headers in a REGISTER invite packet have a lot of information, and one of those headers is called the “Display Name”. This display name is used only internally in your Asterisk server and has no other use, so we figured we could fill in anything and the Asterisk functionality would still work fine. We decided to use it as a port knock password.

How does it work :
The Asterisk administrator sets up a simple iptables rule. The iptables rule checks for a secret phrase inside packets sent to the SIP port ( 5060 by default, 34122 after having changed it ). Unless it finds this secret phrase, it will drop the packets to this port. All the remote phone has to do is fill in the “User Name” SIP property on his SIP phone with the secret phrase, and he will be able to connect.

What you then needed to do was to go to into your Asterisk server and from a Linux command prompt, issue the following command:

iptables -N door

Then for EACH “knock” string you want to use, you would do this from the command prompt (note this is only one line, and note that 34122 is the example port and “mykn0ckstr1ng” is an example “knock”):

iptables -I door 1 -p udp –dport 34122 -m string –string “mykn0ckstr1ng” –algo bm -m recent –set –name portisnowopen

If you have anyone that needs to register with your server but cannot send the “knock”, but is at a fixed IP address, you’d add a line like this for each instance (again the port and ip address would probably need to be changed, and note that an entire subnet can be specified as in this example — just leave off the /24 if it’s a single ip address):

iptables -A INPUT -p udp –dport 34122 –source 10.10.1.0/24 -j ACCEPT

Then you would enter these three lines, but again using the correct port rather than 34122. In the first line you see the number 4000 — that is amount of time in seconds that the port will be open, and should be greater than 3600 because that’s the default registration timeout for many sip phones and VoIP adapters. The original article notes that you could use 86400, which is a full day:

iptables -A INPUT -p udp –dport 34122 -m recent –rcheck –seconds 4000 –name portisnowopen -j ACCEPT
iptables -A INPUT -p udp –dport 34122 -j door
iptables -A INPUT -p udp –dport 34122 -j DROP

And finally, to make iptables use these rules, you’d enter:

service iptables save

The original Sunshine Networks article notes that…

This code keeps port 34122 closed ( DROP ) unless someone has opened the door ( door ) in which case they are allowed to pass the door for a little more than 1 hour ( 4000 seconds ). Each time the phone re-registers , the SIP secret pass header is sent, and the door is reopened for 4000 seconds. Since the default SIP reregistration time on many phones is 3600, the 4000 seconds will make sure that as long as the phone is connected to the SIP server, or needs to be connected, the dynamic firewall rule is always active.

Once you have done this, if you configure the Display Name or User Name setting with the “knock” string, it should be able to get through your firewall. Any phone that doesn’t have this string won’t. Of course you can always make the “knock” something that a phone already sends (in a SIP register packet), as noted in the previous edit, and then you don’t have to reconfigure the phone at all. If a phone or device tries to connect without sending the “knock”, the firewall won’t allow it (assuming you haven’t previously created some other rule that allows the traffic to pass) and the connection will fail, or at least that is how it’s supposed to work (I make no guarantees because I didn’t come up with this).

If you enter the command cat /proc/net/ipt_recent/portisnowopen you will get a list of IP addresses that have successfully used the “knock” to connect. Remember that after you implement this, it can take up to an hour for a device to attempt to reconnect.

If anyone ever spots the original article back online, please let me know and I’ll remove this edit. I’d rather you get the information direct from the original source anyway, and the short excerpts I have provided here don’t give the complete overview that the original article provided.

EDIT (February 23, 2014): It appears that there is an archived copy of that original article on the Wayback Machine, although we do not know if it is the most recent edit of that article prior to the site disappearing.

Link: Using IP tables to secure Linux server against common TCP hack attempts

 

Important
This is an edited version of a post that originally appeared on a blog called The Michigan Telephone Blog, which was written by a friend before he decided to stop blogging. It is reposted with his permission. Comments dated before the year 2013 were originally posted to his blog.

This article was originally published in November, 2010.

Iptables
Image by Jordan W via Flickr

I’m not entirely certain of the original source of this article — I found it on one site, but a quick search reveals that the original source is most likely this site, but I may be wrong. The author of that article says he took some of the info in that article (looks like more than “some” from where I sit) from this article: How to: Linux Iptables block common attacks

Related articles found on that site are Using iptables to secure a Linux based Asterisk installation against hack attempts and Securing Asterisk – Fail2Ban (and that latter article looks suspiciously similar to this one: Fail2Ban (with iptables) And Asterisk).

I don’t know how valid or useful any of this is, but if you are running iptables on your system (if you’re not sure enter iptables -V on the command line — it should show you the version of iptables that is installed, if it is installed) then you might want to check these articles out.  And if you find an earlier source for any of these, let me know and I’ll include the links.  I know that in the technical community sometimes information gets copied around, but would it kill you guys to give attribution and a link to the original source when you are lifting information (or even raw text) from someone else’s article?

Geolock — a Perl script for Asterisk or FreePBX users to enhance security

 

Important
This is an edited version of a post that originally appeared on a blog called The Michigan Telephone Blog, which was written by a friend before he decided to stop blogging. It is reposted with his permission. Comments dated before the year 2013 were originally posted to his blog.

I created the following Perl script and have been running it for a week or so, and it seems to be working well.  The idea is that this script runs once per minute, and whenever a SIP or IAX extension is registered with your Asterisk system the script looks at the IP address that the extension is registering from, and if that address is outside your home country (the United States by default), the IP address is immediately banned using IPtables.  So, your remote extensions could be anywhere in your home country and connect to your system, but if a hacker from some other nation penetrates your system and somehow guesses one of your passwords, they will (in theory) have less than a minute to do any damage before they are banned. And once they are banned, the rightful user of that extension should still have no difficulty connecting, as long as they are not coming in from outside your home country.

For those of you that don’t have any extensions connecting from outside your home country, consider this another tool in your arsenal of defenses against intrusions.  Combine it with strong passwords, and Fail2Ban with IPtables for additional security.

NOTE THAT THIS SCRIPT IS NOT GUARANTEED TO DO ANYTHING AT ALL, other than take up space on your computer.  IT SHOULD STILL BE CONSIDERED EXPERIMENTAL until there has been more testing on it.  I believe it works properly, but have no way to do extreme testing on it to see if or how it might break. THERE IS NO WARRANTY OF ANY KIND!!!

Prerequisite: Obviously, you must have IPtables installed and functioning properly, and you must install either the Geo::IP or Geo::IP::PurePerl Perl module (do NOT install both!). You can install one of these using Webmin (using Webmin’s Others | Perl modules page), or in any other way you usually install Perl modules (e.g. CPAN). The difference between the two was explained in my original article, as follows:

… there is a Perl module called Geo::IP, which calls the GeoIP C API. If you install that API (when downloading, I’d go into the test/ directory and get the latest beta) using the directions on the linked page, and then install the Perl module (you must do it in that order, or installation of the Perl module will fail), you could run a Perl script that shows the location that your off-site extensions are coming in from. If you don’t want to install the API, or can’t figure out how (not difficult if you follow the directions), you can use the Geo::IP::PurePerl Module which is slower, but does not require the additional C library. Just so you know, GeoIP puts its data file at /usr/local/share/GeoIP/GeoIPCity.dat and they suggest that you go to http://www.maxmind.com/download/geoip/database/ every month or so to grab the latest database (the full link for the country database is currently http://geolite.maxmind.com/download/geoip/database/GeoLiteCountry/GeoIP.dat.gz or you can get a much larger city-level database at http://geolite.maxmind.com/download/geoip/database/GeoLiteCity.dat.gz — just make sure you don’t grab a CSV version by mistake!). If you need them, there are installation instructions for the database, although they are primarily for the city-level database. If you buy an account, they’ll give you automatic updates, though I can’t imagine it would be that hard to write a script to do that (or maybe Google could help you find one, or see this message thread).

If the above is confusing to you, I’d stick with the Geo::IP::PurePerl Module. That should at least get you going. You also need the Perl Sys::Syslog module (unless you want to omit all the syslog-related instructions), though chances are you may already have that one.

Now, here is the Perl script. I called it geolock.pl (although you are free to name it whatever you want), and I put it in the /var/lib/asterisk/agi-bin/ directory and made it executable. Note this is in a code block so the long lines will overflow the column width, so you need to copy and paste this into a text editor. Also there are certain lines you will need to change, as explained below:

#!/usr/bin/perl
use strict;
use warnings;
use Geo::IP;
use Sys::Syslog;
my $gi = Geo::IP->new(GEOIP_STANDARD);
my ($ext, @peerline, @extension, $ipaddress, $country, $shellcmd);
my $flag = 0;

my @sippeers = `asterisk -rx "sip show peers" | grep -v 192.168.0. | grep ^[1-9] | grep -v "(Unspecified)" | grep / | sort -n`;
# change grep statements in above line to match your local IP range (1st grep) and first digits of extensions (2nd grep)
foreach (@sippeers) {
@peerline = split(" ");
$ipaddress = $peerline[1];
$country = $gi->country_code_by_name($ipaddress);
@extension = split("/",$peerline[0]);
$ext = $extension[0];
#    print "Extension $ext has IP address $ipaddress which is in country $countryn";
if ($country && $country ne 'US') {
$shellcmd = `iptables -D INPUT -p ALL -s $ipaddress -j DROP 2>&1`;
system("iptables -A INPUT -p ALL -s $ipaddress -j DROP");
openlog($0,'pid','user');
syslog('notice', "Banning IP address $ipaddress in $country because Asterisk SIP Extension $ext is connecting from there");
closelog;
if (index($shellcmd, "Bad rule") >= 0) {
$shellcmd = 'echo "This is an automated message - please do not reply. IP address ' . $ipaddress . ' in country ' . $country . ' was banned in iptables because Asterisk SIP extension ' . $ext . ' was connecting from there." | mail -s "IP address banned on Asterisk box" root@localhost';
system($shellcmd);
$flag = 1;
}
}
}

### INCLUDE THIS NEXT SECTION ONLY IF YOU HAVE IAX2 EXTENSIONS ###
my @iaxpeers = `asterisk -rx "iax2 show peers" | grep -v 192.168.0. | grep ^[1-9] | grep -v "(Unspecified)" | grep -v "iax2 peers" | sort -n`;
# change grep statements in above line to match your local IP range (1st grep) and first digits of extensions (2nd grep)
foreach (@iaxpeers) {
@peerline = split(" ");
$ipaddress = $peerline[1];
$country = $gi->country_code_by_name($ipaddress);
$ext = $peerline[0];
#    print "Extension $ext has IP address $ipaddress which is in country $countryn";
if ($country && $country ne 'US') {
$shellcmd = `iptables -D INPUT -p ALL -s $ipaddress -j DROP 2>&1`;
system("iptables -A INPUT -p ALL -s $ipaddress -j DROP");
openlog($0,'pid','user');
syslog('notice', "Banning IP address $ipaddress in $country because Asterisk IAX2 Extension $ext is connecting from there");
closelog;
if (index($shellcmd, "Bad rule") >= 0) {
$shellcmd = 'echo "This is an automated message - please do not reply. IP address ' . $ipaddress . ' in country ' . $country . ' was banned in iptables because Asterisk IAX2 extension ' . $ext . ' was connecting from there." | mail -s "IP address banned on Asterisk box"
root@localhost';
system($shellcmd);
$flag = 1;
}
}
}
### END OF SECTION ONLY NEEDED IF YOU HAVE IAX2 EXTENSIONS ###

if ($flag == 1) {
`asterisk -rx "restart now"`;
}
else {
openlog($0,'pid','user');
syslog('info', "Completed normally");
closelog;
}

These are the things you need to change for your local installation:

  • If you used the Geo::IP::PurePerl module then be sure to change the two references to Geo::IP to Geo::IP::PurePerl.
  • Remove the optional section for IAX2 extensions if you don’t have any of those (but keep it if you have any IAX2 extensions, even if they are only internal ones).
  • In the line(s) “if ($country && $country ne ‘US’) {” change US to the code for your home country if you are somewhere else in the world. You could also create a more expansive conditional statement here to allow multiple countries, or a more restrictive ones if you want to block an IP that doesn’t resolve to any country (I consider that a database error, but maybe you don’t). If you have installed the city-level database, you could even (in theory) test for something other than country, such as a state or province, city, time zone, ISP, etc. This line appears in the SIP section and also the optional IAX2 section, so make sure you change both lines if necessary.
  • There are two instances of root@localhost in the above script (in the SIP section and also the optional IAX2 section), which you should change to a valid e-mail address if you want to receive e-mail notifications when an IP address is banned. If you don’t want to receive such e-mail notifications, then comment out or remove those two lines in their entirety (they start with: $shellcmd = ‘echo “This is an automated message …) and also remove the following system($shellcmd); line(s).

The following apply to the two lines that begin with "my @sippeers” and, in the optional IAX2 section, “my @iaxpeers”:

  • Change “grep -v 192.168.0.” to a regular expression or pattern that will match it IP address of all extensions on your local network.  The pattern as shown works if all your local extensions will be in the range 192.168.0.x. Since you can use a regular expression, you could do something like “grep -v 192.168.[1-5].” which would match any local address from 192.168.1.0 through 192.168.5.255.
  • Change grep ^[1-9] to match the first digit of your extensions – as shown, anything starting with a digit 1 through 9 would be considered an extension.  The idea here is that we only want to look at extensions, not trunks (which you can restrict using permit and deny statements, if necessary). Most trunks don’t begin with a number (when you do a “sip show peers” or “iax2 show peers” listing from the CLI), so this is what separates extensions from trunks.  You may have to get a bit more creative if you have a trunk that starts with a number that overlaps your extensions. If you run the entire section between the backticks (the ` characters) from a Linux command prompt,  it should show you all of your connected non-local (that is, not on your internal network) SIP or IAX extensions (depending on which line you run), but no trunks, local extensions, offline extensions, or header information.

Sharp-eyed readers may observe that I first try to delete an iptables rule before creating it.  That’s because I don’t want to create the same rule multiple times (iptables happily accepts duplicates, unfortunately).  If I get an error when trying to delete the rule, then I know that what follows will be the first attempt to create it, and I should send an e-mail and restart Asterisk when we’re all finished.  Basically, it’s supposed to be a safety mechanism to keep from repeatedly sending the same e-mail, or restarting Asterisk once a minute if for some reason the iptables rule doesn’t “take” at first.

Again, don’t forget to make the Perl script executable, and run it manually a few times to watch the output (uncomment the commented-out “print” lines during initial testing – you can remove them once you are satisfied it’s working as it should be).  After you have run it a few times, from the Linux command prompt do iptables –list and make sure everything looks okay there.

One thing you should be aware of is that when this script detects an intrusion attempt (a connection from outside the United States), after it bans the IP address it restarts Asterisk, which will interrupt any calls in progress.  That’s deliberate; I assume you want to throw the hackers off your system right now, even if it means your users may have to re-dial their calls. Howerver, if for some reason you don’t want to do that, then you can change the line `asterisk -rx “restart now”`; to `asterisk -rx “restart when convenient”`;, which will wait until there is no usage on your system to restart Asterisk.  In that case, good luck to you if the hacker just placed a call to some $100-a-minute destination! In theory IPtables will interrupt the conversation (no audio will pass) BUT that does not mean Asterisk will tear the call down right away – when an extension “just disappears”, Asterisk tends to wait a LONG time to see if it will come back, and if it never does, well that’s what we call a “zombie” call — it just won’t die (at least not until the other end disconnects)! EDIT: If you don’t want to restart the whole system but do want to throw the hacker off NOW, see the modification by “Florent” in the comments below — I have NOT tested his changes personally, but they may do what you want.

The final step is to make this execute once a minute.  I used Webmin’s “System | Scheduled Cron Jobs” to set this up:

cron job setup using WebminBut if you are more comfortable creating a cron job from the command line, by all means, feel free to do so.

Finally, I always say that suggestions for improvement are welcome, and also, if you want to translate this into some other programming language, you have my blessing. Please be sure to test it thoroughly before relying on it, because if someone manages to hack through anyway, I’m not going to pay your phone bill! Once again, the above should be considered experimental code and is not guaranteed to do anything at all.

Stop entering passwords: How to set up ssh public/private key authentication for connections to a remote server

 

Important
This is an edited version of a post that originally appeared on a blog called The Michigan Telephone Blog, which in turn was reposted with the permission of the original author from a now-defunct Macintosh-oriented blog. It is reposted with his permission. Comments dated before the year 2013 were originally posted to The Michigan Telephone Blog.

This article assumes that you are already able to ssh into a remote server using a password (that is, that your account has been created on the remote system and you are able to access it). Here’s how to set up ssh public/private key authentication so you don’t have to use the password on future logins, or so you can use Public Key authentication with MacFusion.

First, open a terminal or iTerm window as we will be using it for most of the following operations. First, navigate to your home directory, and see if there is a folder called .ssh. Note that Finder will NOT show you this directory unless you have it set to show all file extensions, so since we are at a command line prompt anyway, it’s easiest to just type “cd ~” (without the quotes) to go to your home directory in Terminal or iTerm and type “ls -a” (again without the quotes – always omit the quotes when we quote a command) to see if the .ssh directory exists. If it does, go into the directory (”cd .ssh”) and see if there are two files called id_rsa and id_rsa.pub (use “ls -a” again). If either the directory or the files do not exist, you will need to create them.

ssh-keygen -t rsa -f ~/.ssh/id_rsa -C "your@emailaddress.com"

Replace your@emailaddress.com with your email address – this is just to make sure the keys are unique, because by default it will use your_user_name@your_machine_name.local, which might come up with something too generic, like john@Mac.local. It’s unlikely that anyone else is using your e-mail address in a key.  If this process fails with a “Permission denied” error, it might be because SELinux is enabled.  To check that theory, see How to Disable SELinux, which will show you how to disable it temporarily (for testing) or permanently.

Now, from your terminal window on your local system, execute this command:

ssh-copy-id username@remote

You can run ssh-copy-id -h or man ssh-copy-id to see the available options, but normally you don’t need any. In the event your system does not have ssh-copy-id installed, you can instead run the following three commands from a terminal or iTerm window on your local system. Whichever method you use, replace username with your login name and remote with the address of the remote system. Note that you should NOT be logged into the remote system when you execute these – these are run from a command prompt on your local system, and you probably will be prompted to enter your password (for the remote system):

ssh username@remote ‘mkdir ~/.ssh;chmod 700 ~/.ssh’

The above creates the .ssh directory on the remote system and gives it the correct permissions. If the command fails (for example, I’ve had it complain that mkdir isn’t a valid command, even though it is on just about every Unix/Linux system), then either you have copied and pasted the above line and WordPress changed the single quotes to the “prettified” versions (so change them back) or you may have to actually log into the remote system (using a password) and enter the two commands individually (mkdir ~/.ssh followed by chmod 700 ~/.ssh). Then, if you don’t already have an authorized_keys file on the remote system, go back to your local terminal or iTerm window for this:

scp ~/.ssh/id_rsa.pub username@remote:~/.ssh/authorized_keys

The above creates a new list of authorized keys on the remote system (overwriting any existing file with that name) and copies your public key to it.  If you already have such a file and don’t want it overwritten, then you’ll have to manually add the contents of your local ~/.ssh/id_rsa.pub file to the end of the ~/.ssh/authorized_keys file on the remote system.

ssh username@remote ‘chmod 600 ~/.ssh/authorized_keys’

This fixes the permissions on the authorized_keys file on the remote system. Once again, there may be the odd situation where you can only run the command within the single quotes from the remote system.

And, that’s basically all there is to it. If you are the system administrator of the remote system, but you don’t ever plan to login from a remote location as root, then for extra security edit the file /etc/ssh/sshd_config on the remote system (you’ll probably have to be root, or use sudo to do this task). Just use your favorite text editor on the remote system to open the file, and look for a line that says:

PermitRootLogin yes

And change the “yes” to “no”.

If you are still asked for a password after you are finished making the above changes, look for a line in /etc/ssh/sshd_config that says:

StrictModes yes

And change the “yes” to “no”. You’ll need to reboot or restart the ssh server for this to take effect. An alternate, and probably more secure fix is to check the permissions on your home directory – if it is not writable by anyone but the owner, then it should not be necessary to change the StrictModes parameter. For more troubleshooting hints see Debugging SSH public key authentication problems.

The above are very basic instructions for setting up ssh public/private key authentication. There are other ways to do this (including some that are arguably a bit more secure) but we wanted to keep it simple. Hopefully this will help someone who is using ssh, MacFusion, etc. and wants something a bit more secure and less bothersome than password access.

One other note:  If you find the connection drops within a minute or so, particularly after you’ve just purchased a new router, then on the client machine running Mac OS X edit the file /private/etc/ssh_config (under Linux it’s /etc/ssh/sshd_config and I don’t know what it would be called under Windows, or if they even have such a file) and add this line:

ClientAliveInterval 60

If it still stops working lower the timeout to 30. See How to fix ssh timeout problems for more information.

If you find my instructions confusing, try SSH Passwordless Login Using SSH Keygen in 5 Easy Steps.

And, for hints on making ssh more secure (particularly if you permit access from the Internet in general and not just your local network), see this article on Securing OpenSSH (via the CentOS wiki).

Recent Posts

Recent Comments

Archives

Categories

Meta

GiottoPress by Enrique Chavez