Created
August 6, 2012 21:57
-
-
Save yifanlu/3278820 to your computer and use it in GitHub Desktop.
Vita possible exploit testing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// | |
// main.c | |
// | |
// Created by Yifan Lu on 8/6/12. | |
// | |
#define G_DIR_SEPARATOR '/' | |
// I don't know if __native_client__ is defined on the Vita or not, so | |
// you can try it both ways. | |
#define __native_client__ | |
#include <glib.h> | |
#include <stdio.h> | |
#include <stdlib.h> | |
#include <string.h> | |
gchar * | |
gg_path_get_basename (const char *filename) | |
{ | |
char *r; | |
g_return_val_if_fail (filename != NULL, NULL); | |
/* Empty filename -> . */ | |
if (!*filename) | |
return g_strdup ("."); | |
/* No separator -> filename */ | |
r = strrchr (filename, G_DIR_SEPARATOR);\ | |
if (r == NULL) | |
return g_strdup (filename); | |
/* Trailing slash, remove component */ | |
if (r [1] == 0){ | |
char *copy = g_strdup (filename); | |
copy [r-filename] = 0; | |
r = strrchr (copy, G_DIR_SEPARATOR); | |
if (r == NULL){ | |
g_free (copy); | |
return g_strdup ("/"); | |
} | |
r = g_strdup (&r[1]); | |
g_free (copy); | |
return r; | |
} | |
return g_strdup (&r[1]); | |
} | |
gchar * | |
mono_path_canonicalize (const char *path) | |
{ | |
gchar *abspath, *pos, *lastpos, *dest; | |
int backc; | |
if (g_path_is_absolute (path)) { | |
abspath = g_strdup (path); | |
} else { | |
#ifdef __native_client__ | |
gchar *tmpdir = "."; | |
abspath = g_build_filename (tmpdir, path, NULL); | |
#else | |
gchar *tmpdir = g_get_current_dir (); | |
abspath = g_build_filename (tmpdir, path, NULL); | |
g_free (tmpdir); | |
#endif | |
} | |
abspath = g_strreverse (abspath); | |
backc = 0; | |
dest = lastpos = abspath; | |
pos = strchr (lastpos, G_DIR_SEPARATOR); | |
while (pos != NULL) { | |
int len = pos - lastpos; | |
if (len == 1 && lastpos [0] == '.') { | |
// nop | |
} else if (len == 2 && lastpos [0] == '.' && lastpos [1] == '.') { | |
backc++; | |
} else if (len > 0) { | |
if (backc > 0) { | |
backc--; | |
} else { | |
if (dest != lastpos) | |
/* The two strings can overlap */ | |
memmove (dest, lastpos, len + 1); | |
dest += len + 1; | |
} | |
} | |
lastpos = pos + 1; | |
pos = strchr (lastpos, G_DIR_SEPARATOR); | |
} | |
if (dest != lastpos) strcpy (dest, lastpos); | |
return g_strreverse (abspath); | |
} | |
char * | |
make_vita_path (const char *path) | |
{ | |
gchar *abspath, *pos, *lastpos, *dest; | |
int backc; | |
abspath = strdup (path); | |
int i; | |
for(i = 0; i < strlen(abspath); i++) | |
if(abspath[i] == '\\') | |
abspath[i] = '/'; | |
abspath = g_strreverse (abspath); | |
backc = 0; | |
dest = lastpos = abspath; | |
pos = strchr (lastpos, G_DIR_SEPARATOR); | |
while (pos != NULL) { | |
int len = pos - lastpos; | |
if (len == 1 && lastpos [0] == '.') { | |
// nop | |
} else if (len == 2 && lastpos [0] == '.' && lastpos [1] == '.') { | |
backc++; | |
} else if (len > 0) { | |
if (backc > 0) { | |
backc--; | |
} else { | |
if (dest != lastpos) | |
/* The two strings can overlap */ | |
memmove (dest, lastpos, len + 1); | |
dest += len + 1; | |
} | |
} | |
lastpos = pos + 1; | |
pos = strchr (lastpos, G_DIR_SEPARATOR); | |
} | |
if (dest != lastpos) strcpy (dest, lastpos); | |
return g_strreverse (abspath); | |
} | |
/* | |
The bug here is that 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. | |
This might be impossible and it might be not. Included are the following functions: | |
gg_path_get_basename: This is the actual function on the Vita to get the basename | |
used by eglib on the Vita. Renamed to not conflict with the host's glib2. | |
Maybe there a bug in getting the basename? | |
mono_path_canonicalize: This is the actual function on the Vita to canonicalize | |
the path by mono. Maybe a bug in creating the name? | |
make_vita_path: My own function to simulate what the Vita IO manager sees. Don't | |
worry about this one much and it may have bugs so don't rely on it. | |
You can play around with different path inputs either by passing it as the first | |
command line argument or by modifying the hard coded input. You need glib2 to compile. | |
Try not to compile on Windows since we don't want to screw with the separators. | |
Some ideas: | |
play with .. and . | |
using \\/ in a path | |
using weird ASCII characters (\0\b anyone?) | |
*/ | |
int main(int argc, const char * argv[]) | |
{ | |
const char *input; | |
if(argc > 1) | |
input = argv[1]; | |
else | |
input = "pss0:\\top\\Applications\\a/../\\mscorlib.dll"; | |
char *vita = make_vita_path(input); | |
char *basename = gg_path_get_basename(input); | |
char *cano = mono_path_canonicalize(input); | |
fprintf(stderr, "Inpt: %s\nVita: %s\nBase: %s\nCano: %s\n\n", input, vita, basename, cano); | |
fprintf(stderr, "Check 1) Base CANNOT be \"%s\": %s\n", "mscorlib.dll", strcmp(basename, "mscorlib.dll") == 0 ? "FAILED" : "PASSED"); | |
fprintf(stderr, "Check 2) Canonical path MUST be \"%s\": %s\n", "mscorlib.dll", strcmp(cano, "mscorlib.dll") == 0 ? "PASSED" : "FAILED"); | |
fprintf(stderr, "Check 3) Vita path MUST be \"%s\": %s\n", "pss0:/top/Applications/mscorlib.dll", strcmp(vita, "pss0:/top/Applications/mscorlib.dll") == 0 ? "PASSED" : "FAILED"); | |
fprintf(stderr, "If all three checks passed, you can hack the Vita!"); | |
free(vita); | |
free(basename); | |
free(cano); | |
return 0; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment