Entries : Category [ Hacks ]
Hacks published in the hacks section from the wiki
[OpenBSD]  [BSD]  [FreeBSD]  [Linux]  [Security]  [Python]  [Zope]  [Daily]  [e-shell]  [Hacks]  [PostgreSQL]  [OSX]  [Nintendo DS]  [enlightenment]  [Apache]  [Nintendo Wii]  [Django]  [Music]  [Plone]  [Varnish]  [Lugo]  [Sendmail]  [europython]  [Cherokee]  [self]  [Nature]  [Hiking]  [uwsgi]  [nginx]  [cycling]  [Networking]  [DNS] 

13 mayo

OpenSSH port-forwarding only account

How to limit an SSH account so, without a valid shell, it still can create tunnels

OpenSSH is a very powerful and flexible tool (If you didn't know it, go ahead and visit http://openssh.org to learn more about it).

OpenSSH puffy!

Today I had to give access to some localhost-only service to an external user in one of my servers. I've used SSH port forwarding for quite some time now, I'm familiar with it and I thought it would be the better approach. Using port forwarding I wouldn't have to "open" that locahost-only service to the Internet and all the traffic between the external user and the service will pass through the Internet encrypted.

Let me explain you how I achieved that, because It was trickier than expected.

For the purpose of this article, this was tested using FreeBSD 8.2 and OpenSSH 5.4p1 both in the server and the external user box, but it would work with any other Unix-based OS (other BSDs, Linux, OSx, etc)

First - Create the user account

Obviously, if we want the external user to be able to connect to our server, first we need to create an account for him.

In FreeBSD, we can create the account using adduser, passing the needed parameters as a string:

echo "sshguest::::::Guest account:/home/sshguest:/usr/sbin/nologin:" | sudo adduser -w random -f "-"

The username is sshguest (use whatever you like instead) and we let adduser to asign automatically the UID and GID values for this new user (a new group will be created using the username value as the new group name).

We have set /home/sshguest as the home of the user because a home folder will be needed later (to store ssh public key authentication data) but you can set the home for this user to wherever you like in the filesystem (/tmp/sshguest, /var/tmp/sshguest could be good places for that)

As you probably noticed, In the example above we have set the shell to /usr/sbin/nologin, because we don't want the user to have shell access to our server.

Finally, we passed the "-w random" parameter to adduser so the password for this account would be automatically generated. The adduser tool creates some really strong passwords, so this is a good idea (and we are not going to use password-based authentation anyway).

Second - Get the public key for SSH authentication

Now that we've the account, we have to ask our external user for a public key to enable public key authentication.

If your external user has no idea about what public key authentication is (I would bet there is 90% posibilities of that) first point him to the OpenSSH documentation (RTFM!) and then tell him that he can generate the needed keys using, for example, the following command:

ssh-keygen -t rsa -b 2048

Two files will be generated, he has to send you the one called id_rsa.pub

(Of course, you can generate the keys yourself and send him the private key, instead of asking him for the public one)

Third - Enable public key authentication

Once we've received the key, we have to put that key in the file .ssh/authorized_keys inside the sshguest user (if you choose that name in the first place). In our previous example, it would be something like:

# cat /home/sshguest/.ssh/authorized_keys
ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAMEAyjtJMRtejQaDafYfaL+qc9LrhqHhAQnc7TwF/M3BDTJrZ9ucXLejRwvq/OOcRSsOnUGQyYc2w/TbKQE77cHzujd+PBKgdnQfu8hjJ2Q8to+q8gAEJEOscvLwAACq74llZBmD8gHWBXP6vthkPTFZyd7fkEsKkSgGFiWCZBl+YkibLoRrJpuk462XzPWC4KkOjiUwtJ+2PP1ZvMYYvxnWn+IxwQtbDqwDhY3DnN1dYTeUPT1umtrCCtzQjjynHFFb someuser@example.net

Note: we have to create the .ssh directory within the sshguest home directory and we need to be sure proper permissions are applied to both the directory and the file:

mkdir /home/sshguest/.ssh
echo id_rsa.pub > /home/sshguest/.ssh/authorized_keys
chown -R sshguest /home/sshguest/.ssh
chmod 700 /home/sshguest/.ssh
chmod 600 /home/sshguest/.ssh/authorized_keys

Once we have added the authorized_keys file, we can test the authentication connecting from the external user box (or asking him to try):

ssh sshguest@example.net

What the user will see in the shell/console will be something like:

$ ssh sshguest@example.net
Copyright (c) 1980, 1983, 1986, 1988, 1990, 1991, 1993, 1994
      The Regents of the University of California.  All rights reserved.

FreeBSD 8.2-STABLE (GENERIC) #1: Tue Apr 12 12:27:33 CEST 2011

[ ... skip ... ]

This account is currently not available.
Connection to example.net closed.

What happened here? Well, the SSH connection was opened, authentication procceded correctly and the user's shell was loaded. As the shell was set to /usr/sbin/nologin, the system refuses to give a shell to the user and simply drops the connection.

Which, in the end, was what we were looking for, wasn't it?

Four - Fixing the shell problem

Well, that was what we wanted from the beginning, if it would allow us to use SSH's port forwarding features.

Sadly, that's not the case. If we try to open an SSH connection doing some port forwarding, the connection will be dropped too, and the tunnel will not be created:

$ ssh -L 8080:localhost:80 sshguest@example.net

[ ... skip ... ]

This account is currently not available.
Connection to example.net closed.

This happens because we have set /usr/sbin/nologin as the shell for the sshguest user. That, at least in FreeBSD, disables that user logins.

We have to replace it but replacing it with sh, tcsh or bash is not an option (we don't want to give shell access to this user) so we need a fix for that.

One option would be to set a real shell (like sh, tcsh or bash) and then restrict the commands the user will be able to execute. But, as I've said, I don't like the idea of the user being able to start a shell, even if we restrict the comments he will be able to execute later.

Another option, which I personally prefer, is to create a small script that will act as the shell for this user, restricting access completely.

This is a small python script that will do the trick:

command = ''

while command != 'exit':
    command = raw_input('Type the "exit" command to close the connection: ')

The script will wait for user input and, when the user provides the "exit" command, the script will stop execution and the SSH connection will be closed.

We could save this script inside the home of the sshguest user:

mkdir /home/sshguest/bin
# then put the contents of the script inside /home/sshguest/bin/shell
chown -R sshguest /home/sshguest/bin
chmod -R 700 /home/sshguest/bin

and then we could use vipw to modify the user entry, from:

sshguest:$1$ICdMwdEn$3d3X83jdyT8ifLPnl8D8x/:1117:1117::0:0:Guest account:/home/sshguest:/usr/sbin/nologin


sshguest:$1$ICdMwdEn$3d3X83jdyT8ifLPnl8D8x/:1117:1117::0:0:Guest account:/home/sshguest:/home/sshguest/bin/shell

Important: These lines above apply for my current example, in your case it would be different because of the password hash and the UID/GID values.

Obviously, while the python script is being executed (with minimal resources usage) the SSH connection will be kept opened and then the SSH tunnel will work.

$ ssh -L 8080:localhost:80 sshguest@example.net

[ ... skip ... ]

Type the "exit" command to close the connection:

If the user provides the "exit" command, the connection is dropped:

Type the "exit" command to close the connection: exit
Connection to example.net closed.


This is a quick hack. As you can imagine, the script could be improved a lot. We could provide a more complete shell-like interface so our external user can perform certain operations on the server or the connection.

One thing I miss here is the posibility to restrict port forwarding too, allowing the external user to create tunnels only to, for example, a given set of ports or even only one port.

BTW, this hack helped me a lot this morning, I hope it will help any of you one day.

Posted by wu at 11:11 | Comments (2) | Trackbacks (0)
16 mayo

Using SSL to connect to freenode in weechat

Just another reminder for myself.

If NickServ is right, I've been using Freenode for more than 10 years:

NickServ (NickServ@services.): Registered : May 09 23:49:42 2001 (10 years, 1 week, 1 day, 21:51:41 ago)

During all that time, I've used a variety of IRC clients like BitchX, Epic4, Irssi and, lately, WeeChat.

Today I had to connect to the network from an insecure connection. Usually in a situation like that, I just open an ssh connection to a safe host and then I connect to Freenode from that host.

But today I did remember that Freenode offers the posibility to use SSL encrypted connections when connecting to the network.

In order to get that working in WeeChat, you only have to download the SSL CA cert from http://freenode.net/faq.shtml#sslaccess and save it somewhere in your home directory (~/.weechat/ would be a perfect place for that). Then you have to edit your configuration file (~/.weechat/irc.conf in recent versions of WeeChat) and locate the ssl settings:

ssl = off
ssl_cert = ""
ssl_dhkey_size = 2048
ssl_verify = on

By default ssl is disabled, you only have to enable it, set the path to the SSL CA cert you've downloaded from the Freenode website and, important, modify the value of the ssl_dhkey_size parameter, from the default value (2048) to 1024 (otherwise weechat will complain and refuse to connect to the server). You will end with something like:

ssl = on
ssl_cert = "/home/wu/.weechat/GandiStandardSSLCA.crt"
ssl_dhkey_size = 1024
ssl_verify = on

Then you will have to modify the address parameter of your freenode connection, from the non-ssl configuration:

freenode.addresses = "chat.freenode.net/6667"

to the ssl-enabled one:

freenode.addresses = "chat.freenode.net/7000"

And finally you can start WeeChat and you will notice you are using an SSL-enabled connection because your user will be marked with the Z flag:

[00:02] [8] [irc] 1:server[freenode] [Lag: 0,090] [Act: 7,5,6,2,8]

Posted by wu at 22:14 | Comments (0) | Trackbacks (0)
14 julio

Juniper NetworkConnect for OSx

nice to know if you need to quickly connect to a Juniper VPN

Some days ago I got this support request from a customer, asking me if I could take a look at some servers in trouble (someone got in and they wanted to see if any backdoor was left behind, even if they already cleaned the server).

"Sure" - I replied - "just gimme access over SSH and I'll take a look"

All I got instead was an email with an https address, user, password and the words it is a Juniper VPN.

"Ok" - I thought - "let's get a client to connect to that vpn"

It wasn't that easy though. I went to Juniper's downloads website, but in order to download anything, it seemed that first I should know which kind of Juniper product they had installed there.

Reading a bit more, it seems those VPNs over https work directly from the browser. You only had to open that url and identify yourself, and a plugin should run some kind of Java application and open the connection to the VPN.

Well, that did not work for me. For some reason it kept telling me I had a missing plugin and when trying to find out which plugin that was, it was sending me to the Java download page (even if I've Java installed already).

This being a momentary access to a server I won't be accesing anymore, the least thing I wanted was to start installing stuff on my laptop "a lo loco". So I was in kind of a dead end, and I could not connect to the server.

Searching a bit further down Internet Lane, I found this post here: Manually download the Juniper VPN client for mac, which probed to be quite useful.

It seems you can get the proper version of NetworkConnect for OSx directly from the VPN service itself. All you have to do is open the VPN url in your browser, log in, and then access this url:


For example, if the address of the VPN is https://my-juniper-vpn, it should be something like:


Download that and proceed with the install. After opening it for the first time, you will have to provide the https url for the vpn, then the login credentials. Done.

Finally I had access to the server and I was able to confirm there were some backdoors in there, time for some clean up!

Also, a ver interesting link for the time you are done with the Juniper VPN, if you don't need it anymore, how to uninstall/remove it completely:


Posted by wu at 06:26 | Comments (1) | Trackbacks (0)
Prev  1   [2]