Back to my Homepage
Did this site help you?
Average rating (La Fonera):
2.71/3 (1399 votes)

Hacking the La Fonera

The La Fonera is a wireless access point given away for free by FON under the condition that you connect it and allow other users to use it. It is based on OpenWRT, but is locked down to prevent tampering with its software. However, it is possible to inject Shell code into the system as I found out together with Michael Kebe.

Overview

Note: As of 8th of november 2006, FON has fixed the bug in the web form, so the method presented here does not work anymore. Of course, there is a new method available to open your device. With firmware 0.7.1-2, this method has also been invalidated by FON. We have prepared a new method, this time called kolofonium, which is the most advanced method (and the easiest one for you) yet. Devices that did not come with firmware 0.7.1-2 can simply be reset back to their default firmware and opened with the earlier methods, however Foneras with 0.7.1-2 preinstalled are appearing now. Kolofonium also works with firmware versions up to 0.7.1-5.

How configuration is done

The La Fonera is a locked down system: Configuration is usually not done on the real device, but instead it retrieves its setup data from the FON server. So to configure your network parameters like public and private ESSID or WPA passphrase, you log in to your FON account and change the settings on their website. During boot the boot sequence, the La Fonera then contacts the FON server and retrieves its network configuration. However, a web interface on the router to configure the device does exist as well.

FON also made it impossible to flash a new firmware, since the firmware binaries are signed: Firmware files not carrying the corrects signature are rejected by the system. Although FON has released the source code to the software running on the router, they are not forced to release the key necessary to run the software on their device. This is fine with GPLv2, and one of the main aspects that concern GPL version 3.

So exchanging the firmware is out of option, since there is no way of uploading a working firmware image without posession of the correct cryptographic key: This has also been an issue with the TiVo digital video recorder.

Taking a look at the configuration retrieval

During startup (and on a regular basis), the La Fonera "phones home" to check whether configuration data has been changed. This is done using an SSH connection to download.fon.com on port 1937. You can check for yourself:

stefan@nano:~$ telnet download.fon.com 1937
Trying 213.134.45.191...
Connected to download.fon.com.
Escape character is '^]'.
SSH-2.0-OpenSSH_3.8.1p1 Debian-8.sarge.4

Your router then proceeds to send some information identifying itself, including its MAC addresses and software versions:

mode='start' wlmac='WIRELESS MAC' mac='LAN MAC' fonrev='4' firmware='0.7.0' chillver='1.0' thclver='1.0' device='fonera'

In return, FON sends some shell code, including instructions how to configure the wireless devices (WPA passphrase, ESSIDs).

SSH is an excellent choice from FON's point of view, since it is relatively easy to deploy in a noninteractive context, and provides an elegant way of avoiding spoofing: For the key of download.fon.com is stored on the router, we cannot simply proclaim to be that host it tries to contact and supply our router with our own shell commands.

Authentication is done using a secret key stored on every router and inside the source. However, the Dropbear SSH client is required to use it, OpenSSH demands a password for reasons unknown, while Dropbear does not. Using dbclient it is quite easy to establish a connection with the FON server and retrieve configuration data for our La Fonera:

echo "mode='start' wlmac='' mac='' fonrev='4' firmware='0.7.0' chillver='1.0' thclver='1.0' device='fonera'" | dbclient -T -i key -p 1937 openwrt@download.fon.com

There is no reply, since we left both MAC adresses empty. If we'd use the addresses of an actual La Fonera, we probably would just get this:

rm -f /tmp/.thinclient.sh
    
exit

The file /tmp/.thinclient.sh is the location the output is stored and executed afterwards by the update script. So since FON decided that there is nothing to do, the script removes itself and exits.

If you changed some values in your FON web interface prior to retrieving the data, things will look different: If you change your ESSID, the commands for doing so are transmitted to your router by a bunch of shell commands:

# begin # setssidprivate
awk -v cfgfile="/etc/config/fon" -v "updatestr=private.essid=YOURPRIVATEESSID" -f /usr/lib/webif/uci-update.awk -f - > /etc/config/fon.new <<EOF
BEGIN {
    cfg = read_file(cfgfile)
    print update_config(cfg, updatestr)
}
EOF
if [ $? -eq 0 ]; then
    mv /etc/config/fon.new /etc/config/fon
    ifup lan
else
    rm /etc/config/fon.new
fi
# end # set ssid fonera

# begin # set ssid fonera
awk -v cfgfile="/etc/config/fon" -v "updatestr=public.essid=YOURPUBLICESSID" -f /usr/lib/webif/uci-update.awk -f - > /etc/config/fon.new <<EOF
BEGIN {
    cfg = read_file(cfgfile)
    print update_config(cfg, updatestr)
}
EOF
if [ $? -eq 0 ]; then
    mv /etc/config/fon.new /etc/config/fon
    iwconfig ath0 essid FON_'YOURPUBLICESSID'
else
    rm /etc/config/fon.new
fi
# end # set ssid fonera
    rm -f /tmp/.thinclient.sh
exit

Similar code is transferred for changing the WPA passphrase.

How code can be injected

As you can see, FON did take some precautions to prevent people injecting code: Parameters are enclosed in single quotes to avoid substitutions of any kind. The entering of strange characters is prohibited by the web interface, and even if you manage to get a single quote character into your ESSID, it will be "defused" by prepending a backslash to it.

The kind of injection attack we are trying to do is quite similar to SQL injections: Our aim is to place data into the system that ends the running command (e.g. the iwconfig call) and then starts a new command.

iwconfig ath0 essid FON_'YOURPUBLICESSID'

To use this line as an entry point, we have to substitute YOURPUBLICESSID with something that ends the parameter environment for iwconfig: For single quoted strings, the only character capable of doing so is ', a "closing" single quotation mark. Even a newline character is unable to end the current command line and will be treated as a parameter for iwconfig.

Unfortunately, FON simply replaces any ' with the string \' to avoid such injections. Adding a backslash to a character with special meaning removes its special abilities, so the danger of letting an intruder in is averted.

But wait, is it? I was quite surprised when I consulted the bash manual page:

Enclosing characters in single quotes preserves the literal value of each character within the quotes. A single quote may not occur between single quotes, even when preceded by a backslash.

So a single quote always closes a string surrounded by single quotes, whether it is prepended by a backslash or not. You can check for yourself by executing this little command in your shell:

stefan@nano:~$ echo 'foo\'bar'
>

Instead of printing foo\'bar, bash still waits for a fourth quotation mark, since the quoted string opened by the ' at the end is not closed.

We actually managed it to get code injected this way: All you have to do is include a single quote character and a newline in your ESSID field. Of course, this is not possible with a webbrowser, since FON tries to protect its Interface using Javascript, and entering a newline into a input field could prove rather difficult. There is however a Perl module called WWW::Mechanize that allows a script to walk a website just like a normal user would do: using this script, it was indeed possible to put arbitrary commands into the script retrieved from the FON server.

We then used this open window to open up port 22 and launch the dropbear SSH server, providing us with full shell access to the router.

Climbing through the window and opening the front door

The result of our experiments is a Perl script called shellfon.pl: It takes your email address and your FON password from the command line, and reads shell commands to be executed on the router from standard input. It then logs into FON, places the manipulated SSID. All you have to do then is to reboot your La Fonera.

To start and open up SSH you will need the following command line, which will open the firewall on port 22 and launch dropbear:

echo -e '/usr/sbin/iptables -I INPUT 1 -p tcp --dport 22 -j ACCEPT\n/etc/init.d/dropbear' | perl shellfon.pl email password

After that, follow the guide on this site to permanently enable shell access. Don't forget to take a look at the web interface again to set your SSID to something meaningful again.

Preventing FON from executing code on your box

As I already pointed out, La Fonera receives instructions from FON through the SSH link. This is done by the script /bin/thinclient:

[...]
    . /tmp/.thinclient.sh

If you want to prevent La Fonera from executing that received code, you might want to change the final lines to

### Don't execute code from FON
# . /tmp/.thinclient.sh

Since there might be useful bugfixes from time to time, you could also copy or move the sent script somewhere else for later approval:

cp /tmp/.thinclient.sh /tmp/thinclient-$(date '+%Y%m%d-%H%M')

This way, you can check them from time to time to see what FON is up to.

Something more advanced

If you'd like to keep track of FON updates without filling your box with count- und useless thinclient scripts, try this shell script fragment:

#. /tmp/.thinclient.sh                                                                                                                                      
TCDIR="/etc/thinclient-scripts/"                                                                                                                             
LASTFILE="$(ls $TCDIR | sort -n | tail -n1)"                                                                                                                 
COPY=0                                                                                                                                                       
                                                                                                                                                             
if [ -z "$LASTFILE" ]; then                                                                                                                                 
    COPY=1                                                                                                                                                   
else                                                                                                                                                         
    LASTCS="$(md5sum $TCDIR/$LASTFILE | cut -d\  -f1)"                                                                                                       
    NEWCS="$(md5sum /tmp/.thinclient.sh | cut -d\  -f1)"                                                                                                     
                                                                                                                                                             
    echo "$LASTCS $NEWCS"                                                                                                                                    
    if [ "$LASTCS" != "$NEWCS" ]; then                                                                                                                       
        COPY=1                                                                                                                                               
    else                                                                                                                                                     
        echo "Already seen this file."                                                                                                                       
    fi                                                                                                                                                      
fi                                                      
                                                        
if [ "$COPY" -eq 1 ]; then                              
    NEWFILE="$TCDIR/thinclient-$(date '+%Y%m%d-%H%M')"
    echo "Copying new instruction set to $NEWFILE"    
    cp /tmp/.thinclient.sh $NEWFILE                     
else                                                    
    echo "Nothing new here."                            
fi

This code checks whether the reply from the server is new or already known, and stores new instructions in /etc/thinclient-scripts/ - a directory you should create.

Local code injection

Since it was obvious to us that FON would close the web interface bug quite fast, we tried to locate other methods of code injection prior to publishing our first hack: Identifying exploitable holes in the local webinterface of the router was considered vital to our goal of keeping La Fonera an open system.

Local code injection I: grammofon

The result of our efforts is the script grammofon.pl which exploits a shortcoming in the firmware verison 0.7.0-4: This is the version the current La Fonera devices are delivered with, so if you unpack your La Fonera with the intention of hacking it, the following procedure will work:

Because of some limitations of the exploited formular field, we have to send each command on its own (newline characters as well as the semicolon inside the command will break the hack); And since not much text is allowed in that specific field, grammofon.pl sends the command in several chunks, constructs a temporary shell script from it which then is executed on the device. Quite tricky :-)

Once the router is connected to the Internet, it will upgrade its firmware to version 0.7.1-1, rendering this exploit useless. You can however, since the upgrade procedure is just a hotfix, reset the device to its delivery state - reenabling the grammofon method.

Local code injection II: fondue

Several holes have been closed with the latest firmware upgrades, but with the latest version (0.7.1-1) a new page in the configuration interface was introduced which - of course - is again prone to code injection.

Michael and I again created a perl script to exploit this flaw and open the router, just like our famous shellfon.pl used to, but this time, no communication with the FON server is necessary, just connect the script directly to the router and execute it.

We christened the script fondue.pl, since the time for completely opening the router software is due, and because using the name of a dish consisting of molten cheese getting picked with long forks is quite funny. Now laugh.

To open your router, simply run the following command:

echo -e '/usr/sbin/iptables -I INPUT 1 -p tcp --dport 22 -j ACCEPT\n/etc/init.d/dropbear' | perl fondue.pl ipaddress password

With the latest update to 0.7.1-2 on the third of january, FON has also closed this loophole. However, I saved an image of the 0.7.1-1 firmware, although this image cannot be flashed on La Fonera device through the web interface in order to exploit this flaw, since it does a version check upon installation. However, if your La Fonera was shipped with a firmware version lower than 0.7.1-2, you can use the reset button to restore this original version and use one of the above hacks to gain access.

Kolofonium: A hack for 0.7.1-2

As I pointed out, FON closed most vulnerabilities in the web interface with firmware 0.7.1-2. Michael an I however could identify another flaw in the design of La Fonera that makes SSH access even easier for you. On our side, this was the most complex hack of all, but we did some testing and are about to release it. We kept you waiting for some time now, because we wanted to wait until 0.7.1-2 is really shipping preinstalled on most routers; earlier devices can be reset without trouble and afterwards put through the fondue or grammofon process.

The new hack does not utilize the web interface for its command injection. Since the FON developers did their homework this time while developing 0.7.1-2, I had to find a different way to start the SSH daemon. During my investigation, I tried to find a loop hole in the automatic configuration retrieval method, but since La Fonera is using a link secured by SSH to retrieve its data, this was doomed to failure.

Hey, what's that?

However I noticed that the SSH link to download.fon.com is not the only source of configuration data. During the boot procedure, the init script /etc/init.d/N50chillispot is executed. This script then starts the chillispot daemon responsible for providing the public wifi signal. However, there is something interesting about the script:

[...]
TMP_C=/tmp/chilli.conf
ETC_C=/etc/chilli.conf
PID_F=/var/run/chilli.pid
PID_LOOP_F=/var/run/chilli_loop.pid
LOG_LOOP_F=/var/log/chilli_loop.log
WANIP="$(ifconfig "$wan_ifname" | grep inet | awk -F'[: ]+' '{print $4}')"
MAC=$(ifconfig wifi0 | head -n1 | awk '{print $5}'|sed s/:/-/g)
MAC=${MAC:-fon}
LOOP=true
DELAY=86400
SECONDS=0
DELAY2=10
SECONDS2=0

RADIUSSERVER=radius01.fon.com
RADIUSSECRET=garrafon
RADIUSADMUSR=chillispot
RADIUSADMPWD=chillispot
[...]
radconfig() {
        /usr/sbin/chilli_radconfig \
                -c /dev/null \
                --radiusserver1="$RADIUSSERVER" \
                --radiussecret="$RADIUSSECRET" \
                --adminuser="$RADIUSADMUSR" \
                --adminpasswd="$RADIUSADMPWD" \
                --radiusnasid="$MAC" \
                --dhcpif $wifi_ifname \
                > $TMP_C
        [ -n "$(cat $TMP_C)" ] && {
                MD5SUM_TMP=$(md5sum $TMP_C | awk '{ print $1 }')
                MD5SUM_ETC=$(md5sum $ETC_C | awk '{ print $1 }')
                if [ ! "$MD5SUM_TMP" = "$MD5SUM_ETC" ]; then
                                rm $ETC_C
                                mv $TMP_C $ETC_C
                                circular_log $LOG_LOOP_F "RELOAD"
                                do_reload
                else
                                circular_log $LOG_LOOP_F "NO RELOAD"
                fi
                return 0
        }
        circular_log $LOG_LOOP_F "NO RELOAD"
}
		

The program /usr/sbin/chilli_radconfig is actually used to download the chillispot config from FON. It is retrieved from the FON radius server, who by the same method notices the activation of a FON node and creates a unique ID: This is the strange random string in your uamserver directive inside /etc/chilli.conf. By using that number as the redirection target for your foneros, the FON servers can safely relate them to your specific access point. The unique string however cannot be compared to the unique MAC address, although the MAC address might play a role in its generation (See the radiusnasid parameter in the chilli_radconfig call). It indeed changes on every boot and i generated by the remote server.

As you can see, the retrieved coniguration is written to a temporary file and, should it differ from the present configuration, moved to its correct position. Afterwards, the chillispot daemon is reloaded.

How to exploit it

While FON took some precautions to secure the better known configuration link through the use of SSH encryption and authentication, they somehow forgot to do the same to their radius login. Indeed the configuration is contained in some vendor specific attributes carried by the RADIUS reply - unencrypted. To exploit this flaw, a custom RADIUS server has to be set up that allows logins from La Fonera devices and supplies them with manipulated attributes. On the other side, the to be hacked La Fonera has to contact this spoofed server instead of the official one.

The second aspect is easy to achieve: When chilli_radconf tries to contact radius01.fon.com, the process is prone to DNS spoofing: you can just setup a small DNS server that resolves radius01.fon.com to another IP adress, where your modified RADIUS server is just waiting for your device to request some configuration advice. This is made easy by the fact that you can specify your own DNS server through the La Fonera web interface.

Setting up a fake RADIUS server

To spoof the FON RADIUS server, I chose XTRadius since it was easy to install on my Debian system and claimed to be customizable by shell or perl scripts. This however proved to be more difficult than I thought.

At first, I added the IP address of my La Fonera to the file /etc/raddb/clients:

192.168.10.1	garrafon

The encryption key garrafon is identical on all La Fonera devices, so you don't have to guess.

To ship configuration data through the RADIUS communication, the RADIUS server must know the unique IDs used by them; This can be achieved by adding a file /etc/raddb/dictionary.fon to your XTRadius configuration:

VENDOR		Fon		14559
ATTRIBUTE	CHILLICONF	6	string	Fon

With that preconfiguration done, we can now add a user to our RADIUS server. Just add the following lines to the file /etc/raddb/users:

chillispot Auth-Type = External
        Exec-Program-Wait = "/etc/raddb/fonera.sh",
        CHILLICONF = "radiusserver1 radius01.fon.com",
        CHILLICONF = "radiusserver2 radius02.fon.com",
        CHILLICONF = "radiussecret garrafon",
        CHILLICONF = "dhcpif eth1",
        CHILLICONF = "uamsecret garrafon",
        CHILLICONF = "uamanydns",
        CHILLICONF = "uamallowed www.martinvarsavsky.net,www.google.com,www.flickr.com,static.flickr.com,video.google.com,216.239.51.0/24,66.249.81.0/24",
        CHILLICONF = "uamallowed www.fon.com,www.paypal.com,www.paypalobjects.com,www.skype.com,66.249.93.0/24,72.14.207.0/24,72.14.209.0/24,84.96.67.0/24,213.91.9.0/24,80.118.99.0/24",
        CHILLICONF = "uamallowed shop.fon.co.kr,secure.nuguya.com,inilite.inicis.com,fon-en.custhelp.com,maps.fon.com,c20.statcounter.com",
        CHILLICONF = "uamserver https://login.fon.com/cp/index.php",
        CHILLICONF = "# Greetings from Michael and Stefan",
        CHILLICONF = "# http://mrmuh.blogspot.com/ & http://stefans.datenbruch.de/lafonera/",
        CHILLICONF = "uamallowed stefans.datenbruch.de",
        CHILLICONF = "ipup /etc/init.d/dropbear",
        Fall-Through = 0
		

This simply adds a user chillispot, whose authentication data is alway accepted. With the acknowledgement of the successfull login, the user is supplied with various custom attributes, consisting of configuration lines. The key aspect is the line containing ipup /etc/init.d/dropbear: This instructs chillispot to launch the Dropbear SSH daemon once the public wifi interface has been created.

The original idea was to supply the configuration parameters through the script specified by Exec-Program-Wait: Altough that should be possible by printing to the standard output, the parser inside XTRadius cannot handle the spaces present in the configuration strings - thats why I reverted to a static configuration. The script /etc/raddb/fonera.sh is just a mostly empty shellscript that does nothing more than exit 0 to indicate XTRadius that the user information has been accepted.

Some enhancements

As seen above, each client willing to connect to the RADIUS daemon must be specified in /etc/raddb/clients. While this is fine for most real uses of RADIUS, it is quite annoying for the thing we are aiming at with this hack. Although lacking any knowledge of C, I tried to create a patch to XTRadius that made it possible to specify a wildcard (*) in the clients file. I succeeded, but it sure is ugly and might crash without warning.

Hard for us, easy for you

This whole procedure sounds quite complicated, and it quite was compared to our earlier hacks. But the good news is that you won't have to do the same things again: If you want to gain access to your La Fonera, simply set the DNS server of your La Fonera to the IP address 188.40.206.43, belonging to the host kolofonium.datenbruch.de. I did setup a small DNS service there that redirects requests to radius01.fon.com to a fake RADIUS server that will supply your router with the configuration data needed to enable SSH access.

The Kolofonium server address has changed! You can retrieve the correct address by resolving the hostname "kolofonium.datenbruch.de", e.g. by issueing a ping request. The hostname will always point to the right IP address you can use as fake DNS server.

Once you reboot your device, the SSH daemon should be started automatically. You can access the service through the internal WLAN, otherwise the packet filter will prevent the access to it.

After you enabled SSH permanently, don't forget to reset the DNS configuration - and don't forget to have fun with your new open device as well.

So far, 16745 fonera devices have been freed by kolofonium (See chart). For this statistic, the mac and ip address of every fonera using the kolofonium service is written to a logfile.

Press

The following news sites reported on this page:

The austrian TV station ORF also requested an (written) interview, which can be read here.

And of course there are countless blogs refering to this page: We really really thank you for your support :-)