During the course of our research into the security of Belkin’s WeMo home automation devices we developed a new technique to leverage a SQL injection vulnerability in a SQLite database for arbitrary command execution. This post documents how we were able to create a SQLite database that can be executed as an ash shell script purely from SQL queries. We think this technique has wider applicability to the penetration testing and vulnerability research communities, and we hope that this post is sufficient to recreate our results.
The most obvious way execute arbitrary code with a SQLite injection vulnerability is to execute a function in a shared library with load_extension(). However, the libsqlite3.so library disables this functionality by default, because it’s an obvious security vulnerability. Another technique found in some SQLite injection cheat sheets is to use an ATTACH DATABASE query to create a SQLite file in the web server’s root directory, and populate it with PHP code that the PHP interpreter will execute when the file is requested.
ATTACH DATABASE ‘/var/www/lol.php’ AS lol;
CREATE TABLE lol.pwn (dataz text);
INSERT INTO lol.pwn (dataz) VALUES (‘<?system($_GET[‘cmd’]); ?>’);--
ATTACH DATABASE first looks to see if a file exists at the specified location. If so, then it attempts to open it as a SQLite database. If not, then it will create the file and leave it open for reading and writing as a SQLite database. In the example above the file lol.php is create in /var/www/ and accessible via the database name lol. Then, a table called pwn is created in that database and a string is inserted into the table. When the file is requested via the web server the php file extension will cause the web server to invoke PHP interpreter. The interpreter searches through the file for token
<? and attempts to interpret the text after that and until the terminating
?> token as PHP code. In this case, the code will execute whatever is in the
cmd GET request variable as a command on the system. That’s quite a handy way to go from SQL injection to arbitrary command execution. However, for systems that are likely to use SQLite databases but don’t have the PHP interpreter, like many embedded systems, this technique won’t work.
SQLite as an ash script
A lot of Linux-based embedded systems use the BusyBox tool suite to implement most of the basic Linux commands. By default BusyBox uses the ash shell to implement /bin/sh. So we decided to see if we could create a SQLite database file that can be executed as an ash shell script using only SQL queries. This is trickier than the PHP case, because ash’s command parser is more complicated than PHP. However, it is significantly easier than attempting this feat with a more complicated command interpreter, like bash.
The first step is to understand that ash’s parser mostly cares about newline characters (i.e. ‘\n’) and parenthesis (i.e. ‘(‘ and ‘)’). That’s because when a user hits enter on a command-line a newline is inserted, and a command surrounded by parenthesis indicates it should be executed in a subshell. So, if we can figure out a way to strategically insert these characters into a SQLite database file, then we can use them to control how that file is interpreted by ash.
The trick to inserting newline characters lies in the fact that SQLite will preserve exactly the queries used to build the database schema. An example of this is shown in the CREATE statement at the top of Figure 1. While the entire statement could easily fit on one line the column definition was put on the next line because the resultant database file will include the newline character in its schema definition.
The bottom half of Figure 1 shows what happens when the database file is run as an ash shell script. The first error ash reports is that it can’t find the command called “SQLite”. That’s because it interpreted the first word of the file as a command, and everything until the newline in the CREATE statement as its parameters. The net effect is making ash ignore a whole bunch of file’s contents just by inserting a newline. Now we just have to figure out how to fix the second error, “unterminated quoted string.”
The way to solve the second error is to just insert another newline. Figure 2 shows how we’ve added the “without rowid;” syntax to the CREATE statement on a new line. The newline character that is inserted after the column definition means that the column definition is now surrounded by newline characters, and will be treated as it’s own line of text when the file is parsed as a script. Indeed, the bottom of Figure 2 shows that when the file is executed as a script the echo column name is interpreted as the echo command, and “none primary key” are echoed to the screen. This technically means we have achieved command execution because we could make the column name (i.e. the command) anything, not just echo. However, it’s not arbitrary command execution because we can’t set arbitrary parameters to the command. In order to have a valid column definition the first word after the column name must be one of a set number of types.
To gain arbitrary command execution we refer back to the PHP example where the desired commands were input as table values. In Figure 3 we leverage the same technique with the caveat that the first and last characters of the string must be newlines. Note that the echo command from the column definition still executes, but so does the ls command that was inserted as the table’s only value.
Now you know how to create SQLite files that are executable as ash shell scripts. This should work on any system that uses the version of ash that comes with BusyBox. Happy hacking!