An Introduction to
Return-Oriented
Exploitation on ARM64
by Billy Ellis
BSidesMCR 2018@bellis1000
whoami
•Billy Ellis
•17 year old from UK
•App development & programming for 5 years
•Interested in security & exploitation for 2 years
@bellis1000 BSidesMCR 2018
• Created various ‘exploit exercise’
binaries for ARM/ARM64
• Author of ‘Beginner’s Guide to
Exploitation on ARM’
• Run a YouTube channel teaching
various exploit development &
iOS jailbreaking videos
My work
@bellis1000 BSidesMCR 2018
• Introduce ‘return-oriented’ exploitation techniques (for
those who are unfamiliar)
• Cover fundamentals of ARM/ARM64
• Demo a ROP exploit on ARM64
Focus of my talk
@bellis1000 BSidesMCR 2018
Why target ARM?
@bellis1000 BSidesMCR 2018
• Almost all smartphones & tablets run on ARM-based chips
• Some laptops now also use ARM
• Embedded systems / co-processors (TouchBar) too
Why target ARM?
@bellis1000 BSidesMCR 2018
• Mobile devices have become much more popular in the
last decade
• Makes ARM a worth while target for attackers
Why target ARM?
@bellis1000 BSidesMCR 2018
ARM Fundamentals
@bellis1000 BSidesMCR 2018
• 32-bit RISC architecture
• Instructions of fixed size (32 bits)
• 16-bit mode known as ‘thumb’
• 16 registers
ARMv7
@bellis1000 BSidesMCR 2018
• R0 - R12 (general purpose)
• R13 (stack pointer)
• R14 (link register)
• R15 (program counter)
ARMv7 Registers
@bellis1000 BSidesMCR 2018
• aka ARM64
• 64-bit ARM architecture
• Supports AArch32 for backwards compatibility
• Supports exception levels (EL3 - EL0)
ARMv8
@bellis1000 BSidesMCR 2018
• 30 general purpose registers (X0 - X29)
• W0 - W29 (32-bit context)
• Link Register X30
• Stack Pointer X31
• Program Counter (not directly modifiable)
ARMv8 Registers
@bellis1000 BSidesMCR 2018
Differences
@bellis1000
ARMv7 ARMv8
BSidesMCR 2018
Differences
@bellis1000
ARMv7 ARMv8
Register names
BSidesMCR 2018
Differences
@bellis1000
ARMv7 ARMv8
Instruction mnemonics
BSidesMCR 2018
Differences
@bellis1000
ARMv7 ARMv8
Return instructions
BSidesMCR 2018
Differences
@bellis1000
ARMv7
ARMv8
BSidesMCR 2018
Differences
@bellis1000
ARMv7
ARMv8
Adds specified
registers’ values
to top of stack
BSidesMCR 2018
Differences
@bellis1000
ARMv7
ARMv8
Manually grow
the stack
BSidesMCR 2018
Differences
@bellis1000
ARMv7
ARMv8
Store register
pair at location
specified
BSidesMCR 2018
Differences
@bellis1000
ARMv7
ARMv8
BSidesMCR 2018
Differences
@bellis1000
ARMv7
ARMv8
Remove top
items from stack
and place into
specified
registers
BSidesMCR 2018
Differences
@bellis1000
ARMv7
ARMv8
Load register
pair from
memory location
specified
BSidesMCR 2018
Differences
@bellis1000
ARMv7
ARMv8
Manually shrink
the stack
BSidesMCR 2018
Differences
@bellis1000
ARMv7
ARMv8
Return (branch
to X30)
BSidesMCR 2018
What is ROP?
@bellis1000 BSidesMCR 2018
• Return Oriented Programming
• Modern exploit technique
• Code re-use attack
• Originally used as alternative to shellcode
What is ROP?
@bellis1000 BSidesMCR 2018
• Old fashioned method of writing a payload
• Involves writing byte-representation of instructions to
memory
• Jump to that memory to execute the payload
What is shellcode?
@bellis1000 BSidesMCR 2018
Example
@bellis1000 BSidesMCR 2018
Example
@bellis1000
• NX / DEP prevent stack
data being executed
• Not possible on modern
systems
BSidesMCR 2018
ROP provides a
workaround!
@bellis1000 BSidesMCR 2018
• Uses legitimate instructions out of context
• Chains together several ‘gadgets’ to achieve desired
outcome
• NX / DEP no longer matters
How does it work?
@bellis1000 BSidesMCR 2018
• Short sequences of instructions ending with a ‘RET’
• The ‘RET’ is required in order to chain gadgets
• Gadgets are found within __TEXT segment
• Usually found at the end of a function
Gadgets
@bellis1000 BSidesMCR 2018
Example gadget
@bellis1000 BSidesMCR 2018
Example gadget
@bellis1000
Store Register
instruction
BSidesMCR 2018
Example gadget
@bellis1000
Data
BSidesMCR 2018
Example gadget
@bellis1000
Location
Data
BSidesMCR 2018
Example gadget
@bellis1000
Memory location
(top of stack)
Load Pair of
registers
X29 & X30
(X30 is Link
Register)
BSidesMCR 2018
Example gadget
@bellis1000
Return - branch
to X30
BSidesMCR 2018
Gadget chaining
@bellis1000
• Gadgets can be chained using their ‘RET’ instructions
• Place gadget addresses in order on stack
• Each ‘RET’ will jump to the next address on the stack
BSidesMCR 2018
Example
@bellis1000 BSidesMCR 2018
Example
@bellis1000
Fill stack with junk up
until return address
BSidesMCR 2018
Example
@bellis1000
Overwrite return
address with first
gadget address
BSidesMCR 2018
Example
@bellis1000
Additional gadget
addresses follow
BSidesMCR 2018
Example
@bellis1000
Gadgets are executed
one after the other
BSidesMCR 2018
Example
@bellis1000
The ‘RET’ jumps to
the next gadget
BSidesMCR 2018
Finding gadgets
@bellis1000
• Search binary for ‘RET’ instructions
• Search backwards from the ‘RET’ to find useful
instructions
• Many great tools do this automatically for multiple
architectures
BSidesMCR 2018
ARM Gadget Finders
@bellis1000
• https://github.com/JonathanSalwan/ROPgadget
• https://github.com/sashs/Ropper
• http://ropshell.com
BSidesMCR 2018
Complex ROP Chains
@bellis1000
• Many exploits require huge gadget chains
• Sometimes involving hundreds of gadgets for complex
tasks
• e.g. kernel patching
BSidesMCR 2018
What’s the problem?
@bellis1000 BSidesMCR 2018
What’s the problem?
@bellis1000
• All vulnerabilities are different
• Some may limit the amount of gadgets that can be executed
• Some may only allow a single gadget worth of arbitrary
code execution
• e.g. non-stack-based function pointer overwrite
BSidesMCR 2018
Solution: Stack Pivot
@bellis1000 BSidesMCR 2018
What is Stack Pivoting?
@bellis1000
• Creating a fake stack
• Control SP value to point to new location
• Populate this memory with ROP chain
• Redirect code execution to first gadget in the chain
BSidesMCR 2018
The Stack
@bellis1000
• Theoretically it is a stack
of items
BSidesMCR 2018
The Stack
@bellis1000
• Theoretically it is a stack
of items
• PUSH to add item
BSidesMCR 2018
The Stack
@bellis1000
• Theoretically it is a stack
of items
• PUSH to add item
• POP to remove item
BSidesMCR 2018
In reality…
@bellis1000
• It’s just an abstraction
• The stack does not exist as we imagine it
• It is just an area of memory like any other
BSidesMCR 2018
In reality…
@bellis1000 BSidesMCR 2018
In reality…
@bellis1000
Stack Pointer points to
top of stack
BSidesMCR 2018
In reality…
@bellis1000
“POP {R1}”
BSidesMCR 2018
In reality…
@bellis1000
“POP {R1}”
BSidesMCR 2018
In reality…
@bellis1000
“POP {R1}”
Stack is one
item shorter
BSidesMCR 2018
In reality…
@bellis1000
“POP {R1}”
This memory
does not need to
be cleared
BSidesMCR 2018
In reality…
@bellis1000
“PUSH {R2}”
BSidesMCR 2018
In reality…
@bellis1000
“PUSH {R2}”
BSidesMCR 2018
In reality…
@bellis1000
“PUSH {R2}”
New item is
added to
top of stack
BSidesMCR 2018
Stack Pivot
@bellis1000 BSidesMCR 2018
Stack Pivot
@bellis1000 BSidesMCR 2018
Stack Pivot
@bellis1000
Attacker controlled
memory populated with
gadget addresses
BSidesMCR 2018
Stack Pivot
@bellis1000 BSidesMCR 2018
Stack Pivot
@bellis1000
Modify SP register
to point to start of
ROP stack
BSidesMCR 2018
Stack Pivot
@bellis1000
Program now treats
this as the stack
BSidesMCR 2018
How do we control
Stack Pointer?
@bellis1000 BSidesMCR 2018
How do we control SP?
@bellis1000
• Use a pivot gadget
• Overwrite SP value
BSidesMCR 2018
Stack Pivot Gadget
@bellis1000 BSidesMCR 2018
Stack Pivot Gadget
@bellis1000
Overwrite SP with
value of X5
BSidesMCR 2018
Stack Pivot Gadget
@bellis1000
Load X30 and
Return
BSidesMCR 2018
Example Attack
@bellis1000 BSidesMCR 2018
Target Overview
@bellis1000
Target Name:
Architecture:
Description:
bsides_demo
ARMv7/ARMv8
Small binary vulnerable to a heap
buffer overflow allowing a
function pointer to be
overwritten.
BSidesMCR 2018
Aim
@bellis1000
• Call secret() function
• Pass correct code as first parameter
BSidesMCR 2018
@bellis1000 BSidesMCR 2018
@bellis1000 BSidesMCR 2018
@bellis1000 BSidesMCR 2018
@bellis1000 BSidesMCR 2018
@bellis1000
Vulnerability
BSidesMCR 2018
@bellis1000
Vulnerability
512 byte copy into
object’s name[] char
array
BSidesMCR 2018
@bellis1000
Vulnerability
name[] array is
only 64 bytes long
512 byte copy into
object’s name[] char
array
BSidesMCR 2018
@bellis1000
Vulnerability
Will overflow causing
function pointer to be
overwritten!
512 byte copy into
object’s name[] char
array
BSidesMCR 2018
@bellis1000
Vulnerability
Conveniently placed call
to function pointer ;)
BSidesMCR 2018
@bellis1000
Vulnerability
Offset 0x40 (64) bytes
from ‘name’ buffer
BSidesMCR 2018
@bellis1000
secret()
BSidesMCR 2018
@bellis1000
secret()
Secret code
BSidesMCR 2018
@bellis1000
secret()
Compared against
W0 (first arg)
BSidesMCR 2018
@bellis1000
secret()
Conditional branch
BSidesMCR 2018
@bellis1000
secret()
BSidesMCR 2018
@bellis1000
secret()
BSidesMCR 2018
@bellis1000
secret()
BSidesMCR 2018
@bellis1000
secret()
Why not
jump here?
BSidesMCR 2018
Too easy!
@bellis1000 BSidesMCR 2018
@bellis1000
Too easy!
• The point is to show a ROP example
• This is not a real-life exploit
• We’ll assume we must call secret() from its entry point
BSidesMCR 2018
@bellis1000
Exploit plan
• Gain code execution
• Set up X0/W0 with secret code
• Jump to secret()
BSidesMCR 2018
What do we know?
@bellis1000
• We can control R15/PC by overwriting pointer
• We can execute a single gadget
• We need a stack pivot!
BSidesMCR 2018
Stack Pivot Criteria
@bellis1000
• Must be a single gadget
• Must point SP to start of our heap buffer
BSidesMCR 2018
Look familiar?
@bellis1000 BSidesMCR 2018
Look familiar?
@bellis1000
Overwrites SP
with value of
X5
BSidesMCR 2018
Look familiar?
@bellis1000
main() sets up
X5 to point to
heap object
BSidesMCR 2018
@bellis1000
Checklist
• Find stack pivot
• Load X0/W0 with code
• Call secret()
BSidesMCR 2018
Two gadgets
@bellis1000 BSidesMCR 2018
Two gadgets
@bellis1000
Load X3 and X4
with controlled
values
BSidesMCR 2018
Two gadgets
@bellis1000
Return
BSidesMCR 2018
Two gadgets
@bellis1000
Move value of
X4 into X0
BSidesMCR 2018
Two gadgets
@bellis1000
Return
BSidesMCR 2018
@bellis1000
Checklist
• Find stack pivot
• Load X0/W0 with code
• Call secret()
BSidesMCR 2018
@bellis1000
Checklist
• Find stack pivot
• Load X0/W0 with code
• Call secret()
BSidesMCR 2018
Building the exploit!
@bellis1000 BSidesMCR 2018
@bellis1000
Payload structure
BSidesMCR 2018
@bellis1000
Payload structure
This data is written to
the object’s heap
chunk
BSidesMCR 2018
@bellis1000
Payload structure
char name[64];
BSidesMCR 2018
@bellis1000
Payload structure
Function pointer that
gets overwritten
BSidesMCR 2018
@bellis1000
Payload structure
Points to stack
pivot gadget
BSidesMCR 2018
@bellis1000
Payload structure
Junk bytes
loaded into X29
BSidesMCR 2018
@bellis1000
Payload structure
Points to second
gadget
BSidesMCR 2018
@bellis1000
Payload structure
Junk bytes
loaded into X3
BSidesMCR 2018
@bellis1000
Payload structure
secret() code
loaded into X4
BSidesMCR 2018
@bellis1000
Payload structure
Junk bytes
loaded into X29
BSidesMCR 2018
@bellis1000
Payload structure
Points to third
gadget
BSidesMCR 2018
@bellis1000
Payload structure
Junk bytes
loaded into X29
BSidesMCR 2018
@bellis1000
Payload structure
Points to
secret() function
BSidesMCR 2018
@bellis1000
Running the exploit
BSidesMCR 2018
@bellis1000
Running the exploit
BSidesMCR 2018
Exploit complete!
@bellis1000 BSidesMCR 2018
@bellis1000
Some useful links
• https://azeria-labs.com
• http://liveoverflow.com
• https://quequero.org/2014/04/introduction-to-arm-architecture/
• https://github.com/Billy-Ellis/Exploit-Challenges
• https://zygosec.com
BSidesMCR 2018
@bellis1000
@bellis1000 BSidesMCR 2018

Introduction to Return-Oriented Exploitation on ARM64 - Billy Ellis