Dylan Nugent
December 15, 2018
720

# 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.

## Dylan Nugent

December 15, 2018

## Transcript

Smashing?

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 buﬀer overﬂow 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

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

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 ﬁts. 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 ﬁts. 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 signiﬁcant 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

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 ﬁnd 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 ﬁnd 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

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

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 overﬂow

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 overﬂow

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 overﬂow

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

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!