Emscripten toy vulnerability

291 views
Skip to first unread message

Charles Vaughn

unread,
Apr 22, 2016, 6:31:10 PM4/22/16
to emscripten-discuss
First of all, let me preface this by saying the security of Emscripten running in a modern browser is excellent, stack smashing and ROP are totally mitigated by the fact that Emscripen runs on top of the JavaScript VM. Emscripten, even with inline JavaScript is compatible with CSP, which can further clamp down on attack surfaces.

That being said, code written for Emscripten can harbor potential security issues. The source code for the toy is here:


The ordinary flow of the program is a user's name and password is loaded into a buffer, then handed off to one of a few possible login methods. There is a function of interest "send_ajax_request", but it is not a candidate for a login handler.

Here is a fiddle showing the vulnerability being exploited. 


By overflowing the buffer, the exploit changes the function pointer to "send_ajax_request", as well as pulling in the secret token. The effectiveness of this type of attack is limited in Emscripten by needing to replace a function pointer with one of the exact same signature.

Hopefully this is an interesting PoC. I'd be interested to hear about other potential interesting vulnerable coding patterns.

juj j

unread,
Apr 24, 2016, 3:54:25 AM4/24/16
to emscripte...@googlegroups.com
Indeed it is possible to nuke the function pointer table, but I don't think this is a vulnerability. In order to be a security issue, it would mean there would have to be some kind of escalation to occur. Handwritten JavaScript and asm.js C/C++ code should be viewed at the same security level or arena in a sense, since the developer is in control of the both. Asm.js does not propose a new security layer where handwritten JS outside to the asm.js module could be allowed to considered untrusted, but the usual web security imposed via domain rules applies here.

You have a great point here though that if one is developing a site that accepts outside JS code and executes it, then content in asm.js modules are no more safe than other content in any other piece of handwritten JS on that site.

If we do consider in the above code snippet that the handwritten JS is the unsafe attacker code, and asm.js side is the assumed "secure" content, then to pull the string topsecret, one does not need to call any function in the asm.js module, but one can directly scan the heap of the asm.js module by iterating through HEAP8, and search for any string data in it. (essentially doing https://en.wikipedia.org/wiki/Strings_(Unix)). This will find the characters of the variable topsecret quite easily.

If you did want to hide a top secret value (the master 4K UHD Bluray encryption keys perhaps) in to the asm.js heap, I would recommend storing it in individual bytes across multiple functions as local data, so that it does not end up in the heap as contiguous memory. This would give at least some obfuscation so that the attacker should likely execute code through to identify where the key is scattered to, unless they can pinpoint the location appropriately where it is assembled together. Even though it is an obfuscation step, it improves the attacker challenge from being able to print out the contents of a typed array to needing to be able to reverse engineer minified asm.js code, which is a good step up in the required effort level. This is parallel to native programs, where the strings tool can easily scan through the data section of any plain sight values.

Cheers,
   Jukka


--
You received this message because you are subscribed to the Google Groups "emscripten-discuss" group.
To unsubscribe from this group and stop receiving emails from it, send an email to emscripten-disc...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Brion Vibber

unread,
Apr 24, 2016, 4:20:36 AM4/24/16
to emscripte...@googlegroups.com
On Sunday, April 24, 2016, juj j <juj...@gmail.com> wrote:
Indeed it is possible to nuke the function pointer table, but I don't think this is a vulnerability. In order to be a security issue, it would mean there would have to be some kind of escalation to occur. Handwritten JavaScript and asm.js C/C++ code should be viewed at the same security level or arena in a sense, since the developer is in control of the both. Asm.js does not propose a new security layer where handwritten JS outside to the asm.js module could be allowed to considered untrusted, but the usual web security imposed via domain rules applies here.

There's no need for untrusted handwritten js here; you just need some function in the asm.js module that you can call that does something you as an attacker want and has the same call signature as the function pointer that gets overwritten.

The rough equivalent in native code is things like forcing a call or return into another part of the executable or standard library that happens to do something the attacker finds useful.

Getting something useful out of the exploit might well piggyback on some further vector once you're inside, such as producing malicious html that later gets inserted into the document by code outside the emscripten module (or could you manage to call something more directly via embind::val etc?) -- but that's not code the attacker has to inject previously ... If they could do that, no need to bother with buffer overflows in the asm.js.

-- brion

juj j

unread,
Apr 24, 2016, 4:40:32 AM4/24/16
to emscripte...@googlegroups.com
Right, agreed, there is no security that asm.js offers here, and it is not any kind of goal of asm.js either. Users can tamper with their asm.js pages just fine if they want, like they can tamper with the handwritten JS pages they are visiting.

In the first message, I read the word "vulnerability" from the perspective of "browser vulnerability", and wanted to point out that asm.js does not have any specialties there.

--

Brion Vibber

unread,
Apr 24, 2016, 5:35:48 AM4/24/16
to emscripte...@googlegroups.com
On Sunday, April 24, 2016, juj j <juj...@gmail.com> wrote:
Right, agreed, there is no security that asm.js offers here, and it is not any kind of goal of asm.js either. Users can tamper with their asm.js pages just fine if they want, like they can tamper with the handwritten JS pages they are visiting.

This sort of thing can often be triggered from off-site web pages by injecting input data via the URL, or through a believed to be secure iframe postMessage API. Or by submitting data from one user to the application's server, that is then shown to another user and run through the asm.js'd code.

Compare with standard XSS and CSRF vulnerabilities on the web; I would consider this a related class of attack vectors.

 
In the first message, I read the word "vulnerability" from the perspective of "browser vulnerability", and wanted to point out that asm.js does not have any specialties there. 

Yeah, the vulnerability is in the JS code, doesn't allow escaping the browser's JS sandboxing.

But the addition of C-based code into the JS code on a site does add buffer overflow and related classes of errors that handwritten JS doesn't usually have, and this example confirms they can be used to overwrite function pointers in a potentially exploitable way against an application. So it's something developers ought to consider in their security planning and reviews, when writing or selecting C/C++ code to use via emscripten.

Lack of address space randomization in the function pointer table also means that an attacker can hardcode the target function pointer override in their attack data, whereas attacking native code you might need to scan or make multiple attempts.

-- brion

Charles Vaughn

unread,
Apr 24, 2016, 6:33:43 PM4/24/16
to emscripten-discuss
Brion does a better job than I did conveying what I was looking at. This is about what a malicious input attack would look like on Emscripten. This particular is interesting since it shows how, in the right circumstances, an attacker can redirect control flow, though in a greatly restricted way compared to C/C++ running on a native machine. It would be interesting to look into something ASLR like for function pointers, though not sure how that would look.
To unsubscribe from this group and stop receiving emails from it, send an email to emscripten-discuss+unsub...@googlegroups.com.

For more options, visit https://groups.google.com/d/optout.

--
You received this message because you are subscribed to the Google Groups "emscripten-discuss" group.
To unsubscribe from this group and stop receiving emails from it, send an email to emscripten-discuss+unsub...@googlegroups.com.

Alon Zakai

unread,
Apr 24, 2016, 6:43:12 PM4/24/16
to emscripten-discuss
ASLR for function pointers is an interesting idea. Sounds easy to do, just create a much larger function table than needed, and fill it with aborting stubs, and randomize the location of the actual function pointers in there. This would have some overhead, though.

To unsubscribe from this group and stop receiving emails from it, send an email to emscripten-disc...@googlegroups.com.

For more options, visit https://groups.google.com/d/optout.

--
You received this message because you are subscribed to the Google Groups "emscripten-discuss" group.
To unsubscribe from this group and stop receiving emails from it, send an email to emscripten-disc...@googlegroups.com.

For more options, visit https://groups.google.com/d/optout.

--
You received this message because you are subscribed to the Google Groups "emscripten-discuss" group.
To unsubscribe from this group and stop receiving emails from it, send an email to emscripten-disc...@googlegroups.com.

Charles Vaughn

unread,
Apr 24, 2016, 11:27:14 PM4/24/16
to emscripten-discuss
One of the things I noticed when getting this toy to work was that Emscripten &'s the values of function pointers in the function table. That actually made the exploit more effective since I could effectively concatenate the secret string. Is there a reason for doing this though? One approach to ASLR could be XOR'ing with a token, leaving any malicious value to likely read out of bounds.


On Sunday, April 24, 2016 at 3:43:12 PM UTC-7, Alon Zakai wrote:
ASLR for function pointers is an interesting idea. Sounds easy to do, just create a much larger function table than needed, and fill it with aborting stubs, and randomize the location of the actual function pointers in there. This would have some overhead, though.
On Sun, Apr 24, 2016 at 3:33 PM, Charles Vaughn <cva...@gmail.com> wrote:
Brion does a better job than I did conveying what I was looking at. This is about what a malicious input attack would look like on Emscripten. This particular is interesting since it shows how, in the right circumstances, an attacker can redirect control flow, though in a greatly restricted way compared to C/C++ running on a native machine. It would be interesting to look into something ASLR like for function pointers, though not sure how that would look.

On Sunday, April 24, 2016 at 2:35:48 AM UTC-7, Brion Vibber wrote:
On Sunday, April 24, 2016, juj j <juj...@gmail.com> wrote:
Right, agreed, there is no security that asm.js offers here, and it is not any kind of goal of asm.js either. Users can tamper with their asm.js pages just fine if they want, like they can tamper with the handwritten JS pages they are visiting.

This sort of thing can often be triggered from off-site web pages by injecting input data via the URL, or through a believed to be secure iframe postMessage API. Or by submitting data from one user to the application's server, that is then shown to another user and run through the asm.js'd code.

Compare with standard XSS and CSRF vulnerabilities on the web; I would consider this a related class of attack vectors.
 
In the first message, I read the word "vulnerability" from the perspective of "browser vulnerability", and wanted to point out that asm.js does not have any specialties there. 

Yeah, the vulnerability is in the JS code, doesn't allow escaping the browser's JS sandboxing.

But the addition of C-based code into the JS code on a site does add buffer overflow and related classes of errors that handwritten JS doesn't usually have, and this example confirms they can be used to overwrite function pointers in a potentially exploitable way against an application. So it's something developers ought to consider in their security planning and reviews, when writing or selecting C/C++ code to use via emscripten.

Lack of address space randomization in the function pointer table also means that an attacker can hardcode the target function pointer override in their attack data, whereas attacking native code you might need to scan or make multiple attempts.

-- brion


2016-04-24 11:20 GMT+03:00 Brion Vibber <br...@pobox.com>:
On Sunday, April 24, 2016, juj j <juj...@gmail.com> wrote:
Indeed it is possible to nuke the function pointer table, but I don't think this is a vulnerability. In order to be a security issue, it would mean there would have to be some kind of escalation to occur. Handwritten JavaScript and asm.js C/C++ code should be viewed at the same security level or arena in a sense, since the developer is in control of the both. Asm.js does not propose a new security layer where handwritten JS outside to the asm.js module could be allowed to considered untrusted, but the usual web security imposed via domain rules applies here.

There's no need for untrusted handwritten js here; you just need some function in the asm.js module that you can call that does something you as an attacker want and has the same call signature as the function pointer that gets overwritten.

The rough equivalent in native code is things like forcing a call or return into another part of the executable or standard library that happens to do something the attacker finds useful.

Getting something useful out of the exploit might well piggyback on some further vector once you're inside, such as producing malicious html that later gets inserted into the document by code outside the emscripten module (or could you manage to call something more directly via embind::val etc?) -- but that's not code the attacker has to inject previously ... If they could do that, no need to bother with buffer overflows in the asm.js.

-- brion

--
You received this message because you are subscribed to the Google Groups "emscripten-discuss" group.
To unsubscribe from this group and stop receiving emails from it, send an email to emscripten-discuss+unsub...@googlegroups.com.

For more options, visit https://groups.google.com/d/optout.

--
You received this message because you are subscribed to the Google Groups "emscripten-discuss" group.
To unsubscribe from this group and stop receiving emails from it, send an email to emscripten-discuss+unsub...@googlegroups.com.

For more options, visit https://groups.google.com/d/optout.

--
You received this message because you are subscribed to the Google Groups "emscripten-discuss" group.
To unsubscribe from this group and stop receiving emails from it, send an email to emscripten-discuss+unsub...@googlegroups.com.

Alon Zakai

unread,
Apr 24, 2016, 11:59:30 PM4/24/16
to emscripten-discuss
The reason function table calls are always &'ed is to make optimizing them easy. The asm.js format is

TABLE[x & (tableSize-1)]

and the table size must be a power of 2. As a result, the VM can do the & and then all it needs to do is a table lookup and just call that. It has to be in bounds, and it has to have the right function type as well.

But you can add XORing outside of that, perhaps. The compiler could emit

TABLE[f(x) & (tableSize-1)]

where f(x) does a xor + bounds check, returning 0 if out of bounds (0 is always an invalid function pointer, it will abort).

To unsubscribe from this group and stop receiving emails from it, send an email to emscripten-disc...@googlegroups.com.

For more options, visit https://groups.google.com/d/optout.

--
You received this message because you are subscribed to the Google Groups "emscripten-discuss" group.
To unsubscribe from this group and stop receiving emails from it, send an email to emscripten-disc...@googlegroups.com.

For more options, visit https://groups.google.com/d/optout.

--
You received this message because you are subscribed to the Google Groups "emscripten-discuss" group.
To unsubscribe from this group and stop receiving emails from it, send an email to emscripten-disc...@googlegroups.com.

For more options, visit https://groups.google.com/d/optout.

--
You received this message because you are subscribed to the Google Groups "emscripten-discuss" group.
To unsubscribe from this group and stop receiving emails from it, send an email to emscripten-disc...@googlegroups.com.
Reply all
Reply to author
Forward
0 new messages