6 ms·
Everything old is new again: binary security of WebAssembly
- lstamour 6y agoI’ve only watched the video, but to me this as much highlights how WebAssembly was designed to run in restricted browser sandboxes with CSP and other mitigations readily available, and that the uses of WebAssembly outside of such relatively hardened environments is, as shown, more risky. Outside of the confusion that a WebAssembly binary might be tricked to misbehave though, the rest feels like standard security measures are enough. I’m not yet convinced we need more mitigations at the WebAssembly layer vs better security linting to try and catch the vulnerabilities, and perhaps not trusting any web assembly outputs without validating them first? I might be missing something here. I’ll probably need to read the paper next :)
- foota 6y agoI think the lack of mitigations are things like memory protection, stack canaries, and such that make attacks harder in practice for binary targets, even if there is an exploitable bug in the code.
- xfer 6y agoYes, and people are trying to run this outside browser too(like a jvm alternative). Not sure what's the craze about wasm outside browsers considering all the risks.
- recursive 6y agoYou pretty much explained it yourself. It's a jvm alternative without the Oracle after-taste.
- pjmlp 6y agoAnd IBM, Red-Hat, Azul, Microsoft, SAP, Alibaba, Twitter, Amazon, PTC, Aicas, Gemalto,....
- rubber_duck 6y agoJVM is a different category of VM, it's memory model and bytecode don't fit languages such as C/C++/Rust at all ( AFAIK it doesn't even have unsigned integer operations).
- The_rationalist 6y agoKotlin offer unsigned integers. Graalvm support c/c++ could in theory support rust too.
- alex7o 6y agoThere is a an example of rust using graalvm on their website. I have tried it and it works.
- brabel 6y ago> Kotlin offer unsigned integers. As an experimental feature... I had to use it on one of the projects I work on because using signed bytes was driving me crazy, but I had to suppress warnings for experimental features (and will have to pay the price if they change the feature somehow, as they tend to do with experimental features).
- rubber_duck 6y agoJVM is turing complete so it can run any language, the point is efficiency
- pjmlp 6y agoThey are faked via signed arithmetic, because the JVM does not support them anyway.
- pjmlp 6y agoCLR, mainframe language environments and now lost tech like some phone VM, do support C and C++ like languages.
- rubber_duck 6y ago
- rvz 6y agoExactly. There's so much "WASM without the browser" hype for some time and this analysis puts the risks into perspective. It has been aggresively marketed as a JVM alternative (not equivalent), but with the same old native bugs and even makes XSS attacks possible. Stunning. Maybe that's why all the big media content companies went behind it. Out with Flash and Java and in with 'compile and run WASM programs in every browser' to support this 'open web™'. What they really mean is: 'We can't wait for WASM DRM!'
- deleted 6y ago[deleted]
- infogulch 6y agoThe core WA principle of "protect the host from the program, but not the program from itself" still holds, based on the video this paper does not even attempt to break the WASM host memory barrier. That seems more like a success than anything else. Guess what: developers are still responsible for avoiding security bugs in their code. But at least when they mess up, it still won't damage more than what their dumb web app could have done already.
- hinkley 6y agoChaos is a ladder. And we start the cycle over again around the time that young men and women no longer trust the opinions of people who lived through the last cycle. I used to call this 'fashion' as quite a few other people are fond of doing, but I don't think I'll be doing that anymore. Fashion has an element of frivolity that understates the consequences of all of the churn. I have been trying to figure out if there's a more structured way that I can gather my assumptions (about software in particular) and be able to audit them once in a while. Because we build so many decisions on these assumptions. And I suspect when they start to teeter is when we get the urge to try something very different, 'forget everything we think we know' and start over with a philosophy that we already tried and abandoned thirty years ago. But maybe I only need to forget six things I 'knew', instead of swinging back and forth on the pendulum with everyone else.
- munificent 6y agoThe whole point of a sandbox is that it's only got toys in it so you don't care when the cat shits in it. But, of course, if the sandbox only contains toys, it's not very useful. You can't sit in it and order a pizza if all you've got is a toy phone. So you leave your wallet, phone, and other critical devices in there. But now it has ceased to be a worry-free safe play space. It's no longer acceptable for the cat to shit in it. This is a fundamental tension and we'll probably keep rediscovering this security problem any time a new container model is developed.
- dane-pgp 6y agoAlso known as the Sandboxing Cycle: https://xkcd.com/2044/ https://xkcd.com/2044/
- ineedasername 6y agoYep, this about sums it up: "All I want is a secure system where it's easy to do anything I want. Is that so much to ask?"
- Veedrac 6y agoThe point of a sandbox is that the only things in it are the things you've put in it. A can only touch B through mechanisms interfaces it has been gifted. Computer architecture is too broken to provide this guarantee to anything in the same address space, and operating systems are too broken to provide this guarantee through the majority of their interfaces. Proper, pervasive sandboxing in the architecture, ideally down to the function-level, would solve a huge fraction of security bugs, largely for free. Nobody would have had to invent Rust, because that 70% of memory safety bugs would have been almost entirely impossible to exploit from the start. I mean, it's pretty obvious the tension here is largely imaginary when you consider how much random code browsers run from untrusted sources, day after day, and most of those times they fail are because the architecture and OS and language haven't got sensible de-facto sandboxes (again, see that 70% number). For sure, you need to be careful what you give access to who, but the problem is insufficient sandboxing, and the solution is more sandboxing.
- 6y ago
- rubber_duck 6y agoLike they say at worst WASM can make a mess of it's own data. The selling point of WASM outside of browser to me is native modules for other languages where you can whitelist the exposed APIs (and provide sandboxed versions) while having cross-platform binaries. So for example in the future node can ship with WASM module support and JS can load a C WASM module binary which I can deploy on Windows/Linux/Mac, and I can review what that module has access to via some module manifest, and node WASM exposes wrapped POSIX API based on manifest configuration.
- infogulch 6y agoIt seems they aimed to answer the question: What are the consequences of limiting the WA spec to only try to sandbox the WA binary from outside memory, and not try to prevent it from exploiting itself? The answer they got was that yes, a WA binary may be capable of exploiting itself. I think this is an interesting and valuable result, but I don't think the result is surprising, or that it invalidates the design of WA. The outputs from WA are not guaranteed to be what you expect. Or put another way: C is still C. I wonder if such a vulnerability could be found in a program written in safe Rust. Notably, they don't appear to even try to break the WA-host memory barrier, which I actually find to be a validation of the core design goal of WebAssembly: isolate the damage a vulnerable program can inflict to the memory space (and thus also output) of that program. Protect the host from the program, but not the program from itself. Also, maybe don't dump WA output you can't validate directly into DOM.
- saagarjha 6y agoRust would have to change some things, certainly. Signal handlers won’t cut it anymore, for example.
- est31 6y agoIs this a limitation of the spec or of the implementations? For example, Figure 1 in the paper mentions ASLR as missing in wasm but can't a wasm JIT choose to deploy ASLR if it wants to? Edit: I read the section 3.3 now and it seems that the stack and the heap live in the same linear memory, which is obviously bad. But function addresses can still be randomly offset, no? Also the paper admits that security has been an important component of the design of wasm: "The design of WebAssembly includes various features to ensure binary security. For example, the memory maintained by a WebAssembly program is separated from its code, the execution stack, and the data structures of the underlying VM. To prevent type-related crashes and attacks, binaries are designed to be easily type-checked,which they are statically before execution. Moreoever, WebAssembly programs can only jump to designated code locations,a form of fault isolation that prevents many classic control flow attacks."
- AgentME 6y ago
- justinclift 6y agoThis doesn't really seem to offer anything useful, or even contain new information. eg: * no corruption of, nor access to host memory. * no corruption of, nor access to memory or other processes. It looks like what they did is create a wasm file that generates a JS "Alert !!!" string, then blindly runs that string in the browser without any kind of validation? It's hard to tell from looking at their code though: https://github.com/sola-st/wasm-binary-security/blob/master/end-to-end-exploits/browser-libpng-xss/02-compile-pnm2png-wasm/out/main.html https://github.com/sola-st/wasm-binary-security/blob/master/... The html page there seems to be missing the "main.js" to see what's happening. :( --- Hmmm, it might be this main.js, which looks (without checking) like it came from Emscripten: https://github.com/sola-st/wasm-binary-security/blob/master/attack-primitives/stack-buffer-overflow/out/main.js https://github.com/sola-st/wasm-binary-security/blob/master/...
- rainforest 6y agoThe exploit is against a vulnerable library (the actual input file is here: https://github.com/sola-st/wasm-binary-security/blob/master/end-to-end-exploits/browser-libpng-xss/02-compile-pnm2png-wasm/inputs/exploit https://github.com/sola-st/wasm-binary-security/blob/master/...) If you have a wasm application with vulnerabilities (e.g. in the libraries) there are no mitigations that native binaries provide, so simple buffer overflows give you RCEs again. It's still within the sandbox, but the threat is as severe as running eval on user supplied inputs as there might be useful stuff in that sandbox.
- justinclift 6y agoIsn't it (exactly?) the same as finding a vulnerable JS library, and providing bad input to that? That aside, if the C-to-wasm compiler were to add some of the safeguards mentioned it does sound like it'd go some way towards lessening the potential impact.
- rainforest 6y agoYes, if there was a library that eval'd unsanitised input the damage potential is the same. The practical difference is that it's a lot harder to assure code written in unsafe languages is free of defects like this since they manifest as benign operations (every write to a buffer is a potential vector) rather than obviously dangerous operations. Concretely, you could grep for eval and convince yourself that each use is OK (assuming it's rare - it ought to be) but you couldn't do that for common language constructs that could be exploitable like writes to arrays/pointers.
- Nokinside 6y agoIf you want good security, you can't download new untested code. Sandboxing is important, but the most important part is to not allow arbitrary code to run. WASM seems like very good solution if you want to load random code and still retain as much safety and flexibility as possible. The burden is now moved to code that interacts with potentially misbehaving code. Check and verify all outputs, limit resource usage. Using WASM system It's not so different from calling remote server in the cloud. Anything can happen during executing but only the interacting with the system can cause harm outside the system.
- justinclift 6y agoWonder what the potential for side channel attacks (eg timing analysis, etc) will turn out to be with wasm?
- Nokinside 6y agoMany side channel attacks available for native binaries are impossible in wasm, because code can't be handcrafted. It always goes trough compiler. When they exist, potential WASM side channel attacks are system/compiler specific and can be fixed with software updates. Compilers can be designed to remove the possibility it becomes a real issue.
- justinclift 6y ago> ... are impossible in wasm, because code can't be handcrafted. It always goes trough compiler. That's extremely wrong. People have been hand writing WASM files for ages.
- daniellehmann 6y agoHi everyone, Daniel here (one of the authors, I am the PhD student in the video). Great to see the paper submitted and discussed :-) Sorry for being a bit late to the discussion, I will try to answer the questions in detail that were asked below. I want to clarify one misunderstanding that seems to come up several times, namely the distinction between "host security" and "security of the WebAssembly program itself". WebAssembly does have measures and a good design for host security. E.g., in the browser, WebAssembly programs are run in a sandbox (just as JavaScript is), and writes inside WebAssembly's linear memory should never affect values outside of linear memory (e.g., VMs insert bounds checks when reading/writing from/to WebAssembly pointers). Those techniques protect against malicious WebAssembly binaries, which is of course important in the Web. Here, we look at a different side of WebAssembly's security story: What if the WebAssembly binary is vulnerable and gets fed malicious input? In this attacker model, we can at most do what the host environment allows us to do. But especially for large WebAssembly programs with lots of imports, or WebAssembly binaries for standalone VMs (outside of the browser, without a tried-and-tested sandbox), this can still be a lot of attacker capability! And when we look into the protections inside WebAssembly's linear memory (not between linear memory and host memory), we find that there are very little. All linear memory is always writable, no stack canaries, no guard pages, no ASLR, no safe unlinking in smaller allocators etc. This is worrying as more code gets linked together into a single WebAssembly binary. If you have any further questions, I am more than happy to answer, here and also via email. Thanks again for the interest!
- afiori 6y agoTo my understanding one of the design constraints behind webassembly semantics where given by wanting to keep implementation burden low for browsers. In particular my understanding is that most of MVP WebAssembly almost a subset of asm.js in term of expressivity. Do some of the safety measures you consider translate well in this model?
- daniellehmann 6y ago> Do some of the safety measures you consider translate well in this model? Yes, I think several mitigations could be deployed without requiring a change to the language, only by changing compilers and runtime libraries: * Stack canaries on the unmanaged stack: For storing the reference canary value, you need some "safe" location that cannot be overwritten by regular memory writes. I believe in x86, thread local storage (TLS) / the fs segment register is used. In WebAssembly, one could use a non-mutable global scalar variable, which could only be overwritten by a matching global.set instruction (which cannot be inserted by an attacker). Then, before returning from a function (or really at any point you want to check the integrity of linear memory), you could compare the canary value against this global, as you would in native architectures. * Allocator hardening, e.g., safe unlinking doesn't require any language support, the allocator just needs to do it (and live with the slightly increased code size cost). Other mitigations would require language extensions. E.g., for finer grained control-flow integrity (taking source types into account, not just WebAssembly primitive types), one would require multiple table (part of the reference types proposal). Then, only functions with compatible types should be stored in the same indirect call table. ASLR, unmapped pages, and constants in linear memory are harder, I believe. For ASLR, WebAssembly's 32-bit pointers will most likely provide too little entropy. Unmapped pages and "true constants" would require some host API to make portions of the memory non-writable/readable, but I don't know of any proposal to do so. > wanting to keep implementation burden low for browsers > WebAssembly almost a subset of asm.js Yes, that is also my understanding as to why we are at the current situation. (But I did not take part in WebAssembly's design, so I cannot claim any authority.)