Smashing the Stack (For Fun and Profit)

A94df6a414bc64771690399a940d1c52?s=47 Dylan Nugent
December 15, 2018

Smashing the Stack (For Fun and Profit)

An introductory session on stack smashing and some of the content in the seminal Aleph One paper. Pairs with interactive content which can be found on GitHub here: https://github.com/Dylnuge/stack-smashing.

A94df6a414bc64771690399a940d1c52?s=128

Dylan Nugent

December 15, 2018
Tweet

Transcript

  1. @dylnuge Stack Smashing (For Fun And Profit)

  2. @dylnuge What is Stack Smashing?

  3. @dylnuge Image Credits: Super Mario Wiki, Nintendo What is Stack

    Smashing?
  4. @dylnuge What is Stack Smashing? Image Credits: Super Mario Wiki,

    Nintendo
  5. @dylnuge What is Stack Smashing? Image Credits: Super Mario Wiki,

    Nintendo, Universal Pictures
  6. @dylnuge Image Credits: Super Mario Wiki, Nintendo What is Stack

    Smashing? A form of buffer overflow exploit—we are going to write to memory we’re not supposed to (don’t worry if this doesn’t make sense yet) Modern computers try to protect against this, but it’s far from useless knowledge, even today We’ll come back to Mario at the end (no, seriously)
  7. @dylnuge Resources We’re going to do some real exploits! Download

    the ZIP and follow along! All the source for this is in my stack-smashing repo: https:/ /github.com/Dylnuge/stack- smashing The Aleph1 paper this is about (in part) was published in Phrack. A copy of the text can be found here: https:/ /insecure.org/stf/ smashstack.html
  8. @dylnuge Clobbering Variables

  9. @dylnuge Clobbering Variables Where do variables go?

  10. @dylnuge Clobbering Variables Where do variables go? Each square here

    is 1 byte (8 bits). Each row has 4 squares, so 4 bytes (32 bits) 0x1c 0x00 0x1f 0x03
  11. @dylnuge Clobbering Variables Where do variables go? Let’s push a

    value on this stack: int myInt = 0; 0x1c 0x00 0x1f 0x03 00 00 00 00
  12. @dylnuge Clobbering Variables Where do variables go? Let’s push a

    value on this stack: int myInt = 0;
 int secondInt = 42; 0x1c 0x00 0x1f 0x03 00 00 00 00 2A 00 00 00
  13. @dylnuge Clobbering Variables Where do variables go? Let’s push a

    value on this stack: int myInt = 0;
 int secondInt = 42; Note that as we add to the stack, we move “up” in memory, to lower addresses 0x1c 0x00 0x1f 0x03 00 00 00 00 2A 00 00 00
  14. @dylnuge Clobbering Variables What about strings (text)? char username[8] =

    “dylnuge”; Notes on strings: ASCII format Ends with a 00 (called a “null terminator”) 0x1c 0x00 0x1f 0x03 00 00 00 00 2A 00 00 00 64 79 6C 6E 75 67 65 00
  15. @dylnuge Side Note: ASCII Source: Simple English Wikipedia

  16. @dylnuge Clobbering Variables Let’s read the string from the user

    instead char username[8]; 0x1c 0x00 0x1f 0x03 00 00 00 00 2A 00 00 00 00 00 00 00 00 00 00 00
  17. @dylnuge Clobbering Variables Let’s read the string from the user

    instead char username[8];
 gets(username); I enter “dylnuge” and it’s copied into the variable username 0x1c 0x00 0x1f 0x03 00 00 00 00 2A 00 00 00 00 00 00 00 00 00 00 00 64 79 6C 6E 75 67 65 00
  18. @dylnuge Clobbering Variables Let’s read the string from the user

    instead char username[8];
 gets(username); I enter “dylnuge” and it’s copied into the variable username But that fits. What if I did “dylnuge evil”? 0x1c 0x00 0x1f 0x03 00 00 00 00 2A 00 00 00 00 00 00 00 00 00 00 00 64 79 6C 6E 75 67 65 00
  19. @dylnuge Clobbering Variables Let’s read the string from the user

    instead char username[8];
 gets(username); I enter “dylnuge” and it’s copied into the variable username But that fits. What if I did “dylnuge evil”? 0x1c 0x00 0x1f 0x03 00 00 00 00 65 76 69 6C 00 00 00 00 00 00 00 00 64 79 6C 6E 75 67 65 20
  20. @dylnuge Clobbering Variables int myInt = 0;
 int secondInt =

    42;
 char username[8];
 gets(username);
 printf(“%d\n”, secondInt); 0x1c 0x00 0x1f 0x03 00 00 00 00 65 76 69 6C 00 00 00 00 00 00 00 00 64 79 6C 6E 75 67 65 20
  21. @dylnuge Clobbering Variables int myInt = 0;
 int secondInt =

    42;
 char username[8];
 gets(username);
 printf(“%d\n”, secondInt); We’d expect to print the value 42, but we’d actually print 1818850917 0x1c 0x00 0x1f 0x03 00 00 00 00 65 76 69 6C 00 00 00 00 00 00 00 00 64 79 6C 6E 75 67 65 20
  22. @dylnuge Clobbering Variables int myInt = 0;
 int secondInt =

    42;
 char username[8];
 gets(username);
 printf(“%d\n”, secondInt); We’d expect to print the value 42, but we’d actually print 1818850917 (that’s 0x6C697665) 0x1c 0x00 0x1f 0x03 00 00 00 00 65 76 69 6C 00 00 00 00 00 00 00 00 64 79 6C 6E 75 67 65 20
  23. @dylnuge Side Note: Endianness int myInt = 0x01020304;
 int secondInt

    = 42; Why do these values look weird? We can choose to write a number from most to least significant byte (big-endian) or the other way around (little- endian) Intel (x86) uses little-endian 0x1c 0x00 0x1f 0x03 04 03 02 01 2A 00 00 00
  24. @dylnuge Interactive Example 1

  25. @dylnuge Abusing Function Calls What happens when we call a

    function? 0x1c 0x00 0x1f 0x03
  26. @dylnuge Abusing Function Calls What happens when we call a

    function? What info does our function need? 0x1c 0x00 0x1f 0x03
  27. @dylnuge Arguments Abusing Function Calls What happens when we call

    a function? What info does our function need? Arguments to the function 0x1c 0x00 0x1f 0x03
  28. @dylnuge Return Pointer Arguments Abusing Function Calls What happens when

    we call a function? What info does our function need? Arguments to the function Where to come back to 0x1c 0x00 0x1f 0x03
  29. @dylnuge Frame Pointer Return Pointer Arguments Abusing Function Calls What

    happens when we call a function? What info does our function need? Arguments to the function Where to come back to What the old stack was 0x1c 0x00 0x1f 0x03
  30. @dylnuge Frame Pointer Return Pointer Arguments Abusing Function Calls This

    is “C Calling Convention” There’s no rules things go in this order (so long as they’re consistent and the program knows where to find them) 0x1c 0x00 0x1f 0x03
  31. @dylnuge Frame Pointer Return Pointer Arguments Abusing Function Calls This

    is “C Calling Convention” There’s no rules things go in this order (so long as they’re consistent and the program knows where to find them) As our new function runs, it may put new things on the stack 0x1c 0x00 0x1f 0x03
  32. @dylnuge 2A 00 00 00 Frame Pointer Return Pointer Arguments

    Abusing Function Calls int myVar = 42; 0x1c 0x00 0x1f 0x03
  33. @dylnuge 2A 00 00 00 Frame Pointer Return Pointer Arguments

    Abusing Function Calls int myVar = 42;
 char username[8]; 0x1c 0x00 0x1f 0x03 00 00 00 00 00 00 00 00
  34. @dylnuge 2A 00 00 00 Frame Pointer Return Pointer Arguments

    Abusing Function Calls int myVar = 42;
 char username[8];
 gets(username); 0x1c 0x00 0x1f 0x03 00 00 00 00 00 00 00 00
  35. @dylnuge 2A 00 00 00 Frame Pointer Return Pointer Arguments

    Abusing Function Calls int myVar = 42;
 char username[8];
 gets(username); You can probably see some things we could do with this… 0x1c 0x00 0x1f 0x03 00 00 00 00 00 00 00 00
  36. @dylnuge Process Memory All programs like to think they have

    all the system memory, so they get their own isolated address space. High Low 0x00000000 0xffffffff For right now, we’re changing the scale here. We’ll change it back after this word from our sponsors.
  37. @dylnuge Process Memory They need to put things in this

    space: High Low 0x00000000 0xffffffff
  38. @dylnuge Process Memory They need to put things in this

    space: A stack High Low 0x00000000 0xffffffff
  39. @dylnuge Process Memory They need to put things in this

    space: A stack The code itself (text) High Low 0x00000000 0xffffffff
  40. @dylnuge Process Memory They need to put things in this

    space: A stack The code itself (text) Dynamic data (heap) High Low 0x00000000 0xffffffff
  41. @dylnuge Process Memory They need to put things in this

    space: A stack The code itself (text) Dynamic data (heap) Note that the “text” segment includes all libraries the code uses High Low 0x00000000 0xffffffff
  42. @dylnuge Process Memory Function calls point to the same, consistent

    memory address in the text segment High Low 0x00000000 0xffffffff
  43. @dylnuge Process Memory Function calls point to the same, consistent

    memory address in the text segment High Low 0x00000000 0xffffffff Image Credit: Celeste (Matt Makes Games)
  44. @dylnuge Process Memory Function calls point to the same, consistent

    memory address in the text segment The objdump command will be incredibly useful here. Example time! High Low 0x00000000 0xffffffff
  45. @dylnuge 2A 00 00 00 Frame Pointer Return Pointer Arguments

    Abusing Function Calls int myVar = 42;
 char username[8];
 gets(username); You can probably see some things we could do with this… 0x1c 0x00 0x1f 0x03 00 00 00 00 00 00 00 00
  46. @dylnuge 2A 00 00 00 Frame Pointer Return Pointer Arguments

    Abusing Function Calls int myVar = 42;
 char username[8];
 gets(username); You can probably see some things we could do with this… Like return to an arbitrary function 0x1c 0x00 0x1f 0x03 00 00 00 00 00 00 00 00
  47. @dylnuge 2A 00 00 00 Frame Pointer Return Pointer Arguments

    Abusing Function Calls int myVar = 42;
 char username[8];
 gets(username); You can probably see some things we could do with this… Like return to an arbitrary function The frame pointer will die, but we don’t care 0x1c 0x00 0x1f 0x03 00 00 00 00 00 00 00 00
  48. @dylnuge Interactive Example 2

  49. @dylnuge Powering Up So what can we put on the

    stack?
  50. @dylnuge Powering Up So what can we put on the

    stack? Image Credit: CBS Paramount
  51. @dylnuge Side Note: x86 32-bit Intel (and AMD) processors use

    a machine language called “x86” (or “i386”) 64-bit ones use a similar language called “x64” (or “x86_64” or “amd_64”) Instructions in x86 (and x64) are variable length.
  52. @dylnuge Side Note: x86 Here’s code to subtract 57286 from

    58623 b8 ff e4 00 00 mov eax,0xe4ff
 2d c6 df 00 00 sub eax,0xdfc6
  53. @dylnuge Side Note: x86 Here’s code to subtract 57286 from

    58623 b8 ff e4 00 00 mov eax,0xe4ff
 2d c6 df 00 00 sub eax,0xdfc6 The result of this is stored in the register %eax
  54. @dylnuge Side Note: x86 Here’s code to subtract 57286 from

    58623 b8 ff e4 00 00 mov eax,0xe4ff
 2d c6 df 00 00 sub eax,0xdfc6 The result of this is stored in the register %eax Registers are storage spaces on the processor itself—they’re like variables, but there’s not that many of them, so we’re constantly copying them back and forth from memory
  55. @dylnuge Other Victims
 Variables Buffer Return Pointer Frame Pointer Writing

    Our Own Code Here’s a stack where we know the address that our buffer is at High 0x00aabbcc
  56. @dylnuge Shell code can continue through these (clobbered) Shell code

    (assembly code is just numbers) 0x00aabbcc Who Cares? Writing Our Own Code Here’s a stack where we know the address that our buffer is at High 0x00aabbcc
  57. @dylnuge Shell code can continue through these (clobbered) Shell code

    (assembly code is just numbers) 0x00aabbcc Who Cares? Writing Our Own Code Here’s a stack where we know the address that our buffer is at Imagine that we put the assembly equivalent of execv(“/bin/bash”) High 0x00aabbcc
  58. @dylnuge Shell code can continue through these (clobbered) Shell code

    (assembly code is just numbers) 0x00aabbcc Who Cares? Writing Our Own Code Here’s a stack where we know the address that our buffer is at Imagine that we put the assembly equivalent of execv(“/bin/bash”) Now we have a shell (hence “shell code”) High 0x00aabbcc
  59. @dylnuge Interactive Example 3 (which we’ll leave as homework)

  60. @dylnuge Shell code can continue through these (clobbered) Shell code

    (assembly code is just numbers) 0x00aabbcc Who Cares? NOP NOP, Who’s There? Even if we can execute on the stack, we might not know the exact stack pointer at the time we’re read in High 0x00aabb??
  61. @dylnuge Shell code can start here 90 90 90 90

    90 90 90 90 90 90 90 90 0x00aabbcc Who Cares? NOP NOP, Who’s There? NOP (0x90 in 32-bit x86)
 - Do nothing High 0x00aabb??
  62. @dylnuge Shell code can start here 90 90 90 90

    90 90 90 90 90 90 90 90 0x00aabbcc Who Cares? NOP NOP, Who’s There? NOP (0x90 in 32-bit x86)
 - Do nothing When we run, we jump somewhere into the NOP “sled” (hopefully) High 0x00aabb??
  63. @dylnuge Shell code can start here 90 90 90 90

    90 90 90 0x00aabbcc Who Cares? NOP NOP, Who’s There? NOP (0x90 in 32-bit x86)
 - Do nothing When we run, we jump somewhere into the NOP “sled” (hopefully) High 0x00aabb?? Image Credit: Mercury Productions
  64. @dylnuge Other
 Variables Buffer Return Pointer Frame Pointer ROP ROP

    Till You Drop OK…what if we don’t have even a guess? High Low
  65. @dylnuge Other
 Variables Buffer Return Pointer Frame Pointer ROP ROP

    Till You Drop OK…what if we don’t have even a guess? Or what if our shell code is already in the program’s text? High Low
  66. @dylnuge Other
 Variables Buffer Return Pointer Frame Pointer ROP ROP

    Till You Drop OK…what if we don’t have even a guess? Or what if our shell code is already in the program’s text? With tons of assembly in libraries, we can jump to a part of the code that wasn’t intended High Low
  67. @dylnuge ROP ROP Till You Drop Recall this (32-bit, x86)

    assembly code: b8 ff e4 00 00 mov eax,0xe4ff This is innocuous code that could appear in any library. It moves the number 58,623 into a register
  68. @dylnuge ROP ROP Till You Drop Recall this (32-bit, x86)

    assembly code: b8 ff e4 00 00 mov eax,0xe4ff This is innocuous code that could appear in any library. It moves the number 58,623 into a register But if we jump to the second byte of it, it does something very different…
  69. @dylnuge ROP ROP Till You Drop Recall this (32-bit, x86)

    assembly code: b8 ff e4 00 00 mov eax,0xe4ff This is innocuous code that could appear in any library. It moves the number 58,623 into a register But if we jump to the second byte of it, it does something very different… ff e4 jmp esp
  70. @dylnuge ROP ROP Till You Drop This is called “return

    oriented programming”
  71. @dylnuge ROP ROP Till You Drop This is called “return

    oriented programming” Segments of code in a library that can be interpreted differently when read from an offset that starts in the middle of an instruction are called “gadgets”
  72. @dylnuge ROP ROP Till You Drop This is called “return

    oriented programming” Segments of code in a library that can be interpreted differently when read from an offset that starts in the middle of an instruction are called “gadgets” The example I gave no longer works very well
  73. @dylnuge ROP ROP Till You Drop This is called “return

    oriented programming” Segments of code in a library that can be interpreted differently when read from an offset that starts in the middle of an instruction are called “gadgets” The example I gave no longer works very well But other gadgets can still be found—the sheer quantity of assembly code makes the odds high.
  74. @dylnuge Modern Prevention Modern compilers, OSes, and processors do try

    to stop you from making this mistake
  75. @dylnuge Modern Prevention Modern compilers, OSes, and processors do try

    to stop you from making this mistake Some of the ways they do this include Memory Segmentation and DEP: Preventing data sections from being executed as code
  76. @dylnuge Modern Prevention Modern compilers, OSes, and processors do try

    to stop you from making this mistake Some of the ways they do this include Memory Segmentation and DEP: Preventing data sections from being executed as code ASLR and PIE: Randomizing the memory space of the OS and the executable on load
  77. @dylnuge Modern Prevention Modern compilers, OSes, and processors do try

    to stop you from making this mistake Some of the ways they do this include Memory Segmentation and DEP: Preventing data sections from being executed as code ASLR and PIE: Randomizing the memory space of the OS and the executable on load Stack canaries: Detecting stack smashing when it happens
  78. @dylnuge Modern Examples But stack smashing and other buffer overflow

    attacks still come up all the time Kind of like code injections (e.g. SQL injection), they’re hard to kill
  79. @dylnuge Modern Examples But stack smashing and other buffer overflow

    attacks still come up all the time Kind of like code injections (e.g. SQL injection), they’re hard to kill Image Credit: xkcd 1354
  80. @dylnuge Modern Examples But stack smashing and other buffer overflow

    attacks still come up all the time Kind of like code injections (e.g. SQL injection), they’re hard to kill Image Credits: xkcd 1354, Nintendo
  81. @dylnuge Modern Examples Video Credit: SethBling (https:/ /www.youtube.com/watch?v=HxFh1CJOrTU)

  82. @dylnuge Follow Ups If you enjoyed this talk: Phrak, PoC||GTFO,

    Academic Papers DEFCON, BSides, Tech Talks, Meetups CTFs and Coding Challenges (dcdark.net, cryptopals.com, hackthebox.eu, etc) Teach Someone This! (Or something else!) Happy to take questions and discuss further any time!