First, I want to talk about some of the things I've tried and failed. My first thought is that we should look at mono specific things as implementors may overlook these things. For example, reading http://www.mono-project.com/Interop_wit ... _Libraries, we see that mono allows a DLL name of "__Internal" to refer to loaded functions (aka libc and such). (Unfortunately, it's not as easy as loading exec() from __Internal.) There's also dllmap, which can map library names to other names. Specify the config file from the environment variable MONO_CONFIG and you can "rename" libraries. (Unfortunately, not much here either because PSM never loads any libraries through managed code). I've also took at look at assembly signing and how signing with the ECMA key (all zeros except for one byte) allows you to sign system libraries. (Unfortunately, mono doesn't really care about signing, so even if you sign a library as system, nothing really changes). I've tried using .NET Refractor to rename references to mscorlib and see if we can load another library with custom commands. Doesn't work because the name mscorlib.dll is basically hard coded inside mono and references to it is just a formality. I also tried to use reflections to access private and protected methods/fields but it doesn't work because of the security manager.
Now, here's my attempt at hacking PSM. Please note that this is most likely not the only avenue and I look forward to ideas of other routes.
So what are the security in place to prevent running unmanaged code? First and most importantly, the CoreCLR security manager is turned on. (In fact it is the very first thing PSM does when it starts). This means that all code running is untrusted and cannot call "SecurityCritical" methods. Next, sony made sure that any method that can lead to unmanaged code running is marked as "SecurityCritical". This means all the methods in System.Runtime.Interop.Marshal. This includes Marshal.PreLink() which is what is called when you do a DllLink() attribute on an extern method. This also include the various bridging methods like reading IntPtr and any method that can read/write unmanaged memory. Obviously, they also disabled methods to start processes and in fact even methods to find what path the current domain is in. Most of the icalls are SecurityCritical too, and those that must be called are usually called indirectly through another system method. So in order to run unmanaged code, we can either a) somehow get mono to think our code is trusted, which is hard because all code loaded by untrusted code is untrusted and our code is first loaded as untrusted. b) somehow disable the security manager, which is harder since this would have to be on the realm of exploiting mono, which is a fairly mature project (The last vulnerability was discovered in 2010 and sony's using an April 2012 version of mono). But the one silver lining is that (AFAIK from looking at android and windows version) there is no sony specific security in place and the only thing preventing unsigned code from running are mono features themselves which we have the source code for.
I've spent most of my time trying to find how to make mono think our code is trusted. Basically what happens is that the core assemblies are hard coded as trusted and with some exception, all other trusted code is determined by the core libraries. So the idea is, how do we make mono think we are loading a core assembly? What happens is that the implementation of the mono runtime (in our case psm.exe (windows), libdefault.so (android), and EBOOT.bin (vita)). Passes a callback function to libmono and this function is called with the name of the assembly to check if it is verified. The name is either the canonized path of the assembly if it is external, or just the filename if it is internal (AFAIK, the Vita system assemblies is internal).
Now I've found a tiny bug to work with: glib2 only looks at POSIX-styled path separators: / while the Vita can interprate both Windows-styled \ and POSIX-styled / It's not much, but it's something to start with. In order to disable the security manager, first you must make mono think that the library being loaded is a system library. Sony has hard coded the names "mscorlib.dll", "System.dll", and "Sce.PlayStation.Core.dll" and does a strcmp() with the canonical path of the library being loaded. However, if Mono sees that the basename of the library being loaded is "mscorlib.dll" or any of the other two, it will try to load the embedded version instead of our own. So, what we need to do is feed a path to Assembly.LoadFile() that a) the Vita recognizes. b) gets past the security manager by thinking it's a core library, and c) gets past mono's loader by thinking it's an external library.
If we get past the security manager, running unsigned code is as simple as calling an extern function. No need to deal with stacks or memory addresses. Here's how you can help. I've basically made an application, almost a game that allows you to test input paths. It includes the actual mono and eglib function used by PSM to test the names. Through either passing some malformed string or somehow exploiting the function themselves and getting all three tests to pass, please tell us. Think of it as a puzzle, using the given bug on path separators and any other bugs, find a string that passes the three conditions. I wish I can offer a prize, but I don't have anything except gratitude
https://gist.github.com/3278820
Advertising